@bsv/sdk
Version:
BSV Blockchain Software Development Kit
144 lines • 6.2 kB
JavaScript
;
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
const globals_1 = require("@jest/globals");
const SimplifiedFetchTransport_js_1 = require("../SimplifiedFetchTransport.js");
const Utils = __importStar(require("../../../primitives/utils.js"));
function createGeneralPayload(path = '/resource', method = 'GET') {
const writer = new Utils.Writer();
const requestId = new Array(32).fill(1);
writer.write(requestId);
const methodBytes = Utils.toArray(method, 'utf8');
writer.writeVarIntNum(methodBytes.length);
writer.write(methodBytes);
const pathBytes = Utils.toArray(path, 'utf8');
writer.writeVarIntNum(pathBytes.length);
writer.write(pathBytes);
writer.writeVarIntNum(-1); // no query string
writer.writeVarIntNum(0); // no headers
writer.writeVarIntNum(-1); // no body
return writer.toArray();
}
function createGeneralMessage(overrides = {}) {
return {
version: '1.0',
messageType: 'general',
identityKey: 'client-key',
nonce: 'client-nonce',
yourNonce: 'server-nonce',
payload: createGeneralPayload(),
signature: new Array(64).fill(0),
...overrides
};
}
afterEach(() => {
globals_1.jest.restoreAllMocks();
});
describe('SimplifiedFetchTransport send', () => {
test('wraps network failures with context', async () => {
const fetchMock = globals_1.jest.fn();
fetchMock.mockRejectedValue(new Error('network down'));
const transport = new SimplifiedFetchTransport_js_1.SimplifiedFetchTransport('https://api.example.com', fetchMock);
await transport.onData(async () => { });
const message = createGeneralMessage();
let caught;
await expect((async () => {
try {
await transport.send(message);
}
catch (error) {
caught = error;
throw error;
}
})()).rejects.toThrow('Network error while sending authenticated request to https://api.example.com/resource: network down');
expect(fetchMock).toHaveBeenCalledTimes(1);
expect(fetchMock.mock.calls[0][0]).toBe('https://api.example.com/resource');
expect(caught).toBeInstanceOf(Error);
expect(caught.cause).toBeInstanceOf(Error);
expect(caught.cause?.message).toBe('network down');
});
test('throws when server omits authentication headers', async () => {
const response = new Response('missing auth', {
status: 200,
headers: {
'Content-Type': 'text/plain'
}
});
const fetchMock = globals_1.jest.fn();
fetchMock.mockResolvedValue(response);
const transport = new SimplifiedFetchTransport_js_1.SimplifiedFetchTransport('https://api.example.com', fetchMock);
await transport.onData(async () => { });
const message = createGeneralMessage();
let thrown;
await expect((async () => {
try {
await transport.send(message);
}
catch (error) {
thrown = error;
throw error;
}
})()).rejects.toThrow('Received HTTP 200 from https://api.example.com/resource without valid BSV authentication (missing headers: x-bsv-auth-version, x-bsv-auth-identity-key, x-bsv-auth-signature)');
expect(thrown.details).toMatchObject({
url: 'https://api.example.com/resource',
status: 200,
missingHeaders: [
'x-bsv-auth-version',
'x-bsv-auth-identity-key',
'x-bsv-auth-signature'
]
});
expect(thrown.details.bodyPreview).toContain('missing auth');
});
test('rejects malformed requested certificates header', async () => {
const fetchMock = globals_1.jest.fn();
fetchMock.mockResolvedValue(new Response('', {
status: 200,
headers: {
'x-bsv-auth-version': '0.1',
'x-bsv-auth-identity-key': 'server-key',
'x-bsv-auth-signature': 'deadbeef',
'x-bsv-auth-message-type': 'general',
'x-bsv-auth-request-id': Utils.toBase64(new Array(32).fill(2)),
'x-bsv-auth-requested-certificates': 'not-json'
}
}));
const transport = new SimplifiedFetchTransport_js_1.SimplifiedFetchTransport('https://api.example.com', fetchMock);
await transport.onData(async () => { });
const message = createGeneralMessage();
await expect(transport.send(message)).rejects.toThrow('Failed to parse x-bsv-auth-requested-certificates returned by https://api.example.com/resource: not-json');
});
});
//# sourceMappingURL=SimplifiedFetchTransport.test.js.map