mirror of https://github.com/nodejs/corepack.git
87 lines
2.4 KiB
JavaScript
87 lines
2.4 KiB
JavaScript
"use strict";
|
|
const path = require(`node:path`);
|
|
const crypto = require(`node:crypto`);
|
|
const SQLite3 = require(`better-sqlite3`);
|
|
|
|
const db = new SQLite3(path.join(__dirname, `nocks.db`));
|
|
process.once(`exit`, () => {
|
|
db.close();
|
|
});
|
|
|
|
db.exec(`CREATE TABLE IF NOT EXISTS nocks (
|
|
hash BLOB PRIMARY KEY NOT NULL,
|
|
body BLOB NOT NULL,
|
|
headers BLOB NOT NULL,
|
|
status INTEGER NOT NULL
|
|
)`);
|
|
|
|
|
|
/**
|
|
* @param {string | URL} input
|
|
* @param {RequestInit | undefined} init
|
|
*/
|
|
function getRequestHash(input, init) {
|
|
const hash = crypto.createHash(`sha256`);
|
|
hash.update(`${input}\0`);
|
|
|
|
if (init) {
|
|
for (const key in init) {
|
|
if (init[key] === undefined) continue;
|
|
|
|
switch (key) {
|
|
case `headers`:
|
|
hash.update(`${JSON.stringify(Object.fromEntries(new Headers(init.headers || {})))}\0`);
|
|
break;
|
|
default:
|
|
throw new Error(`Hashing for "${key}" not implemented`);
|
|
}
|
|
}
|
|
}
|
|
|
|
return hash.digest();
|
|
}
|
|
|
|
if (process.env.NOCK_ENV === `record`) {
|
|
const insertNockStatement = db.prepare(`INSERT OR REPLACE INTO nocks (hash, body, headers, status) VALUES (?, ?, jsonb(?), ?)`);
|
|
const realFetch = globalThis.fetch;
|
|
globalThis.fetch = async (input, init) => {
|
|
const response = await realFetch(input, init);
|
|
const data = await response.arrayBuffer();
|
|
|
|
const minimalHeaders = new Headers();
|
|
for (const headerName of [`content-type`, `content-length`]) {
|
|
const headerValue = response.headers.get(headerName);
|
|
if (headerValue != null) {
|
|
minimalHeaders.set(headerName, headerValue);
|
|
}
|
|
}
|
|
|
|
const requestHash = getRequestHash(input, init);
|
|
insertNockStatement.run(
|
|
requestHash,
|
|
Buffer.from(data),
|
|
JSON.stringify(Object.fromEntries(minimalHeaders)),
|
|
response.status,
|
|
);
|
|
|
|
return new Response(data, {
|
|
status: response.status,
|
|
headers: minimalHeaders,
|
|
});
|
|
};
|
|
} else if (process.env.NOCK_ENV === `replay`) {
|
|
const getNockStatement = db.prepare(`SELECT body, json(headers) as headers, status FROM nocks WHERE hash = ?`);
|
|
|
|
globalThis.fetch = async (input, init) => {
|
|
const requestHash = getRequestHash(input, init);
|
|
|
|
const mock = getNockStatement.get(requestHash);
|
|
if (!mock) throw new Error(`No mock found for ${input}; run the tests with NOCK_ENV=record to generate one`);
|
|
|
|
return new Response(mock.body, {
|
|
status: mock.status,
|
|
headers: JSON.parse(mock.headers),
|
|
});
|
|
};
|
|
}
|