@vltpkg/registry-client 0.0.0-8 → 1.0.0-rc.1
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 +1 -1
- package/dist/esm/cache-entry.d.ts +37 -10
- package/dist/esm/cache-entry.d.ts.map +1 -1
- package/dist/esm/cache-entry.js +157 -76
- package/dist/esm/cache-entry.js.map +1 -1
- 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 +4 -4
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/index.js +72 -47
- 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 +1 -1
- package/dist/esm/revalidate.d.ts.map +1 -1
- package/dist/esm/revalidate.js +11 -5
- package/dist/esm/revalidate.js.map +1 -1
- 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 -19
package/README.md
CHANGED
|
@@ -52,7 +52,7 @@ If the response is `content-type: application/octet-stream` and starts
|
|
|
52
52
|
with the gzip header, then we return the raw body as we received it,
|
|
53
53
|
but as a best-effort background job, unzip it and update the cache
|
|
54
54
|
entry to be an unzipped response body. This is done in the
|
|
55
|
-
`@vltpkg/cache-unzip`
|
|
55
|
+
`@vltpkg/cache-unzip` child process.
|
|
56
56
|
|
|
57
57
|
So,
|
|
58
58
|
|
|
@@ -1,10 +1,23 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { ErrorCauseOptions } from '@vltpkg/error-cause';
|
|
2
2
|
import type { Integrity, JSONField } from '@vltpkg/types';
|
|
3
3
|
import ccp from 'cache-control-parser';
|
|
4
4
|
import type { InspectOptions } from 'node:util';
|
|
5
5
|
export type JSONObj = Record<string, JSONField>;
|
|
6
6
|
declare const kCustomInspect: unique symbol;
|
|
7
7
|
export type CacheEntryOptions = {
|
|
8
|
+
/**
|
|
9
|
+
* An optional body to use.
|
|
10
|
+
*
|
|
11
|
+
* This is used when decoding a cache entry from a buffer, and the body
|
|
12
|
+
* is already in a ArrayBuffer we can use. When this option is
|
|
13
|
+
* provided the `addBody` method should not be used.
|
|
14
|
+
*/
|
|
15
|
+
body?: Uint8Array;
|
|
16
|
+
/**
|
|
17
|
+
* An optional content length of the body to use, if undefined the
|
|
18
|
+
* content-length header will be used.
|
|
19
|
+
*/
|
|
20
|
+
contentLength?: number;
|
|
8
21
|
/**
|
|
9
22
|
* The expected integrity value for this response body
|
|
10
23
|
*/
|
|
@@ -37,7 +50,10 @@ export type CacheEntryOptions = {
|
|
|
37
50
|
};
|
|
38
51
|
export declare class CacheEntry {
|
|
39
52
|
#private;
|
|
40
|
-
constructor(statusCode: number, headers:
|
|
53
|
+
constructor(statusCode: number, headers: Uint8Array[], { body, integrity, trustIntegrity, 'stale-while-revalidate-factor': staleWhileRevalidateFactor, contentLength, }?: CacheEntryOptions);
|
|
54
|
+
toJSON(): {
|
|
55
|
+
[k: string]: string | number | boolean | [string, string][] | Date | ccp.CacheControl | undefined;
|
|
56
|
+
};
|
|
41
57
|
[kCustomInspect](depth: number, options: InspectOptions): string;
|
|
42
58
|
get date(): Date | undefined;
|
|
43
59
|
get maxAge(): number;
|
|
@@ -45,9 +61,16 @@ export declare class CacheEntry {
|
|
|
45
61
|
get staleWhileRevalidate(): boolean;
|
|
46
62
|
get contentType(): string;
|
|
47
63
|
get valid(): boolean;
|
|
48
|
-
|
|
64
|
+
/**
|
|
65
|
+
* Add contents to the entry body.
|
|
66
|
+
*/
|
|
67
|
+
addBody(b: Uint8Array): void;
|
|
49
68
|
get statusCode(): number;
|
|
50
|
-
get headers():
|
|
69
|
+
get headers(): Uint8Array[];
|
|
70
|
+
/**
|
|
71
|
+
* Returns the body as a single Uint8Array, concatenating parts if needed.
|
|
72
|
+
*/
|
|
73
|
+
get _body(): Uint8Array;
|
|
51
74
|
/**
|
|
52
75
|
* Check that the sri integrity string that was provided to the ctor
|
|
53
76
|
* matches the body that we actually received. This should only be called
|
|
@@ -61,7 +84,7 @@ export declare class CacheEntry {
|
|
|
61
84
|
*
|
|
62
85
|
* Returns true if anything was actually verified.
|
|
63
86
|
*/
|
|
64
|
-
checkIntegrity(context?:
|
|
87
|
+
checkIntegrity(context?: ErrorCauseOptions): this is CacheEntry & {
|
|
65
88
|
integrity: Integrity;
|
|
66
89
|
};
|
|
67
90
|
get integrityActual(): Integrity;
|
|
@@ -71,16 +94,20 @@ export declare class CacheEntry {
|
|
|
71
94
|
/**
|
|
72
95
|
* Give it a key, and it'll return the buffer of that header value
|
|
73
96
|
*/
|
|
74
|
-
getHeader(h: string):
|
|
97
|
+
getHeader(h: string): Uint8Array | undefined;
|
|
98
|
+
/**
|
|
99
|
+
* Give it a key, and it'll return the decoded string of that header value
|
|
100
|
+
*/
|
|
101
|
+
getHeaderString(h: string): string | undefined;
|
|
75
102
|
/**
|
|
76
103
|
* Set a header to a specific value
|
|
77
104
|
*/
|
|
78
|
-
setHeader(h: string, value:
|
|
105
|
+
setHeader(h: string, value: Uint8Array | string): void;
|
|
79
106
|
/**
|
|
80
107
|
* Return the body of the entry as a Buffer
|
|
81
108
|
*/
|
|
82
109
|
buffer(): Buffer;
|
|
83
|
-
get body():
|
|
110
|
+
get body(): Uint8Array | Record<string, any>;
|
|
84
111
|
get isJSON(): boolean;
|
|
85
112
|
get isGzip(): boolean;
|
|
86
113
|
/**
|
|
@@ -103,8 +130,8 @@ export declare class CacheEntry {
|
|
|
103
130
|
* and this static method will decode it into a CacheEntry representing
|
|
104
131
|
* the cached response.
|
|
105
132
|
*/
|
|
106
|
-
static decode(buffer:
|
|
107
|
-
static isGzipEntry(buffer:
|
|
133
|
+
static decode(buffer: Uint8Array): CacheEntry;
|
|
134
|
+
static isGzipEntry(buffer: Uint8Array): boolean;
|
|
108
135
|
/**
|
|
109
136
|
* Encode the entry as a single Buffer for writing to the cache
|
|
110
137
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cache-entry.d.ts","sourceRoot":"","sources":["../../src/cache-entry.ts"],"names":[],"mappings":"AAqBA,OAAO,KAAK,EAAE,
|
|
1
|
+
{"version":3,"file":"cache-entry.d.ts","sourceRoot":"","sources":["../../src/cache-entry.ts"],"names":[],"mappings":"AAqBA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAA;AAE5D,OAAO,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,eAAe,CAAA;AACzD,OAAO,GAAG,MAAM,sBAAsB,CAAA;AAEtC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,WAAW,CAAA;AAS/C,MAAM,MAAM,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAA;AAyB/C,QAAA,MAAM,cAAc,eAA2C,CAAA;AAE/D,MAAM,MAAM,iBAAiB,GAAG;IAC9B;;;;;;OAMG;IACH,IAAI,CAAC,EAAE,UAAU,CAAA;IAEjB;;;OAGG;IACH,aAAa,CAAC,EAAE,MAAM,CAAA;IAEtB;;OAEG;IACH,SAAS,CAAC,EAAE,SAAS,CAAA;IACrB;;;;;;;OAOG;IACH,cAAc,CAAC,EAAE,OAAO,CAAA;IAExB;;;;;;;;;;;;;;OAcG;IACH,+BAA+B,CAAC,EAAE,MAAM,CAAA;CACzC,CAAA;AAED,qBAAa,UAAU;;gBAsBnB,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,UAAU,EAAE,EACrB,EACE,IAAI,EACJ,SAAS,EACT,cAAsB,EACtB,+BAA+B,EAC7B,0BAA+B,EACjC,aAAa,GACd,GAAE,iBAAsB;IAwC3B,MAAM;;;IAwCN,CAAC,cAAc,CAAC,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,cAAc,GAAG,MAAM;IAShE,IAAI,IAAI,IAAI,IAAI,GAAG,SAAS,CAK3B;IAGD,IAAI,MAAM,IAAI,MAAM,CAQnB;IAGD,IAAI,YAAY,IAAI,GAAG,CAAC,YAAY,CAKnC;IAGD,IAAI,oBAAoB,IAAI,OAAO,CAWlC;IAGD,IAAI,WAAW,WAId;IAOD,IAAI,KAAK,IAAI,OAAO,CAmBnB;IAED;;OAEG;IACH,OAAO,CAAC,CAAC,EAAE,UAAU;IAcrB,IAAI,UAAU,WAEb;IACD,IAAI,OAAO,IAAI,UAAU,EAAE,CAE1B;IAED;;OAEG;IACH,IAAI,KAAK,IAAI,UAAU,CAYtB;IAED;;;;;;;;;;;;OAYG;IACH,cAAc,CACZ,OAAO,GAAE,iBAAsB,GAC9B,IAAI,IAAI,UAAU,GAAG;QAAE,SAAS,EAAE,SAAS,CAAA;KAAE;IAchD,IAAI,eAAe,IAAI,SAAS,CAO/B;IAED,IAAI,eAAe,CAAC,CAAC,EAAE,SAAS,EAG/B;IAED,IAAI,SAAS,CAAC,CAAC,EAAE,SAAS,GAAG,SAAS,EAKrC;IACD,IAAI,SAAS,IANI,SAAS,GAAG,SAAS,CAQrC;IAED;;OAEG;IACH,SAAS,CAAC,CAAC,EAAE,MAAM,GAAG,UAAU,GAAG,SAAS;IAI5C;;OAEG;IACH,eAAe,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IAO9C;;OAEG;IACH,SAAS,CAAC,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,UAAU,GAAG,MAAM;IAI/C;;OAEG;IACH,MAAM,IAAI,MAAM;IAUhB,IAAI,IAAI,IAAI,UAAU,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAE3C;IAGD,IAAI,MAAM,IAAI,OAAO,CAYpB;IAGD,IAAI,MAAM,IAAI,OAAO,CAcpB;IAED;;;;OAIG;IACH,KAAK;IAqBL;;;OAGG;IACH,IAAI;IAKJ;;OAEG;IACH,IAAI,IAAI,OAAO;IAQf;;;;OAIG;IACH,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,UAAU,GAAG,UAAU;IAuD7C,MAAM,CAAC,WAAW,CAAC,MAAM,EAAE,UAAU,GAAG,OAAO;IAO/C;;OAEG;IACH,MAAM,IAAI,MAAM;CAkDjB"}
|
package/dist/esm/cache-entry.js
CHANGED
|
@@ -24,6 +24,7 @@ import { createHash } from 'node:crypto';
|
|
|
24
24
|
import { inspect } from 'node:util';
|
|
25
25
|
import { gunzipSync } from 'node:zlib';
|
|
26
26
|
import { getRawHeader, setRawHeader } from "./raw-header.js";
|
|
27
|
+
import { getDecodedValue, getEncondedValue, } from "./string-encoding.js";
|
|
27
28
|
const readSize = (buf, offset) => {
|
|
28
29
|
const a = buf[offset];
|
|
29
30
|
const b = buf[offset + 1];
|
|
@@ -45,56 +46,87 @@ const readSize = (buf, offset) => {
|
|
|
45
46
|
const kCustomInspect = Symbol.for('nodejs.util.inspect.custom');
|
|
46
47
|
export class CacheEntry {
|
|
47
48
|
#statusCode;
|
|
49
|
+
/** The raw headers as an array of buffers */
|
|
48
50
|
#headers;
|
|
49
|
-
|
|
51
|
+
/** The body buffer, used if the content length is known. */
|
|
52
|
+
#body;
|
|
53
|
+
/**
|
|
54
|
+
* If the content length is unknown we save the body in multiple parts
|
|
55
|
+
* in order to only concatenate once at the end and save extra memory copies.
|
|
56
|
+
*/
|
|
57
|
+
#bodyParts = [];
|
|
58
|
+
/** Used to track the length of the body while reading chunks */
|
|
50
59
|
#bodyLength = 0;
|
|
60
|
+
/** The total length of the body, if known */
|
|
61
|
+
#contentLength;
|
|
51
62
|
#integrity;
|
|
52
63
|
#integrityActual;
|
|
53
64
|
#json;
|
|
54
65
|
#trustIntegrity;
|
|
55
66
|
#staleWhileRevalidateFactor;
|
|
56
|
-
constructor(statusCode, headers, { integrity, trustIntegrity = false, 'stale-while-revalidate-factor': staleWhileRevalidateFactor = 60, } = {}) {
|
|
67
|
+
constructor(statusCode, headers, { body, integrity, trustIntegrity = false, 'stale-while-revalidate-factor': staleWhileRevalidateFactor = 60, contentLength, } = {}) {
|
|
57
68
|
this.#headers = headers;
|
|
58
69
|
this.#statusCode = statusCode;
|
|
59
70
|
this.#trustIntegrity = trustIntegrity;
|
|
60
71
|
this.#staleWhileRevalidateFactor = staleWhileRevalidateFactor;
|
|
61
72
|
if (integrity)
|
|
62
73
|
this.integrity = integrity;
|
|
74
|
+
// if content-legnth is known then we'll only allocate that much memory
|
|
75
|
+
// and we'll avoid copying memory around when adding new chunks.
|
|
76
|
+
if (contentLength != null && typeof contentLength === 'number') {
|
|
77
|
+
this.#contentLength = contentLength;
|
|
78
|
+
}
|
|
79
|
+
// if a body is provided then use that, in this case the `addBody`
|
|
80
|
+
// method should no longer be used.
|
|
81
|
+
if (body) {
|
|
82
|
+
const buffer = new ArrayBuffer(body.byteLength);
|
|
83
|
+
this.#body = new Uint8Array(buffer, 0, body.byteLength);
|
|
84
|
+
this.#body.set(body, 0);
|
|
85
|
+
this.#bodyLength = body.byteLength;
|
|
86
|
+
/* c8 ignore start */
|
|
87
|
+
}
|
|
88
|
+
else if (this.#contentLength) {
|
|
89
|
+
const buffer = new ArrayBuffer(this.#contentLength);
|
|
90
|
+
this.#body = new Uint8Array(buffer, 0, this.#contentLength);
|
|
91
|
+
this.#bodyLength = 0;
|
|
92
|
+
}
|
|
93
|
+
/* c8 ignore stop */
|
|
63
94
|
}
|
|
64
95
|
get #headersAsObject() {
|
|
65
96
|
const ret = [];
|
|
66
97
|
for (let i = 0; i < this.#headers.length - 1; i += 2) {
|
|
67
|
-
const key =
|
|
68
|
-
const val =
|
|
98
|
+
const key = getDecodedValue(this.#headers[i]);
|
|
99
|
+
const val = getDecodedValue(this.#headers[i + 1]);
|
|
69
100
|
ret.push([key, val]);
|
|
70
101
|
}
|
|
71
102
|
return ret;
|
|
72
103
|
}
|
|
73
|
-
|
|
74
|
-
const
|
|
75
|
-
const isBinary = raw.includes('\x00');
|
|
76
|
-
const show = isBinary ? '[binary data]' : raw.substring(0, 512);
|
|
77
|
-
const text = !isBinary && show.length < raw.length ? raw + '…' : show;
|
|
78
|
-
const { valid, staleWhileRevalidate, cacheControl, date, contentType, } = this;
|
|
104
|
+
toJSON() {
|
|
105
|
+
const { statusCode, valid, staleWhileRevalidate, cacheControl, date, contentType, integrity, maxAge, isGzip, isJSON, } = this;
|
|
79
106
|
/* c8 ignore start */
|
|
80
107
|
const age = date ?
|
|
81
108
|
Math.floor((Date.now() - date.getTime()) / 1000)
|
|
82
109
|
: undefined;
|
|
110
|
+
const expires = date ? new Date(date.getTime() + this.maxAge * 1000) : undefined;
|
|
83
111
|
/* c8 ignore end */
|
|
84
|
-
|
|
85
|
-
statusCode
|
|
112
|
+
return Object.fromEntries(Object.entries({
|
|
113
|
+
statusCode,
|
|
86
114
|
headers: this.#headersAsObject,
|
|
87
|
-
// we know that gzip and tar data will always include at least
|
|
88
|
-
// one \x00, and json never will, so this is fine for our purpose,
|
|
89
|
-
// to avoid dumping bells and whatnot to the terminal.
|
|
90
|
-
text,
|
|
91
115
|
contentType,
|
|
116
|
+
integrity,
|
|
92
117
|
date,
|
|
118
|
+
expires,
|
|
93
119
|
cacheControl,
|
|
94
120
|
valid,
|
|
95
121
|
staleWhileRevalidate,
|
|
96
122
|
age,
|
|
97
|
-
|
|
123
|
+
maxAge,
|
|
124
|
+
isGzip,
|
|
125
|
+
isJSON,
|
|
126
|
+
}).filter(([_, v]) => v !== undefined));
|
|
127
|
+
}
|
|
128
|
+
[kCustomInspect](depth, options) {
|
|
129
|
+
const str = inspect(this.toJSON(), {
|
|
98
130
|
depth,
|
|
99
131
|
...options,
|
|
100
132
|
});
|
|
@@ -104,7 +136,7 @@ export class CacheEntry {
|
|
|
104
136
|
get date() {
|
|
105
137
|
if (this.#date)
|
|
106
138
|
return this.#date;
|
|
107
|
-
const dh = this.
|
|
139
|
+
const dh = this.getHeaderString('date');
|
|
108
140
|
if (dh)
|
|
109
141
|
this.#date = new Date(dh);
|
|
110
142
|
return this.#date;
|
|
@@ -124,7 +156,7 @@ export class CacheEntry {
|
|
|
124
156
|
get cacheControl() {
|
|
125
157
|
if (this.#cacheControl)
|
|
126
158
|
return this.#cacheControl;
|
|
127
|
-
const cc = this.
|
|
159
|
+
const cc = this.getHeaderString('cache-control');
|
|
128
160
|
this.#cacheControl = cc ? ccp.parse(cc) : {};
|
|
129
161
|
return this.#cacheControl;
|
|
130
162
|
}
|
|
@@ -144,8 +176,7 @@ export class CacheEntry {
|
|
|
144
176
|
get contentType() {
|
|
145
177
|
if (this.#contentType !== undefined)
|
|
146
178
|
return this.#contentType;
|
|
147
|
-
this.#contentType =
|
|
148
|
-
this.getHeader('content-type')?.toString() ?? '';
|
|
179
|
+
this.#contentType = this.getHeaderString('content-type') ?? '';
|
|
149
180
|
return this.#contentType;
|
|
150
181
|
}
|
|
151
182
|
/**
|
|
@@ -174,9 +205,22 @@ export class CacheEntry {
|
|
|
174
205
|
this.date.getTime() + this.maxAge * 1000 > Date.now();
|
|
175
206
|
return this.#valid;
|
|
176
207
|
}
|
|
208
|
+
/**
|
|
209
|
+
* Add contents to the entry body.
|
|
210
|
+
*/
|
|
177
211
|
addBody(b) {
|
|
178
|
-
|
|
179
|
-
|
|
212
|
+
// when the content length is uknown we store each chunk in an array that
|
|
213
|
+
// later on is concatenate into a single buffer, otherwise we just append
|
|
214
|
+
// the new chunk of bytes to the already allocated buffer keeping track
|
|
215
|
+
// of the current offset in the `this.#bodyLength` property.
|
|
216
|
+
if (!this.#body) {
|
|
217
|
+
this.#bodyParts.push(b);
|
|
218
|
+
this.#bodyLength += b.byteLength;
|
|
219
|
+
}
|
|
220
|
+
else {
|
|
221
|
+
this.#body.set(b, this.#bodyLength);
|
|
222
|
+
this.#bodyLength += b.byteLength;
|
|
223
|
+
}
|
|
180
224
|
}
|
|
181
225
|
get statusCode() {
|
|
182
226
|
return this.#statusCode;
|
|
@@ -184,6 +228,23 @@ export class CacheEntry {
|
|
|
184
228
|
get headers() {
|
|
185
229
|
return this.#headers;
|
|
186
230
|
}
|
|
231
|
+
/**
|
|
232
|
+
* Returns the body as a single Uint8Array, concatenating parts if needed.
|
|
233
|
+
*/
|
|
234
|
+
get _body() {
|
|
235
|
+
// if the body is known we'll just use that
|
|
236
|
+
if (this.#body)
|
|
237
|
+
return this.#body;
|
|
238
|
+
// otherwise we concatenate the body parts into a single buffer
|
|
239
|
+
const buffer = new ArrayBuffer(this.#bodyLength);
|
|
240
|
+
const b = new Uint8Array(buffer, 0, this.#bodyLength);
|
|
241
|
+
let off = 0;
|
|
242
|
+
for (const part of this.#bodyParts) {
|
|
243
|
+
b.set(part, off);
|
|
244
|
+
off += part.byteLength;
|
|
245
|
+
}
|
|
246
|
+
return b;
|
|
247
|
+
}
|
|
187
248
|
/**
|
|
188
249
|
* Check that the sri integrity string that was provided to the ctor
|
|
189
250
|
* matches the body that we actually received. This should only be called
|
|
@@ -215,8 +276,7 @@ export class CacheEntry {
|
|
|
215
276
|
if (this.#integrityActual)
|
|
216
277
|
return this.#integrityActual;
|
|
217
278
|
const hash = createHash('sha512');
|
|
218
|
-
|
|
219
|
-
hash.update(buf);
|
|
279
|
+
hash.update(this._body);
|
|
220
280
|
const i = `sha512-${hash.digest('base64')}`;
|
|
221
281
|
this.integrityActual = i;
|
|
222
282
|
return i;
|
|
@@ -241,6 +301,15 @@ export class CacheEntry {
|
|
|
241
301
|
getHeader(h) {
|
|
242
302
|
return getRawHeader(this.#headers, h);
|
|
243
303
|
}
|
|
304
|
+
/**
|
|
305
|
+
* Give it a key, and it'll return the decoded string of that header value
|
|
306
|
+
*/
|
|
307
|
+
getHeaderString(h) {
|
|
308
|
+
const value = getRawHeader(this.#headers, h);
|
|
309
|
+
if (value) {
|
|
310
|
+
return getDecodedValue(value);
|
|
311
|
+
}
|
|
312
|
+
}
|
|
244
313
|
/**
|
|
245
314
|
* Set a header to a specific value
|
|
246
315
|
*/
|
|
@@ -251,14 +320,7 @@ export class CacheEntry {
|
|
|
251
320
|
* Return the body of the entry as a Buffer
|
|
252
321
|
*/
|
|
253
322
|
buffer() {
|
|
254
|
-
|
|
255
|
-
if (!b)
|
|
256
|
-
return Buffer.allocUnsafe(0);
|
|
257
|
-
if (this.#body.length === 1)
|
|
258
|
-
return b;
|
|
259
|
-
const cat = Buffer.concat(this.#body, this.#bodyLength);
|
|
260
|
-
this.#body = [cat];
|
|
261
|
-
return cat;
|
|
323
|
+
return Buffer.from(this._body.buffer, this._body.byteOffset, this._body.byteLength);
|
|
262
324
|
}
|
|
263
325
|
// return the buffer if it's a tarball, or the parsed
|
|
264
326
|
// JSON if it's not.
|
|
@@ -269,7 +331,7 @@ export class CacheEntry {
|
|
|
269
331
|
get isJSON() {
|
|
270
332
|
if (this.#isJSON !== undefined)
|
|
271
333
|
return this.#isJSON;
|
|
272
|
-
const ct = this.
|
|
334
|
+
const ct = this.getHeaderString('content-type');
|
|
273
335
|
// if it says it's json, assume json
|
|
274
336
|
if (ct)
|
|
275
337
|
return (this.#isJSON = /\bjson\b/.test(ct));
|
|
@@ -287,10 +349,10 @@ export class CacheEntry {
|
|
|
287
349
|
get isGzip() {
|
|
288
350
|
if (this.#isGzip !== undefined)
|
|
289
351
|
return this.#isGzip;
|
|
290
|
-
const ce = this.
|
|
352
|
+
const ce = this.getHeaderString('content-encoding');
|
|
291
353
|
if (ce && !/\bgzip\b/.test(ce))
|
|
292
354
|
return (this.#isGzip = false);
|
|
293
|
-
const buf = this.
|
|
355
|
+
const buf = this._body;
|
|
294
356
|
if (buf.length < 2)
|
|
295
357
|
return false;
|
|
296
358
|
this.#isGzip = buf[0] === 0x1f && buf[1] === 0x8b;
|
|
@@ -313,14 +375,16 @@ export class CacheEntry {
|
|
|
313
375
|
// we know that if we know it's gzip, that the body has been
|
|
314
376
|
// flattened to a single buffer, so save the extra call.
|
|
315
377
|
/* c8 ignore start */
|
|
316
|
-
if (this
|
|
378
|
+
if (this._body.length === 0)
|
|
317
379
|
throw error('Invalid buffer, cant unzip');
|
|
318
380
|
/* c8 ignore stop */
|
|
319
|
-
const b = gunzipSync(this
|
|
381
|
+
const b = gunzipSync(this._body);
|
|
320
382
|
this.setHeader('content-encoding', 'identity');
|
|
321
|
-
|
|
322
|
-
this.#
|
|
323
|
-
this
|
|
383
|
+
const u8 = new Uint8Array(b.buffer, b.byteOffset, b.byteLength);
|
|
384
|
+
this.#body = u8;
|
|
385
|
+
this.#bodyLength = u8.byteLength;
|
|
386
|
+
this.#contentLength = u8.byteLength;
|
|
387
|
+
this.setHeader('content-length', String(this.#contentLength));
|
|
324
388
|
this.#isGzip = false;
|
|
325
389
|
return true;
|
|
326
390
|
}
|
|
@@ -332,7 +396,7 @@ export class CacheEntry {
|
|
|
332
396
|
*/
|
|
333
397
|
text() {
|
|
334
398
|
this.unzip();
|
|
335
|
-
return this.
|
|
399
|
+
return getDecodedValue(this._body);
|
|
336
400
|
}
|
|
337
401
|
/**
|
|
338
402
|
* Parse the entry body as JSON and return the result
|
|
@@ -340,7 +404,8 @@ export class CacheEntry {
|
|
|
340
404
|
json() {
|
|
341
405
|
if (this.#json !== undefined)
|
|
342
406
|
return this.#json;
|
|
343
|
-
const
|
|
407
|
+
const text = this.text();
|
|
408
|
+
const obj = JSON.parse(text || '{}');
|
|
344
409
|
this.#json = obj;
|
|
345
410
|
return obj;
|
|
346
411
|
}
|
|
@@ -357,9 +422,9 @@ export class CacheEntry {
|
|
|
357
422
|
if (buffer.length < headSize) {
|
|
358
423
|
return emptyCacheEntry;
|
|
359
424
|
}
|
|
360
|
-
const statusCode = Number(buffer.subarray(4, 7)
|
|
425
|
+
const statusCode = Number(getDecodedValue(buffer.subarray(4, 7)));
|
|
361
426
|
const headersBuffer = buffer.subarray(7, headSize);
|
|
362
|
-
// walk through the headers array, building up the rawHeaders
|
|
427
|
+
// walk through the headers array, building up the rawHeaders
|
|
363
428
|
const headers = [];
|
|
364
429
|
let i = 0;
|
|
365
430
|
let integrity = undefined;
|
|
@@ -367,20 +432,21 @@ export class CacheEntry {
|
|
|
367
432
|
const size = readSize(headersBuffer, i);
|
|
368
433
|
const val = headersBuffer.subarray(i + 4, i + size);
|
|
369
434
|
// if the last one was the key integrity, then this one is the value
|
|
370
|
-
if (headers.length % 2 === 1
|
|
371
|
-
|
|
372
|
-
|
|
435
|
+
if (headers.length % 2 === 1) {
|
|
436
|
+
const k = getDecodedValue(headers[headers.length - 1]).toLowerCase();
|
|
437
|
+
if (k === 'integrity')
|
|
438
|
+
integrity = getDecodedValue(val);
|
|
373
439
|
}
|
|
374
440
|
headers.push(val);
|
|
375
441
|
i += size;
|
|
376
442
|
}
|
|
377
443
|
const body = buffer.subarray(headSize);
|
|
378
444
|
const c = new CacheEntry(statusCode, setRawHeader(headers, 'content-length', String(body.byteLength)), {
|
|
445
|
+
body,
|
|
379
446
|
integrity,
|
|
380
447
|
trustIntegrity: true,
|
|
448
|
+
contentLength: body.byteLength,
|
|
381
449
|
});
|
|
382
|
-
c.#body = [body];
|
|
383
|
-
c.#bodyLength = body.byteLength;
|
|
384
450
|
if (c.isJSON) {
|
|
385
451
|
try {
|
|
386
452
|
c.json();
|
|
@@ -401,37 +467,52 @@ export class CacheEntry {
|
|
|
401
467
|
/**
|
|
402
468
|
* Encode the entry as a single Buffer for writing to the cache
|
|
403
469
|
*/
|
|
404
|
-
// TODO: should this maybe not concat, and just return Buffer[]?
|
|
405
|
-
// Then we can writev it to the cache file and save the memory copy
|
|
406
470
|
encode() {
|
|
407
471
|
if (this.isJSON)
|
|
408
472
|
this.json();
|
|
409
|
-
const
|
|
410
|
-
const
|
|
411
|
-
|
|
473
|
+
const statusStr = String(this.#statusCode);
|
|
474
|
+
const statusBytes = getEncondedValue(statusStr);
|
|
475
|
+
// compute headLength = 4 (length field itself) + statusBytes + Σ(4 + headerLen) for each header item
|
|
476
|
+
let headLength = 4 + statusBytes.byteLength;
|
|
477
|
+
for (const h of this.#headers)
|
|
478
|
+
headLength += 4 + h.byteLength;
|
|
479
|
+
// allocate and fill head length prefix (big-endian)
|
|
480
|
+
const headLenBytes = new Uint8Array(4);
|
|
481
|
+
headLenBytes[0] = (headLength >> 24) & 0xff;
|
|
482
|
+
headLenBytes[1] = (headLength >> 16) & 0xff;
|
|
483
|
+
headLenBytes[2] = (headLength >> 8) & 0xff;
|
|
484
|
+
headLenBytes[3] = headLength & 0xff;
|
|
485
|
+
// header chunks: [len, bytes] for each header item
|
|
486
|
+
const headerChunks = [];
|
|
412
487
|
for (const h of this.#headers) {
|
|
413
|
-
const
|
|
414
|
-
const
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
488
|
+
const l = headLenBytes.byteLength + h.byteLength;
|
|
489
|
+
const lb = new Uint8Array(4);
|
|
490
|
+
lb[0] = (l >> 24) & 0xff;
|
|
491
|
+
lb[1] = (l >> 16) & 0xff;
|
|
492
|
+
lb[2] = (l >> 8) & 0xff;
|
|
493
|
+
lb[3] = l & 0xff;
|
|
494
|
+
headerChunks.push(lb, h);
|
|
495
|
+
}
|
|
496
|
+
// total size
|
|
497
|
+
const total = headLenBytes.byteLength +
|
|
498
|
+
statusBytes.byteLength +
|
|
499
|
+
headerChunks.reduce((n, b) => n + b.byteLength, 0) +
|
|
500
|
+
this._body.byteLength;
|
|
501
|
+
// returns the concatenate buffer with all the pieces
|
|
502
|
+
const outBuffer = new ArrayBuffer(total);
|
|
503
|
+
const out = Buffer.from(outBuffer, 0, total);
|
|
504
|
+
let off = 0;
|
|
505
|
+
out.set(headLenBytes, off);
|
|
506
|
+
off += headLenBytes.byteLength;
|
|
507
|
+
out.set(statusBytes, off);
|
|
508
|
+
off += statusBytes.byteLength;
|
|
509
|
+
for (const chunk of headerChunks) {
|
|
510
|
+
out.set(chunk, off);
|
|
511
|
+
off += chunk.byteLength;
|
|
423
512
|
}
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
(headLength >> 24) & 0xff,
|
|
427
|
-
(headLength >> 16) & 0xff,
|
|
428
|
-
(headLength >> 8) & 0xff,
|
|
429
|
-
headLength & 0xff,
|
|
430
|
-
], 0);
|
|
431
|
-
chunks.unshift(hlBuf);
|
|
432
|
-
chunks.push(...this.#body);
|
|
433
|
-
return Buffer.concat(chunks, headLength + this.#bodyLength);
|
|
513
|
+
out.set(this._body, off);
|
|
514
|
+
return out;
|
|
434
515
|
}
|
|
435
516
|
}
|
|
436
|
-
const emptyCacheEntry = new CacheEntry(0, []);
|
|
517
|
+
const emptyCacheEntry = new CacheEntry(0, [], { contentLength: 0 });
|
|
437
518
|
//# sourceMappingURL=cache-entry.js.map
|