UNPKG

@dfinity/agent

Version:

JavaScript and TypeScript library to interact with the Internet Computer

130 lines 5.56 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.Expiry = exports.JSON_KEY_EXPIRY = void 0; exports.makeNonceTransform = makeNonceTransform; exports.makeExpiryTransform = makeExpiryTransform; exports.httpHeadersTransform = httpHeadersTransform; const candid_1 = require("@dfinity/candid"); const types_ts_1 = require("./types.js"); const errors_ts_1 = require("../../errors.js"); exports.JSON_KEY_EXPIRY = '__expiry__'; const NANOSECONDS_PER_MILLISECOND = BigInt(1_000_000); const NANOSECONDS_PER_SECOND = NANOSECONDS_PER_MILLISECOND * BigInt(1_000); const SECONDS_PER_MINUTE = BigInt(60); const REPLICA_PERMITTED_DRIFT_MILLISECONDS = 60 * 1000; class Expiry { constructor(__expiry__) { this.__expiry__ = __expiry__; this._isExpiry = true; } /** * Creates an Expiry object from a delta in milliseconds. * If the delta is less than 90 seconds, it is rounded to the nearest second. * Otherwise, the delta is rounded down to the nearest minute, with a * replica permitted drift subtracted. * @param deltaInMs The delta in milliseconds. * @returns {Expiry} an Expiry object */ static fromDeltaInMilliseconds(deltaInMs) { // if ingress as seconds is less than 90, round to nearest second if (deltaInMs < 90 * 1_000) { // Raw value without subtraction of REPLICA_PERMITTED_DRIFT_MILLISECONDS const raw_value = BigInt(Date.now() + deltaInMs) * NANOSECONDS_PER_MILLISECOND; const ingress_as_seconds = raw_value / NANOSECONDS_PER_SECOND; return new Expiry(ingress_as_seconds * NANOSECONDS_PER_SECOND); } // Use bigint because it can overflow the maximum number allowed in a double float. const raw_value = BigInt(Math.floor(Date.now() + deltaInMs - REPLICA_PERMITTED_DRIFT_MILLISECONDS)) * NANOSECONDS_PER_MILLISECOND; // round down to the nearest second const ingress_as_seconds = raw_value / NANOSECONDS_PER_SECOND; // round down to nearest minute const ingress_as_minutes = ingress_as_seconds / SECONDS_PER_MINUTE; const rounded_down_nanos = ingress_as_minutes * SECONDS_PER_MINUTE * NANOSECONDS_PER_SECOND; return new Expiry(rounded_down_nanos); } toBigInt() { return this.__expiry__; } toHash() { return (0, candid_1.lebEncode)(this.__expiry__); } toString() { return this.__expiry__.toString(); } /** * Serializes to JSON * @returns {JsonnableExpiry} a JSON object with a single key, {@link JSON_KEY_EXPIRY}, whose value is the expiry as a string */ toJSON() { return { [exports.JSON_KEY_EXPIRY]: this.toString() }; } /** * Deserializes a {@link JsonnableExpiry} object from a JSON string. * @param input The JSON string to deserialize. * @returns {Expiry} The deserialized Expiry object. */ static fromJSON(input) { const obj = JSON.parse(input); if (obj[exports.JSON_KEY_EXPIRY]) { try { const expiry = BigInt(obj[exports.JSON_KEY_EXPIRY]); return new Expiry(expiry); } catch (error) { throw new errors_ts_1.InputError(new errors_ts_1.ExpiryJsonDeserializeErrorCode(`Not a valid BigInt: ${error}`)); } } throw new errors_ts_1.InputError(new errors_ts_1.ExpiryJsonDeserializeErrorCode(`The input does not contain the key ${exports.JSON_KEY_EXPIRY}`)); } static isExpiry(other) { return (other instanceof Expiry || (typeof other === 'object' && other !== null && '_isExpiry' in other && other['_isExpiry'] === true && '__expiry__' in other && typeof other['__expiry__'] === 'bigint')); } } exports.Expiry = Expiry; /** * Create a Nonce transform, which takes a function that returns a Buffer, and adds it * as the nonce to every call requests. * @param nonceFn A function that returns a buffer. By default uses a semi-random method. */ function makeNonceTransform(nonceFn = types_ts_1.makeNonce) { return async (request) => { // Nonce needs to be inserted into the header for all requests, to enable logs to be correlated with requests. const headers = request.request.headers; // TODO: uncomment this when the http proxy supports it. // headers.set('X-IC-Request-ID', toHex(new Uint8Array(nonce))); request.request.headers = headers; // Nonce only needs to be inserted into the body for async calls, to prevent replay attacks. if (request.endpoint === types_ts_1.Endpoint.Call) { request.body.nonce = nonceFn(); } }; } /** * Create a transform that adds a delay (by default 5 minutes) to the expiry. * @param delayInMilliseconds The delay to add to the call time, in milliseconds. */ function makeExpiryTransform(delayInMilliseconds) { return async (request) => { request.body.ingress_expiry = Expiry.fromDeltaInMilliseconds(delayInMilliseconds); }; } /** * Maps the default fetch headers field to the serializable HttpHeaderField. * @param headers Fetch definition of the headers type * @returns array of header fields */ function httpHeadersTransform(headers) { const headerFields = []; headers.forEach((value, key) => { headerFields.push([key, value]); }); return headerFields; } //# sourceMappingURL=transforms.js.map