From baf1fa76959a40d189824765d6666e0f78115f2e Mon Sep 17 00:00:00 2001 From: Derrick Hammer Date: Wed, 20 Jul 2022 13:51:16 -0400 Subject: [PATCH] *Update builds --- bin/sandbox.d.ts | 2 + bin/sandbox.js | 16 + dist/index.d.ts | 2 +- dist/index.js | 16453 +-------------------------------------------- dist/tester.d.ts | 1 - public/tester.js | 214 +- 6 files changed, 238 insertions(+), 16450 deletions(-) create mode 100644 bin/sandbox.d.ts create mode 100644 bin/sandbox.js delete mode 100644 dist/tester.d.ts diff --git a/bin/sandbox.d.ts b/bin/sandbox.d.ts new file mode 100644 index 0000000..b798801 --- /dev/null +++ b/bin/sandbox.d.ts @@ -0,0 +1,2 @@ +#!/usr/bin/env node +export {}; diff --git a/bin/sandbox.js b/bin/sandbox.js new file mode 100644 index 0000000..b1f10e8 --- /dev/null +++ b/bin/sandbox.js @@ -0,0 +1,16 @@ +#!/usr/bin/env node +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +// @ts-ignore +const index_js_1 = require("../dist/index.js"); +const puppeteer_1 = require("puppeteer"); +let browser; +(async () => { + browser = await puppeteer_1.default.launch({ headless: false, devtools: true }); + const page = (await browser.pages()).pop(); + await (0, index_js_1.login)(page); + await (0, index_js_1.loadTester)(page); +})(); +process.on("SIGTERM", async () => { + await browser.close(); +}); diff --git a/dist/index.d.ts b/dist/index.d.ts index ddcb479..ce7d30c 100644 --- a/dist/index.d.ts +++ b/dist/index.d.ts @@ -2,7 +2,7 @@ import { Page } from "puppeteer"; import { errTuple } from "libskynet/dist"; export declare const KERNEL_TEST_SUITE = "AQCPJ9WRzMpKQHIsPo8no3XJpUydcDCjw7VJy8lG1MCZ3g"; export declare const KERNEL_HELPER_MODULE = "AQCoaLP6JexdZshDDZRQaIwN3B7DqFjlY7byMikR7u1IEA"; -export declare const TEST_KERNEL_SKLINK = "AQCw2_9rg0Fxuy8ky3pvLiDhcJTmAqthy1Buc7Frl2v2fA"; +export declare const TEST_KERNEL_SKLINK = "AQDJDoXMJiiEMBxXodQvUV89qtQHsnXWyV1ViQ9M1pMjUg"; export declare function generateSeedPhrase(): string; export declare function login(page: Page, seed?: string): Promise; export declare function loadTester(page: Page, port?: number): Promise; diff --git a/dist/index.js b/dist/index.js index 705ad2b..e3c6e3b 100644 --- a/dist/index.js +++ b/dist/index.js @@ -1,3629 +1,71 @@ -'use strict'; - -var require$$0$2 = require('path'); -var http$1 = require('node:http'); -var https = require('node:https'); -var zlib = require('node:zlib'); -var Stream = require('node:stream'); -var node_buffer = require('node:buffer'); -var node_util = require('node:util'); -var node_url = require('node:url'); -var node_net = require('node:net'); -require('node:fs'); -require('node:path'); -var require$$6 = require('crypto'); -var require$$0$3 = require('events'); -var require$$1$3 = require('util'); -var require$$2$2 = require('http'); -var require$$3 = require('url'); -var require$$1$1 = require('fs'); -var require$$1$2 = require('child_process'); -var require$$0$1 = require('os'); - -function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; } - -var require$$0__default$1 = /*#__PURE__*/_interopDefaultLegacy(require$$0$2); -var http__default = /*#__PURE__*/_interopDefaultLegacy(http$1); -var https__default = /*#__PURE__*/_interopDefaultLegacy(https); -var zlib__default = /*#__PURE__*/_interopDefaultLegacy(zlib); -var Stream__default = /*#__PURE__*/_interopDefaultLegacy(Stream); -var require$$6__default = /*#__PURE__*/_interopDefaultLegacy(require$$6); -var require$$0__default$2 = /*#__PURE__*/_interopDefaultLegacy(require$$0$3); -var require$$1__default$2 = /*#__PURE__*/_interopDefaultLegacy(require$$1$3); -var require$$2__default = /*#__PURE__*/_interopDefaultLegacy(require$$2$2); -var require$$3__default = /*#__PURE__*/_interopDefaultLegacy(require$$3); -var require$$1__default = /*#__PURE__*/_interopDefaultLegacy(require$$1$1); -var require$$1__default$1 = /*#__PURE__*/_interopDefaultLegacy(require$$1$2); -var require$$0__default = /*#__PURE__*/_interopDefaultLegacy(require$$0$1); - -var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {}; - -function getDefaultExportFromCjs (x) { - return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x; -} - -function getAugmentedNamespace(n) { - var f = n.default; - if (typeof f == "function") { - var a = function () { - return f.apply(this, arguments); - }; - a.prototype = f.prototype; - } else a = {}; - Object.defineProperty(a, '__esModule', {value: true}); - Object.keys(n).forEach(function (k) { - var d = Object.getOwnPropertyDescriptor(n, k); - Object.defineProperty(a, k, d.get ? d : { - enumerable: true, - get: function () { - return n[k]; - } - }); - }); - return a; -} - -var build = {}; - -// Blake2B, adapted from the reference implementation in RFC7693 -// Ported to Javascript by DC - https://github.com/dcposch -// Then ported to typescript by https://github.com/DavidVorick -// 64-bit unsigned addition -// Sets v[a,a+1] += v[b,b+1] -// v should be a Uint32Array -function ADD64AA(v, a, b) { - const o0 = v[a] + v[b]; - let o1 = v[a + 1] + v[b + 1]; - if (o0 >= 0x100000000) { - o1++; - } - v[a] = o0; - v[a + 1] = o1; -} -// 64-bit unsigned addition -// Sets v[a,a+1] += b -// b0 is the low 32 bits of b, b1 represents the high 32 bits -function ADD64AC(v, a, b0, b1) { - let o0 = v[a] + b0; - if (b0 < 0) { - o0 += 0x100000000; - } - let o1 = v[a + 1] + b1; - if (o0 >= 0x100000000) { - o1++; - } - v[a] = o0; - v[a + 1] = o1; -} -// Little-endian byte access -function B2B_GET32(arr, i) { - return arr[i] ^ (arr[i + 1] << 8) ^ (arr[i + 2] << 16) ^ (arr[i + 3] << 24); -} -// G Mixing function -// The ROTRs are inlined for speed -function B2B_G(a, b, c, d, ix, iy, m, v) { - const x0 = m[ix]; - const x1 = m[ix + 1]; - const y0 = m[iy]; - const y1 = m[iy + 1]; - ADD64AA(v, a, b); // v[a,a+1] += v[b,b+1] ... in JS we must store a uint64 as two uint32s - ADD64AC(v, a, x0, x1); // v[a, a+1] += x ... x0 is the low 32 bits of x, x1 is the high 32 bits - // v[d,d+1] = (v[d,d+1] xor v[a,a+1]) rotated to the right by 32 bits - let xor0 = v[d] ^ v[a]; - let xor1 = v[d + 1] ^ v[a + 1]; - v[d] = xor1; - v[d + 1] = xor0; - ADD64AA(v, c, d); - // v[b,b+1] = (v[b,b+1] xor v[c,c+1]) rotated right by 24 bits - xor0 = v[b] ^ v[c]; - xor1 = v[b + 1] ^ v[c + 1]; - v[b] = (xor0 >>> 24) ^ (xor1 << 8); - v[b + 1] = (xor1 >>> 24) ^ (xor0 << 8); - ADD64AA(v, a, b); - ADD64AC(v, a, y0, y1); - // v[d,d+1] = (v[d,d+1] xor v[a,a+1]) rotated right by 16 bits - xor0 = v[d] ^ v[a]; - xor1 = v[d + 1] ^ v[a + 1]; - v[d] = (xor0 >>> 16) ^ (xor1 << 16); - v[d + 1] = (xor1 >>> 16) ^ (xor0 << 16); - ADD64AA(v, c, d); - // v[b,b+1] = (v[b,b+1] xor v[c,c+1]) rotated right by 63 bits - xor0 = v[b] ^ v[c]; - xor1 = v[b + 1] ^ v[c + 1]; - v[b] = (xor1 >>> 31) ^ (xor0 << 1); - v[b + 1] = (xor0 >>> 31) ^ (xor1 << 1); -} -// Initialization Vector -const BLAKE2B_IV32 = new Uint32Array([ - 0xf3bcc908, 0x6a09e667, 0x84caa73b, 0xbb67ae85, 0xfe94f82b, 0x3c6ef372, 0x5f1d36f1, 0xa54ff53a, 0xade682d1, - 0x510e527f, 0x2b3e6c1f, 0x9b05688c, 0xfb41bd6b, 0x1f83d9ab, 0x137e2179, 0x5be0cd19, -]); -const SIGMA8 = [ - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3, 11, 8, 12, - 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4, 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8, 9, 0, 5, 7, 2, 4, 10, - 15, 14, 1, 11, 12, 6, 8, 3, 13, 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9, 12, 5, 1, 15, 14, 13, 4, 10, 0, - 7, 6, 3, 9, 2, 8, 11, 13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10, 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, - 1, 4, 10, 5, 10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, - 15, 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3, -]; -// These are offsets into a uint64 buffer. -// Multiply them all by 2 to make them offsets into a uint32 buffer, -// because this is Javascript and we don't have uint64s -const SIGMA82 = new Uint8Array(SIGMA8.map(function (x) { - return x * 2; -})); -// Compression function. 'last' flag indicates last block. -// Note we're representing 16 uint64s as 32 uint32s -function blake2bCompress(ctx, last) { - const v = new Uint32Array(32); - const m = new Uint32Array(32); - let i = 0; - // init work variables - for (i = 0; i < 16; i++) { - v[i] = ctx.h[i]; - v[i + 16] = BLAKE2B_IV32[i]; - } - // low 64 bits of offset - v[24] = v[24] ^ ctx.t; - v[25] = v[25] ^ (ctx.t / 0x100000000); - // high 64 bits not supported, offset may not be higher than 2**53-1 - // last block flag set ? - if (last) { - v[28] = ~v[28]; - v[29] = ~v[29]; - } - // get little-endian words - for (i = 0; i < 32; i++) { - m[i] = B2B_GET32(ctx.b, 4 * i); - } - // twelve rounds of mixing - for (i = 0; i < 12; i++) { - B2B_G(0, 8, 16, 24, SIGMA82[i * 16 + 0], SIGMA82[i * 16 + 1], m, v); - B2B_G(2, 10, 18, 26, SIGMA82[i * 16 + 2], SIGMA82[i * 16 + 3], m, v); - B2B_G(4, 12, 20, 28, SIGMA82[i * 16 + 4], SIGMA82[i * 16 + 5], m, v); - B2B_G(6, 14, 22, 30, SIGMA82[i * 16 + 6], SIGMA82[i * 16 + 7], m, v); - B2B_G(0, 10, 20, 30, SIGMA82[i * 16 + 8], SIGMA82[i * 16 + 9], m, v); - B2B_G(2, 12, 22, 24, SIGMA82[i * 16 + 10], SIGMA82[i * 16 + 11], m, v); - B2B_G(4, 14, 16, 26, SIGMA82[i * 16 + 12], SIGMA82[i * 16 + 13], m, v); - B2B_G(6, 8, 18, 28, SIGMA82[i * 16 + 14], SIGMA82[i * 16 + 15], m, v); - } - for (i = 0; i < 16; i++) { - ctx.h[i] = ctx.h[i] ^ v[i] ^ v[i + 16]; - } -} -// Creates a BLAKE2b hashing context -// Requires an output length between 1 and 64 bytes -function blake2bInit() { - // state, 'param block' - const ctx = { - b: new Uint8Array(128), - h: new Uint32Array(16), - t: 0, - c: 0, - outlen: 32, // output length in bytes - }; - // initialize hash state - for (let i = 0; i < 16; i++) { - ctx.h[i] = BLAKE2B_IV32[i]; - } - ctx.h[0] ^= 0x01010000 ^ 32; - return ctx; -} -// Updates a BLAKE2b streaming hash -// Requires hash context and Uint8Array (byte array) -function blake2bUpdate(ctx, input) { - for (let i = 0; i < input.length; i++) { - if (ctx.c === 128) { - // buffer full ? - ctx.t += ctx.c; // add counters - blake2bCompress(ctx, false); // compress (not last) - ctx.c = 0; // counter to zero - } - ctx.b[ctx.c++] = input[i]; - } -} -// Completes a BLAKE2b streaming hash -// Returns a Uint8Array containing the message digest -function blake2bFinal(ctx) { - ctx.t += ctx.c; // mark last block offset - while (ctx.c < 128) { - // fill up with zeros - ctx.b[ctx.c++] = 0; - } - blake2bCompress(ctx, true); // final block flag = 1 - // little endian convert and store - const out = new Uint8Array(ctx.outlen); - for (let i = 0; i < ctx.outlen; i++) { - out[i] = ctx.h[i >> 2] >> (8 * (i & 3)); - } - return out; -} -// Computes the blake2b hash of the input. Returns 32 bytes. -let blake2b = function (input) { - const ctx = blake2bInit(); - blake2bUpdate(ctx, input); - return blake2bFinal(ctx); -}; - -const defaultPortalList = ["https://siasky.net", "https://web3portal.com"]; - -// DICTIONARY_UNIQUE_PREFIX defines the number of characters that are -// guaranteed to be unique for each word in the dictionary. The seed code only -// looks at these three characters when parsing a word, allowing users to make -// substitutions for words if they prefer or find it easier to memorize. -const DICTIONARY_UNIQUE_PREFIX = 3; -// dictionary contains the word list for the mysky seed. -const dictionary = [ - "abbey", - "ablaze", - "abort", - "absorb", - "abyss", - "aces", - "aching", - "acidic", - "across", - "acumen", - "adapt", - "adept", - "adjust", - "adopt", - "adult", - "aerial", - "afar", - "affair", - "afield", - "afloat", - "afoot", - "afraid", - "after", - "agenda", - "agile", - "aglow", - "agony", - "agreed", - "ahead", - "aided", - "aisle", - "ajar", - "akin", - "alarms", - "album", - "alerts", - "alley", - "almost", - "aloof", - "alpine", - "also", - "alumni", - "always", - "amaze", - "ambush", - "amidst", - "ammo", - "among", - "amply", - "amused", - "anchor", - "angled", - "ankle", - "antics", - "anvil", - "apart", - "apex", - "aphid", - "aplomb", - "apply", - "archer", - "ardent", - "arena", - "argue", - "arises", - "army", - "around", - "arrow", - "ascend", - "aside", - "asked", - "asleep", - "aspire", - "asylum", - "atlas", - "atom", - "atrium", - "attire", - "auburn", - "audio", - "august", - "aunt", - "autumn", - "avatar", - "avidly", - "avoid", - "awful", - "awning", - "awoken", - "axes", - "axis", - "axle", - "aztec", - "azure", - "baby", - "bacon", - "badge", - "bailed", - "bakery", - "bamboo", - "banjo", - "basin", - "batch", - "bawled", - "bays", - "beer", - "befit", - "begun", - "behind", - "being", - "below", - "bested", - "bevel", - "beware", - "beyond", - "bias", - "bids", - "bikini", - "birth", - "bite", - "blip", - "boat", - "bodies", - "bogeys", - "boil", - "boldly", - "bomb", - "border", - "boss", - "both", - "bovine", - "boxes", - "broken", - "brunt", - "bubble", - "budget", - "buffet", - "bugs", - "bulb", - "bumper", - "bunch", - "butter", - "buying", - "buzzer", - "byline", - "bypass", - "cabin", - "cactus", - "cadets", - "cafe", - "cage", - "cajun", - "cake", - "camp", - "candy", - "casket", - "catch", - "cause", - "cease", - "cedar", - "cell", - "cement", - "cent", - "chrome", - "cider", - "cigar", - "cinema", - "circle", - "claim", - "click", - "clue", - "coal", - "cobra", - "cocoa", - "code", - "coffee", - "cogs", - "coils", - "colony", - "comb", - "cool", - "copy", - "cousin", - "cowl", - "cube", - "cuffs", - "custom", - "dads", - "daft", - "dagger", - "daily", - "damp", - "dapper", - "darted", - "dash", - "dating", - "dawn", - "dazed", - "debut", - "decay", - "deftly", - "deity", - "dented", - "depth", - "desk", - "devoid", - "dice", - "diet", - "digit", - "dilute", - "dime", - "dinner", - "diode", - "ditch", - "divers", - "dizzy", - "doctor", - "dodge", - "does", - "dogs", - "doing", - "donuts", - "dosage", - "dotted", - "double", - "dove", - "down", - "dozen", - "dreams", - "drinks", - "drunk", - "drying", - "dual", - "dubbed", - "dude", - "duets", - "duke", - "dummy", - "dunes", - "duplex", - "dusted", - "duties", - "dwarf", - "dwelt", - "dying", - "each", - "eagle", - "earth", - "easy", - "eating", - "echo", - "eden", - "edgy", - "edited", - "eels", - "eggs", - "eight", - "either", - "eject", - "elapse", - "elbow", - "eldest", - "eleven", - "elite", - "elope", - "else", - "eluded", - "emails", - "ember", - "emerge", - "emit", - "empty", - "energy", - "enigma", - "enjoy", - "enlist", - "enmity", - "enough", - "ensign", - "envy", - "epoxy", - "equip", - "erase", - "error", - "estate", - "etched", - "ethics", - "excess", - "exhale", - "exit", - "exotic", - "extra", - "exult", - "fading", - "faked", - "fall", - "family", - "fancy", - "fatal", - "faulty", - "fawns", - "faxed", - "fazed", - "feast", - "feel", - "feline", - "fences", - "ferry", - "fever", - "fewest", - "fiat", - "fibula", - "fidget", - "fierce", - "fight", - "films", - "firm", - "five", - "fixate", - "fizzle", - "fleet", - "flying", - "foamy", - "focus", - "foes", - "foggy", - "foiled", - "fonts", - "fossil", - "fowls", - "foxes", - "foyer", - "framed", - "frown", - "fruit", - "frying", - "fudge", - "fuel", - "fully", - "fuming", - "fungal", - "future", - "fuzzy", - "gables", - "gadget", - "gags", - "gained", - "galaxy", - "gambit", - "gang", - "gasp", - "gather", - "gauze", - "gave", - "gawk", - "gaze", - "gecko", - "geek", - "gels", - "germs", - "geyser", - "ghetto", - "ghost", - "giant", - "giddy", - "gifts", - "gills", - "ginger", - "girth", - "giving", - "glass", - "glide", - "gnaw", - "gnome", - "goat", - "goblet", - "goes", - "going", - "gone", - "gopher", - "gossip", - "gotten", - "gown", - "grunt", - "guest", - "guide", - "gulp", - "guru", - "gusts", - "gutter", - "guys", - "gypsy", - "gyrate", - "hairy", - "having", - "hawk", - "hazard", - "heels", - "hefty", - "height", - "hence", - "heron", - "hiding", - "hijack", - "hiker", - "hills", - "hinder", - "hippo", - "hire", - "hive", - "hoax", - "hobby", - "hockey", - "hold", - "honked", - "hookup", - "hope", - "hornet", - "hotel", - "hover", - "howls", - "huddle", - "huge", - "hull", - "humid", - "hunter", - "huts", - "hybrid", - "hyper", - "icing", - "icon", - "idiom", - "idled", - "idols", - "igloo", - "ignore", - "iguana", - "impel", - "incur", - "injury", - "inline", - "inmate", - "input", - "insult", - "invoke", - "ionic", - "irate", - "iris", - "irony", - "island", - "issued", - "itches", - "items", - "itself", - "ivory", - "jabbed", - "jaded", - "jagged", - "jailed", - "jargon", - "jaunt", - "jaws", - "jazz", - "jeans", - "jeers", - "jester", - "jewels", - "jigsaw", - "jingle", - "jive", - "jobs", - "jockey", - "jogger", - "joking", - "jolted", - "jostle", - "joyous", - "judge", - "juicy", - "july", - "jump", - "junk", - "jury", - "karate", - "keep", - "kennel", - "kept", - "kettle", - "king", - "kiosk", - "kisses", - "kiwi", - "knee", - "knife", - "koala", - "ladder", - "lagoon", - "lair", - "lakes", - "lamb", - "laptop", - "large", - "last", - "later", - "lava", - "layout", - "lazy", - "ledge", - "leech", - "left", - "legion", - "lemon", - "lesson", - "liar", - "licks", - "lids", - "lied", - "light", - "lilac", - "limits", - "linen", - "lion", - "liquid", - "listen", - "lively", - "loaded", - "locker", - "lodge", - "lofty", - "logic", - "long", - "lopped", - "losing", - "loudly", - "love", - "lower", - "loyal", - "lucky", - "lumber", - "lunar", - "lurk", - "lush", - "luxury", - "lymph", - "lynx", - "lyrics", - "macro", - "mailed", - "major", - "makeup", - "malady", - "mammal", - "maps", - "match", - "maul", - "mayor", - "maze", - "meant", - "memoir", - "menu", - "merger", - "mesh", - "metro", - "mews", - "mice", - "midst", - "mighty", - "mime", - "mirror", - "misery", - "moat", - "mobile", - "mocked", - "mohawk", - "molten", - "moment", - "money", - "moon", - "mops", - "morsel", - "mostly", - "mouth", - "mowing", - "much", - "muddy", - "muffin", - "mugged", - "mullet", - "mumble", - "muppet", - "mural", - "muzzle", - "myriad", - "myth", - "nagged", - "nail", - "names", - "nanny", - "napkin", - "nasty", - "navy", - "nearby", - "needed", - "neon", - "nephew", - "nerves", - "nestle", - "never", - "newt", - "nexus", - "nibs", - "niche", - "niece", - "nifty", - "nimbly", - "nobody", - "nodes", - "noises", - "nomad", - "noted", - "nouns", - "nozzle", - "nuance", - "nudged", - "nugget", - "null", - "number", - "nuns", - "nurse", - "nylon", - "oaks", - "oars", - "oasis", - "object", - "occur", - "ocean", - "odds", - "offend", - "often", - "okay", - "older", - "olive", - "omega", - "onion", - "online", - "onto", - "onward", - "oozed", - "opened", - "opus", - "orange", - "orbit", - "orchid", - "orders", - "organs", - "origin", - "oscar", - "otter", - "ouch", - "ought", - "ounce", - "oust", - "oval", - "oven", - "owed", - "owls", - "owner", - "oxygen", - "oyster", - "ozone", - "pact", - "pager", - "palace", - "paper", - "pastry", - "patio", - "pause", - "peeled", - "pegs", - "pencil", - "people", - "pepper", - "pests", - "petals", - "phase", - "phone", - "piano", - "picked", - "pierce", - "pimple", - "pirate", - "pivot", - "pixels", - "pizza", - "pledge", - "pliers", - "plus", - "poetry", - "point", - "poker", - "polar", - "ponies", - "pool", - "potato", - "pouch", - "powder", - "pram", - "pride", - "pruned", - "prying", - "public", - "puck", - "puddle", - "puffin", - "pulp", - "punch", - "puppy", - "purged", - "push", - "putty", - "pylons", - "python", - "queen", - "quick", - "quote", - "radar", - "rafts", - "rage", - "raking", - "rally", - "ramped", - "rapid", - "rarest", - "rash", - "rated", - "ravine", - "rays", - "razor", - "react", - "rebel", - "recipe", - "reduce", - "reef", - "refer", - "reheat", - "relic", - "remedy", - "repent", - "reruns", - "rest", - "return", - "revamp", - "rewind", - "rhino", - "rhythm", - "ribbon", - "richly", - "ridges", - "rift", - "rigid", - "rims", - "riots", - "ripped", - "rising", - "ritual", - "river", - "roared", - "robot", - "rodent", - "rogue", - "roles", - "roomy", - "roped", - "roster", - "rotate", - "rover", - "royal", - "ruby", - "rudely", - "rugged", - "ruined", - "ruling", - "rumble", - "runway", - "rural", - "sack", - "safety", - "saga", - "sailor", - "sake", - "salads", - "sample", - "sanity", - "sash", - "satin", - "saved", - "scenic", - "school", - "scoop", - "scrub", - "scuba", - "second", - "sedan", - "seeded", - "setup", - "sewage", - "sieve", - "silk", - "sipped", - "siren", - "sizes", - "skater", - "skew", - "skulls", - "slid", - "slower", - "slug", - "smash", - "smog", - "snake", - "sneeze", - "sniff", - "snout", - "snug", - "soapy", - "sober", - "soccer", - "soda", - "soggy", - "soil", - "solved", - "sonic", - "soothe", - "sorry", - "sowed", - "soya", - "space", - "speedy", - "sphere", - "spout", - "sprig", - "spud", - "spying", - "square", - "stick", - "subtly", - "suede", - "sugar", - "summon", - "sunken", - "surfer", - "sushi", - "suture", - "swept", - "sword", - "swung", - "system", - "taboo", - "tacit", - "tagged", - "tail", - "taken", - "talent", - "tamper", - "tanks", - "tasked", - "tattoo", - "taunts", - "tavern", - "tawny", - "taxi", - "tell", - "tender", - "tepid", - "tether", - "thaw", - "thorn", - "thumbs", - "thwart", - "ticket", - "tidy", - "tiers", - "tiger", - "tilt", - "timber", - "tinted", - "tipsy", - "tirade", - "tissue", - "titans", - "today", - "toffee", - "toilet", - "token", - "tonic", - "topic", - "torch", - "tossed", - "total", - "touchy", - "towel", - "toxic", - "toyed", - "trash", - "trendy", - "tribal", - "truth", - "trying", - "tubes", - "tucks", - "tudor", - "tufts", - "tugs", - "tulips", - "tunnel", - "turnip", - "tusks", - "tutor", - "tuxedo", - "twang", - "twice", - "tycoon", - "typist", - "tyrant", - "ugly", - "ulcers", - "umpire", - "uncle", - "under", - "uneven", - "unfit", - "union", - "unmask", - "unrest", - "unsafe", - "until", - "unveil", - "unwind", - "unzip", - "upbeat", - "update", - "uphill", - "upkeep", - "upload", - "upon", - "upper", - "urban", - "urgent", - "usage", - "useful", - "usher", - "using", - "usual", - "utmost", - "utopia", - "vague", - "vain", - "value", - "vane", - "vary", - "vats", - "vaults", - "vector", - "veered", - "vegan", - "vein", - "velvet", - "vessel", - "vexed", - "vials", - "victim", - "video", - "viking", - "violin", - "vipers", - "vitals", - "vivid", - "vixen", - "vocal", - "vogue", - "voice", - "vortex", - "voted", - "vowels", - "voyage", - "wade", - "waffle", - "waist", - "waking", - "wanted", - "warped", - "water", - "waxing", - "wedge", - "weird", - "went", - "wept", - "were", - "whale", - "when", - "whole", - "width", - "wield", - "wife", - "wiggle", - "wildly", - "winter", - "wiring", - "wise", - "wives", - "wizard", - "wobbly", - "woes", - "woken", - "wolf", - "woozy", - "worry", - "woven", - "wrap", - "wrist", - "wrong", - "yacht", - "yahoo", - "yanks", -]; - -var dictionary$1 = /*#__PURE__*/Object.freeze({ - __proto__: null, - DICTIONARY_UNIQUE_PREFIX: DICTIONARY_UNIQUE_PREFIX, - dictionary: dictionary -}); - -// tryStringify will try to turn the provided input into a string. If the input -// object is already a string, the input object will be returned. If the input -// object has a toString method, the toString method will be called. If that -// fails, we try to call JSON.stringify on the object. And if that fails, we -// set the return value to "[stringify failed]". -function tryStringify$1(obj) { - // Check for undefined input. - if (obj === undefined) { - return "[cannot stringify undefined input]"; - } - if (obj === null) { - return "[null]"; - } - // Parse the error into a string. - if (typeof obj === "string") { - return obj; - } - // Check if the object has a 'toString' method defined on it. To ensure - // that we don't crash or throw, check that the toString is a function, and - // also that the return value of toString is a string. - if (Object.prototype.hasOwnProperty.call(obj, "toString")) { - if (typeof obj.toString === "function") { - let str = obj.toString(); - if (typeof str === "string") { - return str; - } - } - } - // If the object does not have a custom toString, attempt to perform a - // JSON.stringify. - try { - return JSON.stringify(obj); - } - catch { - return "[stringify failed]"; - } -} - -// addContextToErr is a helper function that standardizes the formatting of -// adding context to an error. Within the world of go we discovered that being -// persistent about layering context onto errors is helpful when debugging, -// even though it often creates rather verbose error messages. -// -// addContextToErr will return null if the input err is null. -// -// NOTE: To protect against accidental situations where an Error type or some -// other type is provided instead of a string, we wrap both of the inputs with -// tryStringify before returning them. This prevents runtime failures. -function addContextToErr$1(err, context) { - if (err === null) { - err = "[no error provided]"; - } - err = tryStringify$1(err); - return tryStringify$1(context) + ": " + tryStringify$1(err); -} -// composeErr takes a series of inputs and composes them into a single string. -// Each element will be separated by a newline. If the input is not a string, -// it will be transformed into a string with JSON.stringify. -// -// Any object that cannot be stringified will be skipped, though an error will -// be logged. -function composeErr$1(...inputs) { - let result = ""; - let resultEmpty = true; - for (let i = 0; i < inputs.length; i++) { - if (inputs[i] === null) { - continue; - } - if (resultEmpty) { - resultEmpty = false; - } - else { - result += "\n"; - } - result += tryStringify$1(inputs[i]); - } - if (resultEmpty) { - return null; - } - return result; -} - -// Helper consts to make it easy to return empty values alongside errors. -const nu8$7 = new Uint8Array(0); -// b64ToBuf will take an untrusted base64 string and convert it into a -// Uin8Array, returning an error if the input is not valid base64. -function b64ToBuf(b64) { - // Check that the final string is valid base64. - let b64regex = /^[0-9a-zA-Z-_/+=]*$/; - if (!b64regex.test(b64)) { - return [nu8$7, "provided string is not valid base64"]; - } - // Swap any '-' characters for '+', and swap any '_' characters for '/' - // for use in the atob function. - b64 = b64.replace(/-/g, "+").replace(/_/g, "/"); - // Perform the conversion. - let binStr = atob(b64); - let len = binStr.length; - let buf = new Uint8Array(len); - for (let i = 0; i < len; i++) { - buf[i] = binStr.charCodeAt(i); - } - return [buf, null]; -} -// bufToHex takes a Uint8Array as input and returns the hex encoding of those -// bytes as a string. -function bufToHex(buf) { - return [...buf].map((x) => x.toString(16).padStart(2, "0")).join(""); -} -// bufToB64 will convert a Uint8Array to a base64 string with URL encoding and -// no padding characters. -function bufToB64$1(buf) { - let b64Str = btoa(String.fromCharCode.apply(null, buf)); - return b64Str.replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, ""); -} -// bufToStr takes an ArrayBuffer as input and returns a text string. bufToStr -// will check for invalid characters. -function bufToStr(buf) { - try { - let text = new TextDecoder("utf-8", { fatal: true }).decode(buf); - return [text, null]; - } - catch (err) { - return ["", addContextToErr$1(err.toString(), "unable to decode ArrayBuffer to string")]; - } -} -// decodeBigint will take an 8 byte Uint8Array and decode it as a bigint. -function decodeBigint(buf) { - if (buf.length !== 8) { - return [0n, "a number is expected to be 8 bytes"]; - } - let num = 0n; - for (let i = 7; i >= 0; i--) { - num *= 256n; - num += BigInt(buf[i]); - } - return [num, null]; -} -// encodePrefixedBytes takes a Uint8Array as input and returns a Uint8Array -// that has the length prefixed as an 8 byte prefix. The input can be at most 4 -// GiB. -function encodePrefixedBytes(bytes) { - let len = bytes.length; - if (len > 4294968295) { - return [nu8$7, "input is too large to be encoded"]; - } - let buf = new ArrayBuffer(8 + len); - let view = new DataView(buf); - view.setUint32(0, len, true); - let uint8Bytes = new Uint8Array(buf); - uint8Bytes.set(bytes, 8); - return [uint8Bytes, null]; -} -// encodeU64 will encode a bigint in the range of a uint64 to an 8 byte -// Uint8Array. -function encodeU64$1(num) { - // Check the bounds on the bigint. - if (num < 0) { - return [nu8$7, "expected a positive integer"]; - } - if (num > 18446744073709551615n) { - return [nu8$7, "expected a number no larger than a uint64"]; - } - // Encode the bigint into a Uint8Array. - let encoded = new Uint8Array(8); - for (let i = 0; i < encoded.length; i++) { - let byte = Number(num & 0xffn); - encoded[i] = byte; - num = num >> 8n; - } - return [encoded, null]; -} -// hexToBuf takes an untrusted string as input, verifies that the string is -// valid hex, and then converts the string to a Uint8Array. -function hexToBuf(hex) { - // Check that the length makes sense. - if (hex.length % 2 != 0) { - return [nu8$7, "input has incorrect length"]; - } - // Check that all of the characters are legal. - let match = /[0-9A-Fa-f]*/g; - if (!match.test(hex)) { - return [nu8$7, "input has invalid character"]; - } - // Create the buffer and fill it. - let matches = hex.match(/.{1,2}/g); - if (matches === null) { - return [nu8$7, "input is incomplete"]; - } - let u8 = new Uint8Array(matches.map((byte) => parseInt(byte, 16))); - return [u8, null]; -} - -// Helper values for cleanly returning errors. -const nu8$6 = new Uint8Array(0); -// blake2bAddSubtreeToProofStack will add a subtree to a proof stack. -function blake2bAddSubtreeToProofStack(ps, subtreeRoot, subtreeHeight) { - // Input checking. - if (subtreeRoot.length !== 32) { - return "cannot add subtree because root is wrong length"; - } - // If the proofStack has no elements in it yet, add the subtree - // with no further checks. - if (ps.subtreeRoots.length === 0) { - ps.subtreeRoots.push(subtreeRoot); - ps.subtreeHeights.push(subtreeHeight); - return null; - } - // Check the height of the new subtree against the height of the smallest - // subtree in the proofStack. If the new subtree is larger, the subtree - // cannot be added. - let maxHeight = ps.subtreeHeights[ps.subtreeHeights.length - 1]; - if (subtreeHeight > maxHeight) { - return `cannot add a subtree that is taller ${subtreeHeight} than the smallest ${maxHeight} subtree in the stack`; - } - // If the new subtreeHeight is smaller than the max height, we can just - // append the subtree height without doing anything more. - if (subtreeHeight < maxHeight) { - ps.subtreeRoots.push(subtreeRoot); - ps.subtreeHeights.push(subtreeHeight); - return null; - } - // If the new subtree is the same height as the smallest subtree, we - // have to pull the smallest subtree out, combine it with the new - // subtree, and push the result. - let oldSTR = ps.subtreeRoots.pop(); - ps.subtreeHeights.pop(); // We already have the height. - let combinedRoot = new Uint8Array(65); - combinedRoot[0] = 1; - combinedRoot.set(oldSTR, 1); - combinedRoot.set(subtreeRoot, 33); - let newSubtreeRoot = blake2b(combinedRoot); - return blake2bAddSubtreeToProofStack(ps, newSubtreeRoot, subtreeHeight + 1n); -} -// blake2bAddLeafBytesToProofStack will add a leaf to a proof stack. -function blake2bAddLeafBytesToProofStack(ps, leafBytes) { - if (leafBytes.length !== 64) { - return "proofStack expects leafByte objects to be exactly 64 bytes"; - } - let taggedBytes = new Uint8Array(65); - taggedBytes.set(leafBytes, 1); - let subtreeRoot = blake2b(taggedBytes); - return blake2bAddSubtreeToProofStack(ps, subtreeRoot, 1n); -} -// blake2bProofStackRoot returns the final Merkle root of the data in the -// current proof stack. -function blake2bProofStackRoot(ps) { - // Input checking. - if (ps.subtreeRoots.length === 0) { - return [nu8$6, "cannot compute the Merkle root of an empty data set"]; - } - // Algorithm is pretty basic, start with the final tree, and then add - // it to the previous tree. Repeat until there are no more trees. - let baseSubtreeRoot = ps.subtreeRoots.pop(); - while (ps.subtreeRoots.length !== 0) { - let nextSubtreeRoot = ps.subtreeRoots.pop(); - let combinedRoot = new Uint8Array(65); - combinedRoot[0] = 1; - combinedRoot.set(baseSubtreeRoot, 1); - combinedRoot.set(nextSubtreeRoot, 33); - baseSubtreeRoot = blake2b(combinedRoot); - } - return [baseSubtreeRoot, null]; -} -// nextSubtreeHeight returns the height of the largest subtree that contains -// 'start', contains no elements prior to 'start', and also does not contain -// 'end'. -function nextSubtreeHeight(start, end) { - // Input checking. - if (end <= start) { - return [0n, 0n, `end (${end}) must be strictly larger than start (${start})`]; - } - // Merkle trees have a nice mathematical property that the largest tree - // which contains a particular node and no nodes prior to it will have - // a height that is equal to the number of trailing zeroes in the base - // 2 representation of the index of that node. - // - // We are exploiting that property to compute the 'idealTreeHeight'. If - // 'start' is zero, the ideal tree height will just keep counting up - // forever, so we cut it off at 53. - let idealTreeHeight = 1n; - let idealTreeSize = 1n; - // The conditional inside the loop tests if the next ideal tree size is - // acceptable. If it is, we increment the height and double the size. - while (start % (idealTreeSize * 2n) === 0n) { - idealTreeHeight++; - idealTreeSize = idealTreeSize * 2n; - } - // To compute the max tree height, we essentially just find the largest - // power of 2 that is smaller than or equal to the gap between start - // and end. - let maxTreeHeight = 1n; - let maxTreeSize = 1n; - let range = end - start + 1n; - while (maxTreeSize * 2n < range) { - maxTreeHeight++; - maxTreeSize = maxTreeSize * 2n; - } - // Return the smaller of the ideal height and the max height, as each - // of them is an upper bound on how large things are allowed to be. - if (idealTreeHeight < maxTreeHeight) { - return [idealTreeHeight, idealTreeSize, null]; - } - return [maxTreeHeight, maxTreeSize, null]; -} -// blake2bMerkleRoot computes the merkle root of the provided data using a leaf -// size of 64 bytes and blake2b as the hashing function. -function blake2bMerkleRoot(data) { - // Check that the input is an acceptable length. - if (data.length % 64 !== 0) { - return [nu8$6, "cannot take the merkle root of data that is not a multiple of 64 bytes"]; - } - // Compute the Merkle root. - let ps = { - subtreeRoots: [], - subtreeHeights: [], - }; - for (let i = 0; i < data.length; i += 64) { - blake2bAddLeafBytesToProofStack(ps, data.slice(i, i + 64)); - } - return blake2bProofStackRoot(ps); -} -// blake2bVerifySectorRangeProof will verify a merkle proof that the provided -// data exists within the provided sector at the provided range. -// -// NOTE: This implementation only handles a single range, but the transition to -// doing mulit-range proofs is not very large. The main reason I didn't extend -// this function was because it made the inputs a lot messier. The Sia merkle -// tree repo uses the same techniques and has the full implementation, use that -// as a reference if you need to extend this function to support multi-range -// proofs. -function blake2bVerifySectorRangeProof(root, data, rangeStart, rangeEnd, proof) { - // Verify the inputs. - if (root.length !== 32) { - return "provided root is not a blake2b sector root"; - } - if (rangeEnd <= rangeStart) { - return "provided has no data"; - } - if (rangeStart < 0n) { - return "cannot use negative ranges"; - } - if (rangeEnd > 4194304n) { - return "range is out of bounds"; - } - if (proof.length % 32 !== 0) { - return "merkle proof has invalid length"; - } - if (data.length !== Number(rangeEnd - rangeStart)) { - return "data length does not match provided range"; - } - if (data.length % 64 !== 0) { - return "data must have a multiple of 64 bytes"; - } - // We will consume proof elements until we get to the rangeStart of the - // data. - let ps = { - subtreeRoots: [], - subtreeHeights: [], - }; - let currentOffset = 0n; - let proofOffset = 0; - while (currentOffset < rangeStart) { - if (proof.length < proofOffset + 32) { - return "merkle proof has insufficient data"; - } - let [height, size, errNST] = nextSubtreeHeight(currentOffset / 64n, rangeStart / 64n); - if (errNST !== null) { - return addContextToErr$1(errNST, "error computing subtree height of initial proof stack"); - } - let newSubtreeRoot = new Uint8Array(32); - newSubtreeRoot.set(proof.slice(proofOffset, proofOffset + 32), 0); - proofOffset += 32; - let errSPS = blake2bAddSubtreeToProofStack(ps, newSubtreeRoot, height); - if (errSPS !== null) { - return addContextToErr$1(errSPS, "error adding subtree to initial proof stack"); - } - currentOffset += size * 64n; - } - // We will consume data elements until we get to the end of the data. - let dataOffset = 0; - while (data.length > dataOffset) { - let errLBPS = blake2bAddLeafBytesToProofStack(ps, data.slice(dataOffset, dataOffset + 64)); - if (errLBPS !== null) { - return addContextToErr$1(errLBPS, "error adding leaves to proof stack"); - } - dataOffset += 64; - currentOffset += 64n; - } - // Consume proof elements until the entire sector is proven. - let sectorEnd = 4194304n; - while (currentOffset < sectorEnd) { - if (proof.length < proofOffset + 32) { - return "merkle proof has insufficient data"; - } - let [height, size, errNST] = nextSubtreeHeight(currentOffset / 64n, sectorEnd / 64n); - if (errNST !== null) { - return addContextToErr$1(errNST, "error computing subtree height of trailing proof stack"); - } - let newSubtreeRoot = new Uint8Array(32); - newSubtreeRoot.set(proof.slice(proofOffset, proofOffset + 32), 0); - proofOffset += 32; - let errSPS = blake2bAddSubtreeToProofStack(ps, newSubtreeRoot, height); - if (errSPS !== null) { - return addContextToErr$1(errSPS, "error adding subtree to trailing proof stack"); - } - currentOffset += size * 64n; - } - return null; -} - -// Helper consts to make it easier to return empty values in the event of an -// error. -const nu8$5 = new Uint8Array(0); -// verifyDownload will verify a download response from a portal. The input is -// essentially components of a skylink - the offset, length, and merkle root. -// The output is the raw file data. -// -// The 'buf' input should match the standard response body of a verified -// download request to a portal, which is the skylink raw data followed by a -// merkle proof. The offset and length provided as input indicate the offset -// and length of the skylink raw data - not the offset and length of the -// request within the file (that would be a different set of params). -// -// The skylink raw data itself breaks down into a metadata component and a file -// component. The metadata component will contain information like the length -// of the real file, and any fanout structure for large files. The first step -// we need to take is verifying the Merkel proof, which will appear at the end -// of the buffer. We'll have to hash the data we received and then compare it -// against the Merkle proof and ensure it matches the data we are expecting. -// Then we'll have to look at the layout to figure out which pieces of the data -// are the full file, while also checking for corruption as the file can be -// malicious independent of the portal operator. -// -// As long as the Merkle proof matches the root, offset, and length that we -// have as input, the portal is considered non-malicious. Any additional errors -// we find after that can be considered malice or incompetence on the part of -// the person who uploaded the file. -function verifyDownload(root, offset, fetchSize, buf) { - let u8 = new Uint8Array(buf); - // Input checking. If any of this is incorrect, its safe to blame the - // server because the skylink format fundamentally should enable these - // to be correct. - if (u8.length < fetchSize) { - return [nu8$5, true, "provided data is not large enough to cover fetchSize"]; - } - if (u8.length < 99) { - return [nu8$5, true, "provided data is not large enough to contain a skyfile"]; - } - // Grab the skylinkData and Merkle proof from the array, and then - // verify the Merkle proof. - let skylinkData = u8.slice(0, Number(fetchSize)); - let merkleProof = u8.slice(Number(fetchSize), u8.length); - let errVBSRP = blake2bVerifySectorRangeProof(root, skylinkData, offset, fetchSize, merkleProof); - if (errVBSRP !== null) { - return [nu8$5, true, addContextToErr$1(errVBSRP, "provided Merkle proof is not valid")]; - } - // Up until this point, an error indicated that the portal was at fault for - // either returning the wrong data or otherwise providing a malformed - // repsonse. The remaining checks relate to the consistency of the file - // itself, if the file is corrupt but the hash matches, there will be an - // error and the portal will not be at fault. - // The organization of the skylinkData is always: - // layoutBytes || fanoutBytes || metadataBytes || fileBytes - // - // The layout is always exactly 99 bytes. Bytes [1,8] of the layout - // contain the exact size of the fileBytes. Bytes [9, 16] of the layout - // contain the exact size of the metadata. And bytes [17,24] of the - // layout contain the exact size of the fanout. To get the offset of - // the fileData, we need to extract the sizes of the metadata and - // fanout, and then add those values to 99 to get the fileData offset. - let fileSizeBytes = skylinkData.slice(1, 9); - let mdSizeBytes = skylinkData.slice(9, 17); - let fanoutSizeBytes = skylinkData.slice(17, 25); - let [fileSize, errFSDN] = decodeBigint(fileSizeBytes); - if (errFSDN !== null) { - return [nu8$5, false, addContextToErr$1(errFSDN, "unable to decode filesize")]; - } - let [mdSize, errMDDN] = decodeBigint(mdSizeBytes); - if (errMDDN !== null) { - return [nu8$5, false, addContextToErr$1(errMDDN, "unable to decode metadata size")]; - } - let [fanoutSize, errFODN] = decodeBigint(fanoutSizeBytes); - if (errFODN !== null) { - return [nu8$5, false, addContextToErr$1(errFODN, "unable to decode fanout size")]; - } - if (BigInt(skylinkData.length) < 99n + fileSize + mdSize + fanoutSize) { - return [nu8$5, false, "provided data is too short to contain the full skyfile"]; - } - let fileData = skylinkData.slice(Number(99n + mdSize + fanoutSize), Number(99n + mdSize + fanoutSize + fileSize)); - return [fileData, false, null]; -} - -// @ts-nocheck -// json_parse extracted from the json-bigint npm library -// regexpxs extracted from -// (c) BSD-3-Clause -// https://github.com/fastify/secure-json-parse/graphs/contributors and https://github.com/hapijs/bourne/graphs/contributors -const suspectProtoRx = /(?:_|\\u005[Ff])(?:_|\\u005[Ff])(?:p|\\u0070)(?:r|\\u0072)(?:o|\\u006[Ff])(?:t|\\u0074)(?:o|\\u006[Ff])(?:_|\\u005[Ff])(?:_|\\u005[Ff])/; -const suspectConstructorRx = /(?:c|\\u0063)(?:o|\\u006[Ff])(?:n|\\u006[Ee])(?:s|\\u0073)(?:t|\\u0074)(?:r|\\u0072)(?:u|\\u0075)(?:c|\\u0063)(?:t|\\u0074)(?:o|\\u006[Ff])(?:r|\\u0072)/; -let json_parse = function (options) { - // This is a function that can parse a JSON text, producing a JavaScript - // data structure. It is a simple, recursive descent parser. It does not use - // eval or regular expressions, so it can be used as a model for implementing - // a JSON parser in other languages. - // We are defining the function inside of another function to avoid creating - // global variables. - // Default options one can override by passing options to the parse() - let _options = { - strict: false, - storeAsString: false, - alwaysParseAsBig: false, - protoAction: "error", - constructorAction: "error", - }; - // If there are options, then use them to override the default _options - if (options !== undefined && options !== null) { - if (options.strict === true) { - _options.strict = true; - } - if (options.storeAsString === true) { - _options.storeAsString = true; - } - _options.alwaysParseAsBig = options.alwaysParseAsBig === true ? options.alwaysParseAsBig : false; - if (typeof options.constructorAction !== "undefined") { - if (options.constructorAction === "error" || - options.constructorAction === "ignore" || - options.constructorAction === "preserve") { - _options.constructorAction = options.constructorAction; - } - else { - throw new Error(`Incorrect value for constructorAction option, must be "error", "ignore" or undefined but passed ${options.constructorAction}`); - } - } - if (typeof options.protoAction !== "undefined") { - if (options.protoAction === "error" || options.protoAction === "ignore" || options.protoAction === "preserve") { - _options.protoAction = options.protoAction; - } - else { - throw new Error(`Incorrect value for protoAction option, must be "error", "ignore" or undefined but passed ${options.protoAction}`); - } - } - } - let at, // The index of the current character - ch, // The current character - escapee = { - '"': '"', - "\\": "\\", - "/": "/", - b: "\b", - f: "\f", - n: "\n", - r: "\r", - t: "\t", - }, text, error = function (m) { - // Call error when something is wrong. - throw { - name: "SyntaxError", - message: m, - at: at, - text: text, - }; - }, next = function (c) { - // If a c parameter is provided, verify that it matches the current character. - if (c && c !== ch) { - error("Expected '" + c + "' instead of '" + ch + "'"); - } - // Get the next character. When there are no more characters, - // return the empty string. - ch = text.charAt(at); - at += 1; - return ch; - }, number = function () { - // Parse a number value. - let number, string = ""; - if (ch === "-") { - string = "-"; - next("-"); - } - while (ch >= "0" && ch <= "9") { - string += ch; - next(); - } - if (ch === ".") { - string += "."; - while (next() && ch >= "0" && ch <= "9") { - string += ch; - } - } - if (ch === "e" || ch === "E") { - string += ch; - next(); - if (ch === "-" || ch === "+") { - string += ch; - next(); - } - while (ch >= "0" && ch <= "9") { - string += ch; - next(); - } - } - number = +string; - if (!isFinite(number)) { - error("Bad number"); - } - else { - if (Number.isSafeInteger(number)) - return !_options.alwaysParseAsBig ? number : BigInt(number); - // Number with fractional part should be treated as number(double) including big integers in scientific notation, i.e 1.79e+308 - else - return _options.storeAsString ? string : /[.eE]/.test(string) ? number : BigInt(string); - } - }, string = function () { - // Parse a string value. - let hex, i, string = "", uffff; - // When parsing for string values, we must look for " and \ characters. - if (ch === '"') { - let startAt = at; - while (next()) { - if (ch === '"') { - if (at - 1 > startAt) - string += text.substring(startAt, at - 1); - next(); - return string; - } - if (ch === "\\") { - if (at - 1 > startAt) - string += text.substring(startAt, at - 1); - next(); - if (ch === "u") { - uffff = 0; - for (i = 0; i < 4; i += 1) { - hex = parseInt(next(), 16); - if (!isFinite(hex)) { - break; - } - uffff = uffff * 16 + hex; - } - string += String.fromCharCode(uffff); - } - else if (typeof escapee[ch] === "string") { - string += escapee[ch]; - } - else { - break; - } - startAt = at; - } - } - } - error("Bad string"); - }, white = function () { - // Skip whitespace. - while (ch && ch <= " ") { - next(); - } - }, word = function () { - // true, false, or null. - switch (ch) { - case "t": - next("t"); - next("r"); - next("u"); - next("e"); - return true; - case "f": - next("f"); - next("a"); - next("l"); - next("s"); - next("e"); - return false; - case "n": - next("n"); - next("u"); - next("l"); - next("l"); - return null; - } - error("Unexpected '" + ch + "'"); - }, value, // Place holder for the value function. - array = function () { - // Parse an array value. - let array = []; - if (ch === "[") { - next("["); - white(); - if (ch === "]") { - next("]"); - return array; // empty array - } - while (ch) { - array.push(value()); - white(); - if (ch === "]") { - next("]"); - return array; - } - next(","); - white(); - } - } - error("Bad array"); - }, object = function () { - // Parse an object value. - let key, object = Object.create(null); - if (ch === "{") { - next("{"); - white(); - if (ch === "}") { - next("}"); - return object; // empty object - } - while (ch) { - key = string(); - white(); - next(":"); - if (_options.strict === true && Object.hasOwnProperty.call(object, key)) { - error('Duplicate key "' + key + '"'); - } - if (suspectProtoRx.test(key) === true) { - if (_options.protoAction === "error") { - error("Object contains forbidden prototype property"); - } - else if (_options.protoAction === "ignore") { - value(); - } - else { - object[key] = value(); - } - } - else if (suspectConstructorRx.test(key) === true) { - if (_options.constructorAction === "error") { - error("Object contains forbidden constructor property"); - } - else if (_options.constructorAction === "ignore") { - value(); - } - else { - object[key] = value(); - } - } - else { - object[key] = value(); - } - white(); - if (ch === "}") { - next("}"); - return object; - } - next(","); - white(); - } - } - error("Bad object"); - }; - value = function () { - // Parse a JSON value. It could be an object, an array, a string, a number, - // or a word. - white(); - switch (ch) { - case "{": - return object(); - case "[": - return array(); - case '"': - return string(); - case "-": - return number(); - default: - return ch >= "0" && ch <= "9" ? number() : word(); - } - }; - // Return the json_parse function. It will have access to all of the above - // functions and variables. - return function (source, reviver) { - let result; - text = source + ""; - at = 0; - ch = " "; - result = value(); - white(); - if (ch) { - error("Syntax error"); - } - // If there is a reviver function, we recursively walk the new structure, - // passing each name/value pair to the reviver function for possible - // transformation, starting with a temporary root object that holds the result - // in an empty key. If there is not a reviver function, we simply return the - // result. - return typeof reviver === "function" - ? (function walk(holder, key) { - let v, value = holder[key]; - if (value && typeof value === "object") { - Object.keys(value).forEach(function (k) { - v = walk(value, k); - if (v !== undefined) { - value[k] = v; - } - else { - delete value[k]; - } - }); - } - return reviver.call(holder, key, value); - })({ "": result }, "") - : result; - }; -}; -// parseJSON is a wrapper for JSONbig.parse that returns an error rather than -// throwing an error. JSONbig is an alternative to JSON.parse that decodes -// every number as a bigint. This is required when working with the skyd API -// because the skyd API uses 64 bit precision for all of its numbers, and -// therefore cannot be parsed losslessly by javascript. The skyd API is -// cryptographic, therefore full precision is required. -function parseJSON(json) { - try { - let obj = json_parse({ alwaysParseAsBig: true })(json); - return [obj, null]; - } - catch (err) { - return [{}, tryStringify$1(err)]; - } -} - -// Helper consts that make it easier to return empty values when returning an -// error inside of a function. -const nu8$4 = new Uint8Array(0); -// parseSkylinkBitfield parses a skylink bitfield and returns the corresponding -// version, offset, and fetchSize. -function parseSkylinkBitfield(skylink) { - // Validate the input. - if (skylink.length !== 34) { - return [0n, 0n, 0n, "provided skylink has incorrect length"]; - } - // Extract the bitfield. - let bitfield = new DataView(skylink.buffer).getUint16(0, true); - // Extract the version. - let version = (bitfield & 3) + 1; - // Only versions 1 and 2 are recognized. - if (version !== 1 && version !== 2) { - return [0n, 0n, 0n, "provided skylink has unrecognized version"]; - } - // If the skylink is set to version 2, we only recognize the link if - // the rest of the bits in the bitfield are empty. - if (version === 2) { - if ((bitfield & 3) !== bitfield) { - return [0n, 0n, 0n, "provided skylink has unrecognized version"]; - } - return [BigInt(version), 0n, 0n, null]; - } - // Verify that the mode is valid, then fetch the mode. - bitfield = bitfield >> 2; - if ((bitfield & 255) === 255) { - return [0n, 0n, 0n, "provided skylink has an unrecognized version"]; - } - let mode = 0; - for (let i = 0; i < 8; i++) { - if ((bitfield & 1) === 0) { - bitfield = bitfield >> 1; - break; - } - bitfield = bitfield >> 1; - mode++; - } - // If the mode is greater than 7, this is not a valid v1 skylink. - if (mode > 7) { - return [0n, 0n, 0n, "provided skylink has an invalid v1 bitfield"]; - } - // Determine the offset and fetchSize increment. - let offsetIncrement = 4096 << mode; - let fetchSizeIncrement = 4096; - let fetchSizeStart = 0; - if (mode > 0) { - fetchSizeIncrement = fetchSizeIncrement << (mode - 1); - fetchSizeStart = (1 << 15) << (mode - 1); - } - // The next three bits decide the fetchSize. - let fetchSizeBits = bitfield & 7; - fetchSizeBits++; // semantic upstep, range should be [1,8] not [0,8). - let fetchSize = fetchSizeBits * fetchSizeIncrement + fetchSizeStart; - bitfield = bitfield >> 3; - // The remaining bits determine the offset. - let offset = bitfield * offsetIncrement; - if (offset + fetchSize > 1 << 22) { - return [0n, 0n, 0n, "provided skylink has an invalid v1 bitfield"]; - } - // Return what we learned. - return [BigInt(version), BigInt(offset), BigInt(fetchSize), null]; -} -// skylinkV1Bitfield sets the bitfield of a V1 skylink. It assumes the version -// is 1 and the offset is 0. It will determine the appropriate fetchSize from -// the provided dataSize. -function skylinkV1Bitfield(dataSizeBI) { - // Check that the dataSize is not too large. - if (dataSizeBI > 1 << 22) { - return [nu8$4, "dataSize must be less than the sector size"]; - } - let dataSize = Number(dataSizeBI); - // Determine the mode for the file. The mode is determined by the - // dataSize. - let mode = 0; - for (let i = 1 << 15; i < dataSize; i *= 2) { - mode += 1; - } - // Determine the download number. - let downloadNumber = 0; - if (mode === 0) { - if (dataSize !== 0) { - downloadNumber = Math.floor((dataSize - 1) / (1 << 12)); - } - } - else { - let step = 1 << (11 + mode); - let target = dataSize - (1 << (14 + mode)); - if (target !== 0) { - downloadNumber = Math.floor((target - 1) / step); - } - } - // Create the Uint8Array and fill it out. The main reason I switch over - // the 7 modes like this is because I wasn't sure how to make a uint16 - // in javascript. If we could treat the uint8array as a uint16 and then - // later convert it over, we could use basic bitshifiting and really - // simplify the code here. - let bitfield = new Uint8Array(2); - if (mode === 7) { - // 0 0 0 X X X 0 1|1 1 1 1 1 1 0 0 - bitfield[0] = downloadNumber; - bitfield[0] *= 4; - bitfield[0] += 1; - bitfield[1] = 4 + 8 + 16 + 32 + 64 + 128; - } - if (mode === 6) { - // 0 0 0 0 X X X 0|1 1 1 1 1 1 0 0 - bitfield[0] = downloadNumber; - bitfield[0] *= 2; - bitfield[1] = 4 + 8 + 16 + 32 + 64 + 128; - } - if (mode === 5) { - // 0 0 0 0 0 X X X|0 1 1 1 1 1 0 0 - bitfield[0] = downloadNumber; - bitfield[1] = 4 + 8 + 16 + 32 + 64; - } - if (mode === 4) { - // 0 0 0 0 0 0 X X|X 0 1 1 1 1 0 0 - bitfield[0] = downloadNumber; - bitfield[0] /= 2; - bitfield[1] = (downloadNumber & 1) * 128; - bitfield[1] += 4 + 8 + 16 + 32; - } - if (mode === 3) { - // 0 0 0 0 0 0 0 X|X X 0 1 1 1 0 0 - bitfield[0] = downloadNumber; - bitfield[0] /= 4; - bitfield[1] = (downloadNumber & 3) * 64; - bitfield[1] += 4 + 8 + 16; - } - if (mode === 2) { - // 0 0 0 0 0 0 0 0|X X X 0 1 1 0 0 - bitfield[0] = 0; - bitfield[1] = downloadNumber * 32; - bitfield[1] += 4 + 8; - } - if (mode === 1) { - // 0 0 0 0 0 0 0 0|0 X X X 0 1 0 0 - bitfield[0] = 0; - bitfield[1] = downloadNumber * 16; - bitfield[1] += 4; - } - if (mode === 0) { - // 0 0 0 0 0 0 0 0|0 0 X X X 0 0 0 - bitfield[0] = 0; - bitfield[1] = downloadNumber * 8; - } - // Swap the byte order. - let zero = bitfield[0]; - bitfield[0] = bitfield[1]; - bitfield[1] = zero; - return [bitfield, null]; -} - -const HASH_SIZE = 64; -const K = [ - 0x428a2f98, 0xd728ae22, 0x71374491, 0x23ef65cd, 0xb5c0fbcf, 0xec4d3b2f, 0xe9b5dba5, 0x8189dbbc, 0x3956c25b, - 0xf348b538, 0x59f111f1, 0xb605d019, 0x923f82a4, 0xaf194f9b, 0xab1c5ed5, 0xda6d8118, 0xd807aa98, 0xa3030242, - 0x12835b01, 0x45706fbe, 0x243185be, 0x4ee4b28c, 0x550c7dc3, 0xd5ffb4e2, 0x72be5d74, 0xf27b896f, 0x80deb1fe, - 0x3b1696b1, 0x9bdc06a7, 0x25c71235, 0xc19bf174, 0xcf692694, 0xe49b69c1, 0x9ef14ad2, 0xefbe4786, 0x384f25e3, - 0x0fc19dc6, 0x8b8cd5b5, 0x240ca1cc, 0x77ac9c65, 0x2de92c6f, 0x592b0275, 0x4a7484aa, 0x6ea6e483, 0x5cb0a9dc, - 0xbd41fbd4, 0x76f988da, 0x831153b5, 0x983e5152, 0xee66dfab, 0xa831c66d, 0x2db43210, 0xb00327c8, 0x98fb213f, - 0xbf597fc7, 0xbeef0ee4, 0xc6e00bf3, 0x3da88fc2, 0xd5a79147, 0x930aa725, 0x06ca6351, 0xe003826f, 0x14292967, - 0x0a0e6e70, 0x27b70a85, 0x46d22ffc, 0x2e1b2138, 0x5c26c926, 0x4d2c6dfc, 0x5ac42aed, 0x53380d13, 0x9d95b3df, - 0x650a7354, 0x8baf63de, 0x766a0abb, 0x3c77b2a8, 0x81c2c92e, 0x47edaee6, 0x92722c85, 0x1482353b, 0xa2bfe8a1, - 0x4cf10364, 0xa81a664b, 0xbc423001, 0xc24b8b70, 0xd0f89791, 0xc76c51a3, 0x0654be30, 0xd192e819, 0xd6ef5218, - 0xd6990624, 0x5565a910, 0xf40e3585, 0x5771202a, 0x106aa070, 0x32bbd1b8, 0x19a4c116, 0xb8d2d0c8, 0x1e376c08, - 0x5141ab53, 0x2748774c, 0xdf8eeb99, 0x34b0bcb5, 0xe19b48a8, 0x391c0cb3, 0xc5c95a63, 0x4ed8aa4a, 0xe3418acb, - 0x5b9cca4f, 0x7763e373, 0x682e6ff3, 0xd6b2b8a3, 0x748f82ee, 0x5defb2fc, 0x78a5636f, 0x43172f60, 0x84c87814, - 0xa1f0ab72, 0x8cc70208, 0x1a6439ec, 0x90befffa, 0x23631e28, 0xa4506ceb, 0xde82bde9, 0xbef9a3f7, 0xb2c67915, - 0xc67178f2, 0xe372532b, 0xca273ece, 0xea26619c, 0xd186b8c7, 0x21c0c207, 0xeada7dd6, 0xcde0eb1e, 0xf57d4f7f, - 0xee6ed178, 0x06f067aa, 0x72176fba, 0x0a637dc5, 0xa2c898a6, 0x113f9804, 0xbef90dae, 0x1b710b35, 0x131c471b, - 0x28db77f5, 0x23047d84, 0x32caab7b, 0x40c72493, 0x3c9ebe0a, 0x15c9bebc, 0x431d67c4, 0x9c100d4c, 0x4cc5d4be, - 0xcb3e42b6, 0x597f299c, 0xfc657e2a, 0x5fcb6fab, 0x3ad6faec, 0x6c44198c, 0x4a475817, -]; -function ts64(x, i, h, l) { - x[i] = (h >> 24) & 0xff; - x[i + 1] = (h >> 16) & 0xff; - x[i + 2] = (h >> 8) & 0xff; - x[i + 3] = h & 0xff; - x[i + 4] = (l >> 24) & 0xff; - x[i + 5] = (l >> 16) & 0xff; - x[i + 6] = (l >> 8) & 0xff; - x[i + 7] = l & 0xff; -} -function crypto_hashblocks_hl(hh, hl, m, n) { - let wh = new Int32Array(16), wl = new Int32Array(16), bh0, bh1, bh2, bh3, bh4, bh5, bh6, bh7, bl0, bl1, bl2, bl3, bl4, bl5, bl6, bl7, th, tl, i, j, h, l, a, b, c, d; - let ah0 = hh[0], ah1 = hh[1], ah2 = hh[2], ah3 = hh[3], ah4 = hh[4], ah5 = hh[5], ah6 = hh[6], ah7 = hh[7], al0 = hl[0], al1 = hl[1], al2 = hl[2], al3 = hl[3], al4 = hl[4], al5 = hl[5], al6 = hl[6], al7 = hl[7]; - let pos = 0; - while (n >= 128) { - for (i = 0; i < 16; i++) { - j = 8 * i + pos; - wh[i] = (m[j + 0] << 24) | (m[j + 1] << 16) | (m[j + 2] << 8) | m[j + 3]; - wl[i] = (m[j + 4] << 24) | (m[j + 5] << 16) | (m[j + 6] << 8) | m[j + 7]; - } - for (i = 0; i < 80; i++) { - bh0 = ah0; - bh1 = ah1; - bh2 = ah2; - bh3 = ah3; - bh4 = ah4; - bh5 = ah5; - bh6 = ah6; - bh7 = ah7; - bl0 = al0; - bl1 = al1; - bl2 = al2; - bl3 = al3; - bl4 = al4; - bl5 = al5; - bl6 = al6; - bl7 = al7; - // add - h = ah7; - l = al7; - a = l & 0xffff; - b = l >>> 16; - c = h & 0xffff; - d = h >>> 16; - // Sigma1 - h = - ((ah4 >>> 14) | (al4 << (32 - 14))) ^ - ((ah4 >>> 18) | (al4 << (32 - 18))) ^ - ((al4 >>> (41 - 32)) | (ah4 << (32 - (41 - 32)))); - l = - ((al4 >>> 14) | (ah4 << (32 - 14))) ^ - ((al4 >>> 18) | (ah4 << (32 - 18))) ^ - ((ah4 >>> (41 - 32)) | (al4 << (32 - (41 - 32)))); - a += l & 0xffff; - b += l >>> 16; - c += h & 0xffff; - d += h >>> 16; - // Ch - h = (ah4 & ah5) ^ (~ah4 & ah6); - l = (al4 & al5) ^ (~al4 & al6); - a += l & 0xffff; - b += l >>> 16; - c += h & 0xffff; - d += h >>> 16; - // K - h = K[i * 2]; - l = K[i * 2 + 1]; - a += l & 0xffff; - b += l >>> 16; - c += h & 0xffff; - d += h >>> 16; - // w - h = wh[i % 16]; - l = wl[i % 16]; - a += l & 0xffff; - b += l >>> 16; - c += h & 0xffff; - d += h >>> 16; - b += a >>> 16; - c += b >>> 16; - d += c >>> 16; - th = (c & 0xffff) | (d << 16); - tl = (a & 0xffff) | (b << 16); - // add - h = th; - l = tl; - a = l & 0xffff; - b = l >>> 16; - c = h & 0xffff; - d = h >>> 16; - // Sigma0 - h = - ((ah0 >>> 28) | (al0 << (32 - 28))) ^ - ((al0 >>> (34 - 32)) | (ah0 << (32 - (34 - 32)))) ^ - ((al0 >>> (39 - 32)) | (ah0 << (32 - (39 - 32)))); - l = - ((al0 >>> 28) | (ah0 << (32 - 28))) ^ - ((ah0 >>> (34 - 32)) | (al0 << (32 - (34 - 32)))) ^ - ((ah0 >>> (39 - 32)) | (al0 << (32 - (39 - 32)))); - a += l & 0xffff; - b += l >>> 16; - c += h & 0xffff; - d += h >>> 16; - // Maj - h = (ah0 & ah1) ^ (ah0 & ah2) ^ (ah1 & ah2); - l = (al0 & al1) ^ (al0 & al2) ^ (al1 & al2); - a += l & 0xffff; - b += l >>> 16; - c += h & 0xffff; - d += h >>> 16; - b += a >>> 16; - c += b >>> 16; - d += c >>> 16; - bh7 = (c & 0xffff) | (d << 16); - bl7 = (a & 0xffff) | (b << 16); - // add - h = bh3; - l = bl3; - a = l & 0xffff; - b = l >>> 16; - c = h & 0xffff; - d = h >>> 16; - h = th; - l = tl; - a += l & 0xffff; - b += l >>> 16; - c += h & 0xffff; - d += h >>> 16; - b += a >>> 16; - c += b >>> 16; - d += c >>> 16; - bh3 = (c & 0xffff) | (d << 16); - bl3 = (a & 0xffff) | (b << 16); - ah1 = bh0; - ah2 = bh1; - ah3 = bh2; - ah4 = bh3; - ah5 = bh4; - ah6 = bh5; - ah7 = bh6; - ah0 = bh7; - al1 = bl0; - al2 = bl1; - al3 = bl2; - al4 = bl3; - al5 = bl4; - al6 = bl5; - al7 = bl6; - al0 = bl7; - if (i % 16 === 15) { - for (j = 0; j < 16; j++) { - // add - h = wh[j]; - l = wl[j]; - a = l & 0xffff; - b = l >>> 16; - c = h & 0xffff; - d = h >>> 16; - h = wh[(j + 9) % 16]; - l = wl[(j + 9) % 16]; - a += l & 0xffff; - b += l >>> 16; - c += h & 0xffff; - d += h >>> 16; - // sigma0 - th = wh[(j + 1) % 16]; - tl = wl[(j + 1) % 16]; - h = ((th >>> 1) | (tl << (32 - 1))) ^ ((th >>> 8) | (tl << (32 - 8))) ^ (th >>> 7); - l = ((tl >>> 1) | (th << (32 - 1))) ^ ((tl >>> 8) | (th << (32 - 8))) ^ ((tl >>> 7) | (th << (32 - 7))); - a += l & 0xffff; - b += l >>> 16; - c += h & 0xffff; - d += h >>> 16; - // sigma1 - th = wh[(j + 14) % 16]; - tl = wl[(j + 14) % 16]; - h = ((th >>> 19) | (tl << (32 - 19))) ^ ((tl >>> (61 - 32)) | (th << (32 - (61 - 32)))) ^ (th >>> 6); - l = - ((tl >>> 19) | (th << (32 - 19))) ^ - ((th >>> (61 - 32)) | (tl << (32 - (61 - 32)))) ^ - ((tl >>> 6) | (th << (32 - 6))); - a += l & 0xffff; - b += l >>> 16; - c += h & 0xffff; - d += h >>> 16; - b += a >>> 16; - c += b >>> 16; - d += c >>> 16; - wh[j] = (c & 0xffff) | (d << 16); - wl[j] = (a & 0xffff) | (b << 16); - } - } - } - // add - h = ah0; - l = al0; - a = l & 0xffff; - b = l >>> 16; - c = h & 0xffff; - d = h >>> 16; - h = hh[0]; - l = hl[0]; - a += l & 0xffff; - b += l >>> 16; - c += h & 0xffff; - d += h >>> 16; - b += a >>> 16; - c += b >>> 16; - d += c >>> 16; - hh[0] = ah0 = (c & 0xffff) | (d << 16); - hl[0] = al0 = (a & 0xffff) | (b << 16); - h = ah1; - l = al1; - a = l & 0xffff; - b = l >>> 16; - c = h & 0xffff; - d = h >>> 16; - h = hh[1]; - l = hl[1]; - a += l & 0xffff; - b += l >>> 16; - c += h & 0xffff; - d += h >>> 16; - b += a >>> 16; - c += b >>> 16; - d += c >>> 16; - hh[1] = ah1 = (c & 0xffff) | (d << 16); - hl[1] = al1 = (a & 0xffff) | (b << 16); - h = ah2; - l = al2; - a = l & 0xffff; - b = l >>> 16; - c = h & 0xffff; - d = h >>> 16; - h = hh[2]; - l = hl[2]; - a += l & 0xffff; - b += l >>> 16; - c += h & 0xffff; - d += h >>> 16; - b += a >>> 16; - c += b >>> 16; - d += c >>> 16; - hh[2] = ah2 = (c & 0xffff) | (d << 16); - hl[2] = al2 = (a & 0xffff) | (b << 16); - h = ah3; - l = al3; - a = l & 0xffff; - b = l >>> 16; - c = h & 0xffff; - d = h >>> 16; - h = hh[3]; - l = hl[3]; - a += l & 0xffff; - b += l >>> 16; - c += h & 0xffff; - d += h >>> 16; - b += a >>> 16; - c += b >>> 16; - d += c >>> 16; - hh[3] = ah3 = (c & 0xffff) | (d << 16); - hl[3] = al3 = (a & 0xffff) | (b << 16); - h = ah4; - l = al4; - a = l & 0xffff; - b = l >>> 16; - c = h & 0xffff; - d = h >>> 16; - h = hh[4]; - l = hl[4]; - a += l & 0xffff; - b += l >>> 16; - c += h & 0xffff; - d += h >>> 16; - b += a >>> 16; - c += b >>> 16; - d += c >>> 16; - hh[4] = ah4 = (c & 0xffff) | (d << 16); - hl[4] = al4 = (a & 0xffff) | (b << 16); - h = ah5; - l = al5; - a = l & 0xffff; - b = l >>> 16; - c = h & 0xffff; - d = h >>> 16; - h = hh[5]; - l = hl[5]; - a += l & 0xffff; - b += l >>> 16; - c += h & 0xffff; - d += h >>> 16; - b += a >>> 16; - c += b >>> 16; - d += c >>> 16; - hh[5] = ah5 = (c & 0xffff) | (d << 16); - hl[5] = al5 = (a & 0xffff) | (b << 16); - h = ah6; - l = al6; - a = l & 0xffff; - b = l >>> 16; - c = h & 0xffff; - d = h >>> 16; - h = hh[6]; - l = hl[6]; - a += l & 0xffff; - b += l >>> 16; - c += h & 0xffff; - d += h >>> 16; - b += a >>> 16; - c += b >>> 16; - d += c >>> 16; - hh[6] = ah6 = (c & 0xffff) | (d << 16); - hl[6] = al6 = (a & 0xffff) | (b << 16); - h = ah7; - l = al7; - a = l & 0xffff; - b = l >>> 16; - c = h & 0xffff; - d = h >>> 16; - h = hh[7]; - l = hl[7]; - a += l & 0xffff; - b += l >>> 16; - c += h & 0xffff; - d += h >>> 16; - b += a >>> 16; - c += b >>> 16; - d += c >>> 16; - hh[7] = ah7 = (c & 0xffff) | (d << 16); - hl[7] = al7 = (a & 0xffff) | (b << 16); - pos += 128; - n -= 128; - } - return n; -} -const sha512internal = function (out, m, n) { - let hh = new Int32Array(8), hl = new Int32Array(8), x = new Uint8Array(256), i, b = n; - hh[0] = 0x6a09e667; - hh[1] = 0xbb67ae85; - hh[2] = 0x3c6ef372; - hh[3] = 0xa54ff53a; - hh[4] = 0x510e527f; - hh[5] = 0x9b05688c; - hh[6] = 0x1f83d9ab; - hh[7] = 0x5be0cd19; - hl[0] = 0xf3bcc908; - hl[1] = 0x84caa73b; - hl[2] = 0xfe94f82b; - hl[3] = 0x5f1d36f1; - hl[4] = 0xade682d1; - hl[5] = 0x2b3e6c1f; - hl[6] = 0xfb41bd6b; - hl[7] = 0x137e2179; - crypto_hashblocks_hl(hh, hl, m, n); - n %= 128; - for (i = 0; i < n; i++) - x[i] = m[b - n + i]; - x[n] = 128; - n = 256 - 128 * (n < 112 ? 1 : 0); - x[n - 9] = 0; - ts64(x, n - 8, (b / 0x20000000) | 0, b << 3); - crypto_hashblocks_hl(hh, hl, x, n); - for (i = 0; i < 8; i++) - ts64(out, 8 * i, hh[i], hl[i]); - return 0; -}; -// sha512 is the standard sha512 cryptographic hash function. This is the -// default choice for Skynet operations, though many of the Sia protocol -// standards use blake2b instead, so you will see both. -function sha512(m) { - const out = new Uint8Array(HASH_SIZE); - sha512internal(out, m, m.length); - return out; -} - -let crypto_sign_BYTES = 64, crypto_sign_PUBLICKEYBYTES = 32, crypto_sign_SECRETKEYBYTES = 64, crypto_sign_SEEDBYTES = 32; -let gf = function () { - let r = new Float64Array(16); - return r; -}; -let gfi$1 = function (init) { - let i, r = new Float64Array(16); - if (init) - for (i = 0; i < init.length; i++) - r[i] = init[i]; - return r; -}; -let gf0 = gf(), gf1 = gfi$1([1]), D = gfi$1([ - 0x78a3, 0x1359, 0x4dca, 0x75eb, 0xd8ab, 0x4141, 0x0a4d, 0x0070, 0xe898, 0x7779, 0x4079, 0x8cc7, 0xfe73, 0x2b6f, - 0x6cee, 0x5203, -]), D2 = gfi$1([ - 0xf159, 0x26b2, 0x9b94, 0xebd6, 0xb156, 0x8283, 0x149a, 0x00e0, 0xd130, 0xeef3, 0x80f2, 0x198e, 0xfce7, 0x56df, - 0xd9dc, 0x2406, -]), X = gfi$1([ - 0xd51a, 0x8f25, 0x2d60, 0xc956, 0xa7b2, 0x9525, 0xc760, 0x692c, 0xdc5c, 0xfdd6, 0xe231, 0xc0a4, 0x53fe, 0xcd6e, - 0x36d3, 0x2169, -]), Y = gfi$1([ - 0x6658, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, - 0x6666, 0x6666, -]), I = gfi$1([ - 0xa0b0, 0x4a0e, 0x1b27, 0xc4ee, 0xe478, 0xad2f, 0x1806, 0x2f43, 0xd7a7, 0x3dfb, 0x0099, 0x2b4d, 0xdf0b, 0x4fc1, - 0x2480, 0x2b83, -]); -function vn(x, xi, y, yi, n) { - let i, d = 0; - for (i = 0; i < n; i++) - d |= x[xi + i] ^ y[yi + i]; - return (1 & ((d - 1) >>> 8)) - 1; -} -function crypto_verify_32(x, xi, y, yi) { - return vn(x, xi, y, yi, 32); -} -function set25519(r, a) { - let i; - for (i = 0; i < 16; i++) - r[i] = a[i] | 0; -} -function car25519(o) { - let i, v, c = 1; - for (i = 0; i < 16; i++) { - v = o[i] + c + 65535; - c = Math.floor(v / 65536); - o[i] = v - c * 65536; - } - o[0] += c - 1 + 37 * (c - 1); -} -function sel25519(p, q, b) { - let t, c = ~(b - 1); - for (let i = 0; i < 16; i++) { - t = c & (p[i] ^ q[i]); - p[i] ^= t; - q[i] ^= t; - } -} -function pack25519(o, n) { - let i, j, b; - let m = gf(), t = gf(); - for (i = 0; i < 16; i++) - t[i] = n[i]; - car25519(t); - car25519(t); - car25519(t); - for (j = 0; j < 2; j++) { - m[0] = t[0] - 0xffed; - for (i = 1; i < 15; i++) { - m[i] = t[i] - 0xffff - ((m[i - 1] >> 16) & 1); - m[i - 1] &= 0xffff; - } - m[15] = t[15] - 0x7fff - ((m[14] >> 16) & 1); - b = (m[15] >> 16) & 1; - m[14] &= 0xffff; - sel25519(t, m, 1 - b); - } - for (i = 0; i < 16; i++) { - o[2 * i] = t[i] & 0xff; - o[2 * i + 1] = t[i] >> 8; - } -} -function neq25519(a, b) { - let c = new Uint8Array(32), d = new Uint8Array(32); - pack25519(c, a); - pack25519(d, b); - return crypto_verify_32(c, 0, d, 0); -} -function par25519(a) { - let d = new Uint8Array(32); - pack25519(d, a); - return d[0] & 1; -} -function unpack25519(o, n) { - let i; - for (i = 0; i < 16; i++) - o[i] = n[2 * i] + (n[2 * i + 1] << 8); - o[15] &= 0x7fff; -} -function A$1(o, a, b) { - for (let i = 0; i < 16; i++) - o[i] = a[i] + b[i]; -} -function Z$1(o, a, b) { - for (let i = 0; i < 16; i++) - o[i] = a[i] - b[i]; -} -function M(o, a, b) { - let v, c, t0 = 0, t1 = 0, t2 = 0, t3 = 0, t4 = 0, t5 = 0, t6 = 0, t7 = 0, t8 = 0, t9 = 0, t10 = 0, t11 = 0, t12 = 0, t13 = 0, t14 = 0, t15 = 0, t16 = 0, t17 = 0, t18 = 0, t19 = 0, t20 = 0, t21 = 0, t22 = 0, t23 = 0, t24 = 0, t25 = 0, t26 = 0, t27 = 0, t28 = 0, t29 = 0, t30 = 0, b0 = b[0], b1 = b[1], b2 = b[2], b3 = b[3], b4 = b[4], b5 = b[5], b6 = b[6], b7 = b[7], b8 = b[8], b9 = b[9], b10 = b[10], b11 = b[11], b12 = b[12], b13 = b[13], b14 = b[14], b15 = b[15]; - v = a[0]; - t0 += v * b0; - t1 += v * b1; - t2 += v * b2; - t3 += v * b3; - t4 += v * b4; - t5 += v * b5; - t6 += v * b6; - t7 += v * b7; - t8 += v * b8; - t9 += v * b9; - t10 += v * b10; - t11 += v * b11; - t12 += v * b12; - t13 += v * b13; - t14 += v * b14; - t15 += v * b15; - v = a[1]; - t1 += v * b0; - t2 += v * b1; - t3 += v * b2; - t4 += v * b3; - t5 += v * b4; - t6 += v * b5; - t7 += v * b6; - t8 += v * b7; - t9 += v * b8; - t10 += v * b9; - t11 += v * b10; - t12 += v * b11; - t13 += v * b12; - t14 += v * b13; - t15 += v * b14; - t16 += v * b15; - v = a[2]; - t2 += v * b0; - t3 += v * b1; - t4 += v * b2; - t5 += v * b3; - t6 += v * b4; - t7 += v * b5; - t8 += v * b6; - t9 += v * b7; - t10 += v * b8; - t11 += v * b9; - t12 += v * b10; - t13 += v * b11; - t14 += v * b12; - t15 += v * b13; - t16 += v * b14; - t17 += v * b15; - v = a[3]; - t3 += v * b0; - t4 += v * b1; - t5 += v * b2; - t6 += v * b3; - t7 += v * b4; - t8 += v * b5; - t9 += v * b6; - t10 += v * b7; - t11 += v * b8; - t12 += v * b9; - t13 += v * b10; - t14 += v * b11; - t15 += v * b12; - t16 += v * b13; - t17 += v * b14; - t18 += v * b15; - v = a[4]; - t4 += v * b0; - t5 += v * b1; - t6 += v * b2; - t7 += v * b3; - t8 += v * b4; - t9 += v * b5; - t10 += v * b6; - t11 += v * b7; - t12 += v * b8; - t13 += v * b9; - t14 += v * b10; - t15 += v * b11; - t16 += v * b12; - t17 += v * b13; - t18 += v * b14; - t19 += v * b15; - v = a[5]; - t5 += v * b0; - t6 += v * b1; - t7 += v * b2; - t8 += v * b3; - t9 += v * b4; - t10 += v * b5; - t11 += v * b6; - t12 += v * b7; - t13 += v * b8; - t14 += v * b9; - t15 += v * b10; - t16 += v * b11; - t17 += v * b12; - t18 += v * b13; - t19 += v * b14; - t20 += v * b15; - v = a[6]; - t6 += v * b0; - t7 += v * b1; - t8 += v * b2; - t9 += v * b3; - t10 += v * b4; - t11 += v * b5; - t12 += v * b6; - t13 += v * b7; - t14 += v * b8; - t15 += v * b9; - t16 += v * b10; - t17 += v * b11; - t18 += v * b12; - t19 += v * b13; - t20 += v * b14; - t21 += v * b15; - v = a[7]; - t7 += v * b0; - t8 += v * b1; - t9 += v * b2; - t10 += v * b3; - t11 += v * b4; - t12 += v * b5; - t13 += v * b6; - t14 += v * b7; - t15 += v * b8; - t16 += v * b9; - t17 += v * b10; - t18 += v * b11; - t19 += v * b12; - t20 += v * b13; - t21 += v * b14; - t22 += v * b15; - v = a[8]; - t8 += v * b0; - t9 += v * b1; - t10 += v * b2; - t11 += v * b3; - t12 += v * b4; - t13 += v * b5; - t14 += v * b6; - t15 += v * b7; - t16 += v * b8; - t17 += v * b9; - t18 += v * b10; - t19 += v * b11; - t20 += v * b12; - t21 += v * b13; - t22 += v * b14; - t23 += v * b15; - v = a[9]; - t9 += v * b0; - t10 += v * b1; - t11 += v * b2; - t12 += v * b3; - t13 += v * b4; - t14 += v * b5; - t15 += v * b6; - t16 += v * b7; - t17 += v * b8; - t18 += v * b9; - t19 += v * b10; - t20 += v * b11; - t21 += v * b12; - t22 += v * b13; - t23 += v * b14; - t24 += v * b15; - v = a[10]; - t10 += v * b0; - t11 += v * b1; - t12 += v * b2; - t13 += v * b3; - t14 += v * b4; - t15 += v * b5; - t16 += v * b6; - t17 += v * b7; - t18 += v * b8; - t19 += v * b9; - t20 += v * b10; - t21 += v * b11; - t22 += v * b12; - t23 += v * b13; - t24 += v * b14; - t25 += v * b15; - v = a[11]; - t11 += v * b0; - t12 += v * b1; - t13 += v * b2; - t14 += v * b3; - t15 += v * b4; - t16 += v * b5; - t17 += v * b6; - t18 += v * b7; - t19 += v * b8; - t20 += v * b9; - t21 += v * b10; - t22 += v * b11; - t23 += v * b12; - t24 += v * b13; - t25 += v * b14; - t26 += v * b15; - v = a[12]; - t12 += v * b0; - t13 += v * b1; - t14 += v * b2; - t15 += v * b3; - t16 += v * b4; - t17 += v * b5; - t18 += v * b6; - t19 += v * b7; - t20 += v * b8; - t21 += v * b9; - t22 += v * b10; - t23 += v * b11; - t24 += v * b12; - t25 += v * b13; - t26 += v * b14; - t27 += v * b15; - v = a[13]; - t13 += v * b0; - t14 += v * b1; - t15 += v * b2; - t16 += v * b3; - t17 += v * b4; - t18 += v * b5; - t19 += v * b6; - t20 += v * b7; - t21 += v * b8; - t22 += v * b9; - t23 += v * b10; - t24 += v * b11; - t25 += v * b12; - t26 += v * b13; - t27 += v * b14; - t28 += v * b15; - v = a[14]; - t14 += v * b0; - t15 += v * b1; - t16 += v * b2; - t17 += v * b3; - t18 += v * b4; - t19 += v * b5; - t20 += v * b6; - t21 += v * b7; - t22 += v * b8; - t23 += v * b9; - t24 += v * b10; - t25 += v * b11; - t26 += v * b12; - t27 += v * b13; - t28 += v * b14; - t29 += v * b15; - v = a[15]; - t15 += v * b0; - t16 += v * b1; - t17 += v * b2; - t18 += v * b3; - t19 += v * b4; - t20 += v * b5; - t21 += v * b6; - t22 += v * b7; - t23 += v * b8; - t24 += v * b9; - t25 += v * b10; - t26 += v * b11; - t27 += v * b12; - t28 += v * b13; - t29 += v * b14; - t30 += v * b15; - t0 += 38 * t16; - t1 += 38 * t17; - t2 += 38 * t18; - t3 += 38 * t19; - t4 += 38 * t20; - t5 += 38 * t21; - t6 += 38 * t22; - t7 += 38 * t23; - t8 += 38 * t24; - t9 += 38 * t25; - t10 += 38 * t26; - t11 += 38 * t27; - t12 += 38 * t28; - t13 += 38 * t29; - t14 += 38 * t30; - // t15 left as is - // first car - c = 1; - v = t0 + c + 65535; - c = Math.floor(v / 65536); - t0 = v - c * 65536; - v = t1 + c + 65535; - c = Math.floor(v / 65536); - t1 = v - c * 65536; - v = t2 + c + 65535; - c = Math.floor(v / 65536); - t2 = v - c * 65536; - v = t3 + c + 65535; - c = Math.floor(v / 65536); - t3 = v - c * 65536; - v = t4 + c + 65535; - c = Math.floor(v / 65536); - t4 = v - c * 65536; - v = t5 + c + 65535; - c = Math.floor(v / 65536); - t5 = v - c * 65536; - v = t6 + c + 65535; - c = Math.floor(v / 65536); - t6 = v - c * 65536; - v = t7 + c + 65535; - c = Math.floor(v / 65536); - t7 = v - c * 65536; - v = t8 + c + 65535; - c = Math.floor(v / 65536); - t8 = v - c * 65536; - v = t9 + c + 65535; - c = Math.floor(v / 65536); - t9 = v - c * 65536; - v = t10 + c + 65535; - c = Math.floor(v / 65536); - t10 = v - c * 65536; - v = t11 + c + 65535; - c = Math.floor(v / 65536); - t11 = v - c * 65536; - v = t12 + c + 65535; - c = Math.floor(v / 65536); - t12 = v - c * 65536; - v = t13 + c + 65535; - c = Math.floor(v / 65536); - t13 = v - c * 65536; - v = t14 + c + 65535; - c = Math.floor(v / 65536); - t14 = v - c * 65536; - v = t15 + c + 65535; - c = Math.floor(v / 65536); - t15 = v - c * 65536; - t0 += c - 1 + 37 * (c - 1); - // second car - c = 1; - v = t0 + c + 65535; - c = Math.floor(v / 65536); - t0 = v - c * 65536; - v = t1 + c + 65535; - c = Math.floor(v / 65536); - t1 = v - c * 65536; - v = t2 + c + 65535; - c = Math.floor(v / 65536); - t2 = v - c * 65536; - v = t3 + c + 65535; - c = Math.floor(v / 65536); - t3 = v - c * 65536; - v = t4 + c + 65535; - c = Math.floor(v / 65536); - t4 = v - c * 65536; - v = t5 + c + 65535; - c = Math.floor(v / 65536); - t5 = v - c * 65536; - v = t6 + c + 65535; - c = Math.floor(v / 65536); - t6 = v - c * 65536; - v = t7 + c + 65535; - c = Math.floor(v / 65536); - t7 = v - c * 65536; - v = t8 + c + 65535; - c = Math.floor(v / 65536); - t8 = v - c * 65536; - v = t9 + c + 65535; - c = Math.floor(v / 65536); - t9 = v - c * 65536; - v = t10 + c + 65535; - c = Math.floor(v / 65536); - t10 = v - c * 65536; - v = t11 + c + 65535; - c = Math.floor(v / 65536); - t11 = v - c * 65536; - v = t12 + c + 65535; - c = Math.floor(v / 65536); - t12 = v - c * 65536; - v = t13 + c + 65535; - c = Math.floor(v / 65536); - t13 = v - c * 65536; - v = t14 + c + 65535; - c = Math.floor(v / 65536); - t14 = v - c * 65536; - v = t15 + c + 65535; - c = Math.floor(v / 65536); - t15 = v - c * 65536; - t0 += c - 1 + 37 * (c - 1); - o[0] = t0; - o[1] = t1; - o[2] = t2; - o[3] = t3; - o[4] = t4; - o[5] = t5; - o[6] = t6; - o[7] = t7; - o[8] = t8; - o[9] = t9; - o[10] = t10; - o[11] = t11; - o[12] = t12; - o[13] = t13; - o[14] = t14; - o[15] = t15; -} -function S$1(o, a) { - M(o, a, a); -} -function inv25519(o, i) { - let c = gf(); - let a; - for (a = 0; a < 16; a++) - c[a] = i[a]; - for (a = 253; a >= 0; a--) { - S$1(c, c); - if (a !== 2 && a !== 4) - M(c, c, i); - } - for (a = 0; a < 16; a++) - o[a] = c[a]; -} -function pow2523(o, i) { - let c = gf(); - let a; - for (a = 0; a < 16; a++) - c[a] = i[a]; - for (a = 250; a >= 0; a--) { - S$1(c, c); - if (a !== 1) - M(c, c, i); - } - for (a = 0; a < 16; a++) - o[a] = c[a]; -} -function add(p, q) { - let a = gf(), b = gf(), c = gf(), d = gf(), e = gf(), f = gf(), g = gf(), h = gf(), t = gf(); - Z$1(a, p[1], p[0]); - Z$1(t, q[1], q[0]); - M(a, a, t); - A$1(b, p[0], p[1]); - A$1(t, q[0], q[1]); - M(b, b, t); - M(c, p[3], q[3]); - M(c, c, D2); - M(d, p[2], q[2]); - A$1(d, d, d); - Z$1(e, b, a); - Z$1(f, d, c); - A$1(g, d, c); - A$1(h, b, a); - M(p[0], e, f); - M(p[1], h, g); - M(p[2], g, f); - M(p[3], e, h); -} -function cswap(p, q, b) { - let i; - for (i = 0; i < 4; i++) { - sel25519(p[i], q[i], b); - } -} -function pack(r, p) { - let tx = gf(), ty = gf(), zi = gf(); - inv25519(zi, p[2]); - M(tx, p[0], zi); - M(ty, p[1], zi); - pack25519(r, ty); - r[31] ^= par25519(tx) << 7; -} -function scalarmult(p, q, s) { - let b, i; - set25519(p[0], gf0); - set25519(p[1], gf1); - set25519(p[2], gf1); - set25519(p[3], gf0); - for (i = 255; i >= 0; --i) { - b = (s[(i / 8) | 0] >> (i & 7)) & 1; - cswap(p, q, b); - add(q, p); - add(p, p); - cswap(p, q, b); - } -} -function scalarbase(p, s) { - let q = [gf(), gf(), gf(), gf()]; - set25519(q[0], X); - set25519(q[1], Y); - set25519(q[2], gf1); - M(q[3], X, Y); - scalarmult(p, q, s); -} -let L = new Float64Array([ - 0xed, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58, 0xd6, 0x9c, 0xf7, 0xa2, 0xde, 0xf9, 0xde, 0x14, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0x10, -]); -function modL(r, x) { - let carry, i, j, k; - for (i = 63; i >= 32; --i) { - carry = 0; - for (j = i - 32, k = i - 12; j < k; ++j) { - x[j] += carry - 16 * x[i] * L[j - (i - 32)]; - carry = Math.floor((x[j] + 128) / 256); - x[j] -= carry * 256; - } - x[j] += carry; - x[i] = 0; - } - carry = 0; - for (j = 0; j < 32; j++) { - x[j] += carry - (x[31] >> 4) * L[j]; - carry = x[j] >> 8; - x[j] &= 255; - } - for (j = 0; j < 32; j++) - x[j] -= carry * L[j]; - for (i = 0; i < 32; i++) { - x[i + 1] += x[i] >> 8; - r[i] = x[i] & 255; - } -} -function unpackneg(r, p) { - let t = gf(), chk = gf(), num = gf(), den = gf(), den2 = gf(), den4 = gf(), den6 = gf(); - set25519(r[2], gf1); - unpack25519(r[1], p); - S$1(num, r[1]); - M(den, num, D); - Z$1(num, num, r[2]); - A$1(den, r[2], den); - S$1(den2, den); - S$1(den4, den2); - M(den6, den4, den2); - M(t, den6, num); - M(t, t, den); - pow2523(t, t); - M(t, t, num); - M(t, t, den); - M(t, t, den); - M(r[0], t, den); - S$1(chk, r[0]); - M(chk, chk, den); - if (neq25519(chk, num)) - M(r[0], r[0], I); - S$1(chk, r[0]); - M(chk, chk, den); - if (neq25519(chk, num)) - return -1; - if (par25519(r[0]) === p[31] >> 7) - Z$1(r[0], gf0, r[0]); - M(r[3], r[0], r[1]); - return 0; -} -function reduce(r) { - let x = new Float64Array(64), i; - for (i = 0; i < 64; i++) - x[i] = r[i]; - for (i = 0; i < 64; i++) - r[i] = 0; - modL(r, x); -} -function crypto_sign_keypair(pk, sk) { - let d = new Uint8Array(64); - let p = [gf(), gf(), gf(), gf()]; - let i; - sha512internal(d, sk, 32); - d[0] &= 248; - d[31] &= 127; - d[31] |= 64; - scalarbase(p, d); - pack(pk, p); - for (i = 0; i < 32; i++) - sk[i + 32] = pk[i]; - return 0; -} -function crypto_sign_open(m, sm, n, pk) { - let i; - let t = new Uint8Array(32), h = new Uint8Array(64); - let p = [gf(), gf(), gf(), gf()], q = [gf(), gf(), gf(), gf()]; - if (n < 64) - return -1; - if (unpackneg(q, pk)) - return -1; - for (i = 0; i < n; i++) - m[i] = sm[i]; - for (i = 0; i < 32; i++) - m[i + 32] = pk[i]; - sha512internal(h, m, n); - reduce(h); - scalarmult(p, q, h); - scalarbase(q, sm.subarray(32)); - add(p, q); - pack(t, p); - n -= 64; - if (crypto_verify_32(sm, 0, t, 0)) { - for (i = 0; i < n; i++) - m[i] = 0; - return -1; - } - for (i = 0; i < n; i++) - m[i] = sm[i + 64]; - return n; -} -// Note: difference from C - smlen returned, not passed as argument. -function crypto_sign(sm, m, n, sk) { - let d = new Uint8Array(64), h = new Uint8Array(64), r = new Uint8Array(64); - let i, j, x = new Float64Array(64); - let p = [gf(), gf(), gf(), gf()]; - sha512internal(d, sk, 32); - d[0] &= 248; - d[31] &= 127; - d[31] |= 64; - let smlen = n + 64; - for (i = 0; i < n; i++) - sm[64 + i] = m[i]; - for (i = 0; i < 32; i++) - sm[32 + i] = d[32 + i]; - sha512internal(r, sm.subarray(32), n + 32); - reduce(r); - scalarbase(p, r); - pack(sm, p); - for (i = 32; i < 64; i++) - sm[i] = sk[i]; - sha512internal(h, sm, n + 64); - reduce(h); - for (i = 0; i < 64; i++) - x[i] = 0; - for (i = 0; i < 32; i++) - x[i] = r[i]; - for (i = 0; i < 32; i++) { - for (j = 0; j < 32; j++) { - x[i + j] += h[i] * d[j]; - } - } - modL(sm.subarray(32), x); - return smlen; -} -// Zero types to make error returns more convenient. -const nu8$3 = new Uint8Array(0); -const nkp$1 = { publicKey: nu8$3, secretKey: nu8$3 }; -// checkAllUint8Array is a helper function to perform input checking on the -// crypto API functions. Because the kernel is often hot-loading untrusted -// code, we cannot depend on typescript to provide type safety. -function checkAllUint8Array(...args) { - for (let i = 0; i < args.length; i++) { - if (!(args[i] instanceof Uint8Array)) { - return "unexpected type, use Uint8Array"; - } - } - return null; -} -// ed25519KeypairFromEntropy is a function that generates an ed25519 keypair -// from the provided entropy. -function ed25519KeypairFromEntropy(seed) { - // Input checking. - let errU8 = checkAllUint8Array(seed); - if (errU8 !== null) { - return [nkp$1, addContextToErr$1(errU8, "seed is invalid")]; - } - if (seed.length !== crypto_sign_SEEDBYTES) { - return [nkp$1, "bad seed size"]; - } - // Build the keypair. - let pk = new Uint8Array(crypto_sign_PUBLICKEYBYTES); - let sk = new Uint8Array(crypto_sign_SECRETKEYBYTES); - for (let i = 0; i < 32; i++) { - sk[i] = seed[i]; - } - crypto_sign_keypair(pk, sk); - return [ - { - publicKey: pk, - secretKey: sk, - }, - null, - ]; -} -// ed25519Sign will produce an ed25519 signature of a given input. -function ed25519Sign(msg, secretKey) { - // Input checking. - let errU8 = checkAllUint8Array(msg, secretKey); - if (errU8 !== null) { - return [nu8$3, addContextToErr$1(errU8, "inputs are invalid")]; - } - if (secretKey.length !== crypto_sign_SECRETKEYBYTES) { - return [nu8$3, "bad secret key size"]; - } - // Build the signature. - let signedMsg = new Uint8Array(crypto_sign_BYTES + msg.length); - crypto_sign(signedMsg, msg, msg.length, secretKey); - let sig = new Uint8Array(crypto_sign_BYTES); - for (let i = 0; i < sig.length; i++) { - sig[i] = signedMsg[i]; - } - return [sig, null]; -} -// ed25519Verify will check whether a signature is valid against the given -// publicKey and message. -function ed25519Verify(msg, sig, publicKey) { - let errU8 = checkAllUint8Array(msg, sig, publicKey); - if (errU8 !== null) { - return false; - } - if (sig.length !== crypto_sign_BYTES) { - return false; - } - if (publicKey.length !== crypto_sign_PUBLICKEYBYTES) { - return false; - } - let sm = new Uint8Array(crypto_sign_BYTES + msg.length); - let m = new Uint8Array(crypto_sign_BYTES + msg.length); - let i; - for (i = 0; i < crypto_sign_BYTES; i++) { - sm[i] = sig[i]; - } - for (i = 0; i < msg.length; i++) { - sm[i + crypto_sign_BYTES] = msg[i]; - } - return crypto_sign_open(m, sm, sm.length, publicKey) >= 0; -} - -// Define the number of entropy words used when generating the seed. +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.tester = exports.loadTester = exports.login = exports.generateSeedPhrase = exports.TEST_KERNEL_SKLINK = exports.KERNEL_HELPER_MODULE = exports.KERNEL_TEST_SUITE = void 0; +const libskynet_1 = require("libskynet"); +const seed_1 = require("libskynet/dist/seed"); +const dictionary_1 = require("libskynet/dist/dictionary"); +const path = require("path"); +const libskynetnode_1 = require("libskynetnode"); +const kernel = require("libkernel"); +const crypto_1 = require("crypto"); +// @ts-ignore +const StaticServer = require("static-server"); +exports.KERNEL_TEST_SUITE = "AQCPJ9WRzMpKQHIsPo8no3XJpUydcDCjw7VJy8lG1MCZ3g"; +exports.KERNEL_HELPER_MODULE = "AQCoaLP6JexdZshDDZRQaIwN3B7DqFjlY7byMikR7u1IEA"; +exports.TEST_KERNEL_SKLINK = "AQDJDoXMJiiEMBxXodQvUV89qtQHsnXWyV1ViQ9M1pMjUg"; const SEED_ENTROPY_WORDS = 13; -const SEED_BYTES = 16; -// deriveChildSeed is a helper function to derive a child seed from a parent -// seed using a string as the path. -function deriveChildSeed(parentSeed, derivationTag) { - let tagU8 = new TextEncoder().encode(" - " + derivationTag); - let preimage = new Uint8Array(parentSeed.length + tagU8.length); - preimage.set(parentSeed, 0); - preimage.set(tagU8, parentSeed.length); - let hash = sha512(preimage); - return hash.slice(0, SEED_BYTES); -} -// deriveMyskyRoot is a helper function to derive the root mysky seed of the -// provided user seed. -// -// NOTE: This is code is to provide legacy compatibility with the MySky -// ecosystem. Compatibility cannot be broken here. -function deriveMyskyRootKeypair(userSeed) { - let saltBytes = new TextEncoder().encode("root discoverable key"); - let saltHash = sha512(saltBytes); - let userSeedHash = sha512(userSeed); - let mergedHash = sha512(new Uint8Array([...saltHash, ...userSeedHash])); - let keyEntropy = mergedHash.slice(0, 32); - // Error is ignored because it should not be possible with the provided - // inputs. - let [keypair] = ed25519KeypairFromEntropy(keyEntropy); - return keypair; -} -// generateSeedPhraseDeterministic will generate and verify a seed phrase for -// the user. -function generateSeedPhraseDeterministic(password) { - let u8 = new TextEncoder().encode(password); - let buf = sha512(u8); - let randNums = Uint16Array.from(buf); +const crypto = crypto_1.webcrypto; +function generateSeedPhrase() { + // Get the random numbers for the seed phrase. Typically, you need to + // have code that avoids bias by checking the random results and + // re-rolling the random numbers if the result is outside of the range + // of numbers that would produce no bias. Because the search space + // (1024) evenly divides the random number space (2^16), we can skip + // this step and just use a modulus instead. The result will have no + // bias, but only because the search space is a power of 2. + let randNums = new Uint16Array(SEED_ENTROPY_WORDS); + crypto.getRandomValues(randNums); // Generate the seed phrase from the randNums. let seedWords = []; for (let i = 0; i < SEED_ENTROPY_WORDS; i++) { - let wordIndex = randNums[i] % dictionary.length; - if (i == SEED_ENTROPY_WORDS - 1) { - wordIndex = randNums[i] % (dictionary.length / 4); - } - seedWords.push(dictionary[wordIndex]); + let wordIndex = randNums[i] % libskynet_1.dictionary.length; + seedWords.push(libskynet_1.dictionary[wordIndex]); } // Convert the seedWords to a seed. - let [seed, err1] = seedWordsToSeed(seedWords); - if (err1 !== null) { - return ["", err1]; - } + let [seed] = seedWordsToSeed(seedWords); // Compute the checksum. - let [checksumOne, checksumTwo, err2] = seedToChecksumWords(seed); - if (err2 !== null) { - return ["", err2]; - } + let [checksumOne, checksumTwo, err2] = (0, seed_1.seedToChecksumWords)(seed); // Assemble the final seed phrase and set the text field. - let allWords = [...seedWords, checksumOne, checksumTwo]; - let seedPhrase = allWords.join(" "); - return [seedPhrase, null]; + return [...seedWords, checksumOne, checksumTwo].join(" "); } -// seedToChecksumWords will compute the two checksum words for the provided -// seed. The two return values are the two checksum words. -function seedToChecksumWords(seed) { - // Input validation. - if (seed.length !== SEED_BYTES) { - return ["", "", `seed has the wrong length: ${seed.length}`]; - } - // Get the hash. - let h = sha512(seed); - // Turn the hash into two words. - let word1 = h[0] << 8; - word1 += h[1]; - word1 >>= 6; - let word2 = h[1] << 10; - word2 &= 0xffff; - word2 += h[2] << 2; - word2 >>= 6; - return [dictionary[word1], dictionary[word2], null]; -} -// validSeedPhrase checks whether the provided seed phrase is valid, returning -// an error if not. If the seed phrase is valid, the full seed will be returned -// as a Uint8Array. -function validSeedPhrase(seedPhrase) { - // Create a helper function to make the below code more readable. - let prefix = function (s) { - return s.slice(0, DICTIONARY_UNIQUE_PREFIX); - }; - // Pull the seed into its respective parts. - let seedWordsAndChecksum = seedPhrase.split(" "); - let seedWords = seedWordsAndChecksum.slice(0, SEED_ENTROPY_WORDS); - let checksumOne = seedWordsAndChecksum[SEED_ENTROPY_WORDS]; - let checksumTwo = seedWordsAndChecksum[SEED_ENTROPY_WORDS + 1]; - // Convert the seedWords to a seed. - let [seed, err1] = seedWordsToSeed(seedWords); - if (err1 !== null) { - return [new Uint8Array(0), addContextToErr$1(err1, "unable to parse seed phrase")]; - } - let [checksumOneVerify, checksumTwoVerify, err2] = seedToChecksumWords(seed); - if (err2 !== null) { - return [new Uint8Array(0), addContextToErr$1(err2, "could not compute checksum words")]; - } - if (prefix(checksumOne) !== prefix(checksumOneVerify)) { - return [new Uint8Array(0), "first checksum word is invalid"]; - } - if (prefix(checksumTwo) !== prefix(checksumTwoVerify)) { - return [new Uint8Array(0), "second checksum word is invalid"]; - } - return [seed, null]; -} -// seedWordsToSeed will convert a provided seed phrase to to a Uint8Array that -// represents the cryptographic seed in bytes. +exports.generateSeedPhrase = generateSeedPhrase; function seedWordsToSeed(seedWords) { // Input checking. if (seedWords.length !== SEED_ENTROPY_WORDS) { - return [new Uint8Array(0), `Seed words should have length ${SEED_ENTROPY_WORDS} but has length ${seedWords.length}`]; + return [ + new Uint8Array(0), + `Seed words should have length ${SEED_ENTROPY_WORDS} but has length ${seedWords.length}`, + ]; } // We are getting 16 bytes of entropy. - let bytes = new Uint8Array(SEED_BYTES); + let bytes = new Uint8Array(seed_1.SEED_BYTES); let curByte = 0; let curBit = 0; for (let i = 0; i < SEED_ENTROPY_WORDS; i++) { // Determine which number corresponds to the next word. let word = -1; - for (let j = 0; j < dictionary.length; j++) { - if (seedWords[i].slice(0, DICTIONARY_UNIQUE_PREFIX) === dictionary[j].slice(0, DICTIONARY_UNIQUE_PREFIX)) { + for (let j = 0; j < libskynet_1.dictionary.length; j++) { + if (seedWords[i].slice(0, dictionary_1.DICTIONARY_UNIQUE_PREFIX) === + libskynet_1.dictionary[j].slice(0, dictionary_1.DICTIONARY_UNIQUE_PREFIX)) { word = j; break; } } if (word === -1) { - return [new Uint8Array(0), `word '${seedWords[i]}' at index ${i} not found in dictionary`]; + return [ + new Uint8Array(0), + `word '${seedWords[i]}' at index ${i} not found in dictionary`, + ]; } let wordBits = 10; if (i === SEED_ENTROPY_WORDS - 1) { @@ -3645,12777 +87,48 @@ function seedWordsToSeed(seedWords) { } return [bytes, null]; } -// seedPhraseToSeed will take a seed phrase and return the corresponding seed, -// providing an error if the seed phrase is invalid. This is an alias of -// validSeedPhrase. -function seedPhraseToSeed(seedPhrase) { - return validSeedPhrase(seedPhrase); +async function login(page, seed = generateSeedPhrase()) { + await page.goto("http://skt.us"); + let userSeed; + [userSeed] = (0, libskynet_1.seedPhraseToSeed)(seed); + let seedHex = (0, libskynet_1.bufToHex)(userSeed); + await page.evaluate((seed) => { + window.localStorage.setItem("v1-seed", seed); + }, seedHex); + let kernelEntrySeed = (0, libskynet_1.deriveChildSeed)(userSeed, "userPreferredKernel2"); + // Get the registry keys. + let [keypair, dataKey] = (0, libskynet_1.taggedRegistryEntryKeys)(kernelEntrySeed, "user kernel"); + await (0, libskynetnode_1.overwriteRegistryEntry)(keypair, dataKey, (0, libskynet_1.b64ToBuf)(exports.TEST_KERNEL_SKLINK)[0]); } - -var seed = /*#__PURE__*/Object.freeze({ - __proto__: null, - deriveChildSeed: deriveChildSeed, - deriveMyskyRootKeypair: deriveMyskyRootKeypair, - generateSeedPhraseDeterministic: generateSeedPhraseDeterministic, - seedToChecksumWords: seedToChecksumWords, - seedPhraseToSeed: seedPhraseToSeed, - validSeedPhrase: validSeedPhrase, - SEED_BYTES: SEED_BYTES -}); - -// Define some empty values to make our return statements more concise. -const nu8$2 = new Uint8Array(0); -const nkp = { publicKey: nu8$2, secretKey: nu8$2 }; -// computeRegistrySignature will take a secret key and the required fields of a -// registry entry and use them to compute a registry signature, returning both -// the signature and the encoded data for the registry entry. -function computeRegistrySignature(secretKey, dataKey, data, revision) { - // Check that the data is the right size. - if (data.length > 86) { - return [nu8$2, "registry data must be at most 86 bytes"]; - } - // Build the encoded data. - let [encodedData, errEPB] = encodePrefixedBytes(data); - if (errEPB !== null) { - return [nu8$2, addContextToErr$1(errEPB, "unable to encode provided registry data")]; - } - let [encodedRevision, errEU64] = encodeU64$1(revision); - if (errEU64 !== null) { - return [nu8$2, addContextToErr$1(errEU64, "unable to encode the revision number")]; - } - // Build the signing data. - let dataToSign = new Uint8Array(32 + 8 + data.length + 8); - dataToSign.set(dataKey, 0); - dataToSign.set(encodedData, 32); - dataToSign.set(encodedRevision, 32 + 8 + data.length); - let sigHash = blake2b(dataToSign); - // Sign the data. - let [sig, errS] = ed25519Sign(sigHash, secretKey); - if (errS !== null) { - return [nu8$2, addContextToErr$1(errS, "unable to sign registry entry")]; - } - return [sig, null]; -} -// deriveRegistryEntryID derives a registry entry ID from a provided pubkey and -// datakey. -function deriveRegistryEntryID(pubkey, datakey) { - // Check the lengths of the inputs. - if (pubkey.length !== 32) { - return [nu8$2, "pubkey is invalid, length is wrong"]; - } - if (datakey.length !== 32) { - return [nu8$2, "datakey is not a valid hash, length is wrong"]; - } - // Establish the encoding. First 16 bytes is a specifier, second 8 - // bytes declares the length of the pubkey, the next 32 bytes is the - // pubkey and the final 32 bytes is the datakey. This encoding is - // determined by the Sia protocol. - let encoding = new Uint8Array(16 + 8 + 32 + 32); - // Set the specifier. - encoding[0] = "e".charCodeAt(0); - encoding[1] = "d".charCodeAt(0); - encoding[2] = "2".charCodeAt(0); - encoding[3] = "5".charCodeAt(0); - encoding[4] = "5".charCodeAt(0); - encoding[5] = "1".charCodeAt(0); - encoding[6] = "9".charCodeAt(0); - // Set the pubkey. - let [encodedLen, errU64] = encodeU64$1(32n); - if (errU64 !== null) { - return [nu8$2, addContextToErr$1(errU64, "unable to encode pubkey length")]; - } - encoding.set(encodedLen, 16); - encoding.set(pubkey, 16 + 8); - encoding.set(datakey, 16 + 8 + 32); - // Get the final ID by hashing the encoded data. - let id = blake2b(encoding); - return [id, null]; -} -// entryIDToSkylink converts a registry entry id to a resolver skylink. -function entryIDToSkylink(entryID) { - let v2Skylink = new Uint8Array(34); - v2Skylink.set(entryID, 2); - v2Skylink[0] = 1; - return bufToB64$1(v2Skylink); -} -// resolverLink will take a registryEntryID and return the corresponding -// resolver link. -function resolverLink(entryID) { - if (entryID.length !== 32) { - return ["", "provided entry ID has the wrong length"]; - } - let v2Skylink = new Uint8Array(34); - v2Skylink.set(entryID, 2); - v2Skylink[0] = 1; - let skylink = bufToB64$1(v2Skylink); - return [skylink, null]; -} -// registryEntryKeys will use the user's seed to derive a keypair and a datakey -// using the provided seed and tags. The keypairTag is a tag which salts the -// keypair. If you change the input keypairTag, the resulting public key and -// secret key will be different. The dataKey tag is the salt for the datakey, -// if you provide a different datakey tag, the resulting datakey will be -// different. -// -// Note that changing the keypair tag will also change the resulting datakey. -// The purpose of the keypair tag is to obfuscate the fact that two registry -// entries are owned by the same identity. This obfuscation would break if two -// different public keys were using the same datakey. Changing the datakey does -// not change the public key. -function taggedRegistryEntryKeys(seed, keypairTagStr, datakeyTagStr) { - if (seed.length !== SEED_BYTES) { - return [nkp, nu8$2, "seed has the wrong length"]; - } - if (keypairTagStr.length > 255) { - return [nkp, nu8$2, "keypairTag must be less than 256 characters"]; - } - // If no datakey tag was provided, use the empty string. - if (datakeyTagStr === undefined) { - datakeyTagStr = ""; - } - // Generate a unique set of entropy using the seed and keypairTag. - let keypairTag = new TextEncoder().encode(keypairTagStr); - let entropyInput = new Uint8Array(keypairTag.length + seed.length); - entropyInput.set(seed, 0); - entropyInput.set(keypairTag, seed.length); - let keypairEntropy = sha512(entropyInput); - // Use the seed to dervie the datakey for the registry entry. We use - // a different tag to ensure that the datakey is independently random, such - // that the registry entry looks like it could be any other registry entry. - // - // We don't want it to be possible for two different combinations of - // tags to end up with the same datakey. If you don't use a length - // prefix, for example the tags ["123", "456"] and ["12", "3456"] would - // have the same datakey. You have to add the length prefix to the - // first tag otherwise you can get pairs like ["6", "4321"] and ["65", - // "321"] which could end up with the same datakey. - let datakeyTag = new TextEncoder().encode(datakeyTagStr); - let datakeyInput = new Uint8Array(seed.length + 1 + keypairTag.length + datakeyTag.length); - let keypairLen = new Uint8Array(1); - keypairLen[0] = keypairTag.length; - datakeyInput.set(seed); - datakeyInput.set(keypairLen, seed.length); - datakeyInput.set(keypairTag, seed.length + 1); - datakeyInput.set(datakeyTag, seed.length + 1 + keypairTag.length); - let datakeyEntropy = sha512(datakeyInput); - // Create the private key for the registry entry. - let [keypair, errKPFE] = ed25519KeypairFromEntropy(keypairEntropy.slice(0, 32)); - if (errKPFE !== null) { - return [nkp, nu8$2, addContextToErr$1(errKPFE, "unable to derive keypair")]; - } - let datakey = datakeyEntropy.slice(0, 32); - return [keypair, datakey, null]; -} -// verifyRegistrySignature will verify the signature of a registry entry. -function verifyRegistrySignature(pubkey, datakey, data, revision, sig) { - let [encodedData, errEPB] = encodePrefixedBytes(data); - if (errEPB !== null) { - return false; - } - let [encodedRevision, errU64] = encodeU64$1(revision); - if (errU64 !== null) { - return false; - } - let dataToVerify = new Uint8Array(32 + 8 + data.length + 8); - dataToVerify.set(datakey, 0); - dataToVerify.set(encodedData, 32); - dataToVerify.set(encodedRevision, 32 + 8 + data.length); - let sigHash = blake2b(dataToVerify); - return ed25519Verify(sigHash, sig, pubkey); -} - -// validateSkyfilePath checks whether the provided path is a valid path for a -// file in a skylink. -function validateSkyfilePath(path) { - if (path === "") { - return "path cannot be blank"; - } - if (path === "..") { - return "path cannot be .."; - } - if (path === ".") { - return "path cannot be ."; - } - if (path.startsWith("/")) { - return "metdata.Filename cannot start with /"; - } - if (path.startsWith("../")) { - return "metdata.Filename cannot start with ../"; - } - if (path.startsWith("./")) { - return "metdata.Filename cannot start with ./"; - } - let pathElems = path.split("/"); - for (let i = 0; i < pathElems.length; i++) { - if (pathElems[i] === ".") { - return "path cannot have a . element"; - } - if (pathElems[i] === "..") { - return "path cannot have a .. element"; - } - if (pathElems[i] === "") { - return "path cannot have an empty element, cannot contain //"; - } - } - return null; -} -// validateSkyfileMetadata checks whether the provided metadata is valid -// metadata for a skyfile. -function validateSkyfileMetadata(metadata) { - // Check that the filename is valid. - if (!("Filename" in metadata)) { - return "metadata.Filename does not exist"; - } - if (typeof metadata.Filename !== "string") { - return "metadata.Filename is not a string"; - } - let errVSP = validateSkyfilePath(metadata.Filename); - if (errVSP !== null) { - return addContextToErr$1(errVSP, "metadata.Filename does not have a valid path"); - } - // Check that there are no subfiles. - if ("Subfiles" in metadata) { - // TODO: Fill this out using code from - // skymodules.ValidateSkyfileMetadata to support subfiles. - return "cannot upload files that have subfiles"; - } - // Check that the default path rules are being respected. - if ("DisableDefaultPath" in metadata && "DefaultPath" in metadata) { - return "cannot set both a DefaultPath and also DisableDefaultPath"; - } - if ("DefaultPath" in metadata) { - // TODO: Fill this out with code from - // skymodules.validateDefaultPath to support subfiles and - // default paths. - return "cannot set a default path if there are no subfiles"; - } - if ("TryFiles" in metadata) { - if (!metadata.TryFiles.IsArray()) { - return "metadata.TryFiles must be an array"; - } - if (metadata.TryFiles.length === 0) { - return "metadata.TryFiles should not be empty"; - } - if ("DefaultPath" in metadata) { - return "metadata.TryFiles cannot be used alongside DefaultPath"; - } - if ("DisableDefaultPath" in metadata) { - return "metadata.TryFiles cannot be used alongside DisableDefaultPath"; - } - // TODO: finish the TryFiles checking using skymodules.ValidateTryFiles - return "TryFiles is not supported at this time"; - } - if ("ErrorPages" in metadata) { - // TODO: finish using skymodules.ValidateErrorPages - return "ErrorPages is not supported at this time"; - } - return null; -} -// validSkylink returns true if the provided Uint8Array is a valid skylink. -// This is an alias for 'parseSkylinkBitfield', as both perform the same -// validation. -function validSkylink(skylink) { - if (skylink.length !== 34) { - return false; - } - let [, , , errPSB] = parseSkylinkBitfield(skylink); - if (errPSB !== null) { - return false; - } - return true; -} - -// Helper consts to make returning empty values alongside errors more -// convenient. -const nu8$1 = new Uint8Array(0); -// verifyResolverLinkProof will check that the given resolver proof matches the -// provided skylink. If the proof is correct and the signature matches, the -// data will be returned. The returned link will be a verified skylink. -function verifyResolverLinkProof(skylink, proof) { - // Verify the presented skylink is formatted correctly. - if (skylink.length !== 34) { - return [nu8$1, "skylink is malformed, expecting 34 bytes"]; - } - // Verify that all of the required fields are present in the proof. - if (!("data" in proof) || - !("datakey" in proof) || - !("publickey" in proof) || - !("signature" in proof) || - !("type" in proof) || - !("revision" in proof)) { - return [nu8$1, "proof is malformed, fields are missing"]; - } - if (!("algorithm" in proof.publickey) || !("key" in proof.publickey)) { - return [nu8$1, "pubkey is malformed"]; - } - // Verify the typing of the fields. - if (typeof proof.data !== "string") { - return [nu8$1, "data is malformed"]; - } - let dataStr = proof.data; - if (typeof proof.datakey !== "string") { - return [nu8$1, "datakey is malformed"]; - } - let datakeyStr = proof.datakey; - if (proof.publickey.algorithm !== "ed25519") { - return [nu8$1, "pubkey has unrecognized algorithm"]; - } - if (typeof proof.publickey.key !== "string") { - return [nu8$1, "pubkey key is malformed"]; - } - let pubkeyStr = proof.publickey.key; - if (typeof proof.signature !== "string") { - return [nu8$1, "signature is malformed"]; - } - if (proof.type !== 1n) { - return [nu8$1, "registry entry has unrecognized type: " + tryStringify$1(proof.type)]; - } - let sigStr = proof.signature; - if (typeof proof.revision !== "bigint") { - return [nu8$1, "revision is malformed"]; - } - let revision = proof.revision; - // Decode all of the fields. They are presented in varied types and - // encodings. - let [data, errD] = hexToBuf(dataStr); - if (errD !== null) { - return [nu8$1, addContextToErr$1(errD, "data is invalid hex")]; - } - let [datakey, errDK] = hexToBuf(datakeyStr); - if (errDK !== null) { - return [nu8$1, addContextToErr$1(errDK, "datakey is invalid hex")]; - } - let [pubkey, errPK] = b64ToBuf(pubkeyStr); - if (errPK !== null) { - return [nu8$1, addContextToErr$1(errPK, "pubkey key is invalid base64")]; - } - let [sig, errS] = hexToBuf(sigStr); - if (errS !== null) { - return [nu8$1, addContextToErr$1(errS, "signature is invalid hex")]; - } - // Verify that the data is a skylink - this is a proof for a resolver, - // which means the proof is pointing to a specific skylink. - if (!validSkylink(data)) { - return [nu8$1, "this skylink does not resolve to another skylink"]; - } - // Verify that the combination of the datakey and the public key match - // the skylink. - let [entryID, errREID] = deriveRegistryEntryID(pubkey, datakey); - if (errREID !== null) { - return [nu8$1, addContextToErr$1(errREID, "proof pubkey is malformed")]; - } - let linkID = skylink.slice(2, 34); - for (let i = 0; i < entryID.length; i++) { - if (entryID[i] !== linkID[i]) { - return [nu8$1, "proof pubkey and datakey do not match the skylink root"]; - } - } - // Verify the signature. - if (!verifyRegistrySignature(pubkey, datakey, data, revision, sig)) { - return [nu8$1, "signature does not match"]; - } - return [data, null]; -} -// verifyResolverLinkProofs will verify a set of resolver link proofs provided -// by a portal after performing a resolver link lookup. Each proof corresponds -// to one level of resolution. The final value returned will be the V1 skylink -// at the end of the chain. -// -// This function treats the proof as untrusted data and will verify all of the -// fields that are provided. -function verifyResolverLinkProofs(skylink, proof) { - // Check that the proof is an array. - if (!Array.isArray(proof)) { - return [nu8$1, "provided proof is not an array: " + tryStringify$1(proof)]; - } - if (proof.length === 0) { - return [nu8$1, "proof array is empty"]; - } - // Check each proof in the chain, returning the final skylink. - for (let i = 0; i < proof.length; i++) { - let errVRLP; - [skylink, errVRLP] = verifyResolverLinkProof(skylink, proof[i]); - if (errVRLP !== null) { - return [nu8$1, addContextToErr$1(errVRLP, "one of the resolution proofs is invalid")]; - } - } - // Though it says 'skylink', the verifier is actually just returning - // whatever the registry data is. We need to check that the final value - // is a V1 skylink. - if (skylink.length !== 34) { - return [nu8$1, "final value returned by the resolver link is not a skylink"]; - } - let [version, , , errPSB] = parseSkylinkBitfield(skylink); - if (errPSB !== null) { - return [nu8$1, addContextToErr$1(errPSB, "final value returned by resolver link is not a valid skylink")]; - } - if (version !== 1n) { - return [nu8$1, "final value returned by resolver link is not a v1 skylink"]; - } - return [skylink, null]; -} - -// Establish the function that verifies the result is correct. -// -// The fileDataPtr input is an empty object that verifyDownloadResponse will -// fill with the fileData. It basically allows the verify function to -// communicate back to the caller. Note that the verify function might be -// called multiple times in a row if early portals fail to retrieve the data, -// but the verify function doesn't write to the fileDataPtr until it knows that -// the download is final. -function verifyDownloadResponse(response, u8Link, fileDataPtr) { - return new Promise((resolve) => { - // Currently the only valid successful response for a download is a - // 200. Anything else is unexpected and counts as an error. - if (response.status !== 200) { - resolve("unrecognized response status " + tryStringify$1(response.status) + ", expecting 200"); - return; - } - // Break the input link into its components. - let [version, offset, fetchSize, errBF] = parseSkylinkBitfield(u8Link); - if (errBF !== null) { - resolve(addContextToErr$1(errBF, "skylink bitfield could not be parsed")); - return; - } - // If this is a resolver skylink, we need to verify the resolver - // proofs. This conditional will update the value of 'u8Link' to be the - // value of the fully resolved link. - if (version === 2n) { - // Verify the resolver proofs and update the link to the correct - // link. - let proofJSON = response.headers.get("skynet-proof"); - if (proofJSON === null || proofJSON === undefined) { - resolve("response did not include resolver proofs"); - return; - } - let [proof, errPJ] = parseJSON(proofJSON); - if (errPJ !== null) { - resolve(addContextToErr$1(errPJ, "unable to parse resolver link proofs")); - return; - } - // We need to update the u8Link in-place so that the rest of the - // function doesn't need special handling. - let errVRLP; - [u8Link, errVRLP] = verifyResolverLinkProofs(u8Link, proof); - if (errVRLP !== null) { - resolve(addContextToErr$1(errVRLP, "unable to verify resolver link proofs")); - return; - } - // We also need to update the parsed bitfield, because the link has - // changed. - [version, offset, fetchSize, errBF] = parseSkylinkBitfield(u8Link); - if (errBF !== null) { - resolve(addContextToErr$1(errBF, "fully resolved link has invalid bitfield")); - return; - } - if (version !== 1n) { - resolve("fully resolved link does not have version 1"); - return; - } - } - response - .arrayBuffer() - .then((buf) => { - let [fileData, portalAtFault, errVD] = verifyDownload(u8Link.slice(2, 34), offset, fetchSize, buf); - if (errVD !== null && portalAtFault) { - resolve("received invalid download from portal"); - return; - } - if (errVD !== null) { - fileDataPtr.fileData = new Uint8Array(0); - fileDataPtr.err = addContextToErr$1(errVD, "file is corrupt"); - } - else { - fileDataPtr.fileData = fileData; - fileDataPtr.err = null; - } - // If the portal is not at fault, we tell progressiveFetch that - // the download was a success. The caller will have to check - // the fileDataPtr - resolve(null); - }) - .catch((err) => { - resolve(addContextToErr$1(err, "unable to read response body")); - }); +exports.login = login; +async function loadTester(page, port = 8080) { + const server = new StaticServer({ + rootPath: path.resolve(__dirname, "..", "public"), + port, + host: "localhost", + }); + await new Promise((resolve) => { + server.start(resolve); + }); + const stop = () => server.stop(); + process.on("SIGTERM", stop); + page.browser().on("disconnected", stop); + await page.goto(`http://localhost:${port}/`); + await page.evaluate(() => { + return kernel.init(); }); } - -// progressiveFetchHelper is the full progressiveFetch function, split out into -// a helper because the inptus/api is more complicated but only necessary for -// internal use. -function progressiveFetchHelper$1(pfm, resolve, verifyFunction) { - // If we run out of portals, return an error. - if (pfm.remainingPortals.length === 0) { - let newLog = "query failed because all portals have been tried"; - pfm.logs.push(newLog); - resolve({ - success: false, - portal: null, - response: null, - portalsFailed: pfm.portalsFailed, - responsesFailed: pfm.responsesFailed, - messagesFailed: pfm.messagesFailed, - remainingPortals: null, - logs: pfm.logs, - }); - return; +exports.loadTester = loadTester; +class Tester { + page; + constructor(page) { + this.page = page; } - // Grab the portal and query. - let portal = pfm.remainingPortals.shift(); - let query = portal + pfm.endpoint; - // Create a helper function for trying the next portal. - let nextPortal = function (response, log) { - if (response !== null) { - response - .clone() - .text() - .then((t) => { - pfm.logs.push(log); - pfm.portalsFailed.push(portal); - pfm.responsesFailed.push(response); - pfm.messagesFailed.push(t); - progressiveFetchHelper$1(pfm, resolve, verifyFunction); - }); - } - else { - pfm.logs.push(log); - pfm.portalsFailed.push(portal); - pfm.responsesFailed.push(response); - pfm.messagesFailed.push(""); - progressiveFetchHelper$1(pfm, resolve, verifyFunction); - } - }; - // Try sending the query to the portal. - fetch(query, pfm.fetchOpts) - .then((response) => { - // Check for a 5XX error. - if (!("status" in response) || typeof response.status !== "number") { - nextPortal(response, "portal has returned invalid response\n" + tryStringify$1({ portal, query })); - return; - } - if (response.status < 200 || response.status >= 300) { - nextPortal(response, "portal has returned error status\n" + tryStringify$1({ portal, query })); - return; - } - // Check the result against the verify function. - verifyFunction(response.clone()).then((errVF) => { - if (errVF !== null) { - nextPortal(response, "verify function has returned an error from portal " + portal + " - " + errVF); - return; - } - // Success! Return the response. - resolve({ - success: true, - portal, - response, - portalsFailed: pfm.portalsFailed, - responsesFailed: pfm.responsesFailed, - remainingPortals: pfm.remainingPortals, - messagesFailed: pfm.messagesFailed, - logs: pfm.logs, - }); - }); - }) - .catch((err) => { - // This portal failed, try again with the next portal. - nextPortal(null, "fetch returned an error\n" + tryStringify$1(err) + tryStringify$1(pfm.fetchOpts)); - return; - }); -} -// progressiveFetch will query multiple portals until one returns with a -// non-error response. In the event of a 4XX response, progressiveFetch will -// keep querying additional portals to try and find a working 2XX response. In -// the event that no working 2XX response is found, the first 4XX response will -// be returned. -// -// If progressiveFetch returns a 2XX response, it merely means that the portal -// returned a 2XX response. progressiveFetch cannot be confident that the -// portal has returned a correct/honest message, the verification has to be -// handled by the caller. The response (progressiveFetchResult) contains the -// list of portals that progressiveFetch hasn't tried yet. In the event that -// the 2XX response is not correct, the progressiveFetchResult contains the -// list of failover portals that have not been used yet, allowing -// progressiveFetch to be called again. -// -// This progressive method of querying portals helps prevent queries from -// failing, but if the first portal is not a good portal it introduces -// substantial latency. progressiveFetch does not do anything to make sure the -// portals are the best portals, it just queries them in order. The caller -// should make a best attempt to always have the best, most reliable and -// fastest portal as the first portal in the list. -// -// The reason that we don't blindly accept a 4XX response from a portal is that -// we have no way of verifying that the 4XX is legitimate. We don't trust the -// portal, and we can't give a rogue portal the opportunity to interrupt our -// user experience simply by returning a dishonest 404. So we need to keep -// querying more portals and gain confidence that the 404 a truthful response. -function progressiveFetch$1(endpoint, fetchOpts, portals, verifyFunction) { - let portalsCopy = [...portals]; - return new Promise((resolve) => { - let pfm = { - endpoint, - fetchOpts, - remainingPortals: portalsCopy, - portalsFailed: [], - responsesFailed: [], - messagesFailed: [], - logs: [], - }; - progressiveFetchHelper$1(pfm, resolve, verifyFunction); - }); -} - -// downloadSkylink will download the provided skylink. -function downloadSkylink(skylink) { - return new Promise((resolve) => { - // Get the Uint8Array of the input skylink. - let [u8Link, errBTB] = b64ToBuf(skylink); - if (errBTB !== null) { - resolve([new Uint8Array(0), addContextToErr$1(errBTB, "unable to decode skylink")]); - return; - } - if (!validSkylink(u8Link)) { - resolve([new Uint8Array(0), "skylink appears to be invalid"]); - return; - } - // Prepare the download call. - let endpoint = "/skynet/trustless/basesector/" + skylink; - let fileDataPtr = { fileData: new Uint8Array(0), err: null }; - let verifyFunction = function (response) { - return verifyDownloadResponse(response, u8Link, fileDataPtr); - }; - // Perform the download call. - progressiveFetch$1(endpoint, null, defaultPortalList, verifyFunction).then((result) => { - // Return an error if the call failed. - if (result.success !== true) { - // Check for a 404. - for (let i = 0; i < result.responsesFailed.length; i++) { - if (result.responsesFailed[i].status === 404) { - resolve([new Uint8Array(0), "404"]); - return; - } - } - // Error is not a 404, return the logs as the error. - let err = tryStringify$1(result.logs); - resolve([new Uint8Array(0), addContextToErr$1(err, "unable to complete download")]); - return; - } - // Check if the portal is honest but the download is corrupt. - if (fileDataPtr.err !== null) { - resolve([new Uint8Array(0), addContextToErr$1(fileDataPtr.err, "download is corrupt")]); - return; - } - resolve([fileDataPtr.fileData, null]); - }); - }); -} - -// verifyDecodedResp will verify the decoded response from a portal for a -// regRead call. -function verifyDecodedResp(resp, data, pubkey, datakey) { - // Status is expected to be 200. - if (resp.status !== 200) { - return "expected 200 response status, got: " + tryStringify$1(resp.status); - } - // Verify that all required fields were provided. - if (!("data" in data)) { - return "expected data field in response"; - } - if (typeof data.data !== "string") { - return "expected data field to be a string"; - } - if (!("revision" in data)) { - return "expected revision in response"; - } - if (typeof data.revision !== "bigint") { - return "expected revision to be a number"; - } - if (!("signature" in data)) { - return "expected signature in response"; - } - if (typeof data.signature !== "string") { - return "expected signature to be a string"; - } - // Parse out the fields we need. - let [entryData, errHTB] = hexToBuf(data.data); - if (errHTB !== null) { - return "could not decode registry data from response"; - } - let [sig, errHTB2] = hexToBuf(data.signature); - if (errHTB2 !== null) { - return "could not decode signature from response"; - } - // Verify the signature. - if (!verifyRegistrySignature(pubkey, datakey, entryData, data.revision, sig)) { - return "signature mismatch"; - } - // TODO: Need to be handling type 2 registry entries here otherwise we will - // be flagging non malicious portals as malicious. - return null; -} -// verifyRegistryReadResponse will verify that the registry read response from -// the portal was correct. -function verifyRegistryReadResponse(resp, pubkey, datakey) { - return new Promise((resolve) => { - resp - .text() - .then((str) => { - let [obj, errPJ] = parseJSON(str); - if (errPJ !== null) { - resolve(addContextToErr$1(errPJ, "unable to parse registry response")); - return; - } - let errVDR = verifyDecodedResp(resp, obj, pubkey, datakey); - if (errVDR !== null) { - resolve(addContextToErr$1(errVDR, "regRead response failed verification")); - return; - } - resolve(null); - }) - .catch((err) => { - resolve(addContextToErr$1(tryStringify$1(err), "unable to decode response")); - }); - }); -} -// verifyRegistryWriteResponse will verify that the response from a -// registryWrite call is valid. There's not much to verify beyond looking for -// the right response code, as the portal is not providing us with data, just -// confirming that a write succeeded. -function verifyRegistryWriteResponse(resp) { - return new Promise((resolve) => { - if (resp.status === 204) { - resolve(null); - } - resolve("expecting 200 status code for registry write, got:" + resp.status.toString()); - }); -} - -// stringifyjson.ts is split into a separate file to avoid a circular -// dependency. If you merge it with stringifytry.ts you have a circular import -// where err.js is importing stringify.js and stringify.js is importing err.js. -// Splitting the functions out resolves this issue. -// jsonStringify is a replacement for JSON.stringify that returns an error -// rather than throwing. -function jsonStringify(obj) { - try { - let str = JSON.stringify(obj); - return [str, null]; - } - catch (err) { - return ["", addContextToErr$1(tryStringify$1(err), "unable to stringify object")]; + async callModule(id, method, data = {}) { + return this.page.evaluate(async (id, method, data) => { + return kernel.callModule(id, method, data); + }, id, method, data); } } - -var dist$2 = /*#__PURE__*/Object.freeze({ - __proto__: null, - blake2b: blake2b, - defaultPortalList: defaultPortalList, - dictionary: dictionary, - downloadSkylink: downloadSkylink, - verifyDownload: verifyDownload, - verifyDownloadResponse: verifyDownloadResponse, - ed25519Sign: ed25519Sign, - ed25519Verify: ed25519Verify, - b64ToBuf: b64ToBuf, - bufToB64: bufToB64$1, - bufToHex: bufToHex, - bufToStr: bufToStr, - encodePrefixedBytes: encodePrefixedBytes, - encodeU64: encodeU64$1, - hexToBuf: hexToBuf, - addContextToErr: addContextToErr$1, - composeErr: composeErr$1, - blake2bAddLeafBytesToProofStack: blake2bAddLeafBytesToProofStack, - blake2bMerkleRoot: blake2bMerkleRoot, - blake2bProofStackRoot: blake2bProofStackRoot, - parseJSON: parseJSON, - progressiveFetch: progressiveFetch$1, - computeRegistrySignature: computeRegistrySignature, - deriveRegistryEntryID: deriveRegistryEntryID, - entryIDToSkylink: entryIDToSkylink, - resolverLink: resolverLink, - taggedRegistryEntryKeys: taggedRegistryEntryKeys, - verifyRegistrySignature: verifyRegistrySignature, - verifyRegistryReadResponse: verifyRegistryReadResponse, - verifyRegistryWriteResponse: verifyRegistryWriteResponse, - deriveChildSeed: deriveChildSeed, - deriveMyskyRootKeypair: deriveMyskyRootKeypair, - generateSeedPhraseDeterministic: generateSeedPhraseDeterministic, - seedPhraseToSeed: seedPhraseToSeed, - validSeedPhrase: validSeedPhrase, - sha512: sha512, - parseSkylinkBitfield: parseSkylinkBitfield, - skylinkV1Bitfield: skylinkV1Bitfield, - validateSkyfileMetadata: validateSkyfileMetadata, - validateSkyfilePath: validateSkyfilePath, - validSkylink: validSkylink, - verifyResolverLinkProofs: verifyResolverLinkProofs, - jsonStringify: jsonStringify, - tryStringify: tryStringify$1 -}); - -var require$$0 = /*@__PURE__*/getAugmentedNamespace(dist$2); - -var require$$1 = /*@__PURE__*/getAugmentedNamespace(seed); - -var require$$2$1 = /*@__PURE__*/getAugmentedNamespace(dictionary$1); - -/** - * Returns a `Buffer` instance from the given data URI `uri`. - * - * @param {String} uri Data URI to turn into a Buffer instance - * @returns {Buffer} Buffer instance from Data URI - * @api public - */ -function dataUriToBuffer(uri) { - if (!/^data:/i.test(uri)) { - throw new TypeError('`uri` does not appear to be a Data URI (must begin with "data:")'); - } - // strip newlines - uri = uri.replace(/\r?\n/g, ''); - // split the URI up into the "metadata" and the "data" portions - const firstComma = uri.indexOf(','); - if (firstComma === -1 || firstComma <= 4) { - throw new TypeError('malformed data: URI'); - } - // remove the "data:" scheme and parse the metadata - const meta = uri.substring(5, firstComma).split(';'); - let charset = ''; - let base64 = false; - const type = meta[0] || 'text/plain'; - let typeFull = type; - for (let i = 1; i < meta.length; i++) { - if (meta[i] === 'base64') { - base64 = true; - } - else { - typeFull += `;${meta[i]}`; - if (meta[i].indexOf('charset=') === 0) { - charset = meta[i].substring(8); - } - } - } - // defaults to US-ASCII only if type is not provided - if (!meta[0] && !charset.length) { - typeFull += ';charset=US-ASCII'; - charset = 'US-ASCII'; - } - // get the encoded data portion and decode URI-encoded chars - const encoding = base64 ? 'base64' : 'ascii'; - const data = unescape(uri.substring(firstComma + 1)); - const buffer = Buffer.from(data, encoding); - // set `.type` and `.typeFull` properties to MIME type - buffer.type = type; - buffer.typeFull = typeFull; - // set the `.charset` property - buffer.charset = charset; - return buffer; -} - -var ponyfill_es2018 = {exports: {}}; - -/** - * web-streams-polyfill v3.2.1 - */ - -var hasRequiredPonyfill_es2018; - -function requirePonyfill_es2018 () { - if (hasRequiredPonyfill_es2018) return ponyfill_es2018.exports; - hasRequiredPonyfill_es2018 = 1; - (function (module, exports) { - (function (global, factory) { - factory(exports) ; - }(commonjsGlobal, (function (exports) { - /// - const SymbolPolyfill = typeof Symbol === 'function' && typeof Symbol.iterator === 'symbol' ? - Symbol : - description => `Symbol(${description})`; - - /// - function noop() { - return undefined; - } - function getGlobals() { - if (typeof self !== 'undefined') { - return self; - } - else if (typeof window !== 'undefined') { - return window; - } - else if (typeof commonjsGlobal !== 'undefined') { - return commonjsGlobal; - } - return undefined; - } - const globals = getGlobals(); - - function typeIsObject(x) { - return (typeof x === 'object' && x !== null) || typeof x === 'function'; - } - const rethrowAssertionErrorRejection = noop; - - const originalPromise = Promise; - const originalPromiseThen = Promise.prototype.then; - const originalPromiseResolve = Promise.resolve.bind(originalPromise); - const originalPromiseReject = Promise.reject.bind(originalPromise); - function newPromise(executor) { - return new originalPromise(executor); - } - function promiseResolvedWith(value) { - return originalPromiseResolve(value); - } - function promiseRejectedWith(reason) { - return originalPromiseReject(reason); - } - function PerformPromiseThen(promise, onFulfilled, onRejected) { - // There doesn't appear to be any way to correctly emulate the behaviour from JavaScript, so this is just an - // approximation. - return originalPromiseThen.call(promise, onFulfilled, onRejected); - } - function uponPromise(promise, onFulfilled, onRejected) { - PerformPromiseThen(PerformPromiseThen(promise, onFulfilled, onRejected), undefined, rethrowAssertionErrorRejection); - } - function uponFulfillment(promise, onFulfilled) { - uponPromise(promise, onFulfilled); - } - function uponRejection(promise, onRejected) { - uponPromise(promise, undefined, onRejected); - } - function transformPromiseWith(promise, fulfillmentHandler, rejectionHandler) { - return PerformPromiseThen(promise, fulfillmentHandler, rejectionHandler); - } - function setPromiseIsHandledToTrue(promise) { - PerformPromiseThen(promise, undefined, rethrowAssertionErrorRejection); - } - const queueMicrotask = (() => { - const globalQueueMicrotask = globals && globals.queueMicrotask; - if (typeof globalQueueMicrotask === 'function') { - return globalQueueMicrotask; - } - const resolvedPromise = promiseResolvedWith(undefined); - return (fn) => PerformPromiseThen(resolvedPromise, fn); - })(); - function reflectCall(F, V, args) { - if (typeof F !== 'function') { - throw new TypeError('Argument is not a function'); - } - return Function.prototype.apply.call(F, V, args); - } - function promiseCall(F, V, args) { - try { - return promiseResolvedWith(reflectCall(F, V, args)); - } - catch (value) { - return promiseRejectedWith(value); - } - } - - // Original from Chromium - // https://chromium.googlesource.com/chromium/src/+/0aee4434a4dba42a42abaea9bfbc0cd196a63bc1/third_party/blink/renderer/core/streams/SimpleQueue.js - const QUEUE_MAX_ARRAY_SIZE = 16384; - /** - * Simple queue structure. - * - * Avoids scalability issues with using a packed array directly by using - * multiple arrays in a linked list and keeping the array size bounded. - */ - class SimpleQueue { - constructor() { - this._cursor = 0; - this._size = 0; - // _front and _back are always defined. - this._front = { - _elements: [], - _next: undefined - }; - this._back = this._front; - // The cursor is used to avoid calling Array.shift(). - // It contains the index of the front element of the array inside the - // front-most node. It is always in the range [0, QUEUE_MAX_ARRAY_SIZE). - this._cursor = 0; - // When there is only one node, size === elements.length - cursor. - this._size = 0; - } - get length() { - return this._size; - } - // For exception safety, this method is structured in order: - // 1. Read state - // 2. Calculate required state mutations - // 3. Perform state mutations - push(element) { - const oldBack = this._back; - let newBack = oldBack; - if (oldBack._elements.length === QUEUE_MAX_ARRAY_SIZE - 1) { - newBack = { - _elements: [], - _next: undefined - }; - } - // push() is the mutation most likely to throw an exception, so it - // goes first. - oldBack._elements.push(element); - if (newBack !== oldBack) { - this._back = newBack; - oldBack._next = newBack; - } - ++this._size; - } - // Like push(), shift() follows the read -> calculate -> mutate pattern for - // exception safety. - shift() { // must not be called on an empty queue - const oldFront = this._front; - let newFront = oldFront; - const oldCursor = this._cursor; - let newCursor = oldCursor + 1; - const elements = oldFront._elements; - const element = elements[oldCursor]; - if (newCursor === QUEUE_MAX_ARRAY_SIZE) { - newFront = oldFront._next; - newCursor = 0; - } - // No mutations before this point. - --this._size; - this._cursor = newCursor; - if (oldFront !== newFront) { - this._front = newFront; - } - // Permit shifted element to be garbage collected. - elements[oldCursor] = undefined; - return element; - } - // The tricky thing about forEach() is that it can be called - // re-entrantly. The queue may be mutated inside the callback. It is easy to - // see that push() within the callback has no negative effects since the end - // of the queue is checked for on every iteration. If shift() is called - // repeatedly within the callback then the next iteration may return an - // element that has been removed. In this case the callback will be called - // with undefined values until we either "catch up" with elements that still - // exist or reach the back of the queue. - forEach(callback) { - let i = this._cursor; - let node = this._front; - let elements = node._elements; - while (i !== elements.length || node._next !== undefined) { - if (i === elements.length) { - node = node._next; - elements = node._elements; - i = 0; - if (elements.length === 0) { - break; - } - } - callback(elements[i]); - ++i; - } - } - // Return the element that would be returned if shift() was called now, - // without modifying the queue. - peek() { // must not be called on an empty queue - const front = this._front; - const cursor = this._cursor; - return front._elements[cursor]; - } - } - - function ReadableStreamReaderGenericInitialize(reader, stream) { - reader._ownerReadableStream = stream; - stream._reader = reader; - if (stream._state === 'readable') { - defaultReaderClosedPromiseInitialize(reader); - } - else if (stream._state === 'closed') { - defaultReaderClosedPromiseInitializeAsResolved(reader); - } - else { - defaultReaderClosedPromiseInitializeAsRejected(reader, stream._storedError); - } - } - // A client of ReadableStreamDefaultReader and ReadableStreamBYOBReader may use these functions directly to bypass state - // check. - function ReadableStreamReaderGenericCancel(reader, reason) { - const stream = reader._ownerReadableStream; - return ReadableStreamCancel(stream, reason); - } - function ReadableStreamReaderGenericRelease(reader) { - if (reader._ownerReadableStream._state === 'readable') { - defaultReaderClosedPromiseReject(reader, new TypeError(`Reader was released and can no longer be used to monitor the stream's closedness`)); - } - else { - defaultReaderClosedPromiseResetToRejected(reader, new TypeError(`Reader was released and can no longer be used to monitor the stream's closedness`)); - } - reader._ownerReadableStream._reader = undefined; - reader._ownerReadableStream = undefined; - } - // Helper functions for the readers. - function readerLockException(name) { - return new TypeError('Cannot ' + name + ' a stream using a released reader'); - } - // Helper functions for the ReadableStreamDefaultReader. - function defaultReaderClosedPromiseInitialize(reader) { - reader._closedPromise = newPromise((resolve, reject) => { - reader._closedPromise_resolve = resolve; - reader._closedPromise_reject = reject; - }); - } - function defaultReaderClosedPromiseInitializeAsRejected(reader, reason) { - defaultReaderClosedPromiseInitialize(reader); - defaultReaderClosedPromiseReject(reader, reason); - } - function defaultReaderClosedPromiseInitializeAsResolved(reader) { - defaultReaderClosedPromiseInitialize(reader); - defaultReaderClosedPromiseResolve(reader); - } - function defaultReaderClosedPromiseReject(reader, reason) { - if (reader._closedPromise_reject === undefined) { - return; - } - setPromiseIsHandledToTrue(reader._closedPromise); - reader._closedPromise_reject(reason); - reader._closedPromise_resolve = undefined; - reader._closedPromise_reject = undefined; - } - function defaultReaderClosedPromiseResetToRejected(reader, reason) { - defaultReaderClosedPromiseInitializeAsRejected(reader, reason); - } - function defaultReaderClosedPromiseResolve(reader) { - if (reader._closedPromise_resolve === undefined) { - return; - } - reader._closedPromise_resolve(undefined); - reader._closedPromise_resolve = undefined; - reader._closedPromise_reject = undefined; - } - - const AbortSteps = SymbolPolyfill('[[AbortSteps]]'); - const ErrorSteps = SymbolPolyfill('[[ErrorSteps]]'); - const CancelSteps = SymbolPolyfill('[[CancelSteps]]'); - const PullSteps = SymbolPolyfill('[[PullSteps]]'); - - /// - // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/isFinite#Polyfill - const NumberIsFinite = Number.isFinite || function (x) { - return typeof x === 'number' && isFinite(x); - }; - - /// - // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/trunc#Polyfill - const MathTrunc = Math.trunc || function (v) { - return v < 0 ? Math.ceil(v) : Math.floor(v); - }; - - // https://heycam.github.io/webidl/#idl-dictionaries - function isDictionary(x) { - return typeof x === 'object' || typeof x === 'function'; - } - function assertDictionary(obj, context) { - if (obj !== undefined && !isDictionary(obj)) { - throw new TypeError(`${context} is not an object.`); - } - } - // https://heycam.github.io/webidl/#idl-callback-functions - function assertFunction(x, context) { - if (typeof x !== 'function') { - throw new TypeError(`${context} is not a function.`); - } - } - // https://heycam.github.io/webidl/#idl-object - function isObject(x) { - return (typeof x === 'object' && x !== null) || typeof x === 'function'; - } - function assertObject(x, context) { - if (!isObject(x)) { - throw new TypeError(`${context} is not an object.`); - } - } - function assertRequiredArgument(x, position, context) { - if (x === undefined) { - throw new TypeError(`Parameter ${position} is required in '${context}'.`); - } - } - function assertRequiredField(x, field, context) { - if (x === undefined) { - throw new TypeError(`${field} is required in '${context}'.`); - } - } - // https://heycam.github.io/webidl/#idl-unrestricted-double - function convertUnrestrictedDouble(value) { - return Number(value); - } - function censorNegativeZero(x) { - return x === 0 ? 0 : x; - } - function integerPart(x) { - return censorNegativeZero(MathTrunc(x)); - } - // https://heycam.github.io/webidl/#idl-unsigned-long-long - function convertUnsignedLongLongWithEnforceRange(value, context) { - const lowerBound = 0; - const upperBound = Number.MAX_SAFE_INTEGER; - let x = Number(value); - x = censorNegativeZero(x); - if (!NumberIsFinite(x)) { - throw new TypeError(`${context} is not a finite number`); - } - x = integerPart(x); - if (x < lowerBound || x > upperBound) { - throw new TypeError(`${context} is outside the accepted range of ${lowerBound} to ${upperBound}, inclusive`); - } - if (!NumberIsFinite(x) || x === 0) { - return 0; - } - // TODO Use BigInt if supported? - // let xBigInt = BigInt(integerPart(x)); - // xBigInt = BigInt.asUintN(64, xBigInt); - // return Number(xBigInt); - return x; - } - - function assertReadableStream(x, context) { - if (!IsReadableStream(x)) { - throw new TypeError(`${context} is not a ReadableStream.`); - } - } - - // Abstract operations for the ReadableStream. - function AcquireReadableStreamDefaultReader(stream) { - return new ReadableStreamDefaultReader(stream); - } - // ReadableStream API exposed for controllers. - function ReadableStreamAddReadRequest(stream, readRequest) { - stream._reader._readRequests.push(readRequest); - } - function ReadableStreamFulfillReadRequest(stream, chunk, done) { - const reader = stream._reader; - const readRequest = reader._readRequests.shift(); - if (done) { - readRequest._closeSteps(); - } - else { - readRequest._chunkSteps(chunk); - } - } - function ReadableStreamGetNumReadRequests(stream) { - return stream._reader._readRequests.length; - } - function ReadableStreamHasDefaultReader(stream) { - const reader = stream._reader; - if (reader === undefined) { - return false; - } - if (!IsReadableStreamDefaultReader(reader)) { - return false; - } - return true; - } - /** - * A default reader vended by a {@link ReadableStream}. - * - * @public - */ - class ReadableStreamDefaultReader { - constructor(stream) { - assertRequiredArgument(stream, 1, 'ReadableStreamDefaultReader'); - assertReadableStream(stream, 'First parameter'); - if (IsReadableStreamLocked(stream)) { - throw new TypeError('This stream has already been locked for exclusive reading by another reader'); - } - ReadableStreamReaderGenericInitialize(this, stream); - this._readRequests = new SimpleQueue(); - } - /** - * Returns a promise that will be fulfilled when the stream becomes closed, - * or rejected if the stream ever errors or the reader's lock is released before the stream finishes closing. - */ - get closed() { - if (!IsReadableStreamDefaultReader(this)) { - return promiseRejectedWith(defaultReaderBrandCheckException('closed')); - } - return this._closedPromise; - } - /** - * If the reader is active, behaves the same as {@link ReadableStream.cancel | stream.cancel(reason)}. - */ - cancel(reason = undefined) { - if (!IsReadableStreamDefaultReader(this)) { - return promiseRejectedWith(defaultReaderBrandCheckException('cancel')); - } - if (this._ownerReadableStream === undefined) { - return promiseRejectedWith(readerLockException('cancel')); - } - return ReadableStreamReaderGenericCancel(this, reason); - } - /** - * Returns a promise that allows access to the next chunk from the stream's internal queue, if available. - * - * If reading a chunk causes the queue to become empty, more data will be pulled from the underlying source. - */ - read() { - if (!IsReadableStreamDefaultReader(this)) { - return promiseRejectedWith(defaultReaderBrandCheckException('read')); - } - if (this._ownerReadableStream === undefined) { - return promiseRejectedWith(readerLockException('read from')); - } - let resolvePromise; - let rejectPromise; - const promise = newPromise((resolve, reject) => { - resolvePromise = resolve; - rejectPromise = reject; - }); - const readRequest = { - _chunkSteps: chunk => resolvePromise({ value: chunk, done: false }), - _closeSteps: () => resolvePromise({ value: undefined, done: true }), - _errorSteps: e => rejectPromise(e) - }; - ReadableStreamDefaultReaderRead(this, readRequest); - return promise; - } - /** - * Releases the reader's lock on the corresponding stream. After the lock is released, the reader is no longer active. - * If the associated stream is errored when the lock is released, the reader will appear errored in the same way - * from now on; otherwise, the reader will appear closed. - * - * A reader's lock cannot be released while it still has a pending read request, i.e., if a promise returned by - * the reader's {@link ReadableStreamDefaultReader.read | read()} method has not yet been settled. Attempting to - * do so will throw a `TypeError` and leave the reader locked to the stream. - */ - releaseLock() { - if (!IsReadableStreamDefaultReader(this)) { - throw defaultReaderBrandCheckException('releaseLock'); - } - if (this._ownerReadableStream === undefined) { - return; - } - if (this._readRequests.length > 0) { - throw new TypeError('Tried to release a reader lock when that reader has pending read() calls un-settled'); - } - ReadableStreamReaderGenericRelease(this); - } - } - Object.defineProperties(ReadableStreamDefaultReader.prototype, { - cancel: { enumerable: true }, - read: { enumerable: true }, - releaseLock: { enumerable: true }, - closed: { enumerable: true } - }); - if (typeof SymbolPolyfill.toStringTag === 'symbol') { - Object.defineProperty(ReadableStreamDefaultReader.prototype, SymbolPolyfill.toStringTag, { - value: 'ReadableStreamDefaultReader', - configurable: true - }); - } - // Abstract operations for the readers. - function IsReadableStreamDefaultReader(x) { - if (!typeIsObject(x)) { - return false; - } - if (!Object.prototype.hasOwnProperty.call(x, '_readRequests')) { - return false; - } - return x instanceof ReadableStreamDefaultReader; - } - function ReadableStreamDefaultReaderRead(reader, readRequest) { - const stream = reader._ownerReadableStream; - stream._disturbed = true; - if (stream._state === 'closed') { - readRequest._closeSteps(); - } - else if (stream._state === 'errored') { - readRequest._errorSteps(stream._storedError); - } - else { - stream._readableStreamController[PullSteps](readRequest); - } - } - // Helper functions for the ReadableStreamDefaultReader. - function defaultReaderBrandCheckException(name) { - return new TypeError(`ReadableStreamDefaultReader.prototype.${name} can only be used on a ReadableStreamDefaultReader`); - } - - /// - /* eslint-disable @typescript-eslint/no-empty-function */ - const AsyncIteratorPrototype = Object.getPrototypeOf(Object.getPrototypeOf(async function* () { }).prototype); - - /// - class ReadableStreamAsyncIteratorImpl { - constructor(reader, preventCancel) { - this._ongoingPromise = undefined; - this._isFinished = false; - this._reader = reader; - this._preventCancel = preventCancel; - } - next() { - const nextSteps = () => this._nextSteps(); - this._ongoingPromise = this._ongoingPromise ? - transformPromiseWith(this._ongoingPromise, nextSteps, nextSteps) : - nextSteps(); - return this._ongoingPromise; - } - return(value) { - const returnSteps = () => this._returnSteps(value); - return this._ongoingPromise ? - transformPromiseWith(this._ongoingPromise, returnSteps, returnSteps) : - returnSteps(); - } - _nextSteps() { - if (this._isFinished) { - return Promise.resolve({ value: undefined, done: true }); - } - const reader = this._reader; - if (reader._ownerReadableStream === undefined) { - return promiseRejectedWith(readerLockException('iterate')); - } - let resolvePromise; - let rejectPromise; - const promise = newPromise((resolve, reject) => { - resolvePromise = resolve; - rejectPromise = reject; - }); - const readRequest = { - _chunkSteps: chunk => { - this._ongoingPromise = undefined; - // This needs to be delayed by one microtask, otherwise we stop pulling too early which breaks a test. - // FIXME Is this a bug in the specification, or in the test? - queueMicrotask(() => resolvePromise({ value: chunk, done: false })); - }, - _closeSteps: () => { - this._ongoingPromise = undefined; - this._isFinished = true; - ReadableStreamReaderGenericRelease(reader); - resolvePromise({ value: undefined, done: true }); - }, - _errorSteps: reason => { - this._ongoingPromise = undefined; - this._isFinished = true; - ReadableStreamReaderGenericRelease(reader); - rejectPromise(reason); - } - }; - ReadableStreamDefaultReaderRead(reader, readRequest); - return promise; - } - _returnSteps(value) { - if (this._isFinished) { - return Promise.resolve({ value, done: true }); - } - this._isFinished = true; - const reader = this._reader; - if (reader._ownerReadableStream === undefined) { - return promiseRejectedWith(readerLockException('finish iterating')); - } - if (!this._preventCancel) { - const result = ReadableStreamReaderGenericCancel(reader, value); - ReadableStreamReaderGenericRelease(reader); - return transformPromiseWith(result, () => ({ value, done: true })); - } - ReadableStreamReaderGenericRelease(reader); - return promiseResolvedWith({ value, done: true }); - } - } - const ReadableStreamAsyncIteratorPrototype = { - next() { - if (!IsReadableStreamAsyncIterator(this)) { - return promiseRejectedWith(streamAsyncIteratorBrandCheckException('next')); - } - return this._asyncIteratorImpl.next(); - }, - return(value) { - if (!IsReadableStreamAsyncIterator(this)) { - return promiseRejectedWith(streamAsyncIteratorBrandCheckException('return')); - } - return this._asyncIteratorImpl.return(value); - } - }; - if (AsyncIteratorPrototype !== undefined) { - Object.setPrototypeOf(ReadableStreamAsyncIteratorPrototype, AsyncIteratorPrototype); - } - // Abstract operations for the ReadableStream. - function AcquireReadableStreamAsyncIterator(stream, preventCancel) { - const reader = AcquireReadableStreamDefaultReader(stream); - const impl = new ReadableStreamAsyncIteratorImpl(reader, preventCancel); - const iterator = Object.create(ReadableStreamAsyncIteratorPrototype); - iterator._asyncIteratorImpl = impl; - return iterator; - } - function IsReadableStreamAsyncIterator(x) { - if (!typeIsObject(x)) { - return false; - } - if (!Object.prototype.hasOwnProperty.call(x, '_asyncIteratorImpl')) { - return false; - } - try { - // noinspection SuspiciousTypeOfGuard - return x._asyncIteratorImpl instanceof - ReadableStreamAsyncIteratorImpl; - } - catch (_a) { - return false; - } - } - // Helper functions for the ReadableStream. - function streamAsyncIteratorBrandCheckException(name) { - return new TypeError(`ReadableStreamAsyncIterator.${name} can only be used on a ReadableSteamAsyncIterator`); - } - - /// - // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/isNaN#Polyfill - const NumberIsNaN = Number.isNaN || function (x) { - // eslint-disable-next-line no-self-compare - return x !== x; - }; - - function CreateArrayFromList(elements) { - // We use arrays to represent lists, so this is basically a no-op. - // Do a slice though just in case we happen to depend on the unique-ness. - return elements.slice(); - } - function CopyDataBlockBytes(dest, destOffset, src, srcOffset, n) { - new Uint8Array(dest).set(new Uint8Array(src, srcOffset, n), destOffset); - } - // Not implemented correctly - function TransferArrayBuffer(O) { - return O; - } - // Not implemented correctly - // eslint-disable-next-line @typescript-eslint/no-unused-vars - function IsDetachedBuffer(O) { - return false; - } - function ArrayBufferSlice(buffer, begin, end) { - // ArrayBuffer.prototype.slice is not available on IE10 - // https://www.caniuse.com/mdn-javascript_builtins_arraybuffer_slice - if (buffer.slice) { - return buffer.slice(begin, end); - } - const length = end - begin; - const slice = new ArrayBuffer(length); - CopyDataBlockBytes(slice, 0, buffer, begin, length); - return slice; - } - - function IsNonNegativeNumber(v) { - if (typeof v !== 'number') { - return false; - } - if (NumberIsNaN(v)) { - return false; - } - if (v < 0) { - return false; - } - return true; - } - function CloneAsUint8Array(O) { - const buffer = ArrayBufferSlice(O.buffer, O.byteOffset, O.byteOffset + O.byteLength); - return new Uint8Array(buffer); - } - - function DequeueValue(container) { - const pair = container._queue.shift(); - container._queueTotalSize -= pair.size; - if (container._queueTotalSize < 0) { - container._queueTotalSize = 0; - } - return pair.value; - } - function EnqueueValueWithSize(container, value, size) { - if (!IsNonNegativeNumber(size) || size === Infinity) { - throw new RangeError('Size must be a finite, non-NaN, non-negative number.'); - } - container._queue.push({ value, size }); - container._queueTotalSize += size; - } - function PeekQueueValue(container) { - const pair = container._queue.peek(); - return pair.value; - } - function ResetQueue(container) { - container._queue = new SimpleQueue(); - container._queueTotalSize = 0; - } - - /** - * A pull-into request in a {@link ReadableByteStreamController}. - * - * @public - */ - class ReadableStreamBYOBRequest { - constructor() { - throw new TypeError('Illegal constructor'); - } - /** - * Returns the view for writing in to, or `null` if the BYOB request has already been responded to. - */ - get view() { - if (!IsReadableStreamBYOBRequest(this)) { - throw byobRequestBrandCheckException('view'); - } - return this._view; - } - respond(bytesWritten) { - if (!IsReadableStreamBYOBRequest(this)) { - throw byobRequestBrandCheckException('respond'); - } - assertRequiredArgument(bytesWritten, 1, 'respond'); - bytesWritten = convertUnsignedLongLongWithEnforceRange(bytesWritten, 'First parameter'); - if (this._associatedReadableByteStreamController === undefined) { - throw new TypeError('This BYOB request has been invalidated'); - } - if (IsDetachedBuffer(this._view.buffer)) ; - ReadableByteStreamControllerRespond(this._associatedReadableByteStreamController, bytesWritten); - } - respondWithNewView(view) { - if (!IsReadableStreamBYOBRequest(this)) { - throw byobRequestBrandCheckException('respondWithNewView'); - } - assertRequiredArgument(view, 1, 'respondWithNewView'); - if (!ArrayBuffer.isView(view)) { - throw new TypeError('You can only respond with array buffer views'); - } - if (this._associatedReadableByteStreamController === undefined) { - throw new TypeError('This BYOB request has been invalidated'); - } - if (IsDetachedBuffer(view.buffer)) ; - ReadableByteStreamControllerRespondWithNewView(this._associatedReadableByteStreamController, view); - } - } - Object.defineProperties(ReadableStreamBYOBRequest.prototype, { - respond: { enumerable: true }, - respondWithNewView: { enumerable: true }, - view: { enumerable: true } - }); - if (typeof SymbolPolyfill.toStringTag === 'symbol') { - Object.defineProperty(ReadableStreamBYOBRequest.prototype, SymbolPolyfill.toStringTag, { - value: 'ReadableStreamBYOBRequest', - configurable: true - }); - } - /** - * Allows control of a {@link ReadableStream | readable byte stream}'s state and internal queue. - * - * @public - */ - class ReadableByteStreamController { - constructor() { - throw new TypeError('Illegal constructor'); - } - /** - * Returns the current BYOB pull request, or `null` if there isn't one. - */ - get byobRequest() { - if (!IsReadableByteStreamController(this)) { - throw byteStreamControllerBrandCheckException('byobRequest'); - } - return ReadableByteStreamControllerGetBYOBRequest(this); - } - /** - * Returns the desired size to fill the controlled stream's internal queue. It can be negative, if the queue is - * over-full. An underlying byte source ought to use this information to determine when and how to apply backpressure. - */ - get desiredSize() { - if (!IsReadableByteStreamController(this)) { - throw byteStreamControllerBrandCheckException('desiredSize'); - } - return ReadableByteStreamControllerGetDesiredSize(this); - } - /** - * Closes the controlled readable stream. Consumers will still be able to read any previously-enqueued chunks from - * the stream, but once those are read, the stream will become closed. - */ - close() { - if (!IsReadableByteStreamController(this)) { - throw byteStreamControllerBrandCheckException('close'); - } - if (this._closeRequested) { - throw new TypeError('The stream has already been closed; do not close it again!'); - } - const state = this._controlledReadableByteStream._state; - if (state !== 'readable') { - throw new TypeError(`The stream (in ${state} state) is not in the readable state and cannot be closed`); - } - ReadableByteStreamControllerClose(this); - } - enqueue(chunk) { - if (!IsReadableByteStreamController(this)) { - throw byteStreamControllerBrandCheckException('enqueue'); - } - assertRequiredArgument(chunk, 1, 'enqueue'); - if (!ArrayBuffer.isView(chunk)) { - throw new TypeError('chunk must be an array buffer view'); - } - if (chunk.byteLength === 0) { - throw new TypeError('chunk must have non-zero byteLength'); - } - if (chunk.buffer.byteLength === 0) { - throw new TypeError(`chunk's buffer must have non-zero byteLength`); - } - if (this._closeRequested) { - throw new TypeError('stream is closed or draining'); - } - const state = this._controlledReadableByteStream._state; - if (state !== 'readable') { - throw new TypeError(`The stream (in ${state} state) is not in the readable state and cannot be enqueued to`); - } - ReadableByteStreamControllerEnqueue(this, chunk); - } - /** - * Errors the controlled readable stream, making all future interactions with it fail with the given error `e`. - */ - error(e = undefined) { - if (!IsReadableByteStreamController(this)) { - throw byteStreamControllerBrandCheckException('error'); - } - ReadableByteStreamControllerError(this, e); - } - /** @internal */ - [CancelSteps](reason) { - ReadableByteStreamControllerClearPendingPullIntos(this); - ResetQueue(this); - const result = this._cancelAlgorithm(reason); - ReadableByteStreamControllerClearAlgorithms(this); - return result; - } - /** @internal */ - [PullSteps](readRequest) { - const stream = this._controlledReadableByteStream; - if (this._queueTotalSize > 0) { - const entry = this._queue.shift(); - this._queueTotalSize -= entry.byteLength; - ReadableByteStreamControllerHandleQueueDrain(this); - const view = new Uint8Array(entry.buffer, entry.byteOffset, entry.byteLength); - readRequest._chunkSteps(view); - return; - } - const autoAllocateChunkSize = this._autoAllocateChunkSize; - if (autoAllocateChunkSize !== undefined) { - let buffer; - try { - buffer = new ArrayBuffer(autoAllocateChunkSize); - } - catch (bufferE) { - readRequest._errorSteps(bufferE); - return; - } - const pullIntoDescriptor = { - buffer, - bufferByteLength: autoAllocateChunkSize, - byteOffset: 0, - byteLength: autoAllocateChunkSize, - bytesFilled: 0, - elementSize: 1, - viewConstructor: Uint8Array, - readerType: 'default' - }; - this._pendingPullIntos.push(pullIntoDescriptor); - } - ReadableStreamAddReadRequest(stream, readRequest); - ReadableByteStreamControllerCallPullIfNeeded(this); - } - } - Object.defineProperties(ReadableByteStreamController.prototype, { - close: { enumerable: true }, - enqueue: { enumerable: true }, - error: { enumerable: true }, - byobRequest: { enumerable: true }, - desiredSize: { enumerable: true } - }); - if (typeof SymbolPolyfill.toStringTag === 'symbol') { - Object.defineProperty(ReadableByteStreamController.prototype, SymbolPolyfill.toStringTag, { - value: 'ReadableByteStreamController', - configurable: true - }); - } - // Abstract operations for the ReadableByteStreamController. - function IsReadableByteStreamController(x) { - if (!typeIsObject(x)) { - return false; - } - if (!Object.prototype.hasOwnProperty.call(x, '_controlledReadableByteStream')) { - return false; - } - return x instanceof ReadableByteStreamController; - } - function IsReadableStreamBYOBRequest(x) { - if (!typeIsObject(x)) { - return false; - } - if (!Object.prototype.hasOwnProperty.call(x, '_associatedReadableByteStreamController')) { - return false; - } - return x instanceof ReadableStreamBYOBRequest; - } - function ReadableByteStreamControllerCallPullIfNeeded(controller) { - const shouldPull = ReadableByteStreamControllerShouldCallPull(controller); - if (!shouldPull) { - return; - } - if (controller._pulling) { - controller._pullAgain = true; - return; - } - controller._pulling = true; - // TODO: Test controller argument - const pullPromise = controller._pullAlgorithm(); - uponPromise(pullPromise, () => { - controller._pulling = false; - if (controller._pullAgain) { - controller._pullAgain = false; - ReadableByteStreamControllerCallPullIfNeeded(controller); - } - }, e => { - ReadableByteStreamControllerError(controller, e); - }); - } - function ReadableByteStreamControllerClearPendingPullIntos(controller) { - ReadableByteStreamControllerInvalidateBYOBRequest(controller); - controller._pendingPullIntos = new SimpleQueue(); - } - function ReadableByteStreamControllerCommitPullIntoDescriptor(stream, pullIntoDescriptor) { - let done = false; - if (stream._state === 'closed') { - done = true; - } - const filledView = ReadableByteStreamControllerConvertPullIntoDescriptor(pullIntoDescriptor); - if (pullIntoDescriptor.readerType === 'default') { - ReadableStreamFulfillReadRequest(stream, filledView, done); - } - else { - ReadableStreamFulfillReadIntoRequest(stream, filledView, done); - } - } - function ReadableByteStreamControllerConvertPullIntoDescriptor(pullIntoDescriptor) { - const bytesFilled = pullIntoDescriptor.bytesFilled; - const elementSize = pullIntoDescriptor.elementSize; - return new pullIntoDescriptor.viewConstructor(pullIntoDescriptor.buffer, pullIntoDescriptor.byteOffset, bytesFilled / elementSize); - } - function ReadableByteStreamControllerEnqueueChunkToQueue(controller, buffer, byteOffset, byteLength) { - controller._queue.push({ buffer, byteOffset, byteLength }); - controller._queueTotalSize += byteLength; - } - function ReadableByteStreamControllerFillPullIntoDescriptorFromQueue(controller, pullIntoDescriptor) { - const elementSize = pullIntoDescriptor.elementSize; - const currentAlignedBytes = pullIntoDescriptor.bytesFilled - pullIntoDescriptor.bytesFilled % elementSize; - const maxBytesToCopy = Math.min(controller._queueTotalSize, pullIntoDescriptor.byteLength - pullIntoDescriptor.bytesFilled); - const maxBytesFilled = pullIntoDescriptor.bytesFilled + maxBytesToCopy; - const maxAlignedBytes = maxBytesFilled - maxBytesFilled % elementSize; - let totalBytesToCopyRemaining = maxBytesToCopy; - let ready = false; - if (maxAlignedBytes > currentAlignedBytes) { - totalBytesToCopyRemaining = maxAlignedBytes - pullIntoDescriptor.bytesFilled; - ready = true; - } - const queue = controller._queue; - while (totalBytesToCopyRemaining > 0) { - const headOfQueue = queue.peek(); - const bytesToCopy = Math.min(totalBytesToCopyRemaining, headOfQueue.byteLength); - const destStart = pullIntoDescriptor.byteOffset + pullIntoDescriptor.bytesFilled; - CopyDataBlockBytes(pullIntoDescriptor.buffer, destStart, headOfQueue.buffer, headOfQueue.byteOffset, bytesToCopy); - if (headOfQueue.byteLength === bytesToCopy) { - queue.shift(); - } - else { - headOfQueue.byteOffset += bytesToCopy; - headOfQueue.byteLength -= bytesToCopy; - } - controller._queueTotalSize -= bytesToCopy; - ReadableByteStreamControllerFillHeadPullIntoDescriptor(controller, bytesToCopy, pullIntoDescriptor); - totalBytesToCopyRemaining -= bytesToCopy; - } - return ready; - } - function ReadableByteStreamControllerFillHeadPullIntoDescriptor(controller, size, pullIntoDescriptor) { - pullIntoDescriptor.bytesFilled += size; - } - function ReadableByteStreamControllerHandleQueueDrain(controller) { - if (controller._queueTotalSize === 0 && controller._closeRequested) { - ReadableByteStreamControllerClearAlgorithms(controller); - ReadableStreamClose(controller._controlledReadableByteStream); - } - else { - ReadableByteStreamControllerCallPullIfNeeded(controller); - } - } - function ReadableByteStreamControllerInvalidateBYOBRequest(controller) { - if (controller._byobRequest === null) { - return; - } - controller._byobRequest._associatedReadableByteStreamController = undefined; - controller._byobRequest._view = null; - controller._byobRequest = null; - } - function ReadableByteStreamControllerProcessPullIntoDescriptorsUsingQueue(controller) { - while (controller._pendingPullIntos.length > 0) { - if (controller._queueTotalSize === 0) { - return; - } - const pullIntoDescriptor = controller._pendingPullIntos.peek(); - if (ReadableByteStreamControllerFillPullIntoDescriptorFromQueue(controller, pullIntoDescriptor)) { - ReadableByteStreamControllerShiftPendingPullInto(controller); - ReadableByteStreamControllerCommitPullIntoDescriptor(controller._controlledReadableByteStream, pullIntoDescriptor); - } - } - } - function ReadableByteStreamControllerPullInto(controller, view, readIntoRequest) { - const stream = controller._controlledReadableByteStream; - let elementSize = 1; - if (view.constructor !== DataView) { - elementSize = view.constructor.BYTES_PER_ELEMENT; - } - const ctor = view.constructor; - // try { - const buffer = TransferArrayBuffer(view.buffer); - // } catch (e) { - // readIntoRequest._errorSteps(e); - // return; - // } - const pullIntoDescriptor = { - buffer, - bufferByteLength: buffer.byteLength, - byteOffset: view.byteOffset, - byteLength: view.byteLength, - bytesFilled: 0, - elementSize, - viewConstructor: ctor, - readerType: 'byob' - }; - if (controller._pendingPullIntos.length > 0) { - controller._pendingPullIntos.push(pullIntoDescriptor); - // No ReadableByteStreamControllerCallPullIfNeeded() call since: - // - No change happens on desiredSize - // - The source has already been notified of that there's at least 1 pending read(view) - ReadableStreamAddReadIntoRequest(stream, readIntoRequest); - return; - } - if (stream._state === 'closed') { - const emptyView = new ctor(pullIntoDescriptor.buffer, pullIntoDescriptor.byteOffset, 0); - readIntoRequest._closeSteps(emptyView); - return; - } - if (controller._queueTotalSize > 0) { - if (ReadableByteStreamControllerFillPullIntoDescriptorFromQueue(controller, pullIntoDescriptor)) { - const filledView = ReadableByteStreamControllerConvertPullIntoDescriptor(pullIntoDescriptor); - ReadableByteStreamControllerHandleQueueDrain(controller); - readIntoRequest._chunkSteps(filledView); - return; - } - if (controller._closeRequested) { - const e = new TypeError('Insufficient bytes to fill elements in the given buffer'); - ReadableByteStreamControllerError(controller, e); - readIntoRequest._errorSteps(e); - return; - } - } - controller._pendingPullIntos.push(pullIntoDescriptor); - ReadableStreamAddReadIntoRequest(stream, readIntoRequest); - ReadableByteStreamControllerCallPullIfNeeded(controller); - } - function ReadableByteStreamControllerRespondInClosedState(controller, firstDescriptor) { - const stream = controller._controlledReadableByteStream; - if (ReadableStreamHasBYOBReader(stream)) { - while (ReadableStreamGetNumReadIntoRequests(stream) > 0) { - const pullIntoDescriptor = ReadableByteStreamControllerShiftPendingPullInto(controller); - ReadableByteStreamControllerCommitPullIntoDescriptor(stream, pullIntoDescriptor); - } - } - } - function ReadableByteStreamControllerRespondInReadableState(controller, bytesWritten, pullIntoDescriptor) { - ReadableByteStreamControllerFillHeadPullIntoDescriptor(controller, bytesWritten, pullIntoDescriptor); - if (pullIntoDescriptor.bytesFilled < pullIntoDescriptor.elementSize) { - return; - } - ReadableByteStreamControllerShiftPendingPullInto(controller); - const remainderSize = pullIntoDescriptor.bytesFilled % pullIntoDescriptor.elementSize; - if (remainderSize > 0) { - const end = pullIntoDescriptor.byteOffset + pullIntoDescriptor.bytesFilled; - const remainder = ArrayBufferSlice(pullIntoDescriptor.buffer, end - remainderSize, end); - ReadableByteStreamControllerEnqueueChunkToQueue(controller, remainder, 0, remainder.byteLength); - } - pullIntoDescriptor.bytesFilled -= remainderSize; - ReadableByteStreamControllerCommitPullIntoDescriptor(controller._controlledReadableByteStream, pullIntoDescriptor); - ReadableByteStreamControllerProcessPullIntoDescriptorsUsingQueue(controller); - } - function ReadableByteStreamControllerRespondInternal(controller, bytesWritten) { - const firstDescriptor = controller._pendingPullIntos.peek(); - ReadableByteStreamControllerInvalidateBYOBRequest(controller); - const state = controller._controlledReadableByteStream._state; - if (state === 'closed') { - ReadableByteStreamControllerRespondInClosedState(controller); - } - else { - ReadableByteStreamControllerRespondInReadableState(controller, bytesWritten, firstDescriptor); - } - ReadableByteStreamControllerCallPullIfNeeded(controller); - } - function ReadableByteStreamControllerShiftPendingPullInto(controller) { - const descriptor = controller._pendingPullIntos.shift(); - return descriptor; - } - function ReadableByteStreamControllerShouldCallPull(controller) { - const stream = controller._controlledReadableByteStream; - if (stream._state !== 'readable') { - return false; - } - if (controller._closeRequested) { - return false; - } - if (!controller._started) { - return false; - } - if (ReadableStreamHasDefaultReader(stream) && ReadableStreamGetNumReadRequests(stream) > 0) { - return true; - } - if (ReadableStreamHasBYOBReader(stream) && ReadableStreamGetNumReadIntoRequests(stream) > 0) { - return true; - } - const desiredSize = ReadableByteStreamControllerGetDesiredSize(controller); - if (desiredSize > 0) { - return true; - } - return false; - } - function ReadableByteStreamControllerClearAlgorithms(controller) { - controller._pullAlgorithm = undefined; - controller._cancelAlgorithm = undefined; - } - // A client of ReadableByteStreamController may use these functions directly to bypass state check. - function ReadableByteStreamControllerClose(controller) { - const stream = controller._controlledReadableByteStream; - if (controller._closeRequested || stream._state !== 'readable') { - return; - } - if (controller._queueTotalSize > 0) { - controller._closeRequested = true; - return; - } - if (controller._pendingPullIntos.length > 0) { - const firstPendingPullInto = controller._pendingPullIntos.peek(); - if (firstPendingPullInto.bytesFilled > 0) { - const e = new TypeError('Insufficient bytes to fill elements in the given buffer'); - ReadableByteStreamControllerError(controller, e); - throw e; - } - } - ReadableByteStreamControllerClearAlgorithms(controller); - ReadableStreamClose(stream); - } - function ReadableByteStreamControllerEnqueue(controller, chunk) { - const stream = controller._controlledReadableByteStream; - if (controller._closeRequested || stream._state !== 'readable') { - return; - } - const buffer = chunk.buffer; - const byteOffset = chunk.byteOffset; - const byteLength = chunk.byteLength; - const transferredBuffer = TransferArrayBuffer(buffer); - if (controller._pendingPullIntos.length > 0) { - const firstPendingPullInto = controller._pendingPullIntos.peek(); - if (IsDetachedBuffer(firstPendingPullInto.buffer)) ; - firstPendingPullInto.buffer = TransferArrayBuffer(firstPendingPullInto.buffer); - } - ReadableByteStreamControllerInvalidateBYOBRequest(controller); - if (ReadableStreamHasDefaultReader(stream)) { - if (ReadableStreamGetNumReadRequests(stream) === 0) { - ReadableByteStreamControllerEnqueueChunkToQueue(controller, transferredBuffer, byteOffset, byteLength); - } - else { - if (controller._pendingPullIntos.length > 0) { - ReadableByteStreamControllerShiftPendingPullInto(controller); - } - const transferredView = new Uint8Array(transferredBuffer, byteOffset, byteLength); - ReadableStreamFulfillReadRequest(stream, transferredView, false); - } - } - else if (ReadableStreamHasBYOBReader(stream)) { - // TODO: Ideally in this branch detaching should happen only if the buffer is not consumed fully. - ReadableByteStreamControllerEnqueueChunkToQueue(controller, transferredBuffer, byteOffset, byteLength); - ReadableByteStreamControllerProcessPullIntoDescriptorsUsingQueue(controller); - } - else { - ReadableByteStreamControllerEnqueueChunkToQueue(controller, transferredBuffer, byteOffset, byteLength); - } - ReadableByteStreamControllerCallPullIfNeeded(controller); - } - function ReadableByteStreamControllerError(controller, e) { - const stream = controller._controlledReadableByteStream; - if (stream._state !== 'readable') { - return; - } - ReadableByteStreamControllerClearPendingPullIntos(controller); - ResetQueue(controller); - ReadableByteStreamControllerClearAlgorithms(controller); - ReadableStreamError(stream, e); - } - function ReadableByteStreamControllerGetBYOBRequest(controller) { - if (controller._byobRequest === null && controller._pendingPullIntos.length > 0) { - const firstDescriptor = controller._pendingPullIntos.peek(); - const view = new Uint8Array(firstDescriptor.buffer, firstDescriptor.byteOffset + firstDescriptor.bytesFilled, firstDescriptor.byteLength - firstDescriptor.bytesFilled); - const byobRequest = Object.create(ReadableStreamBYOBRequest.prototype); - SetUpReadableStreamBYOBRequest(byobRequest, controller, view); - controller._byobRequest = byobRequest; - } - return controller._byobRequest; - } - function ReadableByteStreamControllerGetDesiredSize(controller) { - const state = controller._controlledReadableByteStream._state; - if (state === 'errored') { - return null; - } - if (state === 'closed') { - return 0; - } - return controller._strategyHWM - controller._queueTotalSize; - } - function ReadableByteStreamControllerRespond(controller, bytesWritten) { - const firstDescriptor = controller._pendingPullIntos.peek(); - const state = controller._controlledReadableByteStream._state; - if (state === 'closed') { - if (bytesWritten !== 0) { - throw new TypeError('bytesWritten must be 0 when calling respond() on a closed stream'); - } - } - else { - if (bytesWritten === 0) { - throw new TypeError('bytesWritten must be greater than 0 when calling respond() on a readable stream'); - } - if (firstDescriptor.bytesFilled + bytesWritten > firstDescriptor.byteLength) { - throw new RangeError('bytesWritten out of range'); - } - } - firstDescriptor.buffer = TransferArrayBuffer(firstDescriptor.buffer); - ReadableByteStreamControllerRespondInternal(controller, bytesWritten); - } - function ReadableByteStreamControllerRespondWithNewView(controller, view) { - const firstDescriptor = controller._pendingPullIntos.peek(); - const state = controller._controlledReadableByteStream._state; - if (state === 'closed') { - if (view.byteLength !== 0) { - throw new TypeError('The view\'s length must be 0 when calling respondWithNewView() on a closed stream'); - } - } - else { - if (view.byteLength === 0) { - throw new TypeError('The view\'s length must be greater than 0 when calling respondWithNewView() on a readable stream'); - } - } - if (firstDescriptor.byteOffset + firstDescriptor.bytesFilled !== view.byteOffset) { - throw new RangeError('The region specified by view does not match byobRequest'); - } - if (firstDescriptor.bufferByteLength !== view.buffer.byteLength) { - throw new RangeError('The buffer of view has different capacity than byobRequest'); - } - if (firstDescriptor.bytesFilled + view.byteLength > firstDescriptor.byteLength) { - throw new RangeError('The region specified by view is larger than byobRequest'); - } - const viewByteLength = view.byteLength; - firstDescriptor.buffer = TransferArrayBuffer(view.buffer); - ReadableByteStreamControllerRespondInternal(controller, viewByteLength); - } - function SetUpReadableByteStreamController(stream, controller, startAlgorithm, pullAlgorithm, cancelAlgorithm, highWaterMark, autoAllocateChunkSize) { - controller._controlledReadableByteStream = stream; - controller._pullAgain = false; - controller._pulling = false; - controller._byobRequest = null; - // Need to set the slots so that the assert doesn't fire. In the spec the slots already exist implicitly. - controller._queue = controller._queueTotalSize = undefined; - ResetQueue(controller); - controller._closeRequested = false; - controller._started = false; - controller._strategyHWM = highWaterMark; - controller._pullAlgorithm = pullAlgorithm; - controller._cancelAlgorithm = cancelAlgorithm; - controller._autoAllocateChunkSize = autoAllocateChunkSize; - controller._pendingPullIntos = new SimpleQueue(); - stream._readableStreamController = controller; - const startResult = startAlgorithm(); - uponPromise(promiseResolvedWith(startResult), () => { - controller._started = true; - ReadableByteStreamControllerCallPullIfNeeded(controller); - }, r => { - ReadableByteStreamControllerError(controller, r); - }); - } - function SetUpReadableByteStreamControllerFromUnderlyingSource(stream, underlyingByteSource, highWaterMark) { - const controller = Object.create(ReadableByteStreamController.prototype); - let startAlgorithm = () => undefined; - let pullAlgorithm = () => promiseResolvedWith(undefined); - let cancelAlgorithm = () => promiseResolvedWith(undefined); - if (underlyingByteSource.start !== undefined) { - startAlgorithm = () => underlyingByteSource.start(controller); - } - if (underlyingByteSource.pull !== undefined) { - pullAlgorithm = () => underlyingByteSource.pull(controller); - } - if (underlyingByteSource.cancel !== undefined) { - cancelAlgorithm = reason => underlyingByteSource.cancel(reason); - } - const autoAllocateChunkSize = underlyingByteSource.autoAllocateChunkSize; - if (autoAllocateChunkSize === 0) { - throw new TypeError('autoAllocateChunkSize must be greater than 0'); - } - SetUpReadableByteStreamController(stream, controller, startAlgorithm, pullAlgorithm, cancelAlgorithm, highWaterMark, autoAllocateChunkSize); - } - function SetUpReadableStreamBYOBRequest(request, controller, view) { - request._associatedReadableByteStreamController = controller; - request._view = view; - } - // Helper functions for the ReadableStreamBYOBRequest. - function byobRequestBrandCheckException(name) { - return new TypeError(`ReadableStreamBYOBRequest.prototype.${name} can only be used on a ReadableStreamBYOBRequest`); - } - // Helper functions for the ReadableByteStreamController. - function byteStreamControllerBrandCheckException(name) { - return new TypeError(`ReadableByteStreamController.prototype.${name} can only be used on a ReadableByteStreamController`); - } - - // Abstract operations for the ReadableStream. - function AcquireReadableStreamBYOBReader(stream) { - return new ReadableStreamBYOBReader(stream); - } - // ReadableStream API exposed for controllers. - function ReadableStreamAddReadIntoRequest(stream, readIntoRequest) { - stream._reader._readIntoRequests.push(readIntoRequest); - } - function ReadableStreamFulfillReadIntoRequest(stream, chunk, done) { - const reader = stream._reader; - const readIntoRequest = reader._readIntoRequests.shift(); - if (done) { - readIntoRequest._closeSteps(chunk); - } - else { - readIntoRequest._chunkSteps(chunk); - } - } - function ReadableStreamGetNumReadIntoRequests(stream) { - return stream._reader._readIntoRequests.length; - } - function ReadableStreamHasBYOBReader(stream) { - const reader = stream._reader; - if (reader === undefined) { - return false; - } - if (!IsReadableStreamBYOBReader(reader)) { - return false; - } - return true; - } - /** - * A BYOB reader vended by a {@link ReadableStream}. - * - * @public - */ - class ReadableStreamBYOBReader { - constructor(stream) { - assertRequiredArgument(stream, 1, 'ReadableStreamBYOBReader'); - assertReadableStream(stream, 'First parameter'); - if (IsReadableStreamLocked(stream)) { - throw new TypeError('This stream has already been locked for exclusive reading by another reader'); - } - if (!IsReadableByteStreamController(stream._readableStreamController)) { - throw new TypeError('Cannot construct a ReadableStreamBYOBReader for a stream not constructed with a byte ' + - 'source'); - } - ReadableStreamReaderGenericInitialize(this, stream); - this._readIntoRequests = new SimpleQueue(); - } - /** - * Returns a promise that will be fulfilled when the stream becomes closed, or rejected if the stream ever errors or - * the reader's lock is released before the stream finishes closing. - */ - get closed() { - if (!IsReadableStreamBYOBReader(this)) { - return promiseRejectedWith(byobReaderBrandCheckException('closed')); - } - return this._closedPromise; - } - /** - * If the reader is active, behaves the same as {@link ReadableStream.cancel | stream.cancel(reason)}. - */ - cancel(reason = undefined) { - if (!IsReadableStreamBYOBReader(this)) { - return promiseRejectedWith(byobReaderBrandCheckException('cancel')); - } - if (this._ownerReadableStream === undefined) { - return promiseRejectedWith(readerLockException('cancel')); - } - return ReadableStreamReaderGenericCancel(this, reason); - } - /** - * Attempts to reads bytes into view, and returns a promise resolved with the result. - * - * If reading a chunk causes the queue to become empty, more data will be pulled from the underlying source. - */ - read(view) { - if (!IsReadableStreamBYOBReader(this)) { - return promiseRejectedWith(byobReaderBrandCheckException('read')); - } - if (!ArrayBuffer.isView(view)) { - return promiseRejectedWith(new TypeError('view must be an array buffer view')); - } - if (view.byteLength === 0) { - return promiseRejectedWith(new TypeError('view must have non-zero byteLength')); - } - if (view.buffer.byteLength === 0) { - return promiseRejectedWith(new TypeError(`view's buffer must have non-zero byteLength`)); - } - if (IsDetachedBuffer(view.buffer)) ; - if (this._ownerReadableStream === undefined) { - return promiseRejectedWith(readerLockException('read from')); - } - let resolvePromise; - let rejectPromise; - const promise = newPromise((resolve, reject) => { - resolvePromise = resolve; - rejectPromise = reject; - }); - const readIntoRequest = { - _chunkSteps: chunk => resolvePromise({ value: chunk, done: false }), - _closeSteps: chunk => resolvePromise({ value: chunk, done: true }), - _errorSteps: e => rejectPromise(e) - }; - ReadableStreamBYOBReaderRead(this, view, readIntoRequest); - return promise; - } - /** - * Releases the reader's lock on the corresponding stream. After the lock is released, the reader is no longer active. - * If the associated stream is errored when the lock is released, the reader will appear errored in the same way - * from now on; otherwise, the reader will appear closed. - * - * A reader's lock cannot be released while it still has a pending read request, i.e., if a promise returned by - * the reader's {@link ReadableStreamBYOBReader.read | read()} method has not yet been settled. Attempting to - * do so will throw a `TypeError` and leave the reader locked to the stream. - */ - releaseLock() { - if (!IsReadableStreamBYOBReader(this)) { - throw byobReaderBrandCheckException('releaseLock'); - } - if (this._ownerReadableStream === undefined) { - return; - } - if (this._readIntoRequests.length > 0) { - throw new TypeError('Tried to release a reader lock when that reader has pending read() calls un-settled'); - } - ReadableStreamReaderGenericRelease(this); - } - } - Object.defineProperties(ReadableStreamBYOBReader.prototype, { - cancel: { enumerable: true }, - read: { enumerable: true }, - releaseLock: { enumerable: true }, - closed: { enumerable: true } - }); - if (typeof SymbolPolyfill.toStringTag === 'symbol') { - Object.defineProperty(ReadableStreamBYOBReader.prototype, SymbolPolyfill.toStringTag, { - value: 'ReadableStreamBYOBReader', - configurable: true - }); - } - // Abstract operations for the readers. - function IsReadableStreamBYOBReader(x) { - if (!typeIsObject(x)) { - return false; - } - if (!Object.prototype.hasOwnProperty.call(x, '_readIntoRequests')) { - return false; - } - return x instanceof ReadableStreamBYOBReader; - } - function ReadableStreamBYOBReaderRead(reader, view, readIntoRequest) { - const stream = reader._ownerReadableStream; - stream._disturbed = true; - if (stream._state === 'errored') { - readIntoRequest._errorSteps(stream._storedError); - } - else { - ReadableByteStreamControllerPullInto(stream._readableStreamController, view, readIntoRequest); - } - } - // Helper functions for the ReadableStreamBYOBReader. - function byobReaderBrandCheckException(name) { - return new TypeError(`ReadableStreamBYOBReader.prototype.${name} can only be used on a ReadableStreamBYOBReader`); - } - - function ExtractHighWaterMark(strategy, defaultHWM) { - const { highWaterMark } = strategy; - if (highWaterMark === undefined) { - return defaultHWM; - } - if (NumberIsNaN(highWaterMark) || highWaterMark < 0) { - throw new RangeError('Invalid highWaterMark'); - } - return highWaterMark; - } - function ExtractSizeAlgorithm(strategy) { - const { size } = strategy; - if (!size) { - return () => 1; - } - return size; - } - - function convertQueuingStrategy(init, context) { - assertDictionary(init, context); - const highWaterMark = init === null || init === void 0 ? void 0 : init.highWaterMark; - const size = init === null || init === void 0 ? void 0 : init.size; - return { - highWaterMark: highWaterMark === undefined ? undefined : convertUnrestrictedDouble(highWaterMark), - size: size === undefined ? undefined : convertQueuingStrategySize(size, `${context} has member 'size' that`) - }; - } - function convertQueuingStrategySize(fn, context) { - assertFunction(fn, context); - return chunk => convertUnrestrictedDouble(fn(chunk)); - } - - function convertUnderlyingSink(original, context) { - assertDictionary(original, context); - const abort = original === null || original === void 0 ? void 0 : original.abort; - const close = original === null || original === void 0 ? void 0 : original.close; - const start = original === null || original === void 0 ? void 0 : original.start; - const type = original === null || original === void 0 ? void 0 : original.type; - const write = original === null || original === void 0 ? void 0 : original.write; - return { - abort: abort === undefined ? - undefined : - convertUnderlyingSinkAbortCallback(abort, original, `${context} has member 'abort' that`), - close: close === undefined ? - undefined : - convertUnderlyingSinkCloseCallback(close, original, `${context} has member 'close' that`), - start: start === undefined ? - undefined : - convertUnderlyingSinkStartCallback(start, original, `${context} has member 'start' that`), - write: write === undefined ? - undefined : - convertUnderlyingSinkWriteCallback(write, original, `${context} has member 'write' that`), - type - }; - } - function convertUnderlyingSinkAbortCallback(fn, original, context) { - assertFunction(fn, context); - return (reason) => promiseCall(fn, original, [reason]); - } - function convertUnderlyingSinkCloseCallback(fn, original, context) { - assertFunction(fn, context); - return () => promiseCall(fn, original, []); - } - function convertUnderlyingSinkStartCallback(fn, original, context) { - assertFunction(fn, context); - return (controller) => reflectCall(fn, original, [controller]); - } - function convertUnderlyingSinkWriteCallback(fn, original, context) { - assertFunction(fn, context); - return (chunk, controller) => promiseCall(fn, original, [chunk, controller]); - } - - function assertWritableStream(x, context) { - if (!IsWritableStream(x)) { - throw new TypeError(`${context} is not a WritableStream.`); - } - } - - function isAbortSignal(value) { - if (typeof value !== 'object' || value === null) { - return false; - } - try { - return typeof value.aborted === 'boolean'; - } - catch (_a) { - // AbortSignal.prototype.aborted throws if its brand check fails - return false; - } - } - const supportsAbortController = typeof AbortController === 'function'; - /** - * Construct a new AbortController, if supported by the platform. - * - * @internal - */ - function createAbortController() { - if (supportsAbortController) { - return new AbortController(); - } - return undefined; - } - - /** - * A writable stream represents a destination for data, into which you can write. - * - * @public - */ - class WritableStream { - constructor(rawUnderlyingSink = {}, rawStrategy = {}) { - if (rawUnderlyingSink === undefined) { - rawUnderlyingSink = null; - } - else { - assertObject(rawUnderlyingSink, 'First parameter'); - } - const strategy = convertQueuingStrategy(rawStrategy, 'Second parameter'); - const underlyingSink = convertUnderlyingSink(rawUnderlyingSink, 'First parameter'); - InitializeWritableStream(this); - const type = underlyingSink.type; - if (type !== undefined) { - throw new RangeError('Invalid type is specified'); - } - const sizeAlgorithm = ExtractSizeAlgorithm(strategy); - const highWaterMark = ExtractHighWaterMark(strategy, 1); - SetUpWritableStreamDefaultControllerFromUnderlyingSink(this, underlyingSink, highWaterMark, sizeAlgorithm); - } - /** - * Returns whether or not the writable stream is locked to a writer. - */ - get locked() { - if (!IsWritableStream(this)) { - throw streamBrandCheckException$2('locked'); - } - return IsWritableStreamLocked(this); - } - /** - * Aborts the stream, signaling that the producer can no longer successfully write to the stream and it is to be - * immediately moved to an errored state, with any queued-up writes discarded. This will also execute any abort - * mechanism of the underlying sink. - * - * The returned promise will fulfill if the stream shuts down successfully, or reject if the underlying sink signaled - * that there was an error doing so. Additionally, it will reject with a `TypeError` (without attempting to cancel - * the stream) if the stream is currently locked. - */ - abort(reason = undefined) { - if (!IsWritableStream(this)) { - return promiseRejectedWith(streamBrandCheckException$2('abort')); - } - if (IsWritableStreamLocked(this)) { - return promiseRejectedWith(new TypeError('Cannot abort a stream that already has a writer')); - } - return WritableStreamAbort(this, reason); - } - /** - * Closes the stream. The underlying sink will finish processing any previously-written chunks, before invoking its - * close behavior. During this time any further attempts to write will fail (without erroring the stream). - * - * The method returns a promise that will fulfill if all remaining chunks are successfully written and the stream - * successfully closes, or rejects if an error is encountered during this process. Additionally, it will reject with - * a `TypeError` (without attempting to cancel the stream) if the stream is currently locked. - */ - close() { - if (!IsWritableStream(this)) { - return promiseRejectedWith(streamBrandCheckException$2('close')); - } - if (IsWritableStreamLocked(this)) { - return promiseRejectedWith(new TypeError('Cannot close a stream that already has a writer')); - } - if (WritableStreamCloseQueuedOrInFlight(this)) { - return promiseRejectedWith(new TypeError('Cannot close an already-closing stream')); - } - return WritableStreamClose(this); - } - /** - * Creates a {@link WritableStreamDefaultWriter | writer} and locks the stream to the new writer. While the stream - * is locked, no other writer can be acquired until this one is released. - * - * This functionality is especially useful for creating abstractions that desire the ability to write to a stream - * without interruption or interleaving. By getting a writer for the stream, you can ensure nobody else can write at - * the same time, which would cause the resulting written data to be unpredictable and probably useless. - */ - getWriter() { - if (!IsWritableStream(this)) { - throw streamBrandCheckException$2('getWriter'); - } - return AcquireWritableStreamDefaultWriter(this); - } - } - Object.defineProperties(WritableStream.prototype, { - abort: { enumerable: true }, - close: { enumerable: true }, - getWriter: { enumerable: true }, - locked: { enumerable: true } - }); - if (typeof SymbolPolyfill.toStringTag === 'symbol') { - Object.defineProperty(WritableStream.prototype, SymbolPolyfill.toStringTag, { - value: 'WritableStream', - configurable: true - }); - } - // Abstract operations for the WritableStream. - function AcquireWritableStreamDefaultWriter(stream) { - return new WritableStreamDefaultWriter(stream); - } - // Throws if and only if startAlgorithm throws. - function CreateWritableStream(startAlgorithm, writeAlgorithm, closeAlgorithm, abortAlgorithm, highWaterMark = 1, sizeAlgorithm = () => 1) { - const stream = Object.create(WritableStream.prototype); - InitializeWritableStream(stream); - const controller = Object.create(WritableStreamDefaultController.prototype); - SetUpWritableStreamDefaultController(stream, controller, startAlgorithm, writeAlgorithm, closeAlgorithm, abortAlgorithm, highWaterMark, sizeAlgorithm); - return stream; - } - function InitializeWritableStream(stream) { - stream._state = 'writable'; - // The error that will be reported by new method calls once the state becomes errored. Only set when [[state]] is - // 'erroring' or 'errored'. May be set to an undefined value. - stream._storedError = undefined; - stream._writer = undefined; - // Initialize to undefined first because the constructor of the controller checks this - // variable to validate the caller. - stream._writableStreamController = undefined; - // This queue is placed here instead of the writer class in order to allow for passing a writer to the next data - // producer without waiting for the queued writes to finish. - stream._writeRequests = new SimpleQueue(); - // Write requests are removed from _writeRequests when write() is called on the underlying sink. This prevents - // them from being erroneously rejected on error. If a write() call is in-flight, the request is stored here. - stream._inFlightWriteRequest = undefined; - // The promise that was returned from writer.close(). Stored here because it may be fulfilled after the writer - // has been detached. - stream._closeRequest = undefined; - // Close request is removed from _closeRequest when close() is called on the underlying sink. This prevents it - // from being erroneously rejected on error. If a close() call is in-flight, the request is stored here. - stream._inFlightCloseRequest = undefined; - // The promise that was returned from writer.abort(). This may also be fulfilled after the writer has detached. - stream._pendingAbortRequest = undefined; - // The backpressure signal set by the controller. - stream._backpressure = false; - } - function IsWritableStream(x) { - if (!typeIsObject(x)) { - return false; - } - if (!Object.prototype.hasOwnProperty.call(x, '_writableStreamController')) { - return false; - } - return x instanceof WritableStream; - } - function IsWritableStreamLocked(stream) { - if (stream._writer === undefined) { - return false; - } - return true; - } - function WritableStreamAbort(stream, reason) { - var _a; - if (stream._state === 'closed' || stream._state === 'errored') { - return promiseResolvedWith(undefined); - } - stream._writableStreamController._abortReason = reason; - (_a = stream._writableStreamController._abortController) === null || _a === void 0 ? void 0 : _a.abort(); - // TypeScript narrows the type of `stream._state` down to 'writable' | 'erroring', - // but it doesn't know that signaling abort runs author code that might have changed the state. - // Widen the type again by casting to WritableStreamState. - const state = stream._state; - if (state === 'closed' || state === 'errored') { - return promiseResolvedWith(undefined); - } - if (stream._pendingAbortRequest !== undefined) { - return stream._pendingAbortRequest._promise; - } - let wasAlreadyErroring = false; - if (state === 'erroring') { - wasAlreadyErroring = true; - // reason will not be used, so don't keep a reference to it. - reason = undefined; - } - const promise = newPromise((resolve, reject) => { - stream._pendingAbortRequest = { - _promise: undefined, - _resolve: resolve, - _reject: reject, - _reason: reason, - _wasAlreadyErroring: wasAlreadyErroring - }; - }); - stream._pendingAbortRequest._promise = promise; - if (!wasAlreadyErroring) { - WritableStreamStartErroring(stream, reason); - } - return promise; - } - function WritableStreamClose(stream) { - const state = stream._state; - if (state === 'closed' || state === 'errored') { - return promiseRejectedWith(new TypeError(`The stream (in ${state} state) is not in the writable state and cannot be closed`)); - } - const promise = newPromise((resolve, reject) => { - const closeRequest = { - _resolve: resolve, - _reject: reject - }; - stream._closeRequest = closeRequest; - }); - const writer = stream._writer; - if (writer !== undefined && stream._backpressure && state === 'writable') { - defaultWriterReadyPromiseResolve(writer); - } - WritableStreamDefaultControllerClose(stream._writableStreamController); - return promise; - } - // WritableStream API exposed for controllers. - function WritableStreamAddWriteRequest(stream) { - const promise = newPromise((resolve, reject) => { - const writeRequest = { - _resolve: resolve, - _reject: reject - }; - stream._writeRequests.push(writeRequest); - }); - return promise; - } - function WritableStreamDealWithRejection(stream, error) { - const state = stream._state; - if (state === 'writable') { - WritableStreamStartErroring(stream, error); - return; - } - WritableStreamFinishErroring(stream); - } - function WritableStreamStartErroring(stream, reason) { - const controller = stream._writableStreamController; - stream._state = 'erroring'; - stream._storedError = reason; - const writer = stream._writer; - if (writer !== undefined) { - WritableStreamDefaultWriterEnsureReadyPromiseRejected(writer, reason); - } - if (!WritableStreamHasOperationMarkedInFlight(stream) && controller._started) { - WritableStreamFinishErroring(stream); - } - } - function WritableStreamFinishErroring(stream) { - stream._state = 'errored'; - stream._writableStreamController[ErrorSteps](); - const storedError = stream._storedError; - stream._writeRequests.forEach(writeRequest => { - writeRequest._reject(storedError); - }); - stream._writeRequests = new SimpleQueue(); - if (stream._pendingAbortRequest === undefined) { - WritableStreamRejectCloseAndClosedPromiseIfNeeded(stream); - return; - } - const abortRequest = stream._pendingAbortRequest; - stream._pendingAbortRequest = undefined; - if (abortRequest._wasAlreadyErroring) { - abortRequest._reject(storedError); - WritableStreamRejectCloseAndClosedPromiseIfNeeded(stream); - return; - } - const promise = stream._writableStreamController[AbortSteps](abortRequest._reason); - uponPromise(promise, () => { - abortRequest._resolve(); - WritableStreamRejectCloseAndClosedPromiseIfNeeded(stream); - }, (reason) => { - abortRequest._reject(reason); - WritableStreamRejectCloseAndClosedPromiseIfNeeded(stream); - }); - } - function WritableStreamFinishInFlightWrite(stream) { - stream._inFlightWriteRequest._resolve(undefined); - stream._inFlightWriteRequest = undefined; - } - function WritableStreamFinishInFlightWriteWithError(stream, error) { - stream._inFlightWriteRequest._reject(error); - stream._inFlightWriteRequest = undefined; - WritableStreamDealWithRejection(stream, error); - } - function WritableStreamFinishInFlightClose(stream) { - stream._inFlightCloseRequest._resolve(undefined); - stream._inFlightCloseRequest = undefined; - const state = stream._state; - if (state === 'erroring') { - // The error was too late to do anything, so it is ignored. - stream._storedError = undefined; - if (stream._pendingAbortRequest !== undefined) { - stream._pendingAbortRequest._resolve(); - stream._pendingAbortRequest = undefined; - } - } - stream._state = 'closed'; - const writer = stream._writer; - if (writer !== undefined) { - defaultWriterClosedPromiseResolve(writer); - } - } - function WritableStreamFinishInFlightCloseWithError(stream, error) { - stream._inFlightCloseRequest._reject(error); - stream._inFlightCloseRequest = undefined; - // Never execute sink abort() after sink close(). - if (stream._pendingAbortRequest !== undefined) { - stream._pendingAbortRequest._reject(error); - stream._pendingAbortRequest = undefined; - } - WritableStreamDealWithRejection(stream, error); - } - // TODO(ricea): Fix alphabetical order. - function WritableStreamCloseQueuedOrInFlight(stream) { - if (stream._closeRequest === undefined && stream._inFlightCloseRequest === undefined) { - return false; - } - return true; - } - function WritableStreamHasOperationMarkedInFlight(stream) { - if (stream._inFlightWriteRequest === undefined && stream._inFlightCloseRequest === undefined) { - return false; - } - return true; - } - function WritableStreamMarkCloseRequestInFlight(stream) { - stream._inFlightCloseRequest = stream._closeRequest; - stream._closeRequest = undefined; - } - function WritableStreamMarkFirstWriteRequestInFlight(stream) { - stream._inFlightWriteRequest = stream._writeRequests.shift(); - } - function WritableStreamRejectCloseAndClosedPromiseIfNeeded(stream) { - if (stream._closeRequest !== undefined) { - stream._closeRequest._reject(stream._storedError); - stream._closeRequest = undefined; - } - const writer = stream._writer; - if (writer !== undefined) { - defaultWriterClosedPromiseReject(writer, stream._storedError); - } - } - function WritableStreamUpdateBackpressure(stream, backpressure) { - const writer = stream._writer; - if (writer !== undefined && backpressure !== stream._backpressure) { - if (backpressure) { - defaultWriterReadyPromiseReset(writer); - } - else { - defaultWriterReadyPromiseResolve(writer); - } - } - stream._backpressure = backpressure; - } - /** - * A default writer vended by a {@link WritableStream}. - * - * @public - */ - class WritableStreamDefaultWriter { - constructor(stream) { - assertRequiredArgument(stream, 1, 'WritableStreamDefaultWriter'); - assertWritableStream(stream, 'First parameter'); - if (IsWritableStreamLocked(stream)) { - throw new TypeError('This stream has already been locked for exclusive writing by another writer'); - } - this._ownerWritableStream = stream; - stream._writer = this; - const state = stream._state; - if (state === 'writable') { - if (!WritableStreamCloseQueuedOrInFlight(stream) && stream._backpressure) { - defaultWriterReadyPromiseInitialize(this); - } - else { - defaultWriterReadyPromiseInitializeAsResolved(this); - } - defaultWriterClosedPromiseInitialize(this); - } - else if (state === 'erroring') { - defaultWriterReadyPromiseInitializeAsRejected(this, stream._storedError); - defaultWriterClosedPromiseInitialize(this); - } - else if (state === 'closed') { - defaultWriterReadyPromiseInitializeAsResolved(this); - defaultWriterClosedPromiseInitializeAsResolved(this); - } - else { - const storedError = stream._storedError; - defaultWriterReadyPromiseInitializeAsRejected(this, storedError); - defaultWriterClosedPromiseInitializeAsRejected(this, storedError); - } - } - /** - * Returns a promise that will be fulfilled when the stream becomes closed, or rejected if the stream ever errors or - * the writer’s lock is released before the stream finishes closing. - */ - get closed() { - if (!IsWritableStreamDefaultWriter(this)) { - return promiseRejectedWith(defaultWriterBrandCheckException('closed')); - } - return this._closedPromise; - } - /** - * Returns the desired size to fill the stream’s internal queue. It can be negative, if the queue is over-full. - * A producer can use this information to determine the right amount of data to write. - * - * It will be `null` if the stream cannot be successfully written to (due to either being errored, or having an abort - * queued up). It will return zero if the stream is closed. And the getter will throw an exception if invoked when - * the writer’s lock is released. - */ - get desiredSize() { - if (!IsWritableStreamDefaultWriter(this)) { - throw defaultWriterBrandCheckException('desiredSize'); - } - if (this._ownerWritableStream === undefined) { - throw defaultWriterLockException('desiredSize'); - } - return WritableStreamDefaultWriterGetDesiredSize(this); - } - /** - * Returns a promise that will be fulfilled when the desired size to fill the stream’s internal queue transitions - * from non-positive to positive, signaling that it is no longer applying backpressure. Once the desired size dips - * back to zero or below, the getter will return a new promise that stays pending until the next transition. - * - * If the stream becomes errored or aborted, or the writer’s lock is released, the returned promise will become - * rejected. - */ - get ready() { - if (!IsWritableStreamDefaultWriter(this)) { - return promiseRejectedWith(defaultWriterBrandCheckException('ready')); - } - return this._readyPromise; - } - /** - * If the reader is active, behaves the same as {@link WritableStream.abort | stream.abort(reason)}. - */ - abort(reason = undefined) { - if (!IsWritableStreamDefaultWriter(this)) { - return promiseRejectedWith(defaultWriterBrandCheckException('abort')); - } - if (this._ownerWritableStream === undefined) { - return promiseRejectedWith(defaultWriterLockException('abort')); - } - return WritableStreamDefaultWriterAbort(this, reason); - } - /** - * If the reader is active, behaves the same as {@link WritableStream.close | stream.close()}. - */ - close() { - if (!IsWritableStreamDefaultWriter(this)) { - return promiseRejectedWith(defaultWriterBrandCheckException('close')); - } - const stream = this._ownerWritableStream; - if (stream === undefined) { - return promiseRejectedWith(defaultWriterLockException('close')); - } - if (WritableStreamCloseQueuedOrInFlight(stream)) { - return promiseRejectedWith(new TypeError('Cannot close an already-closing stream')); - } - return WritableStreamDefaultWriterClose(this); - } - /** - * Releases the writer’s lock on the corresponding stream. After the lock is released, the writer is no longer active. - * If the associated stream is errored when the lock is released, the writer will appear errored in the same way from - * now on; otherwise, the writer will appear closed. - * - * Note that the lock can still be released even if some ongoing writes have not yet finished (i.e. even if the - * promises returned from previous calls to {@link WritableStreamDefaultWriter.write | write()} have not yet settled). - * It’s not necessary to hold the lock on the writer for the duration of the write; the lock instead simply prevents - * other producers from writing in an interleaved manner. - */ - releaseLock() { - if (!IsWritableStreamDefaultWriter(this)) { - throw defaultWriterBrandCheckException('releaseLock'); - } - const stream = this._ownerWritableStream; - if (stream === undefined) { - return; - } - WritableStreamDefaultWriterRelease(this); - } - write(chunk = undefined) { - if (!IsWritableStreamDefaultWriter(this)) { - return promiseRejectedWith(defaultWriterBrandCheckException('write')); - } - if (this._ownerWritableStream === undefined) { - return promiseRejectedWith(defaultWriterLockException('write to')); - } - return WritableStreamDefaultWriterWrite(this, chunk); - } - } - Object.defineProperties(WritableStreamDefaultWriter.prototype, { - abort: { enumerable: true }, - close: { enumerable: true }, - releaseLock: { enumerable: true }, - write: { enumerable: true }, - closed: { enumerable: true }, - desiredSize: { enumerable: true }, - ready: { enumerable: true } - }); - if (typeof SymbolPolyfill.toStringTag === 'symbol') { - Object.defineProperty(WritableStreamDefaultWriter.prototype, SymbolPolyfill.toStringTag, { - value: 'WritableStreamDefaultWriter', - configurable: true - }); - } - // Abstract operations for the WritableStreamDefaultWriter. - function IsWritableStreamDefaultWriter(x) { - if (!typeIsObject(x)) { - return false; - } - if (!Object.prototype.hasOwnProperty.call(x, '_ownerWritableStream')) { - return false; - } - return x instanceof WritableStreamDefaultWriter; - } - // A client of WritableStreamDefaultWriter may use these functions directly to bypass state check. - function WritableStreamDefaultWriterAbort(writer, reason) { - const stream = writer._ownerWritableStream; - return WritableStreamAbort(stream, reason); - } - function WritableStreamDefaultWriterClose(writer) { - const stream = writer._ownerWritableStream; - return WritableStreamClose(stream); - } - function WritableStreamDefaultWriterCloseWithErrorPropagation(writer) { - const stream = writer._ownerWritableStream; - const state = stream._state; - if (WritableStreamCloseQueuedOrInFlight(stream) || state === 'closed') { - return promiseResolvedWith(undefined); - } - if (state === 'errored') { - return promiseRejectedWith(stream._storedError); - } - return WritableStreamDefaultWriterClose(writer); - } - function WritableStreamDefaultWriterEnsureClosedPromiseRejected(writer, error) { - if (writer._closedPromiseState === 'pending') { - defaultWriterClosedPromiseReject(writer, error); - } - else { - defaultWriterClosedPromiseResetToRejected(writer, error); - } - } - function WritableStreamDefaultWriterEnsureReadyPromiseRejected(writer, error) { - if (writer._readyPromiseState === 'pending') { - defaultWriterReadyPromiseReject(writer, error); - } - else { - defaultWriterReadyPromiseResetToRejected(writer, error); - } - } - function WritableStreamDefaultWriterGetDesiredSize(writer) { - const stream = writer._ownerWritableStream; - const state = stream._state; - if (state === 'errored' || state === 'erroring') { - return null; - } - if (state === 'closed') { - return 0; - } - return WritableStreamDefaultControllerGetDesiredSize(stream._writableStreamController); - } - function WritableStreamDefaultWriterRelease(writer) { - const stream = writer._ownerWritableStream; - const releasedError = new TypeError(`Writer was released and can no longer be used to monitor the stream's closedness`); - WritableStreamDefaultWriterEnsureReadyPromiseRejected(writer, releasedError); - // The state transitions to "errored" before the sink abort() method runs, but the writer.closed promise is not - // rejected until afterwards. This means that simply testing state will not work. - WritableStreamDefaultWriterEnsureClosedPromiseRejected(writer, releasedError); - stream._writer = undefined; - writer._ownerWritableStream = undefined; - } - function WritableStreamDefaultWriterWrite(writer, chunk) { - const stream = writer._ownerWritableStream; - const controller = stream._writableStreamController; - const chunkSize = WritableStreamDefaultControllerGetChunkSize(controller, chunk); - if (stream !== writer._ownerWritableStream) { - return promiseRejectedWith(defaultWriterLockException('write to')); - } - const state = stream._state; - if (state === 'errored') { - return promiseRejectedWith(stream._storedError); - } - if (WritableStreamCloseQueuedOrInFlight(stream) || state === 'closed') { - return promiseRejectedWith(new TypeError('The stream is closing or closed and cannot be written to')); - } - if (state === 'erroring') { - return promiseRejectedWith(stream._storedError); - } - const promise = WritableStreamAddWriteRequest(stream); - WritableStreamDefaultControllerWrite(controller, chunk, chunkSize); - return promise; - } - const closeSentinel = {}; - /** - * Allows control of a {@link WritableStream | writable stream}'s state and internal queue. - * - * @public - */ - class WritableStreamDefaultController { - constructor() { - throw new TypeError('Illegal constructor'); - } - /** - * The reason which was passed to `WritableStream.abort(reason)` when the stream was aborted. - * - * @deprecated - * This property has been removed from the specification, see https://github.com/whatwg/streams/pull/1177. - * Use {@link WritableStreamDefaultController.signal}'s `reason` instead. - */ - get abortReason() { - if (!IsWritableStreamDefaultController(this)) { - throw defaultControllerBrandCheckException$2('abortReason'); - } - return this._abortReason; - } - /** - * An `AbortSignal` that can be used to abort the pending write or close operation when the stream is aborted. - */ - get signal() { - if (!IsWritableStreamDefaultController(this)) { - throw defaultControllerBrandCheckException$2('signal'); - } - if (this._abortController === undefined) { - // Older browsers or older Node versions may not support `AbortController` or `AbortSignal`. - // We don't want to bundle and ship an `AbortController` polyfill together with our polyfill, - // so instead we only implement support for `signal` if we find a global `AbortController` constructor. - throw new TypeError('WritableStreamDefaultController.prototype.signal is not supported'); - } - return this._abortController.signal; - } - /** - * Closes the controlled writable stream, making all future interactions with it fail with the given error `e`. - * - * This method is rarely used, since usually it suffices to return a rejected promise from one of the underlying - * sink's methods. However, it can be useful for suddenly shutting down a stream in response to an event outside the - * normal lifecycle of interactions with the underlying sink. - */ - error(e = undefined) { - if (!IsWritableStreamDefaultController(this)) { - throw defaultControllerBrandCheckException$2('error'); - } - const state = this._controlledWritableStream._state; - if (state !== 'writable') { - // The stream is closed, errored or will be soon. The sink can't do anything useful if it gets an error here, so - // just treat it as a no-op. - return; - } - WritableStreamDefaultControllerError(this, e); - } - /** @internal */ - [AbortSteps](reason) { - const result = this._abortAlgorithm(reason); - WritableStreamDefaultControllerClearAlgorithms(this); - return result; - } - /** @internal */ - [ErrorSteps]() { - ResetQueue(this); - } - } - Object.defineProperties(WritableStreamDefaultController.prototype, { - abortReason: { enumerable: true }, - signal: { enumerable: true }, - error: { enumerable: true } - }); - if (typeof SymbolPolyfill.toStringTag === 'symbol') { - Object.defineProperty(WritableStreamDefaultController.prototype, SymbolPolyfill.toStringTag, { - value: 'WritableStreamDefaultController', - configurable: true - }); - } - // Abstract operations implementing interface required by the WritableStream. - function IsWritableStreamDefaultController(x) { - if (!typeIsObject(x)) { - return false; - } - if (!Object.prototype.hasOwnProperty.call(x, '_controlledWritableStream')) { - return false; - } - return x instanceof WritableStreamDefaultController; - } - function SetUpWritableStreamDefaultController(stream, controller, startAlgorithm, writeAlgorithm, closeAlgorithm, abortAlgorithm, highWaterMark, sizeAlgorithm) { - controller._controlledWritableStream = stream; - stream._writableStreamController = controller; - // Need to set the slots so that the assert doesn't fire. In the spec the slots already exist implicitly. - controller._queue = undefined; - controller._queueTotalSize = undefined; - ResetQueue(controller); - controller._abortReason = undefined; - controller._abortController = createAbortController(); - controller._started = false; - controller._strategySizeAlgorithm = sizeAlgorithm; - controller._strategyHWM = highWaterMark; - controller._writeAlgorithm = writeAlgorithm; - controller._closeAlgorithm = closeAlgorithm; - controller._abortAlgorithm = abortAlgorithm; - const backpressure = WritableStreamDefaultControllerGetBackpressure(controller); - WritableStreamUpdateBackpressure(stream, backpressure); - const startResult = startAlgorithm(); - const startPromise = promiseResolvedWith(startResult); - uponPromise(startPromise, () => { - controller._started = true; - WritableStreamDefaultControllerAdvanceQueueIfNeeded(controller); - }, r => { - controller._started = true; - WritableStreamDealWithRejection(stream, r); - }); - } - function SetUpWritableStreamDefaultControllerFromUnderlyingSink(stream, underlyingSink, highWaterMark, sizeAlgorithm) { - const controller = Object.create(WritableStreamDefaultController.prototype); - let startAlgorithm = () => undefined; - let writeAlgorithm = () => promiseResolvedWith(undefined); - let closeAlgorithm = () => promiseResolvedWith(undefined); - let abortAlgorithm = () => promiseResolvedWith(undefined); - if (underlyingSink.start !== undefined) { - startAlgorithm = () => underlyingSink.start(controller); - } - if (underlyingSink.write !== undefined) { - writeAlgorithm = chunk => underlyingSink.write(chunk, controller); - } - if (underlyingSink.close !== undefined) { - closeAlgorithm = () => underlyingSink.close(); - } - if (underlyingSink.abort !== undefined) { - abortAlgorithm = reason => underlyingSink.abort(reason); - } - SetUpWritableStreamDefaultController(stream, controller, startAlgorithm, writeAlgorithm, closeAlgorithm, abortAlgorithm, highWaterMark, sizeAlgorithm); - } - // ClearAlgorithms may be called twice. Erroring the same stream in multiple ways will often result in redundant calls. - function WritableStreamDefaultControllerClearAlgorithms(controller) { - controller._writeAlgorithm = undefined; - controller._closeAlgorithm = undefined; - controller._abortAlgorithm = undefined; - controller._strategySizeAlgorithm = undefined; - } - function WritableStreamDefaultControllerClose(controller) { - EnqueueValueWithSize(controller, closeSentinel, 0); - WritableStreamDefaultControllerAdvanceQueueIfNeeded(controller); - } - function WritableStreamDefaultControllerGetChunkSize(controller, chunk) { - try { - return controller._strategySizeAlgorithm(chunk); - } - catch (chunkSizeE) { - WritableStreamDefaultControllerErrorIfNeeded(controller, chunkSizeE); - return 1; - } - } - function WritableStreamDefaultControllerGetDesiredSize(controller) { - return controller._strategyHWM - controller._queueTotalSize; - } - function WritableStreamDefaultControllerWrite(controller, chunk, chunkSize) { - try { - EnqueueValueWithSize(controller, chunk, chunkSize); - } - catch (enqueueE) { - WritableStreamDefaultControllerErrorIfNeeded(controller, enqueueE); - return; - } - const stream = controller._controlledWritableStream; - if (!WritableStreamCloseQueuedOrInFlight(stream) && stream._state === 'writable') { - const backpressure = WritableStreamDefaultControllerGetBackpressure(controller); - WritableStreamUpdateBackpressure(stream, backpressure); - } - WritableStreamDefaultControllerAdvanceQueueIfNeeded(controller); - } - // Abstract operations for the WritableStreamDefaultController. - function WritableStreamDefaultControllerAdvanceQueueIfNeeded(controller) { - const stream = controller._controlledWritableStream; - if (!controller._started) { - return; - } - if (stream._inFlightWriteRequest !== undefined) { - return; - } - const state = stream._state; - if (state === 'erroring') { - WritableStreamFinishErroring(stream); - return; - } - if (controller._queue.length === 0) { - return; - } - const value = PeekQueueValue(controller); - if (value === closeSentinel) { - WritableStreamDefaultControllerProcessClose(controller); - } - else { - WritableStreamDefaultControllerProcessWrite(controller, value); - } - } - function WritableStreamDefaultControllerErrorIfNeeded(controller, error) { - if (controller._controlledWritableStream._state === 'writable') { - WritableStreamDefaultControllerError(controller, error); - } - } - function WritableStreamDefaultControllerProcessClose(controller) { - const stream = controller._controlledWritableStream; - WritableStreamMarkCloseRequestInFlight(stream); - DequeueValue(controller); - const sinkClosePromise = controller._closeAlgorithm(); - WritableStreamDefaultControllerClearAlgorithms(controller); - uponPromise(sinkClosePromise, () => { - WritableStreamFinishInFlightClose(stream); - }, reason => { - WritableStreamFinishInFlightCloseWithError(stream, reason); - }); - } - function WritableStreamDefaultControllerProcessWrite(controller, chunk) { - const stream = controller._controlledWritableStream; - WritableStreamMarkFirstWriteRequestInFlight(stream); - const sinkWritePromise = controller._writeAlgorithm(chunk); - uponPromise(sinkWritePromise, () => { - WritableStreamFinishInFlightWrite(stream); - const state = stream._state; - DequeueValue(controller); - if (!WritableStreamCloseQueuedOrInFlight(stream) && state === 'writable') { - const backpressure = WritableStreamDefaultControllerGetBackpressure(controller); - WritableStreamUpdateBackpressure(stream, backpressure); - } - WritableStreamDefaultControllerAdvanceQueueIfNeeded(controller); - }, reason => { - if (stream._state === 'writable') { - WritableStreamDefaultControllerClearAlgorithms(controller); - } - WritableStreamFinishInFlightWriteWithError(stream, reason); - }); - } - function WritableStreamDefaultControllerGetBackpressure(controller) { - const desiredSize = WritableStreamDefaultControllerGetDesiredSize(controller); - return desiredSize <= 0; - } - // A client of WritableStreamDefaultController may use these functions directly to bypass state check. - function WritableStreamDefaultControllerError(controller, error) { - const stream = controller._controlledWritableStream; - WritableStreamDefaultControllerClearAlgorithms(controller); - WritableStreamStartErroring(stream, error); - } - // Helper functions for the WritableStream. - function streamBrandCheckException$2(name) { - return new TypeError(`WritableStream.prototype.${name} can only be used on a WritableStream`); - } - // Helper functions for the WritableStreamDefaultController. - function defaultControllerBrandCheckException$2(name) { - return new TypeError(`WritableStreamDefaultController.prototype.${name} can only be used on a WritableStreamDefaultController`); - } - // Helper functions for the WritableStreamDefaultWriter. - function defaultWriterBrandCheckException(name) { - return new TypeError(`WritableStreamDefaultWriter.prototype.${name} can only be used on a WritableStreamDefaultWriter`); - } - function defaultWriterLockException(name) { - return new TypeError('Cannot ' + name + ' a stream using a released writer'); - } - function defaultWriterClosedPromiseInitialize(writer) { - writer._closedPromise = newPromise((resolve, reject) => { - writer._closedPromise_resolve = resolve; - writer._closedPromise_reject = reject; - writer._closedPromiseState = 'pending'; - }); - } - function defaultWriterClosedPromiseInitializeAsRejected(writer, reason) { - defaultWriterClosedPromiseInitialize(writer); - defaultWriterClosedPromiseReject(writer, reason); - } - function defaultWriterClosedPromiseInitializeAsResolved(writer) { - defaultWriterClosedPromiseInitialize(writer); - defaultWriterClosedPromiseResolve(writer); - } - function defaultWriterClosedPromiseReject(writer, reason) { - if (writer._closedPromise_reject === undefined) { - return; - } - setPromiseIsHandledToTrue(writer._closedPromise); - writer._closedPromise_reject(reason); - writer._closedPromise_resolve = undefined; - writer._closedPromise_reject = undefined; - writer._closedPromiseState = 'rejected'; - } - function defaultWriterClosedPromiseResetToRejected(writer, reason) { - defaultWriterClosedPromiseInitializeAsRejected(writer, reason); - } - function defaultWriterClosedPromiseResolve(writer) { - if (writer._closedPromise_resolve === undefined) { - return; - } - writer._closedPromise_resolve(undefined); - writer._closedPromise_resolve = undefined; - writer._closedPromise_reject = undefined; - writer._closedPromiseState = 'resolved'; - } - function defaultWriterReadyPromiseInitialize(writer) { - writer._readyPromise = newPromise((resolve, reject) => { - writer._readyPromise_resolve = resolve; - writer._readyPromise_reject = reject; - }); - writer._readyPromiseState = 'pending'; - } - function defaultWriterReadyPromiseInitializeAsRejected(writer, reason) { - defaultWriterReadyPromiseInitialize(writer); - defaultWriterReadyPromiseReject(writer, reason); - } - function defaultWriterReadyPromiseInitializeAsResolved(writer) { - defaultWriterReadyPromiseInitialize(writer); - defaultWriterReadyPromiseResolve(writer); - } - function defaultWriterReadyPromiseReject(writer, reason) { - if (writer._readyPromise_reject === undefined) { - return; - } - setPromiseIsHandledToTrue(writer._readyPromise); - writer._readyPromise_reject(reason); - writer._readyPromise_resolve = undefined; - writer._readyPromise_reject = undefined; - writer._readyPromiseState = 'rejected'; - } - function defaultWriterReadyPromiseReset(writer) { - defaultWriterReadyPromiseInitialize(writer); - } - function defaultWriterReadyPromiseResetToRejected(writer, reason) { - defaultWriterReadyPromiseInitializeAsRejected(writer, reason); - } - function defaultWriterReadyPromiseResolve(writer) { - if (writer._readyPromise_resolve === undefined) { - return; - } - writer._readyPromise_resolve(undefined); - writer._readyPromise_resolve = undefined; - writer._readyPromise_reject = undefined; - writer._readyPromiseState = 'fulfilled'; - } - - /// - const NativeDOMException = typeof DOMException !== 'undefined' ? DOMException : undefined; - - /// - function isDOMExceptionConstructor(ctor) { - if (!(typeof ctor === 'function' || typeof ctor === 'object')) { - return false; - } - try { - new ctor(); - return true; - } - catch (_a) { - return false; - } - } - function createDOMExceptionPolyfill() { - // eslint-disable-next-line no-shadow - const ctor = function DOMException(message, name) { - this.message = message || ''; - this.name = name || 'Error'; - if (Error.captureStackTrace) { - Error.captureStackTrace(this, this.constructor); - } - }; - ctor.prototype = Object.create(Error.prototype); - Object.defineProperty(ctor.prototype, 'constructor', { value: ctor, writable: true, configurable: true }); - return ctor; - } - // eslint-disable-next-line no-redeclare - const DOMException$1 = isDOMExceptionConstructor(NativeDOMException) ? NativeDOMException : createDOMExceptionPolyfill(); - - function ReadableStreamPipeTo(source, dest, preventClose, preventAbort, preventCancel, signal) { - const reader = AcquireReadableStreamDefaultReader(source); - const writer = AcquireWritableStreamDefaultWriter(dest); - source._disturbed = true; - let shuttingDown = false; - // This is used to keep track of the spec's requirement that we wait for ongoing writes during shutdown. - let currentWrite = promiseResolvedWith(undefined); - return newPromise((resolve, reject) => { - let abortAlgorithm; - if (signal !== undefined) { - abortAlgorithm = () => { - const error = new DOMException$1('Aborted', 'AbortError'); - const actions = []; - if (!preventAbort) { - actions.push(() => { - if (dest._state === 'writable') { - return WritableStreamAbort(dest, error); - } - return promiseResolvedWith(undefined); - }); - } - if (!preventCancel) { - actions.push(() => { - if (source._state === 'readable') { - return ReadableStreamCancel(source, error); - } - return promiseResolvedWith(undefined); - }); - } - shutdownWithAction(() => Promise.all(actions.map(action => action())), true, error); - }; - if (signal.aborted) { - abortAlgorithm(); - return; - } - signal.addEventListener('abort', abortAlgorithm); - } - // Using reader and writer, read all chunks from this and write them to dest - // - Backpressure must be enforced - // - Shutdown must stop all activity - function pipeLoop() { - return newPromise((resolveLoop, rejectLoop) => { - function next(done) { - if (done) { - resolveLoop(); - } - else { - // Use `PerformPromiseThen` instead of `uponPromise` to avoid - // adding unnecessary `.catch(rethrowAssertionErrorRejection)` handlers - PerformPromiseThen(pipeStep(), next, rejectLoop); - } - } - next(false); - }); - } - function pipeStep() { - if (shuttingDown) { - return promiseResolvedWith(true); - } - return PerformPromiseThen(writer._readyPromise, () => { - return newPromise((resolveRead, rejectRead) => { - ReadableStreamDefaultReaderRead(reader, { - _chunkSteps: chunk => { - currentWrite = PerformPromiseThen(WritableStreamDefaultWriterWrite(writer, chunk), undefined, noop); - resolveRead(false); - }, - _closeSteps: () => resolveRead(true), - _errorSteps: rejectRead - }); - }); - }); - } - // Errors must be propagated forward - isOrBecomesErrored(source, reader._closedPromise, storedError => { - if (!preventAbort) { - shutdownWithAction(() => WritableStreamAbort(dest, storedError), true, storedError); - } - else { - shutdown(true, storedError); - } - }); - // Errors must be propagated backward - isOrBecomesErrored(dest, writer._closedPromise, storedError => { - if (!preventCancel) { - shutdownWithAction(() => ReadableStreamCancel(source, storedError), true, storedError); - } - else { - shutdown(true, storedError); - } - }); - // Closing must be propagated forward - isOrBecomesClosed(source, reader._closedPromise, () => { - if (!preventClose) { - shutdownWithAction(() => WritableStreamDefaultWriterCloseWithErrorPropagation(writer)); - } - else { - shutdown(); - } - }); - // Closing must be propagated backward - if (WritableStreamCloseQueuedOrInFlight(dest) || dest._state === 'closed') { - const destClosed = new TypeError('the destination writable stream closed before all data could be piped to it'); - if (!preventCancel) { - shutdownWithAction(() => ReadableStreamCancel(source, destClosed), true, destClosed); - } - else { - shutdown(true, destClosed); - } - } - setPromiseIsHandledToTrue(pipeLoop()); - function waitForWritesToFinish() { - // Another write may have started while we were waiting on this currentWrite, so we have to be sure to wait - // for that too. - const oldCurrentWrite = currentWrite; - return PerformPromiseThen(currentWrite, () => oldCurrentWrite !== currentWrite ? waitForWritesToFinish() : undefined); - } - function isOrBecomesErrored(stream, promise, action) { - if (stream._state === 'errored') { - action(stream._storedError); - } - else { - uponRejection(promise, action); - } - } - function isOrBecomesClosed(stream, promise, action) { - if (stream._state === 'closed') { - action(); - } - else { - uponFulfillment(promise, action); - } - } - function shutdownWithAction(action, originalIsError, originalError) { - if (shuttingDown) { - return; - } - shuttingDown = true; - if (dest._state === 'writable' && !WritableStreamCloseQueuedOrInFlight(dest)) { - uponFulfillment(waitForWritesToFinish(), doTheRest); - } - else { - doTheRest(); - } - function doTheRest() { - uponPromise(action(), () => finalize(originalIsError, originalError), newError => finalize(true, newError)); - } - } - function shutdown(isError, error) { - if (shuttingDown) { - return; - } - shuttingDown = true; - if (dest._state === 'writable' && !WritableStreamCloseQueuedOrInFlight(dest)) { - uponFulfillment(waitForWritesToFinish(), () => finalize(isError, error)); - } - else { - finalize(isError, error); - } - } - function finalize(isError, error) { - WritableStreamDefaultWriterRelease(writer); - ReadableStreamReaderGenericRelease(reader); - if (signal !== undefined) { - signal.removeEventListener('abort', abortAlgorithm); - } - if (isError) { - reject(error); - } - else { - resolve(undefined); - } - } - }); - } - - /** - * Allows control of a {@link ReadableStream | readable stream}'s state and internal queue. - * - * @public - */ - class ReadableStreamDefaultController { - constructor() { - throw new TypeError('Illegal constructor'); - } - /** - * Returns the desired size to fill the controlled stream's internal queue. It can be negative, if the queue is - * over-full. An underlying source ought to use this information to determine when and how to apply backpressure. - */ - get desiredSize() { - if (!IsReadableStreamDefaultController(this)) { - throw defaultControllerBrandCheckException$1('desiredSize'); - } - return ReadableStreamDefaultControllerGetDesiredSize(this); - } - /** - * Closes the controlled readable stream. Consumers will still be able to read any previously-enqueued chunks from - * the stream, but once those are read, the stream will become closed. - */ - close() { - if (!IsReadableStreamDefaultController(this)) { - throw defaultControllerBrandCheckException$1('close'); - } - if (!ReadableStreamDefaultControllerCanCloseOrEnqueue(this)) { - throw new TypeError('The stream is not in a state that permits close'); - } - ReadableStreamDefaultControllerClose(this); - } - enqueue(chunk = undefined) { - if (!IsReadableStreamDefaultController(this)) { - throw defaultControllerBrandCheckException$1('enqueue'); - } - if (!ReadableStreamDefaultControllerCanCloseOrEnqueue(this)) { - throw new TypeError('The stream is not in a state that permits enqueue'); - } - return ReadableStreamDefaultControllerEnqueue(this, chunk); - } - /** - * Errors the controlled readable stream, making all future interactions with it fail with the given error `e`. - */ - error(e = undefined) { - if (!IsReadableStreamDefaultController(this)) { - throw defaultControllerBrandCheckException$1('error'); - } - ReadableStreamDefaultControllerError(this, e); - } - /** @internal */ - [CancelSteps](reason) { - ResetQueue(this); - const result = this._cancelAlgorithm(reason); - ReadableStreamDefaultControllerClearAlgorithms(this); - return result; - } - /** @internal */ - [PullSteps](readRequest) { - const stream = this._controlledReadableStream; - if (this._queue.length > 0) { - const chunk = DequeueValue(this); - if (this._closeRequested && this._queue.length === 0) { - ReadableStreamDefaultControllerClearAlgorithms(this); - ReadableStreamClose(stream); - } - else { - ReadableStreamDefaultControllerCallPullIfNeeded(this); - } - readRequest._chunkSteps(chunk); - } - else { - ReadableStreamAddReadRequest(stream, readRequest); - ReadableStreamDefaultControllerCallPullIfNeeded(this); - } - } - } - Object.defineProperties(ReadableStreamDefaultController.prototype, { - close: { enumerable: true }, - enqueue: { enumerable: true }, - error: { enumerable: true }, - desiredSize: { enumerable: true } - }); - if (typeof SymbolPolyfill.toStringTag === 'symbol') { - Object.defineProperty(ReadableStreamDefaultController.prototype, SymbolPolyfill.toStringTag, { - value: 'ReadableStreamDefaultController', - configurable: true - }); - } - // Abstract operations for the ReadableStreamDefaultController. - function IsReadableStreamDefaultController(x) { - if (!typeIsObject(x)) { - return false; - } - if (!Object.prototype.hasOwnProperty.call(x, '_controlledReadableStream')) { - return false; - } - return x instanceof ReadableStreamDefaultController; - } - function ReadableStreamDefaultControllerCallPullIfNeeded(controller) { - const shouldPull = ReadableStreamDefaultControllerShouldCallPull(controller); - if (!shouldPull) { - return; - } - if (controller._pulling) { - controller._pullAgain = true; - return; - } - controller._pulling = true; - const pullPromise = controller._pullAlgorithm(); - uponPromise(pullPromise, () => { - controller._pulling = false; - if (controller._pullAgain) { - controller._pullAgain = false; - ReadableStreamDefaultControllerCallPullIfNeeded(controller); - } - }, e => { - ReadableStreamDefaultControllerError(controller, e); - }); - } - function ReadableStreamDefaultControllerShouldCallPull(controller) { - const stream = controller._controlledReadableStream; - if (!ReadableStreamDefaultControllerCanCloseOrEnqueue(controller)) { - return false; - } - if (!controller._started) { - return false; - } - if (IsReadableStreamLocked(stream) && ReadableStreamGetNumReadRequests(stream) > 0) { - return true; - } - const desiredSize = ReadableStreamDefaultControllerGetDesiredSize(controller); - if (desiredSize > 0) { - return true; - } - return false; - } - function ReadableStreamDefaultControllerClearAlgorithms(controller) { - controller._pullAlgorithm = undefined; - controller._cancelAlgorithm = undefined; - controller._strategySizeAlgorithm = undefined; - } - // A client of ReadableStreamDefaultController may use these functions directly to bypass state check. - function ReadableStreamDefaultControllerClose(controller) { - if (!ReadableStreamDefaultControllerCanCloseOrEnqueue(controller)) { - return; - } - const stream = controller._controlledReadableStream; - controller._closeRequested = true; - if (controller._queue.length === 0) { - ReadableStreamDefaultControllerClearAlgorithms(controller); - ReadableStreamClose(stream); - } - } - function ReadableStreamDefaultControllerEnqueue(controller, chunk) { - if (!ReadableStreamDefaultControllerCanCloseOrEnqueue(controller)) { - return; - } - const stream = controller._controlledReadableStream; - if (IsReadableStreamLocked(stream) && ReadableStreamGetNumReadRequests(stream) > 0) { - ReadableStreamFulfillReadRequest(stream, chunk, false); - } - else { - let chunkSize; - try { - chunkSize = controller._strategySizeAlgorithm(chunk); - } - catch (chunkSizeE) { - ReadableStreamDefaultControllerError(controller, chunkSizeE); - throw chunkSizeE; - } - try { - EnqueueValueWithSize(controller, chunk, chunkSize); - } - catch (enqueueE) { - ReadableStreamDefaultControllerError(controller, enqueueE); - throw enqueueE; - } - } - ReadableStreamDefaultControllerCallPullIfNeeded(controller); - } - function ReadableStreamDefaultControllerError(controller, e) { - const stream = controller._controlledReadableStream; - if (stream._state !== 'readable') { - return; - } - ResetQueue(controller); - ReadableStreamDefaultControllerClearAlgorithms(controller); - ReadableStreamError(stream, e); - } - function ReadableStreamDefaultControllerGetDesiredSize(controller) { - const state = controller._controlledReadableStream._state; - if (state === 'errored') { - return null; - } - if (state === 'closed') { - return 0; - } - return controller._strategyHWM - controller._queueTotalSize; - } - // This is used in the implementation of TransformStream. - function ReadableStreamDefaultControllerHasBackpressure(controller) { - if (ReadableStreamDefaultControllerShouldCallPull(controller)) { - return false; - } - return true; - } - function ReadableStreamDefaultControllerCanCloseOrEnqueue(controller) { - const state = controller._controlledReadableStream._state; - if (!controller._closeRequested && state === 'readable') { - return true; - } - return false; - } - function SetUpReadableStreamDefaultController(stream, controller, startAlgorithm, pullAlgorithm, cancelAlgorithm, highWaterMark, sizeAlgorithm) { - controller._controlledReadableStream = stream; - controller._queue = undefined; - controller._queueTotalSize = undefined; - ResetQueue(controller); - controller._started = false; - controller._closeRequested = false; - controller._pullAgain = false; - controller._pulling = false; - controller._strategySizeAlgorithm = sizeAlgorithm; - controller._strategyHWM = highWaterMark; - controller._pullAlgorithm = pullAlgorithm; - controller._cancelAlgorithm = cancelAlgorithm; - stream._readableStreamController = controller; - const startResult = startAlgorithm(); - uponPromise(promiseResolvedWith(startResult), () => { - controller._started = true; - ReadableStreamDefaultControllerCallPullIfNeeded(controller); - }, r => { - ReadableStreamDefaultControllerError(controller, r); - }); - } - function SetUpReadableStreamDefaultControllerFromUnderlyingSource(stream, underlyingSource, highWaterMark, sizeAlgorithm) { - const controller = Object.create(ReadableStreamDefaultController.prototype); - let startAlgorithm = () => undefined; - let pullAlgorithm = () => promiseResolvedWith(undefined); - let cancelAlgorithm = () => promiseResolvedWith(undefined); - if (underlyingSource.start !== undefined) { - startAlgorithm = () => underlyingSource.start(controller); - } - if (underlyingSource.pull !== undefined) { - pullAlgorithm = () => underlyingSource.pull(controller); - } - if (underlyingSource.cancel !== undefined) { - cancelAlgorithm = reason => underlyingSource.cancel(reason); - } - SetUpReadableStreamDefaultController(stream, controller, startAlgorithm, pullAlgorithm, cancelAlgorithm, highWaterMark, sizeAlgorithm); - } - // Helper functions for the ReadableStreamDefaultController. - function defaultControllerBrandCheckException$1(name) { - return new TypeError(`ReadableStreamDefaultController.prototype.${name} can only be used on a ReadableStreamDefaultController`); - } - - function ReadableStreamTee(stream, cloneForBranch2) { - if (IsReadableByteStreamController(stream._readableStreamController)) { - return ReadableByteStreamTee(stream); - } - return ReadableStreamDefaultTee(stream); - } - function ReadableStreamDefaultTee(stream, cloneForBranch2) { - const reader = AcquireReadableStreamDefaultReader(stream); - let reading = false; - let readAgain = false; - let canceled1 = false; - let canceled2 = false; - let reason1; - let reason2; - let branch1; - let branch2; - let resolveCancelPromise; - const cancelPromise = newPromise(resolve => { - resolveCancelPromise = resolve; - }); - function pullAlgorithm() { - if (reading) { - readAgain = true; - return promiseResolvedWith(undefined); - } - reading = true; - const readRequest = { - _chunkSteps: chunk => { - // This needs to be delayed a microtask because it takes at least a microtask to detect errors (using - // reader._closedPromise below), and we want errors in stream to error both branches immediately. We cannot let - // successful synchronously-available reads get ahead of asynchronously-available errors. - queueMicrotask(() => { - readAgain = false; - const chunk1 = chunk; - const chunk2 = chunk; - // There is no way to access the cloning code right now in the reference implementation. - // If we add one then we'll need an implementation for serializable objects. - // if (!canceled2 && cloneForBranch2) { - // chunk2 = StructuredDeserialize(StructuredSerialize(chunk2)); - // } - if (!canceled1) { - ReadableStreamDefaultControllerEnqueue(branch1._readableStreamController, chunk1); - } - if (!canceled2) { - ReadableStreamDefaultControllerEnqueue(branch2._readableStreamController, chunk2); - } - reading = false; - if (readAgain) { - pullAlgorithm(); - } - }); - }, - _closeSteps: () => { - reading = false; - if (!canceled1) { - ReadableStreamDefaultControllerClose(branch1._readableStreamController); - } - if (!canceled2) { - ReadableStreamDefaultControllerClose(branch2._readableStreamController); - } - if (!canceled1 || !canceled2) { - resolveCancelPromise(undefined); - } - }, - _errorSteps: () => { - reading = false; - } - }; - ReadableStreamDefaultReaderRead(reader, readRequest); - return promiseResolvedWith(undefined); - } - function cancel1Algorithm(reason) { - canceled1 = true; - reason1 = reason; - if (canceled2) { - const compositeReason = CreateArrayFromList([reason1, reason2]); - const cancelResult = ReadableStreamCancel(stream, compositeReason); - resolveCancelPromise(cancelResult); - } - return cancelPromise; - } - function cancel2Algorithm(reason) { - canceled2 = true; - reason2 = reason; - if (canceled1) { - const compositeReason = CreateArrayFromList([reason1, reason2]); - const cancelResult = ReadableStreamCancel(stream, compositeReason); - resolveCancelPromise(cancelResult); - } - return cancelPromise; - } - function startAlgorithm() { - // do nothing - } - branch1 = CreateReadableStream(startAlgorithm, pullAlgorithm, cancel1Algorithm); - branch2 = CreateReadableStream(startAlgorithm, pullAlgorithm, cancel2Algorithm); - uponRejection(reader._closedPromise, (r) => { - ReadableStreamDefaultControllerError(branch1._readableStreamController, r); - ReadableStreamDefaultControllerError(branch2._readableStreamController, r); - if (!canceled1 || !canceled2) { - resolveCancelPromise(undefined); - } - }); - return [branch1, branch2]; - } - function ReadableByteStreamTee(stream) { - let reader = AcquireReadableStreamDefaultReader(stream); - let reading = false; - let readAgainForBranch1 = false; - let readAgainForBranch2 = false; - let canceled1 = false; - let canceled2 = false; - let reason1; - let reason2; - let branch1; - let branch2; - let resolveCancelPromise; - const cancelPromise = newPromise(resolve => { - resolveCancelPromise = resolve; - }); - function forwardReaderError(thisReader) { - uponRejection(thisReader._closedPromise, r => { - if (thisReader !== reader) { - return; - } - ReadableByteStreamControllerError(branch1._readableStreamController, r); - ReadableByteStreamControllerError(branch2._readableStreamController, r); - if (!canceled1 || !canceled2) { - resolveCancelPromise(undefined); - } - }); - } - function pullWithDefaultReader() { - if (IsReadableStreamBYOBReader(reader)) { - ReadableStreamReaderGenericRelease(reader); - reader = AcquireReadableStreamDefaultReader(stream); - forwardReaderError(reader); - } - const readRequest = { - _chunkSteps: chunk => { - // This needs to be delayed a microtask because it takes at least a microtask to detect errors (using - // reader._closedPromise below), and we want errors in stream to error both branches immediately. We cannot let - // successful synchronously-available reads get ahead of asynchronously-available errors. - queueMicrotask(() => { - readAgainForBranch1 = false; - readAgainForBranch2 = false; - const chunk1 = chunk; - let chunk2 = chunk; - if (!canceled1 && !canceled2) { - try { - chunk2 = CloneAsUint8Array(chunk); - } - catch (cloneE) { - ReadableByteStreamControllerError(branch1._readableStreamController, cloneE); - ReadableByteStreamControllerError(branch2._readableStreamController, cloneE); - resolveCancelPromise(ReadableStreamCancel(stream, cloneE)); - return; - } - } - if (!canceled1) { - ReadableByteStreamControllerEnqueue(branch1._readableStreamController, chunk1); - } - if (!canceled2) { - ReadableByteStreamControllerEnqueue(branch2._readableStreamController, chunk2); - } - reading = false; - if (readAgainForBranch1) { - pull1Algorithm(); - } - else if (readAgainForBranch2) { - pull2Algorithm(); - } - }); - }, - _closeSteps: () => { - reading = false; - if (!canceled1) { - ReadableByteStreamControllerClose(branch1._readableStreamController); - } - if (!canceled2) { - ReadableByteStreamControllerClose(branch2._readableStreamController); - } - if (branch1._readableStreamController._pendingPullIntos.length > 0) { - ReadableByteStreamControllerRespond(branch1._readableStreamController, 0); - } - if (branch2._readableStreamController._pendingPullIntos.length > 0) { - ReadableByteStreamControllerRespond(branch2._readableStreamController, 0); - } - if (!canceled1 || !canceled2) { - resolveCancelPromise(undefined); - } - }, - _errorSteps: () => { - reading = false; - } - }; - ReadableStreamDefaultReaderRead(reader, readRequest); - } - function pullWithBYOBReader(view, forBranch2) { - if (IsReadableStreamDefaultReader(reader)) { - ReadableStreamReaderGenericRelease(reader); - reader = AcquireReadableStreamBYOBReader(stream); - forwardReaderError(reader); - } - const byobBranch = forBranch2 ? branch2 : branch1; - const otherBranch = forBranch2 ? branch1 : branch2; - const readIntoRequest = { - _chunkSteps: chunk => { - // This needs to be delayed a microtask because it takes at least a microtask to detect errors (using - // reader._closedPromise below), and we want errors in stream to error both branches immediately. We cannot let - // successful synchronously-available reads get ahead of asynchronously-available errors. - queueMicrotask(() => { - readAgainForBranch1 = false; - readAgainForBranch2 = false; - const byobCanceled = forBranch2 ? canceled2 : canceled1; - const otherCanceled = forBranch2 ? canceled1 : canceled2; - if (!otherCanceled) { - let clonedChunk; - try { - clonedChunk = CloneAsUint8Array(chunk); - } - catch (cloneE) { - ReadableByteStreamControllerError(byobBranch._readableStreamController, cloneE); - ReadableByteStreamControllerError(otherBranch._readableStreamController, cloneE); - resolveCancelPromise(ReadableStreamCancel(stream, cloneE)); - return; - } - if (!byobCanceled) { - ReadableByteStreamControllerRespondWithNewView(byobBranch._readableStreamController, chunk); - } - ReadableByteStreamControllerEnqueue(otherBranch._readableStreamController, clonedChunk); - } - else if (!byobCanceled) { - ReadableByteStreamControllerRespondWithNewView(byobBranch._readableStreamController, chunk); - } - reading = false; - if (readAgainForBranch1) { - pull1Algorithm(); - } - else if (readAgainForBranch2) { - pull2Algorithm(); - } - }); - }, - _closeSteps: chunk => { - reading = false; - const byobCanceled = forBranch2 ? canceled2 : canceled1; - const otherCanceled = forBranch2 ? canceled1 : canceled2; - if (!byobCanceled) { - ReadableByteStreamControllerClose(byobBranch._readableStreamController); - } - if (!otherCanceled) { - ReadableByteStreamControllerClose(otherBranch._readableStreamController); - } - if (chunk !== undefined) { - if (!byobCanceled) { - ReadableByteStreamControllerRespondWithNewView(byobBranch._readableStreamController, chunk); - } - if (!otherCanceled && otherBranch._readableStreamController._pendingPullIntos.length > 0) { - ReadableByteStreamControllerRespond(otherBranch._readableStreamController, 0); - } - } - if (!byobCanceled || !otherCanceled) { - resolveCancelPromise(undefined); - } - }, - _errorSteps: () => { - reading = false; - } - }; - ReadableStreamBYOBReaderRead(reader, view, readIntoRequest); - } - function pull1Algorithm() { - if (reading) { - readAgainForBranch1 = true; - return promiseResolvedWith(undefined); - } - reading = true; - const byobRequest = ReadableByteStreamControllerGetBYOBRequest(branch1._readableStreamController); - if (byobRequest === null) { - pullWithDefaultReader(); - } - else { - pullWithBYOBReader(byobRequest._view, false); - } - return promiseResolvedWith(undefined); - } - function pull2Algorithm() { - if (reading) { - readAgainForBranch2 = true; - return promiseResolvedWith(undefined); - } - reading = true; - const byobRequest = ReadableByteStreamControllerGetBYOBRequest(branch2._readableStreamController); - if (byobRequest === null) { - pullWithDefaultReader(); - } - else { - pullWithBYOBReader(byobRequest._view, true); - } - return promiseResolvedWith(undefined); - } - function cancel1Algorithm(reason) { - canceled1 = true; - reason1 = reason; - if (canceled2) { - const compositeReason = CreateArrayFromList([reason1, reason2]); - const cancelResult = ReadableStreamCancel(stream, compositeReason); - resolveCancelPromise(cancelResult); - } - return cancelPromise; - } - function cancel2Algorithm(reason) { - canceled2 = true; - reason2 = reason; - if (canceled1) { - const compositeReason = CreateArrayFromList([reason1, reason2]); - const cancelResult = ReadableStreamCancel(stream, compositeReason); - resolveCancelPromise(cancelResult); - } - return cancelPromise; - } - function startAlgorithm() { - return; - } - branch1 = CreateReadableByteStream(startAlgorithm, pull1Algorithm, cancel1Algorithm); - branch2 = CreateReadableByteStream(startAlgorithm, pull2Algorithm, cancel2Algorithm); - forwardReaderError(reader); - return [branch1, branch2]; - } - - function convertUnderlyingDefaultOrByteSource(source, context) { - assertDictionary(source, context); - const original = source; - const autoAllocateChunkSize = original === null || original === void 0 ? void 0 : original.autoAllocateChunkSize; - const cancel = original === null || original === void 0 ? void 0 : original.cancel; - const pull = original === null || original === void 0 ? void 0 : original.pull; - const start = original === null || original === void 0 ? void 0 : original.start; - const type = original === null || original === void 0 ? void 0 : original.type; - return { - autoAllocateChunkSize: autoAllocateChunkSize === undefined ? - undefined : - convertUnsignedLongLongWithEnforceRange(autoAllocateChunkSize, `${context} has member 'autoAllocateChunkSize' that`), - cancel: cancel === undefined ? - undefined : - convertUnderlyingSourceCancelCallback(cancel, original, `${context} has member 'cancel' that`), - pull: pull === undefined ? - undefined : - convertUnderlyingSourcePullCallback(pull, original, `${context} has member 'pull' that`), - start: start === undefined ? - undefined : - convertUnderlyingSourceStartCallback(start, original, `${context} has member 'start' that`), - type: type === undefined ? undefined : convertReadableStreamType(type, `${context} has member 'type' that`) - }; - } - function convertUnderlyingSourceCancelCallback(fn, original, context) { - assertFunction(fn, context); - return (reason) => promiseCall(fn, original, [reason]); - } - function convertUnderlyingSourcePullCallback(fn, original, context) { - assertFunction(fn, context); - return (controller) => promiseCall(fn, original, [controller]); - } - function convertUnderlyingSourceStartCallback(fn, original, context) { - assertFunction(fn, context); - return (controller) => reflectCall(fn, original, [controller]); - } - function convertReadableStreamType(type, context) { - type = `${type}`; - if (type !== 'bytes') { - throw new TypeError(`${context} '${type}' is not a valid enumeration value for ReadableStreamType`); - } - return type; - } - - function convertReaderOptions(options, context) { - assertDictionary(options, context); - const mode = options === null || options === void 0 ? void 0 : options.mode; - return { - mode: mode === undefined ? undefined : convertReadableStreamReaderMode(mode, `${context} has member 'mode' that`) - }; - } - function convertReadableStreamReaderMode(mode, context) { - mode = `${mode}`; - if (mode !== 'byob') { - throw new TypeError(`${context} '${mode}' is not a valid enumeration value for ReadableStreamReaderMode`); - } - return mode; - } - - function convertIteratorOptions(options, context) { - assertDictionary(options, context); - const preventCancel = options === null || options === void 0 ? void 0 : options.preventCancel; - return { preventCancel: Boolean(preventCancel) }; - } - - function convertPipeOptions(options, context) { - assertDictionary(options, context); - const preventAbort = options === null || options === void 0 ? void 0 : options.preventAbort; - const preventCancel = options === null || options === void 0 ? void 0 : options.preventCancel; - const preventClose = options === null || options === void 0 ? void 0 : options.preventClose; - const signal = options === null || options === void 0 ? void 0 : options.signal; - if (signal !== undefined) { - assertAbortSignal(signal, `${context} has member 'signal' that`); - } - return { - preventAbort: Boolean(preventAbort), - preventCancel: Boolean(preventCancel), - preventClose: Boolean(preventClose), - signal - }; - } - function assertAbortSignal(signal, context) { - if (!isAbortSignal(signal)) { - throw new TypeError(`${context} is not an AbortSignal.`); - } - } - - function convertReadableWritablePair(pair, context) { - assertDictionary(pair, context); - const readable = pair === null || pair === void 0 ? void 0 : pair.readable; - assertRequiredField(readable, 'readable', 'ReadableWritablePair'); - assertReadableStream(readable, `${context} has member 'readable' that`); - const writable = pair === null || pair === void 0 ? void 0 : pair.writable; - assertRequiredField(writable, 'writable', 'ReadableWritablePair'); - assertWritableStream(writable, `${context} has member 'writable' that`); - return { readable, writable }; - } - - /** - * A readable stream represents a source of data, from which you can read. - * - * @public - */ - class ReadableStream { - constructor(rawUnderlyingSource = {}, rawStrategy = {}) { - if (rawUnderlyingSource === undefined) { - rawUnderlyingSource = null; - } - else { - assertObject(rawUnderlyingSource, 'First parameter'); - } - const strategy = convertQueuingStrategy(rawStrategy, 'Second parameter'); - const underlyingSource = convertUnderlyingDefaultOrByteSource(rawUnderlyingSource, 'First parameter'); - InitializeReadableStream(this); - if (underlyingSource.type === 'bytes') { - if (strategy.size !== undefined) { - throw new RangeError('The strategy for a byte stream cannot have a size function'); - } - const highWaterMark = ExtractHighWaterMark(strategy, 0); - SetUpReadableByteStreamControllerFromUnderlyingSource(this, underlyingSource, highWaterMark); - } - else { - const sizeAlgorithm = ExtractSizeAlgorithm(strategy); - const highWaterMark = ExtractHighWaterMark(strategy, 1); - SetUpReadableStreamDefaultControllerFromUnderlyingSource(this, underlyingSource, highWaterMark, sizeAlgorithm); - } - } - /** - * Whether or not the readable stream is locked to a {@link ReadableStreamDefaultReader | reader}. - */ - get locked() { - if (!IsReadableStream(this)) { - throw streamBrandCheckException$1('locked'); - } - return IsReadableStreamLocked(this); - } - /** - * Cancels the stream, signaling a loss of interest in the stream by a consumer. - * - * The supplied `reason` argument will be given to the underlying source's {@link UnderlyingSource.cancel | cancel()} - * method, which might or might not use it. - */ - cancel(reason = undefined) { - if (!IsReadableStream(this)) { - return promiseRejectedWith(streamBrandCheckException$1('cancel')); - } - if (IsReadableStreamLocked(this)) { - return promiseRejectedWith(new TypeError('Cannot cancel a stream that already has a reader')); - } - return ReadableStreamCancel(this, reason); - } - getReader(rawOptions = undefined) { - if (!IsReadableStream(this)) { - throw streamBrandCheckException$1('getReader'); - } - const options = convertReaderOptions(rawOptions, 'First parameter'); - if (options.mode === undefined) { - return AcquireReadableStreamDefaultReader(this); - } - return AcquireReadableStreamBYOBReader(this); - } - pipeThrough(rawTransform, rawOptions = {}) { - if (!IsReadableStream(this)) { - throw streamBrandCheckException$1('pipeThrough'); - } - assertRequiredArgument(rawTransform, 1, 'pipeThrough'); - const transform = convertReadableWritablePair(rawTransform, 'First parameter'); - const options = convertPipeOptions(rawOptions, 'Second parameter'); - if (IsReadableStreamLocked(this)) { - throw new TypeError('ReadableStream.prototype.pipeThrough cannot be used on a locked ReadableStream'); - } - if (IsWritableStreamLocked(transform.writable)) { - throw new TypeError('ReadableStream.prototype.pipeThrough cannot be used on a locked WritableStream'); - } - const promise = ReadableStreamPipeTo(this, transform.writable, options.preventClose, options.preventAbort, options.preventCancel, options.signal); - setPromiseIsHandledToTrue(promise); - return transform.readable; - } - pipeTo(destination, rawOptions = {}) { - if (!IsReadableStream(this)) { - return promiseRejectedWith(streamBrandCheckException$1('pipeTo')); - } - if (destination === undefined) { - return promiseRejectedWith(`Parameter 1 is required in 'pipeTo'.`); - } - if (!IsWritableStream(destination)) { - return promiseRejectedWith(new TypeError(`ReadableStream.prototype.pipeTo's first argument must be a WritableStream`)); - } - let options; - try { - options = convertPipeOptions(rawOptions, 'Second parameter'); - } - catch (e) { - return promiseRejectedWith(e); - } - if (IsReadableStreamLocked(this)) { - return promiseRejectedWith(new TypeError('ReadableStream.prototype.pipeTo cannot be used on a locked ReadableStream')); - } - if (IsWritableStreamLocked(destination)) { - return promiseRejectedWith(new TypeError('ReadableStream.prototype.pipeTo cannot be used on a locked WritableStream')); - } - return ReadableStreamPipeTo(this, destination, options.preventClose, options.preventAbort, options.preventCancel, options.signal); - } - /** - * Tees this readable stream, returning a two-element array containing the two resulting branches as - * new {@link ReadableStream} instances. - * - * Teeing a stream will lock it, preventing any other consumer from acquiring a reader. - * To cancel the stream, cancel both of the resulting branches; a composite cancellation reason will then be - * propagated to the stream's underlying source. - * - * Note that the chunks seen in each branch will be the same object. If the chunks are not immutable, - * this could allow interference between the two branches. - */ - tee() { - if (!IsReadableStream(this)) { - throw streamBrandCheckException$1('tee'); - } - const branches = ReadableStreamTee(this); - return CreateArrayFromList(branches); - } - values(rawOptions = undefined) { - if (!IsReadableStream(this)) { - throw streamBrandCheckException$1('values'); - } - const options = convertIteratorOptions(rawOptions, 'First parameter'); - return AcquireReadableStreamAsyncIterator(this, options.preventCancel); - } - } - Object.defineProperties(ReadableStream.prototype, { - cancel: { enumerable: true }, - getReader: { enumerable: true }, - pipeThrough: { enumerable: true }, - pipeTo: { enumerable: true }, - tee: { enumerable: true }, - values: { enumerable: true }, - locked: { enumerable: true } - }); - if (typeof SymbolPolyfill.toStringTag === 'symbol') { - Object.defineProperty(ReadableStream.prototype, SymbolPolyfill.toStringTag, { - value: 'ReadableStream', - configurable: true - }); - } - if (typeof SymbolPolyfill.asyncIterator === 'symbol') { - Object.defineProperty(ReadableStream.prototype, SymbolPolyfill.asyncIterator, { - value: ReadableStream.prototype.values, - writable: true, - configurable: true - }); - } - // Abstract operations for the ReadableStream. - // Throws if and only if startAlgorithm throws. - function CreateReadableStream(startAlgorithm, pullAlgorithm, cancelAlgorithm, highWaterMark = 1, sizeAlgorithm = () => 1) { - const stream = Object.create(ReadableStream.prototype); - InitializeReadableStream(stream); - const controller = Object.create(ReadableStreamDefaultController.prototype); - SetUpReadableStreamDefaultController(stream, controller, startAlgorithm, pullAlgorithm, cancelAlgorithm, highWaterMark, sizeAlgorithm); - return stream; - } - // Throws if and only if startAlgorithm throws. - function CreateReadableByteStream(startAlgorithm, pullAlgorithm, cancelAlgorithm) { - const stream = Object.create(ReadableStream.prototype); - InitializeReadableStream(stream); - const controller = Object.create(ReadableByteStreamController.prototype); - SetUpReadableByteStreamController(stream, controller, startAlgorithm, pullAlgorithm, cancelAlgorithm, 0, undefined); - return stream; - } - function InitializeReadableStream(stream) { - stream._state = 'readable'; - stream._reader = undefined; - stream._storedError = undefined; - stream._disturbed = false; - } - function IsReadableStream(x) { - if (!typeIsObject(x)) { - return false; - } - if (!Object.prototype.hasOwnProperty.call(x, '_readableStreamController')) { - return false; - } - return x instanceof ReadableStream; - } - function IsReadableStreamLocked(stream) { - if (stream._reader === undefined) { - return false; - } - return true; - } - // ReadableStream API exposed for controllers. - function ReadableStreamCancel(stream, reason) { - stream._disturbed = true; - if (stream._state === 'closed') { - return promiseResolvedWith(undefined); - } - if (stream._state === 'errored') { - return promiseRejectedWith(stream._storedError); - } - ReadableStreamClose(stream); - const reader = stream._reader; - if (reader !== undefined && IsReadableStreamBYOBReader(reader)) { - reader._readIntoRequests.forEach(readIntoRequest => { - readIntoRequest._closeSteps(undefined); - }); - reader._readIntoRequests = new SimpleQueue(); - } - const sourceCancelPromise = stream._readableStreamController[CancelSteps](reason); - return transformPromiseWith(sourceCancelPromise, noop); - } - function ReadableStreamClose(stream) { - stream._state = 'closed'; - const reader = stream._reader; - if (reader === undefined) { - return; - } - defaultReaderClosedPromiseResolve(reader); - if (IsReadableStreamDefaultReader(reader)) { - reader._readRequests.forEach(readRequest => { - readRequest._closeSteps(); - }); - reader._readRequests = new SimpleQueue(); - } - } - function ReadableStreamError(stream, e) { - stream._state = 'errored'; - stream._storedError = e; - const reader = stream._reader; - if (reader === undefined) { - return; - } - defaultReaderClosedPromiseReject(reader, e); - if (IsReadableStreamDefaultReader(reader)) { - reader._readRequests.forEach(readRequest => { - readRequest._errorSteps(e); - }); - reader._readRequests = new SimpleQueue(); - } - else { - reader._readIntoRequests.forEach(readIntoRequest => { - readIntoRequest._errorSteps(e); - }); - reader._readIntoRequests = new SimpleQueue(); - } - } - // Helper functions for the ReadableStream. - function streamBrandCheckException$1(name) { - return new TypeError(`ReadableStream.prototype.${name} can only be used on a ReadableStream`); - } - - function convertQueuingStrategyInit(init, context) { - assertDictionary(init, context); - const highWaterMark = init === null || init === void 0 ? void 0 : init.highWaterMark; - assertRequiredField(highWaterMark, 'highWaterMark', 'QueuingStrategyInit'); - return { - highWaterMark: convertUnrestrictedDouble(highWaterMark) - }; - } - - // The size function must not have a prototype property nor be a constructor - const byteLengthSizeFunction = (chunk) => { - return chunk.byteLength; - }; - try { - Object.defineProperty(byteLengthSizeFunction, 'name', { - value: 'size', - configurable: true - }); - } - catch (_a) { - // This property is non-configurable in older browsers, so ignore if this throws. - // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/name#browser_compatibility - } - /** - * A queuing strategy that counts the number of bytes in each chunk. - * - * @public - */ - class ByteLengthQueuingStrategy { - constructor(options) { - assertRequiredArgument(options, 1, 'ByteLengthQueuingStrategy'); - options = convertQueuingStrategyInit(options, 'First parameter'); - this._byteLengthQueuingStrategyHighWaterMark = options.highWaterMark; - } - /** - * Returns the high water mark provided to the constructor. - */ - get highWaterMark() { - if (!IsByteLengthQueuingStrategy(this)) { - throw byteLengthBrandCheckException('highWaterMark'); - } - return this._byteLengthQueuingStrategyHighWaterMark; - } - /** - * Measures the size of `chunk` by returning the value of its `byteLength` property. - */ - get size() { - if (!IsByteLengthQueuingStrategy(this)) { - throw byteLengthBrandCheckException('size'); - } - return byteLengthSizeFunction; - } - } - Object.defineProperties(ByteLengthQueuingStrategy.prototype, { - highWaterMark: { enumerable: true }, - size: { enumerable: true } - }); - if (typeof SymbolPolyfill.toStringTag === 'symbol') { - Object.defineProperty(ByteLengthQueuingStrategy.prototype, SymbolPolyfill.toStringTag, { - value: 'ByteLengthQueuingStrategy', - configurable: true - }); - } - // Helper functions for the ByteLengthQueuingStrategy. - function byteLengthBrandCheckException(name) { - return new TypeError(`ByteLengthQueuingStrategy.prototype.${name} can only be used on a ByteLengthQueuingStrategy`); - } - function IsByteLengthQueuingStrategy(x) { - if (!typeIsObject(x)) { - return false; - } - if (!Object.prototype.hasOwnProperty.call(x, '_byteLengthQueuingStrategyHighWaterMark')) { - return false; - } - return x instanceof ByteLengthQueuingStrategy; - } - - // The size function must not have a prototype property nor be a constructor - const countSizeFunction = () => { - return 1; - }; - try { - Object.defineProperty(countSizeFunction, 'name', { - value: 'size', - configurable: true - }); - } - catch (_a) { - // This property is non-configurable in older browsers, so ignore if this throws. - // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/name#browser_compatibility - } - /** - * A queuing strategy that counts the number of chunks. - * - * @public - */ - class CountQueuingStrategy { - constructor(options) { - assertRequiredArgument(options, 1, 'CountQueuingStrategy'); - options = convertQueuingStrategyInit(options, 'First parameter'); - this._countQueuingStrategyHighWaterMark = options.highWaterMark; - } - /** - * Returns the high water mark provided to the constructor. - */ - get highWaterMark() { - if (!IsCountQueuingStrategy(this)) { - throw countBrandCheckException('highWaterMark'); - } - return this._countQueuingStrategyHighWaterMark; - } - /** - * Measures the size of `chunk` by always returning 1. - * This ensures that the total queue size is a count of the number of chunks in the queue. - */ - get size() { - if (!IsCountQueuingStrategy(this)) { - throw countBrandCheckException('size'); - } - return countSizeFunction; - } - } - Object.defineProperties(CountQueuingStrategy.prototype, { - highWaterMark: { enumerable: true }, - size: { enumerable: true } - }); - if (typeof SymbolPolyfill.toStringTag === 'symbol') { - Object.defineProperty(CountQueuingStrategy.prototype, SymbolPolyfill.toStringTag, { - value: 'CountQueuingStrategy', - configurable: true - }); - } - // Helper functions for the CountQueuingStrategy. - function countBrandCheckException(name) { - return new TypeError(`CountQueuingStrategy.prototype.${name} can only be used on a CountQueuingStrategy`); - } - function IsCountQueuingStrategy(x) { - if (!typeIsObject(x)) { - return false; - } - if (!Object.prototype.hasOwnProperty.call(x, '_countQueuingStrategyHighWaterMark')) { - return false; - } - return x instanceof CountQueuingStrategy; - } - - function convertTransformer(original, context) { - assertDictionary(original, context); - const flush = original === null || original === void 0 ? void 0 : original.flush; - const readableType = original === null || original === void 0 ? void 0 : original.readableType; - const start = original === null || original === void 0 ? void 0 : original.start; - const transform = original === null || original === void 0 ? void 0 : original.transform; - const writableType = original === null || original === void 0 ? void 0 : original.writableType; - return { - flush: flush === undefined ? - undefined : - convertTransformerFlushCallback(flush, original, `${context} has member 'flush' that`), - readableType, - start: start === undefined ? - undefined : - convertTransformerStartCallback(start, original, `${context} has member 'start' that`), - transform: transform === undefined ? - undefined : - convertTransformerTransformCallback(transform, original, `${context} has member 'transform' that`), - writableType - }; - } - function convertTransformerFlushCallback(fn, original, context) { - assertFunction(fn, context); - return (controller) => promiseCall(fn, original, [controller]); - } - function convertTransformerStartCallback(fn, original, context) { - assertFunction(fn, context); - return (controller) => reflectCall(fn, original, [controller]); - } - function convertTransformerTransformCallback(fn, original, context) { - assertFunction(fn, context); - return (chunk, controller) => promiseCall(fn, original, [chunk, controller]); - } - - // Class TransformStream - /** - * A transform stream consists of a pair of streams: a {@link WritableStream | writable stream}, - * known as its writable side, and a {@link ReadableStream | readable stream}, known as its readable side. - * In a manner specific to the transform stream in question, writes to the writable side result in new data being - * made available for reading from the readable side. - * - * @public - */ - class TransformStream { - constructor(rawTransformer = {}, rawWritableStrategy = {}, rawReadableStrategy = {}) { - if (rawTransformer === undefined) { - rawTransformer = null; - } - const writableStrategy = convertQueuingStrategy(rawWritableStrategy, 'Second parameter'); - const readableStrategy = convertQueuingStrategy(rawReadableStrategy, 'Third parameter'); - const transformer = convertTransformer(rawTransformer, 'First parameter'); - if (transformer.readableType !== undefined) { - throw new RangeError('Invalid readableType specified'); - } - if (transformer.writableType !== undefined) { - throw new RangeError('Invalid writableType specified'); - } - const readableHighWaterMark = ExtractHighWaterMark(readableStrategy, 0); - const readableSizeAlgorithm = ExtractSizeAlgorithm(readableStrategy); - const writableHighWaterMark = ExtractHighWaterMark(writableStrategy, 1); - const writableSizeAlgorithm = ExtractSizeAlgorithm(writableStrategy); - let startPromise_resolve; - const startPromise = newPromise(resolve => { - startPromise_resolve = resolve; - }); - InitializeTransformStream(this, startPromise, writableHighWaterMark, writableSizeAlgorithm, readableHighWaterMark, readableSizeAlgorithm); - SetUpTransformStreamDefaultControllerFromTransformer(this, transformer); - if (transformer.start !== undefined) { - startPromise_resolve(transformer.start(this._transformStreamController)); - } - else { - startPromise_resolve(undefined); - } - } - /** - * The readable side of the transform stream. - */ - get readable() { - if (!IsTransformStream(this)) { - throw streamBrandCheckException('readable'); - } - return this._readable; - } - /** - * The writable side of the transform stream. - */ - get writable() { - if (!IsTransformStream(this)) { - throw streamBrandCheckException('writable'); - } - return this._writable; - } - } - Object.defineProperties(TransformStream.prototype, { - readable: { enumerable: true }, - writable: { enumerable: true } - }); - if (typeof SymbolPolyfill.toStringTag === 'symbol') { - Object.defineProperty(TransformStream.prototype, SymbolPolyfill.toStringTag, { - value: 'TransformStream', - configurable: true - }); - } - function InitializeTransformStream(stream, startPromise, writableHighWaterMark, writableSizeAlgorithm, readableHighWaterMark, readableSizeAlgorithm) { - function startAlgorithm() { - return startPromise; - } - function writeAlgorithm(chunk) { - return TransformStreamDefaultSinkWriteAlgorithm(stream, chunk); - } - function abortAlgorithm(reason) { - return TransformStreamDefaultSinkAbortAlgorithm(stream, reason); - } - function closeAlgorithm() { - return TransformStreamDefaultSinkCloseAlgorithm(stream); - } - stream._writable = CreateWritableStream(startAlgorithm, writeAlgorithm, closeAlgorithm, abortAlgorithm, writableHighWaterMark, writableSizeAlgorithm); - function pullAlgorithm() { - return TransformStreamDefaultSourcePullAlgorithm(stream); - } - function cancelAlgorithm(reason) { - TransformStreamErrorWritableAndUnblockWrite(stream, reason); - return promiseResolvedWith(undefined); - } - stream._readable = CreateReadableStream(startAlgorithm, pullAlgorithm, cancelAlgorithm, readableHighWaterMark, readableSizeAlgorithm); - // The [[backpressure]] slot is set to undefined so that it can be initialised by TransformStreamSetBackpressure. - stream._backpressure = undefined; - stream._backpressureChangePromise = undefined; - stream._backpressureChangePromise_resolve = undefined; - TransformStreamSetBackpressure(stream, true); - stream._transformStreamController = undefined; - } - function IsTransformStream(x) { - if (!typeIsObject(x)) { - return false; - } - if (!Object.prototype.hasOwnProperty.call(x, '_transformStreamController')) { - return false; - } - return x instanceof TransformStream; - } - // This is a no-op if both sides are already errored. - function TransformStreamError(stream, e) { - ReadableStreamDefaultControllerError(stream._readable._readableStreamController, e); - TransformStreamErrorWritableAndUnblockWrite(stream, e); - } - function TransformStreamErrorWritableAndUnblockWrite(stream, e) { - TransformStreamDefaultControllerClearAlgorithms(stream._transformStreamController); - WritableStreamDefaultControllerErrorIfNeeded(stream._writable._writableStreamController, e); - if (stream._backpressure) { - // Pretend that pull() was called to permit any pending write() calls to complete. TransformStreamSetBackpressure() - // cannot be called from enqueue() or pull() once the ReadableStream is errored, so this will will be the final time - // _backpressure is set. - TransformStreamSetBackpressure(stream, false); - } - } - function TransformStreamSetBackpressure(stream, backpressure) { - // Passes also when called during construction. - if (stream._backpressureChangePromise !== undefined) { - stream._backpressureChangePromise_resolve(); - } - stream._backpressureChangePromise = newPromise(resolve => { - stream._backpressureChangePromise_resolve = resolve; - }); - stream._backpressure = backpressure; - } - // Class TransformStreamDefaultController - /** - * Allows control of the {@link ReadableStream} and {@link WritableStream} of the associated {@link TransformStream}. - * - * @public - */ - class TransformStreamDefaultController { - constructor() { - throw new TypeError('Illegal constructor'); - } - /** - * Returns the desired size to fill the readable side’s internal queue. It can be negative, if the queue is over-full. - */ - get desiredSize() { - if (!IsTransformStreamDefaultController(this)) { - throw defaultControllerBrandCheckException('desiredSize'); - } - const readableController = this._controlledTransformStream._readable._readableStreamController; - return ReadableStreamDefaultControllerGetDesiredSize(readableController); - } - enqueue(chunk = undefined) { - if (!IsTransformStreamDefaultController(this)) { - throw defaultControllerBrandCheckException('enqueue'); - } - TransformStreamDefaultControllerEnqueue(this, chunk); - } - /** - * Errors both the readable side and the writable side of the controlled transform stream, making all future - * interactions with it fail with the given error `e`. Any chunks queued for transformation will be discarded. - */ - error(reason = undefined) { - if (!IsTransformStreamDefaultController(this)) { - throw defaultControllerBrandCheckException('error'); - } - TransformStreamDefaultControllerError(this, reason); - } - /** - * Closes the readable side and errors the writable side of the controlled transform stream. This is useful when the - * transformer only needs to consume a portion of the chunks written to the writable side. - */ - terminate() { - if (!IsTransformStreamDefaultController(this)) { - throw defaultControllerBrandCheckException('terminate'); - } - TransformStreamDefaultControllerTerminate(this); - } - } - Object.defineProperties(TransformStreamDefaultController.prototype, { - enqueue: { enumerable: true }, - error: { enumerable: true }, - terminate: { enumerable: true }, - desiredSize: { enumerable: true } - }); - if (typeof SymbolPolyfill.toStringTag === 'symbol') { - Object.defineProperty(TransformStreamDefaultController.prototype, SymbolPolyfill.toStringTag, { - value: 'TransformStreamDefaultController', - configurable: true - }); - } - // Transform Stream Default Controller Abstract Operations - function IsTransformStreamDefaultController(x) { - if (!typeIsObject(x)) { - return false; - } - if (!Object.prototype.hasOwnProperty.call(x, '_controlledTransformStream')) { - return false; - } - return x instanceof TransformStreamDefaultController; - } - function SetUpTransformStreamDefaultController(stream, controller, transformAlgorithm, flushAlgorithm) { - controller._controlledTransformStream = stream; - stream._transformStreamController = controller; - controller._transformAlgorithm = transformAlgorithm; - controller._flushAlgorithm = flushAlgorithm; - } - function SetUpTransformStreamDefaultControllerFromTransformer(stream, transformer) { - const controller = Object.create(TransformStreamDefaultController.prototype); - let transformAlgorithm = (chunk) => { - try { - TransformStreamDefaultControllerEnqueue(controller, chunk); - return promiseResolvedWith(undefined); - } - catch (transformResultE) { - return promiseRejectedWith(transformResultE); - } - }; - let flushAlgorithm = () => promiseResolvedWith(undefined); - if (transformer.transform !== undefined) { - transformAlgorithm = chunk => transformer.transform(chunk, controller); - } - if (transformer.flush !== undefined) { - flushAlgorithm = () => transformer.flush(controller); - } - SetUpTransformStreamDefaultController(stream, controller, transformAlgorithm, flushAlgorithm); - } - function TransformStreamDefaultControllerClearAlgorithms(controller) { - controller._transformAlgorithm = undefined; - controller._flushAlgorithm = undefined; - } - function TransformStreamDefaultControllerEnqueue(controller, chunk) { - const stream = controller._controlledTransformStream; - const readableController = stream._readable._readableStreamController; - if (!ReadableStreamDefaultControllerCanCloseOrEnqueue(readableController)) { - throw new TypeError('Readable side is not in a state that permits enqueue'); - } - // We throttle transform invocations based on the backpressure of the ReadableStream, but we still - // accept TransformStreamDefaultControllerEnqueue() calls. - try { - ReadableStreamDefaultControllerEnqueue(readableController, chunk); - } - catch (e) { - // This happens when readableStrategy.size() throws. - TransformStreamErrorWritableAndUnblockWrite(stream, e); - throw stream._readable._storedError; - } - const backpressure = ReadableStreamDefaultControllerHasBackpressure(readableController); - if (backpressure !== stream._backpressure) { - TransformStreamSetBackpressure(stream, true); - } - } - function TransformStreamDefaultControllerError(controller, e) { - TransformStreamError(controller._controlledTransformStream, e); - } - function TransformStreamDefaultControllerPerformTransform(controller, chunk) { - const transformPromise = controller._transformAlgorithm(chunk); - return transformPromiseWith(transformPromise, undefined, r => { - TransformStreamError(controller._controlledTransformStream, r); - throw r; - }); - } - function TransformStreamDefaultControllerTerminate(controller) { - const stream = controller._controlledTransformStream; - const readableController = stream._readable._readableStreamController; - ReadableStreamDefaultControllerClose(readableController); - const error = new TypeError('TransformStream terminated'); - TransformStreamErrorWritableAndUnblockWrite(stream, error); - } - // TransformStreamDefaultSink Algorithms - function TransformStreamDefaultSinkWriteAlgorithm(stream, chunk) { - const controller = stream._transformStreamController; - if (stream._backpressure) { - const backpressureChangePromise = stream._backpressureChangePromise; - return transformPromiseWith(backpressureChangePromise, () => { - const writable = stream._writable; - const state = writable._state; - if (state === 'erroring') { - throw writable._storedError; - } - return TransformStreamDefaultControllerPerformTransform(controller, chunk); - }); - } - return TransformStreamDefaultControllerPerformTransform(controller, chunk); - } - function TransformStreamDefaultSinkAbortAlgorithm(stream, reason) { - // abort() is not called synchronously, so it is possible for abort() to be called when the stream is already - // errored. - TransformStreamError(stream, reason); - return promiseResolvedWith(undefined); - } - function TransformStreamDefaultSinkCloseAlgorithm(stream) { - // stream._readable cannot change after construction, so caching it across a call to user code is safe. - const readable = stream._readable; - const controller = stream._transformStreamController; - const flushPromise = controller._flushAlgorithm(); - TransformStreamDefaultControllerClearAlgorithms(controller); - // Return a promise that is fulfilled with undefined on success. - return transformPromiseWith(flushPromise, () => { - if (readable._state === 'errored') { - throw readable._storedError; - } - ReadableStreamDefaultControllerClose(readable._readableStreamController); - }, r => { - TransformStreamError(stream, r); - throw readable._storedError; - }); - } - // TransformStreamDefaultSource Algorithms - function TransformStreamDefaultSourcePullAlgorithm(stream) { - // Invariant. Enforced by the promises returned by start() and pull(). - TransformStreamSetBackpressure(stream, false); - // Prevent the next pull() call until there is backpressure. - return stream._backpressureChangePromise; - } - // Helper functions for the TransformStreamDefaultController. - function defaultControllerBrandCheckException(name) { - return new TypeError(`TransformStreamDefaultController.prototype.${name} can only be used on a TransformStreamDefaultController`); - } - // Helper functions for the TransformStream. - function streamBrandCheckException(name) { - return new TypeError(`TransformStream.prototype.${name} can only be used on a TransformStream`); - } - - exports.ByteLengthQueuingStrategy = ByteLengthQueuingStrategy; - exports.CountQueuingStrategy = CountQueuingStrategy; - exports.ReadableByteStreamController = ReadableByteStreamController; - exports.ReadableStream = ReadableStream; - exports.ReadableStreamBYOBReader = ReadableStreamBYOBReader; - exports.ReadableStreamBYOBRequest = ReadableStreamBYOBRequest; - exports.ReadableStreamDefaultController = ReadableStreamDefaultController; - exports.ReadableStreamDefaultReader = ReadableStreamDefaultReader; - exports.TransformStream = TransformStream; - exports.TransformStreamDefaultController = TransformStreamDefaultController; - exports.WritableStream = WritableStream; - exports.WritableStreamDefaultController = WritableStreamDefaultController; - exports.WritableStreamDefaultWriter = WritableStreamDefaultWriter; - - Object.defineProperty(exports, '__esModule', { value: true }); - - }))); - -} (ponyfill_es2018, ponyfill_es2018.exports)); - return ponyfill_es2018.exports; -} - -/* c8 ignore start */ - -// 64 KiB (same size chrome slice theirs blob into Uint8array's) -const POOL_SIZE$1 = 65536; - -if (!globalThis.ReadableStream) { - // `node:stream/web` got introduced in v16.5.0 as experimental - // and it's preferred over the polyfilled version. So we also - // suppress the warning that gets emitted by NodeJS for using it. - try { - const process = require('node:process'); - const { emitWarning } = process; - try { - process.emitWarning = () => {}; - Object.assign(globalThis, require('node:stream/web')); - process.emitWarning = emitWarning; - } catch (error) { - process.emitWarning = emitWarning; - throw error - } - } catch (error) { - // fallback to polyfill implementation - Object.assign(globalThis, requirePonyfill_es2018()); - } -} - -try { - // Don't use node: prefix for this, require+node: is not supported until node v14.14 - // Only `import()` can use prefix in 12.20 and later - const { Blob } = require('buffer'); - if (Blob && !Blob.prototype.stream) { - Blob.prototype.stream = function name (params) { - let position = 0; - const blob = this; - - return new ReadableStream({ - type: 'bytes', - async pull (ctrl) { - const chunk = blob.slice(position, Math.min(blob.size, position + POOL_SIZE$1)); - const buffer = await chunk.arrayBuffer(); - position += buffer.byteLength; - ctrl.enqueue(new Uint8Array(buffer)); - - if (position === blob.size) { - ctrl.close(); - } - } - }) - }; - } -} catch (error) {} - -/*! fetch-blob. MIT License. Jimmy Wärting */ - -// 64 KiB (same size chrome slice theirs blob into Uint8array's) -const POOL_SIZE = 65536; - -/** @param {(Blob | Uint8Array)[]} parts */ -async function * toIterator (parts, clone = true) { - for (const part of parts) { - if ('stream' in part) { - yield * (/** @type {AsyncIterableIterator} */ (part.stream())); - } else if (ArrayBuffer.isView(part)) { - if (clone) { - let position = part.byteOffset; - const end = part.byteOffset + part.byteLength; - while (position !== end) { - const size = Math.min(end - position, POOL_SIZE); - const chunk = part.buffer.slice(position, position + size); - position += chunk.byteLength; - yield new Uint8Array(chunk); - } - } else { - yield part; - } - /* c8 ignore next 10 */ - } else { - // For blobs that have arrayBuffer but no stream method (nodes buffer.Blob) - let position = 0, b = (/** @type {Blob} */ (part)); - while (position !== b.size) { - const chunk = b.slice(position, Math.min(b.size, position + POOL_SIZE)); - const buffer = await chunk.arrayBuffer(); - position += buffer.byteLength; - yield new Uint8Array(buffer); - } - } - } -} - -const _Blob = class Blob { - /** @type {Array.<(Blob|Uint8Array)>} */ - #parts = [] - #type = '' - #size = 0 - #endings = 'transparent' - - /** - * The Blob() constructor returns a new Blob object. The content - * of the blob consists of the concatenation of the values given - * in the parameter array. - * - * @param {*} blobParts - * @param {{ type?: string, endings?: string }} [options] - */ - constructor (blobParts = [], options = {}) { - if (typeof blobParts !== 'object' || blobParts === null) { - throw new TypeError('Failed to construct \'Blob\': The provided value cannot be converted to a sequence.') - } - - if (typeof blobParts[Symbol.iterator] !== 'function') { - throw new TypeError('Failed to construct \'Blob\': The object must have a callable @@iterator property.') - } - - if (typeof options !== 'object' && typeof options !== 'function') { - throw new TypeError('Failed to construct \'Blob\': parameter 2 cannot convert to dictionary.') - } - - if (options === null) options = {}; - - const encoder = new TextEncoder(); - for (const element of blobParts) { - let part; - if (ArrayBuffer.isView(element)) { - part = new Uint8Array(element.buffer.slice(element.byteOffset, element.byteOffset + element.byteLength)); - } else if (element instanceof ArrayBuffer) { - part = new Uint8Array(element.slice(0)); - } else if (element instanceof Blob) { - part = element; - } else { - part = encoder.encode(`${element}`); - } - - const size = ArrayBuffer.isView(part) ? part.byteLength : part.size; - // Avoid pushing empty parts into the array to better GC them - if (size) { - this.#size += size; - this.#parts.push(part); - } - } - - this.#endings = `${options.endings === undefined ? 'transparent' : options.endings}`; - const type = options.type === undefined ? '' : String(options.type); - this.#type = /^[\x20-\x7E]*$/.test(type) ? type : ''; - } - - /** - * The Blob interface's size property returns the - * size of the Blob in bytes. - */ - get size () { - return this.#size - } - - /** - * The type property of a Blob object returns the MIME type of the file. - */ - get type () { - return this.#type - } - - /** - * The text() method in the Blob interface returns a Promise - * that resolves with a string containing the contents of - * the blob, interpreted as UTF-8. - * - * @return {Promise} - */ - async text () { - // More optimized than using this.arrayBuffer() - // that requires twice as much ram - const decoder = new TextDecoder(); - let str = ''; - for await (const part of toIterator(this.#parts, false)) { - str += decoder.decode(part, { stream: true }); - } - // Remaining - str += decoder.decode(); - return str - } - - /** - * The arrayBuffer() method in the Blob interface returns a - * Promise that resolves with the contents of the blob as - * binary data contained in an ArrayBuffer. - * - * @return {Promise} - */ - async arrayBuffer () { - // Easier way... Just a unnecessary overhead - // const view = new Uint8Array(this.size); - // await this.stream().getReader({mode: 'byob'}).read(view); - // return view.buffer; - - const data = new Uint8Array(this.size); - let offset = 0; - for await (const chunk of toIterator(this.#parts, false)) { - data.set(chunk, offset); - offset += chunk.length; - } - - return data.buffer - } - - stream () { - const it = toIterator(this.#parts, true); - - return new globalThis.ReadableStream({ - // @ts-ignore - type: 'bytes', - async pull (ctrl) { - const chunk = await it.next(); - chunk.done ? ctrl.close() : ctrl.enqueue(chunk.value); - }, - - async cancel () { - await it.return(); - } - }) - } - - /** - * The Blob interface's slice() method creates and returns a - * new Blob object which contains data from a subset of the - * blob on which it's called. - * - * @param {number} [start] - * @param {number} [end] - * @param {string} [type] - */ - slice (start = 0, end = this.size, type = '') { - const { size } = this; - - let relativeStart = start < 0 ? Math.max(size + start, 0) : Math.min(start, size); - let relativeEnd = end < 0 ? Math.max(size + end, 0) : Math.min(end, size); - - const span = Math.max(relativeEnd - relativeStart, 0); - const parts = this.#parts; - const blobParts = []; - let added = 0; - - for (const part of parts) { - // don't add the overflow to new blobParts - if (added >= span) { - break - } - - const size = ArrayBuffer.isView(part) ? part.byteLength : part.size; - if (relativeStart && size <= relativeStart) { - // Skip the beginning and change the relative - // start & end position as we skip the unwanted parts - relativeStart -= size; - relativeEnd -= size; - } else { - let chunk; - if (ArrayBuffer.isView(part)) { - chunk = part.subarray(relativeStart, Math.min(size, relativeEnd)); - added += chunk.byteLength; - } else { - chunk = part.slice(relativeStart, Math.min(size, relativeEnd)); - added += chunk.size; - } - relativeEnd -= size; - blobParts.push(chunk); - relativeStart = 0; // All next sequential parts should start at 0 - } - } - - const blob = new Blob([], { type: String(type).toLowerCase() }); - blob.#size = span; - blob.#parts = blobParts; - - return blob - } - - get [Symbol.toStringTag] () { - return 'Blob' - } - - static [Symbol.hasInstance] (object) { - return ( - object && - typeof object === 'object' && - typeof object.constructor === 'function' && - ( - typeof object.stream === 'function' || - typeof object.arrayBuffer === 'function' - ) && - /^(Blob|File)$/.test(object[Symbol.toStringTag]) - ) - } -}; - -Object.defineProperties(_Blob.prototype, { - size: { enumerable: true }, - type: { enumerable: true }, - slice: { enumerable: true } -}); - -/** @type {typeof globalThis.Blob} */ -const Blob = _Blob; - -const _File = class File extends Blob { - #lastModified = 0 - #name = '' - - /** - * @param {*[]} fileBits - * @param {string} fileName - * @param {{lastModified?: number, type?: string}} options - */// @ts-ignore - constructor (fileBits, fileName, options = {}) { - if (arguments.length < 2) { - throw new TypeError(`Failed to construct 'File': 2 arguments required, but only ${arguments.length} present.`) - } - super(fileBits, options); - - if (options === null) options = {}; - - // Simulate WebIDL type casting for NaN value in lastModified option. - const lastModified = options.lastModified === undefined ? Date.now() : Number(options.lastModified); - if (!Number.isNaN(lastModified)) { - this.#lastModified = lastModified; - } - - this.#name = String(fileName); - } - - get name () { - return this.#name - } - - get lastModified () { - return this.#lastModified - } - - get [Symbol.toStringTag] () { - return 'File' - } - - static [Symbol.hasInstance] (object) { - return !!object && object instanceof Blob && - /^(File)$/.test(object[Symbol.toStringTag]) - } -}; - -/** @type {typeof globalThis.File} */// @ts-ignore -const File = _File; - -/*! formdata-polyfill. MIT License. Jimmy Wärting */ - -var {toStringTag:t,iterator:i,hasInstance:h}=Symbol, -r=Math.random, -m='append,set,get,getAll,delete,keys,values,entries,forEach,constructor'.split(','), -f$1=(a,b,c)=>(a+='',/^(Blob|File)$/.test(b && b[t])?[(c=c!==void 0?c+'':b[t]=='File'?b.name:'blob',a),b.name!==c||b[t]=='blob'?new File([b],c,b):b]:[a,b+'']), -e=(c,f)=>(f?c:c.replace(/\r?\n|\r/g,'\r\n')).replace(/\n/g,'%0A').replace(/\r/g,'%0D').replace(/"/g,'%22'), -x=(n, a, e)=>{if(a.lengthtypeof o[m]!='function')} -append(...a){x('append',arguments,2);this.#d.push(f$1(...a));} -delete(a){x('delete',arguments,1);a+='';this.#d=this.#d.filter(([b])=>b!==a);} -get(a){x('get',arguments,1);a+='';for(var b=this.#d,l=b.length,c=0;cc[0]===a&&b.push(c[1]));return b} -has(a){x('has',arguments,1);a+='';return this.#d.some(b=>b[0]===a)} -forEach(a,b){x('forEach',arguments,1);for(var [c,d]of this)a.call(b,d,c,this);} -set(...a){x('set',arguments,2);var b=[],c=!0;a=f$1(...a);this.#d.forEach(d=>{d[0]===a[0]?c&&(c=!b.push(a)):b.push(d);});c&&b.push(a);this.#d=b;} -*entries(){yield*this.#d;} -*keys(){for(var[a]of this)yield a;} -*values(){for(var[,a]of this)yield a;}}; - -/** @param {FormData} F */ -function formDataToBlob (F,B=Blob){ -var b=`${r()}${r()}`.replace(/\./g, '').slice(-28).padStart(32, '-'),c=[],p=`--${b}\r\nContent-Disposition: form-data; name="`; -F.forEach((v,n)=>typeof v=='string' -?c.push(p+e(n)+`"\r\n\r\n${v.replace(/\r(?!\n)|(? { - return ( - typeof object === 'object' && - typeof object.append === 'function' && - typeof object.delete === 'function' && - typeof object.get === 'function' && - typeof object.getAll === 'function' && - typeof object.has === 'function' && - typeof object.set === 'function' && - typeof object.sort === 'function' && - object[NAME] === 'URLSearchParams' - ); -}; - -/** - * Check if `object` is a W3C `Blob` object (which `File` inherits from) - * @param {*} object - Object to check for - * @return {boolean} - */ -const isBlob = object => { - return ( - object && - typeof object === 'object' && - typeof object.arrayBuffer === 'function' && - typeof object.type === 'string' && - typeof object.stream === 'function' && - typeof object.constructor === 'function' && - /^(Blob|File)$/.test(object[NAME]) - ); -}; - -/** - * Check if `obj` is an instance of AbortSignal. - * @param {*} object - Object to check for - * @return {boolean} - */ -const isAbortSignal = object => { - return ( - typeof object === 'object' && ( - object[NAME] === 'AbortSignal' || - object[NAME] === 'EventTarget' - ) - ); -}; - -/** - * isDomainOrSubdomain reports whether sub is a subdomain (or exact match) of - * the parent domain. - * - * Both domains must already be in canonical form. - * @param {string|URL} original - * @param {string|URL} destination - */ -const isDomainOrSubdomain = (destination, original) => { - const orig = new URL(original).hostname; - const dest = new URL(destination).hostname; - - return orig === dest || orig.endsWith(`.${dest}`); -}; - -const pipeline = node_util.promisify(Stream__default["default"].pipeline); -const INTERNALS$2 = Symbol('Body internals'); - -/** - * Body mixin - * - * Ref: https://fetch.spec.whatwg.org/#body - * - * @param Stream body Readable stream - * @param Object opts Response options - * @return Void - */ -class Body { - constructor(body, { - size = 0 - } = {}) { - let boundary = null; - - if (body === null) { - // Body is undefined or null - body = null; - } else if (isURLSearchParameters(body)) { - // Body is a URLSearchParams - body = node_buffer.Buffer.from(body.toString()); - } else if (isBlob(body)) ; else if (node_buffer.Buffer.isBuffer(body)) ; else if (node_util.types.isAnyArrayBuffer(body)) { - // Body is ArrayBuffer - body = node_buffer.Buffer.from(body); - } else if (ArrayBuffer.isView(body)) { - // Body is ArrayBufferView - body = node_buffer.Buffer.from(body.buffer, body.byteOffset, body.byteLength); - } else if (body instanceof Stream__default["default"]) ; else if (body instanceof FormData) { - // Body is FormData - body = formDataToBlob(body); - boundary = body.type.split('=')[1]; - } else { - // None of the above - // coerce to string then buffer - body = node_buffer.Buffer.from(String(body)); - } - - let stream = body; - - if (node_buffer.Buffer.isBuffer(body)) { - stream = Stream__default["default"].Readable.from(body); - } else if (isBlob(body)) { - stream = Stream__default["default"].Readable.from(body.stream()); - } - - this[INTERNALS$2] = { - body, - stream, - boundary, - disturbed: false, - error: null - }; - this.size = size; - - if (body instanceof Stream__default["default"]) { - body.on('error', error_ => { - const error = error_ instanceof FetchBaseError ? - error_ : - new FetchError(`Invalid response body while trying to fetch ${this.url}: ${error_.message}`, 'system', error_); - this[INTERNALS$2].error = error; - }); - } - } - - get body() { - return this[INTERNALS$2].stream; - } - - get bodyUsed() { - return this[INTERNALS$2].disturbed; - } - - /** - * Decode response as ArrayBuffer - * - * @return Promise - */ - async arrayBuffer() { - const {buffer, byteOffset, byteLength} = await consumeBody(this); - return buffer.slice(byteOffset, byteOffset + byteLength); - } - - async formData() { - const ct = this.headers.get('content-type'); - - if (ct.startsWith('application/x-www-form-urlencoded')) { - const formData = new FormData(); - const parameters = new URLSearchParams(await this.text()); - - for (const [name, value] of parameters) { - formData.append(name, value); - } - - return formData; - } - - const {toFormData} = await Promise.resolve().then(function () { return multipartParser; }); - return toFormData(this.body, ct); - } - - /** - * Return raw response as Blob - * - * @return Promise - */ - async blob() { - const ct = (this.headers && this.headers.get('content-type')) || (this[INTERNALS$2].body && this[INTERNALS$2].body.type) || ''; - const buf = await this.arrayBuffer(); - - return new Blob([buf], { - type: ct - }); - } - - /** - * Decode response as json - * - * @return Promise - */ - async json() { - const text = await this.text(); - return JSON.parse(text); - } - - /** - * Decode response as text - * - * @return Promise - */ - async text() { - const buffer = await consumeBody(this); - return new TextDecoder().decode(buffer); - } - - /** - * Decode response as buffer (non-spec api) - * - * @return Promise - */ - buffer() { - return consumeBody(this); - } -} - -Body.prototype.buffer = node_util.deprecate(Body.prototype.buffer, 'Please use \'response.arrayBuffer()\' instead of \'response.buffer()\'', 'node-fetch#buffer'); - -// In browsers, all properties are enumerable. -Object.defineProperties(Body.prototype, { - body: {enumerable: true}, - bodyUsed: {enumerable: true}, - arrayBuffer: {enumerable: true}, - blob: {enumerable: true}, - json: {enumerable: true}, - text: {enumerable: true}, - data: {get: node_util.deprecate(() => {}, - 'data doesn\'t exist, use json(), text(), arrayBuffer(), or body instead', - 'https://github.com/node-fetch/node-fetch/issues/1000 (response)')} -}); - -/** - * Consume and convert an entire Body to a Buffer. - * - * Ref: https://fetch.spec.whatwg.org/#concept-body-consume-body - * - * @return Promise - */ -async function consumeBody(data) { - if (data[INTERNALS$2].disturbed) { - throw new TypeError(`body used already for: ${data.url}`); - } - - data[INTERNALS$2].disturbed = true; - - if (data[INTERNALS$2].error) { - throw data[INTERNALS$2].error; - } - - const {body} = data; - - // Body is null - if (body === null) { - return node_buffer.Buffer.alloc(0); - } - - /* c8 ignore next 3 */ - if (!(body instanceof Stream__default["default"])) { - return node_buffer.Buffer.alloc(0); - } - - // Body is stream - // get ready to actually consume the body - const accum = []; - let accumBytes = 0; - - try { - for await (const chunk of body) { - if (data.size > 0 && accumBytes + chunk.length > data.size) { - const error = new FetchError(`content size at ${data.url} over limit: ${data.size}`, 'max-size'); - body.destroy(error); - throw error; - } - - accumBytes += chunk.length; - accum.push(chunk); - } - } catch (error) { - const error_ = error instanceof FetchBaseError ? error : new FetchError(`Invalid response body while trying to fetch ${data.url}: ${error.message}`, 'system', error); - throw error_; - } - - if (body.readableEnded === true || body._readableState.ended === true) { - try { - if (accum.every(c => typeof c === 'string')) { - return node_buffer.Buffer.from(accum.join('')); - } - - return node_buffer.Buffer.concat(accum, accumBytes); - } catch (error) { - throw new FetchError(`Could not create Buffer from response body for ${data.url}: ${error.message}`, 'system', error); - } - } else { - throw new FetchError(`Premature close of server response while trying to fetch ${data.url}`); - } -} - -/** - * Clone body given Res/Req instance - * - * @param Mixed instance Response or Request instance - * @param String highWaterMark highWaterMark for both PassThrough body streams - * @return Mixed - */ -const clone = (instance, highWaterMark) => { - let p1; - let p2; - let {body} = instance[INTERNALS$2]; - - // Don't allow cloning a used body - if (instance.bodyUsed) { - throw new Error('cannot clone body after it is used'); - } - - // Check that body is a stream and not form-data object - // note: we can't clone the form-data object without having it as a dependency - if ((body instanceof Stream__default["default"]) && (typeof body.getBoundary !== 'function')) { - // Tee instance body - p1 = new Stream.PassThrough({highWaterMark}); - p2 = new Stream.PassThrough({highWaterMark}); - body.pipe(p1); - body.pipe(p2); - // Set instance body to teed body and return the other teed body - instance[INTERNALS$2].stream = p1; - body = p2; - } - - return body; -}; - -const getNonSpecFormDataBoundary = node_util.deprecate( - body => body.getBoundary(), - 'form-data doesn\'t follow the spec and requires special treatment. Use alternative package', - 'https://github.com/node-fetch/node-fetch/issues/1167' -); - -/** - * Performs the operation "extract a `Content-Type` value from |object|" as - * specified in the specification: - * https://fetch.spec.whatwg.org/#concept-bodyinit-extract - * - * This function assumes that instance.body is present. - * - * @param {any} body Any options.body input - * @returns {string | null} - */ -const extractContentType = (body, request) => { - // Body is null or undefined - if (body === null) { - return null; - } - - // Body is string - if (typeof body === 'string') { - return 'text/plain;charset=UTF-8'; - } - - // Body is a URLSearchParams - if (isURLSearchParameters(body)) { - return 'application/x-www-form-urlencoded;charset=UTF-8'; - } - - // Body is blob - if (isBlob(body)) { - return body.type || null; - } - - // Body is a Buffer (Buffer, ArrayBuffer or ArrayBufferView) - if (node_buffer.Buffer.isBuffer(body) || node_util.types.isAnyArrayBuffer(body) || ArrayBuffer.isView(body)) { - return null; - } - - if (body instanceof FormData) { - return `multipart/form-data; boundary=${request[INTERNALS$2].boundary}`; - } - - // Detect form data input from form-data module - if (body && typeof body.getBoundary === 'function') { - return `multipart/form-data;boundary=${getNonSpecFormDataBoundary(body)}`; - } - - // Body is stream - can't really do much about this - if (body instanceof Stream__default["default"]) { - return null; - } - - // Body constructor defaults other things to string - return 'text/plain;charset=UTF-8'; -}; - -/** - * The Fetch Standard treats this as if "total bytes" is a property on the body. - * For us, we have to explicitly get it with a function. - * - * ref: https://fetch.spec.whatwg.org/#concept-body-total-bytes - * - * @param {any} obj.body Body object from the Body instance. - * @returns {number | null} - */ -const getTotalBytes = request => { - const {body} = request[INTERNALS$2]; - - // Body is null or undefined - if (body === null) { - return 0; - } - - // Body is Blob - if (isBlob(body)) { - return body.size; - } - - // Body is Buffer - if (node_buffer.Buffer.isBuffer(body)) { - return body.length; - } - - // Detect form data input from form-data module - if (body && typeof body.getLengthSync === 'function') { - return body.hasKnownLength && body.hasKnownLength() ? body.getLengthSync() : null; - } - - // Body is stream - return null; -}; - -/** - * Write a Body to a Node.js WritableStream (e.g. http.Request) object. - * - * @param {Stream.Writable} dest The stream to write to. - * @param obj.body Body object from the Body instance. - * @returns {Promise} - */ -const writeToStream = async (dest, {body}) => { - if (body === null) { - // Body is null - dest.end(); - } else { - // Body is stream - await pipeline(body, dest); - } -}; - -/** - * Headers.js - * - * Headers class offers convenient helpers - */ - -/* c8 ignore next 9 */ -const validateHeaderName = typeof http__default["default"].validateHeaderName === 'function' ? - http__default["default"].validateHeaderName : - name => { - if (!/^[\^`\-\w!#$%&'*+.|~]+$/.test(name)) { - const error = new TypeError(`Header name must be a valid HTTP token [${name}]`); - Object.defineProperty(error, 'code', {value: 'ERR_INVALID_HTTP_TOKEN'}); - throw error; - } - }; - -/* c8 ignore next 9 */ -const validateHeaderValue = typeof http__default["default"].validateHeaderValue === 'function' ? - http__default["default"].validateHeaderValue : - (name, value) => { - if (/[^\t\u0020-\u007E\u0080-\u00FF]/.test(value)) { - const error = new TypeError(`Invalid character in header content ["${name}"]`); - Object.defineProperty(error, 'code', {value: 'ERR_INVALID_CHAR'}); - throw error; - } - }; - -/** - * @typedef {Headers | Record | Iterable | Iterable>} HeadersInit - */ - -/** - * This Fetch API interface allows you to perform various actions on HTTP request and response headers. - * These actions include retrieving, setting, adding to, and removing. - * A Headers object has an associated header list, which is initially empty and consists of zero or more name and value pairs. - * You can add to this using methods like append() (see Examples.) - * In all methods of this interface, header names are matched by case-insensitive byte sequence. - * - */ -class Headers extends URLSearchParams { - /** - * Headers class - * - * @constructor - * @param {HeadersInit} [init] - Response headers - */ - constructor(init) { - // Validate and normalize init object in [name, value(s)][] - /** @type {string[][]} */ - let result = []; - if (init instanceof Headers) { - const raw = init.raw(); - for (const [name, values] of Object.entries(raw)) { - result.push(...values.map(value => [name, value])); - } - } else if (init == null) ; else if (typeof init === 'object' && !node_util.types.isBoxedPrimitive(init)) { - const method = init[Symbol.iterator]; - // eslint-disable-next-line no-eq-null, eqeqeq - if (method == null) { - // Record - result.push(...Object.entries(init)); - } else { - if (typeof method !== 'function') { - throw new TypeError('Header pairs must be iterable'); - } - - // Sequence> - // Note: per spec we have to first exhaust the lists then process them - result = [...init] - .map(pair => { - if ( - typeof pair !== 'object' || node_util.types.isBoxedPrimitive(pair) - ) { - throw new TypeError('Each header pair must be an iterable object'); - } - - return [...pair]; - }).map(pair => { - if (pair.length !== 2) { - throw new TypeError('Each header pair must be a name/value tuple'); - } - - return [...pair]; - }); - } - } else { - throw new TypeError('Failed to construct \'Headers\': The provided value is not of type \'(sequence> or record)'); - } - - // Validate and lowercase - result = - result.length > 0 ? - result.map(([name, value]) => { - validateHeaderName(name); - validateHeaderValue(name, String(value)); - return [String(name).toLowerCase(), String(value)]; - }) : - undefined; - - super(result); - - // Returning a Proxy that will lowercase key names, validate parameters and sort keys - // eslint-disable-next-line no-constructor-return - return new Proxy(this, { - get(target, p, receiver) { - switch (p) { - case 'append': - case 'set': - return (name, value) => { - validateHeaderName(name); - validateHeaderValue(name, String(value)); - return URLSearchParams.prototype[p].call( - target, - String(name).toLowerCase(), - String(value) - ); - }; - - case 'delete': - case 'has': - case 'getAll': - return name => { - validateHeaderName(name); - return URLSearchParams.prototype[p].call( - target, - String(name).toLowerCase() - ); - }; - - case 'keys': - return () => { - target.sort(); - return new Set(URLSearchParams.prototype.keys.call(target)).keys(); - }; - - default: - return Reflect.get(target, p, receiver); - } - } - }); - /* c8 ignore next */ - } - - get [Symbol.toStringTag]() { - return this.constructor.name; - } - - toString() { - return Object.prototype.toString.call(this); - } - - get(name) { - const values = this.getAll(name); - if (values.length === 0) { - return null; - } - - let value = values.join(', '); - if (/^content-encoding$/i.test(name)) { - value = value.toLowerCase(); - } - - return value; - } - - forEach(callback, thisArg = undefined) { - for (const name of this.keys()) { - Reflect.apply(callback, thisArg, [this.get(name), name, this]); - } - } - - * values() { - for (const name of this.keys()) { - yield this.get(name); - } - } - - /** - * @type {() => IterableIterator<[string, string]>} - */ - * entries() { - for (const name of this.keys()) { - yield [name, this.get(name)]; - } - } - - [Symbol.iterator]() { - return this.entries(); - } - - /** - * Node-fetch non-spec method - * returning all headers and their values as array - * @returns {Record} - */ - raw() { - return [...this.keys()].reduce((result, key) => { - result[key] = this.getAll(key); - return result; - }, {}); - } - - /** - * For better console.log(headers) and also to convert Headers into Node.js Request compatible format - */ - [Symbol.for('nodejs.util.inspect.custom')]() { - return [...this.keys()].reduce((result, key) => { - const values = this.getAll(key); - // Http.request() only supports string as Host header. - // This hack makes specifying custom Host header possible. - if (key === 'host') { - result[key] = values[0]; - } else { - result[key] = values.length > 1 ? values : values[0]; - } - - return result; - }, {}); - } -} - -/** - * Re-shaping object for Web IDL tests - * Only need to do it for overridden methods - */ -Object.defineProperties( - Headers.prototype, - ['get', 'entries', 'forEach', 'values'].reduce((result, property) => { - result[property] = {enumerable: true}; - return result; - }, {}) -); - -/** - * Create a Headers object from an http.IncomingMessage.rawHeaders, ignoring those that do - * not conform to HTTP grammar productions. - * @param {import('http').IncomingMessage['rawHeaders']} headers - */ -function fromRawHeaders(headers = []) { - return new Headers( - headers - // Split into pairs - .reduce((result, value, index, array) => { - if (index % 2 === 0) { - result.push(array.slice(index, index + 2)); - } - - return result; - }, []) - .filter(([name, value]) => { - try { - validateHeaderName(name); - validateHeaderValue(name, String(value)); - return true; - } catch { - return false; - } - }) - - ); -} - -const redirectStatus = new Set([301, 302, 303, 307, 308]); - -/** - * Redirect code matching - * - * @param {number} code - Status code - * @return {boolean} - */ -const isRedirect = code => { - return redirectStatus.has(code); -}; - -/** - * Response.js - * - * Response class provides content decoding - */ - -const INTERNALS$1 = Symbol('Response internals'); - -/** - * Response class - * - * Ref: https://fetch.spec.whatwg.org/#response-class - * - * @param Stream body Readable stream - * @param Object opts Response options - * @return Void - */ -class Response extends Body { - constructor(body = null, options = {}) { - super(body, options); - - // eslint-disable-next-line no-eq-null, eqeqeq, no-negated-condition - const status = options.status != null ? options.status : 200; - - const headers = new Headers(options.headers); - - if (body !== null && !headers.has('Content-Type')) { - const contentType = extractContentType(body, this); - if (contentType) { - headers.append('Content-Type', contentType); - } - } - - this[INTERNALS$1] = { - type: 'default', - url: options.url, - status, - statusText: options.statusText || '', - headers, - counter: options.counter, - highWaterMark: options.highWaterMark - }; - } - - get type() { - return this[INTERNALS$1].type; - } - - get url() { - return this[INTERNALS$1].url || ''; - } - - get status() { - return this[INTERNALS$1].status; - } - - /** - * Convenience property representing if the request ended normally - */ - get ok() { - return this[INTERNALS$1].status >= 200 && this[INTERNALS$1].status < 300; - } - - get redirected() { - return this[INTERNALS$1].counter > 0; - } - - get statusText() { - return this[INTERNALS$1].statusText; - } - - get headers() { - return this[INTERNALS$1].headers; - } - - get highWaterMark() { - return this[INTERNALS$1].highWaterMark; - } - - /** - * Clone this response - * - * @return Response - */ - clone() { - return new Response(clone(this, this.highWaterMark), { - type: this.type, - url: this.url, - status: this.status, - statusText: this.statusText, - headers: this.headers, - ok: this.ok, - redirected: this.redirected, - size: this.size, - highWaterMark: this.highWaterMark - }); - } - - /** - * @param {string} url The URL that the new response is to originate from. - * @param {number} status An optional status code for the response (e.g., 302.) - * @returns {Response} A Response object. - */ - static redirect(url, status = 302) { - if (!isRedirect(status)) { - throw new RangeError('Failed to execute "redirect" on "response": Invalid status code'); - } - - return new Response(null, { - headers: { - location: new URL(url).toString() - }, - status - }); - } - - static error() { - const response = new Response(null, {status: 0, statusText: ''}); - response[INTERNALS$1].type = 'error'; - return response; - } - - get [Symbol.toStringTag]() { - return 'Response'; - } -} - -Object.defineProperties(Response.prototype, { - type: {enumerable: true}, - url: {enumerable: true}, - status: {enumerable: true}, - ok: {enumerable: true}, - redirected: {enumerable: true}, - statusText: {enumerable: true}, - headers: {enumerable: true}, - clone: {enumerable: true} -}); - -const getSearch = parsedURL => { - if (parsedURL.search) { - return parsedURL.search; - } - - const lastOffset = parsedURL.href.length - 1; - const hash = parsedURL.hash || (parsedURL.href[lastOffset] === '#' ? '#' : ''); - return parsedURL.href[lastOffset - hash.length] === '?' ? '?' : ''; -}; - -/** - * @external URL - * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/URL|URL} - */ - -/** - * @module utils/referrer - * @private - */ - -/** - * @see {@link https://w3c.github.io/webappsec-referrer-policy/#strip-url|Referrer Policy §8.4. Strip url for use as a referrer} - * @param {string} URL - * @param {boolean} [originOnly=false] - */ -function stripURLForUseAsAReferrer(url, originOnly = false) { - // 1. If url is null, return no referrer. - if (url == null) { // eslint-disable-line no-eq-null, eqeqeq - return 'no-referrer'; - } - - url = new URL(url); - - // 2. If url's scheme is a local scheme, then return no referrer. - if (/^(about|blob|data):$/.test(url.protocol)) { - return 'no-referrer'; - } - - // 3. Set url's username to the empty string. - url.username = ''; - - // 4. Set url's password to null. - // Note: `null` appears to be a mistake as this actually results in the password being `"null"`. - url.password = ''; - - // 5. Set url's fragment to null. - // Note: `null` appears to be a mistake as this actually results in the fragment being `"#null"`. - url.hash = ''; - - // 6. If the origin-only flag is true, then: - if (originOnly) { - // 6.1. Set url's path to null. - // Note: `null` appears to be a mistake as this actually results in the path being `"/null"`. - url.pathname = ''; - - // 6.2. Set url's query to null. - // Note: `null` appears to be a mistake as this actually results in the query being `"?null"`. - url.search = ''; - } - - // 7. Return url. - return url; -} - -/** - * @see {@link https://w3c.github.io/webappsec-referrer-policy/#enumdef-referrerpolicy|enum ReferrerPolicy} - */ -const ReferrerPolicy = new Set([ - '', - 'no-referrer', - 'no-referrer-when-downgrade', - 'same-origin', - 'origin', - 'strict-origin', - 'origin-when-cross-origin', - 'strict-origin-when-cross-origin', - 'unsafe-url' -]); - -/** - * @see {@link https://w3c.github.io/webappsec-referrer-policy/#default-referrer-policy|default referrer policy} - */ -const DEFAULT_REFERRER_POLICY = 'strict-origin-when-cross-origin'; - -/** - * @see {@link https://w3c.github.io/webappsec-referrer-policy/#referrer-policies|Referrer Policy §3. Referrer Policies} - * @param {string} referrerPolicy - * @returns {string} referrerPolicy - */ -function validateReferrerPolicy(referrerPolicy) { - if (!ReferrerPolicy.has(referrerPolicy)) { - throw new TypeError(`Invalid referrerPolicy: ${referrerPolicy}`); - } - - return referrerPolicy; -} - -/** - * @see {@link https://w3c.github.io/webappsec-secure-contexts/#is-origin-trustworthy|Referrer Policy §3.2. Is origin potentially trustworthy?} - * @param {external:URL} url - * @returns `true`: "Potentially Trustworthy", `false`: "Not Trustworthy" - */ -function isOriginPotentiallyTrustworthy(url) { - // 1. If origin is an opaque origin, return "Not Trustworthy". - // Not applicable - - // 2. Assert: origin is a tuple origin. - // Not for implementations - - // 3. If origin's scheme is either "https" or "wss", return "Potentially Trustworthy". - if (/^(http|ws)s:$/.test(url.protocol)) { - return true; - } - - // 4. If origin's host component matches one of the CIDR notations 127.0.0.0/8 or ::1/128 [RFC4632], return "Potentially Trustworthy". - const hostIp = url.host.replace(/(^\[)|(]$)/g, ''); - const hostIPVersion = node_net.isIP(hostIp); - - if (hostIPVersion === 4 && /^127\./.test(hostIp)) { - return true; - } - - if (hostIPVersion === 6 && /^(((0+:){7})|(::(0+:){0,6}))0*1$/.test(hostIp)) { - return true; - } - - // 5. If origin's host component is "localhost" or falls within ".localhost", and the user agent conforms to the name resolution rules in [let-localhost-be-localhost], return "Potentially Trustworthy". - // We are returning FALSE here because we cannot ensure conformance to - // let-localhost-be-loalhost (https://tools.ietf.org/html/draft-west-let-localhost-be-localhost) - if (/^(.+\.)*localhost$/.test(url.host)) { - return false; - } - - // 6. If origin's scheme component is file, return "Potentially Trustworthy". - if (url.protocol === 'file:') { - return true; - } - - // 7. If origin's scheme component is one which the user agent considers to be authenticated, return "Potentially Trustworthy". - // Not supported - - // 8. If origin has been configured as a trustworthy origin, return "Potentially Trustworthy". - // Not supported - - // 9. Return "Not Trustworthy". - return false; -} - -/** - * @see {@link https://w3c.github.io/webappsec-secure-contexts/#is-url-trustworthy|Referrer Policy §3.3. Is url potentially trustworthy?} - * @param {external:URL} url - * @returns `true`: "Potentially Trustworthy", `false`: "Not Trustworthy" - */ -function isUrlPotentiallyTrustworthy(url) { - // 1. If url is "about:blank" or "about:srcdoc", return "Potentially Trustworthy". - if (/^about:(blank|srcdoc)$/.test(url)) { - return true; - } - - // 2. If url's scheme is "data", return "Potentially Trustworthy". - if (url.protocol === 'data:') { - return true; - } - - // Note: The origin of blob: and filesystem: URLs is the origin of the context in which they were - // created. Therefore, blobs created in a trustworthy origin will themselves be potentially - // trustworthy. - if (/^(blob|filesystem):$/.test(url.protocol)) { - return true; - } - - // 3. Return the result of executing §3.2 Is origin potentially trustworthy? on url's origin. - return isOriginPotentiallyTrustworthy(url); -} - -/** - * Modifies the referrerURL to enforce any extra security policy considerations. - * @see {@link https://w3c.github.io/webappsec-referrer-policy/#determine-requests-referrer|Referrer Policy §8.3. Determine request's Referrer}, step 7 - * @callback module:utils/referrer~referrerURLCallback - * @param {external:URL} referrerURL - * @returns {external:URL} modified referrerURL - */ - -/** - * Modifies the referrerOrigin to enforce any extra security policy considerations. - * @see {@link https://w3c.github.io/webappsec-referrer-policy/#determine-requests-referrer|Referrer Policy §8.3. Determine request's Referrer}, step 7 - * @callback module:utils/referrer~referrerOriginCallback - * @param {external:URL} referrerOrigin - * @returns {external:URL} modified referrerOrigin - */ - -/** - * @see {@link https://w3c.github.io/webappsec-referrer-policy/#determine-requests-referrer|Referrer Policy §8.3. Determine request's Referrer} - * @param {Request} request - * @param {object} o - * @param {module:utils/referrer~referrerURLCallback} o.referrerURLCallback - * @param {module:utils/referrer~referrerOriginCallback} o.referrerOriginCallback - * @returns {external:URL} Request's referrer - */ -function determineRequestsReferrer(request, {referrerURLCallback, referrerOriginCallback} = {}) { - // There are 2 notes in the specification about invalid pre-conditions. We return null, here, for - // these cases: - // > Note: If request's referrer is "no-referrer", Fetch will not call into this algorithm. - // > Note: If request's referrer policy is the empty string, Fetch will not call into this - // > algorithm. - if (request.referrer === 'no-referrer' || request.referrerPolicy === '') { - return null; - } - - // 1. Let policy be request's associated referrer policy. - const policy = request.referrerPolicy; - - // 2. Let environment be request's client. - // not applicable to node.js - - // 3. Switch on request's referrer: - if (request.referrer === 'about:client') { - return 'no-referrer'; - } - - // "a URL": Let referrerSource be request's referrer. - const referrerSource = request.referrer; - - // 4. Let request's referrerURL be the result of stripping referrerSource for use as a referrer. - let referrerURL = stripURLForUseAsAReferrer(referrerSource); - - // 5. Let referrerOrigin be the result of stripping referrerSource for use as a referrer, with the - // origin-only flag set to true. - let referrerOrigin = stripURLForUseAsAReferrer(referrerSource, true); - - // 6. If the result of serializing referrerURL is a string whose length is greater than 4096, set - // referrerURL to referrerOrigin. - if (referrerURL.toString().length > 4096) { - referrerURL = referrerOrigin; - } - - // 7. The user agent MAY alter referrerURL or referrerOrigin at this point to enforce arbitrary - // policy considerations in the interests of minimizing data leakage. For example, the user - // agent could strip the URL down to an origin, modify its host, replace it with an empty - // string, etc. - if (referrerURLCallback) { - referrerURL = referrerURLCallback(referrerURL); - } - - if (referrerOriginCallback) { - referrerOrigin = referrerOriginCallback(referrerOrigin); - } - - // 8.Execute the statements corresponding to the value of policy: - const currentURL = new URL(request.url); - - switch (policy) { - case 'no-referrer': - return 'no-referrer'; - - case 'origin': - return referrerOrigin; - - case 'unsafe-url': - return referrerURL; - - case 'strict-origin': - // 1. If referrerURL is a potentially trustworthy URL and request's current URL is not a - // potentially trustworthy URL, then return no referrer. - if (isUrlPotentiallyTrustworthy(referrerURL) && !isUrlPotentiallyTrustworthy(currentURL)) { - return 'no-referrer'; - } - - // 2. Return referrerOrigin. - return referrerOrigin.toString(); - - case 'strict-origin-when-cross-origin': - // 1. If the origin of referrerURL and the origin of request's current URL are the same, then - // return referrerURL. - if (referrerURL.origin === currentURL.origin) { - return referrerURL; - } - - // 2. If referrerURL is a potentially trustworthy URL and request's current URL is not a - // potentially trustworthy URL, then return no referrer. - if (isUrlPotentiallyTrustworthy(referrerURL) && !isUrlPotentiallyTrustworthy(currentURL)) { - return 'no-referrer'; - } - - // 3. Return referrerOrigin. - return referrerOrigin; - - case 'same-origin': - // 1. If the origin of referrerURL and the origin of request's current URL are the same, then - // return referrerURL. - if (referrerURL.origin === currentURL.origin) { - return referrerURL; - } - - // 2. Return no referrer. - return 'no-referrer'; - - case 'origin-when-cross-origin': - // 1. If the origin of referrerURL and the origin of request's current URL are the same, then - // return referrerURL. - if (referrerURL.origin === currentURL.origin) { - return referrerURL; - } - - // Return referrerOrigin. - return referrerOrigin; - - case 'no-referrer-when-downgrade': - // 1. If referrerURL is a potentially trustworthy URL and request's current URL is not a - // potentially trustworthy URL, then return no referrer. - if (isUrlPotentiallyTrustworthy(referrerURL) && !isUrlPotentiallyTrustworthy(currentURL)) { - return 'no-referrer'; - } - - // 2. Return referrerURL. - return referrerURL; - - default: - throw new TypeError(`Invalid referrerPolicy: ${policy}`); - } -} - -/** - * @see {@link https://w3c.github.io/webappsec-referrer-policy/#parse-referrer-policy-from-header|Referrer Policy §8.1. Parse a referrer policy from a Referrer-Policy header} - * @param {Headers} headers Response headers - * @returns {string} policy - */ -function parseReferrerPolicyFromHeader(headers) { - // 1. Let policy-tokens be the result of extracting header list values given `Referrer-Policy` - // and response’s header list. - const policyTokens = (headers.get('referrer-policy') || '').split(/[,\s]+/); - - // 2. Let policy be the empty string. - let policy = ''; - - // 3. For each token in policy-tokens, if token is a referrer policy and token is not the empty - // string, then set policy to token. - // Note: This algorithm loops over multiple policy values to allow deployment of new policy - // values with fallbacks for older user agents, as described in § 11.1 Unknown Policy Values. - for (const token of policyTokens) { - if (token && ReferrerPolicy.has(token)) { - policy = token; - } - } - - // 4. Return policy. - return policy; -} - -/** - * Request.js - * - * Request class contains server only options - * - * All spec algorithm step numbers are based on https://fetch.spec.whatwg.org/commit-snapshots/ae716822cb3a61843226cd090eefc6589446c1d2/. - */ - -const INTERNALS = Symbol('Request internals'); - -/** - * Check if `obj` is an instance of Request. - * - * @param {*} object - * @return {boolean} - */ -const isRequest = object => { - return ( - typeof object === 'object' && - typeof object[INTERNALS] === 'object' - ); -}; - -const doBadDataWarn = node_util.deprecate(() => {}, - '.data is not a valid RequestInit property, use .body instead', - 'https://github.com/node-fetch/node-fetch/issues/1000 (request)'); - -/** - * Request class - * - * Ref: https://fetch.spec.whatwg.org/#request-class - * - * @param Mixed input Url or Request instance - * @param Object init Custom options - * @return Void - */ -class Request extends Body { - constructor(input, init = {}) { - let parsedURL; - - // Normalize input and force URL to be encoded as UTF-8 (https://github.com/node-fetch/node-fetch/issues/245) - if (isRequest(input)) { - parsedURL = new URL(input.url); - } else { - parsedURL = new URL(input); - input = {}; - } - - if (parsedURL.username !== '' || parsedURL.password !== '') { - throw new TypeError(`${parsedURL} is an url with embedded credentials.`); - } - - let method = init.method || input.method || 'GET'; - if (/^(delete|get|head|options|post|put)$/i.test(method)) { - method = method.toUpperCase(); - } - - if ('data' in init) { - doBadDataWarn(); - } - - // eslint-disable-next-line no-eq-null, eqeqeq - if ((init.body != null || (isRequest(input) && input.body !== null)) && - (method === 'GET' || method === 'HEAD')) { - throw new TypeError('Request with GET/HEAD method cannot have body'); - } - - const inputBody = init.body ? - init.body : - (isRequest(input) && input.body !== null ? - clone(input) : - null); - - super(inputBody, { - size: init.size || input.size || 0 - }); - - const headers = new Headers(init.headers || input.headers || {}); - - if (inputBody !== null && !headers.has('Content-Type')) { - const contentType = extractContentType(inputBody, this); - if (contentType) { - headers.set('Content-Type', contentType); - } - } - - let signal = isRequest(input) ? - input.signal : - null; - if ('signal' in init) { - signal = init.signal; - } - - // eslint-disable-next-line no-eq-null, eqeqeq - if (signal != null && !isAbortSignal(signal)) { - throw new TypeError('Expected signal to be an instanceof AbortSignal or EventTarget'); - } - - // §5.4, Request constructor steps, step 15.1 - // eslint-disable-next-line no-eq-null, eqeqeq - let referrer = init.referrer == null ? input.referrer : init.referrer; - if (referrer === '') { - // §5.4, Request constructor steps, step 15.2 - referrer = 'no-referrer'; - } else if (referrer) { - // §5.4, Request constructor steps, step 15.3.1, 15.3.2 - const parsedReferrer = new URL(referrer); - // §5.4, Request constructor steps, step 15.3.3, 15.3.4 - referrer = /^about:(\/\/)?client$/.test(parsedReferrer) ? 'client' : parsedReferrer; - } else { - referrer = undefined; - } - - this[INTERNALS] = { - method, - redirect: init.redirect || input.redirect || 'follow', - headers, - parsedURL, - signal, - referrer - }; - - // Node-fetch-only options - this.follow = init.follow === undefined ? (input.follow === undefined ? 20 : input.follow) : init.follow; - this.compress = init.compress === undefined ? (input.compress === undefined ? true : input.compress) : init.compress; - this.counter = init.counter || input.counter || 0; - this.agent = init.agent || input.agent; - this.highWaterMark = init.highWaterMark || input.highWaterMark || 16384; - this.insecureHTTPParser = init.insecureHTTPParser || input.insecureHTTPParser || false; - - // §5.4, Request constructor steps, step 16. - // Default is empty string per https://fetch.spec.whatwg.org/#concept-request-referrer-policy - this.referrerPolicy = init.referrerPolicy || input.referrerPolicy || ''; - } - - /** @returns {string} */ - get method() { - return this[INTERNALS].method; - } - - /** @returns {string} */ - get url() { - return node_url.format(this[INTERNALS].parsedURL); - } - - /** @returns {Headers} */ - get headers() { - return this[INTERNALS].headers; - } - - get redirect() { - return this[INTERNALS].redirect; - } - - /** @returns {AbortSignal} */ - get signal() { - return this[INTERNALS].signal; - } - - // https://fetch.spec.whatwg.org/#dom-request-referrer - get referrer() { - if (this[INTERNALS].referrer === 'no-referrer') { - return ''; - } - - if (this[INTERNALS].referrer === 'client') { - return 'about:client'; - } - - if (this[INTERNALS].referrer) { - return this[INTERNALS].referrer.toString(); - } - - return undefined; - } - - get referrerPolicy() { - return this[INTERNALS].referrerPolicy; - } - - set referrerPolicy(referrerPolicy) { - this[INTERNALS].referrerPolicy = validateReferrerPolicy(referrerPolicy); - } - - /** - * Clone this request - * - * @return Request - */ - clone() { - return new Request(this); - } - - get [Symbol.toStringTag]() { - return 'Request'; - } -} - -Object.defineProperties(Request.prototype, { - method: {enumerable: true}, - url: {enumerable: true}, - headers: {enumerable: true}, - redirect: {enumerable: true}, - clone: {enumerable: true}, - signal: {enumerable: true}, - referrer: {enumerable: true}, - referrerPolicy: {enumerable: true} -}); - -/** - * Convert a Request to Node.js http request options. - * - * @param {Request} request - A Request instance - * @return The options object to be passed to http.request - */ -const getNodeRequestOptions = request => { - const {parsedURL} = request[INTERNALS]; - const headers = new Headers(request[INTERNALS].headers); - - // Fetch step 1.3 - if (!headers.has('Accept')) { - headers.set('Accept', '*/*'); - } - - // HTTP-network-or-cache fetch steps 2.4-2.7 - let contentLengthValue = null; - if (request.body === null && /^(post|put)$/i.test(request.method)) { - contentLengthValue = '0'; - } - - if (request.body !== null) { - const totalBytes = getTotalBytes(request); - // Set Content-Length if totalBytes is a number (that is not NaN) - if (typeof totalBytes === 'number' && !Number.isNaN(totalBytes)) { - contentLengthValue = String(totalBytes); - } - } - - if (contentLengthValue) { - headers.set('Content-Length', contentLengthValue); - } - - // 4.1. Main fetch, step 2.6 - // > If request's referrer policy is the empty string, then set request's referrer policy to the - // > default referrer policy. - if (request.referrerPolicy === '') { - request.referrerPolicy = DEFAULT_REFERRER_POLICY; - } - - // 4.1. Main fetch, step 2.7 - // > If request's referrer is not "no-referrer", set request's referrer to the result of invoking - // > determine request's referrer. - if (request.referrer && request.referrer !== 'no-referrer') { - request[INTERNALS].referrer = determineRequestsReferrer(request); - } else { - request[INTERNALS].referrer = 'no-referrer'; - } - - // 4.5. HTTP-network-or-cache fetch, step 6.9 - // > If httpRequest's referrer is a URL, then append `Referer`/httpRequest's referrer, serialized - // > and isomorphic encoded, to httpRequest's header list. - if (request[INTERNALS].referrer instanceof URL) { - headers.set('Referer', request.referrer); - } - - // HTTP-network-or-cache fetch step 2.11 - if (!headers.has('User-Agent')) { - headers.set('User-Agent', 'node-fetch'); - } - - // HTTP-network-or-cache fetch step 2.15 - if (request.compress && !headers.has('Accept-Encoding')) { - headers.set('Accept-Encoding', 'gzip, deflate, br'); - } - - let {agent} = request; - if (typeof agent === 'function') { - agent = agent(parsedURL); - } - - if (!headers.has('Connection') && !agent) { - headers.set('Connection', 'close'); - } - - // HTTP-network fetch step 4.2 - // chunked encoding is handled by Node.js - - const search = getSearch(parsedURL); - - // Pass the full URL directly to request(), but overwrite the following - // options: - const options = { - // Overwrite search to retain trailing ? (issue #776) - path: parsedURL.pathname + search, - // The following options are not expressed in the URL - method: request.method, - headers: headers[Symbol.for('nodejs.util.inspect.custom')](), - insecureHTTPParser: request.insecureHTTPParser, - agent - }; - - return { - /** @type {URL} */ - parsedURL, - options - }; -}; - -/** - * AbortError interface for cancelled requests - */ -class AbortError extends FetchBaseError { - constructor(message, type = 'aborted') { - super(message, type); - } -} - -/*! node-domexception. MIT License. Jimmy Wärting */ - -if (!globalThis.DOMException) { - try { - const { MessageChannel } = require('worker_threads'), - port = new MessageChannel().port1, - ab = new ArrayBuffer(); - port.postMessage(ab, [ab, ab]); - } catch (err) { - err.constructor.name === 'DOMException' && ( - globalThis.DOMException = err.constructor - ); - } -} - -/** - * Index.js - * - * a request API compatible with window.fetch - * - * All spec algorithm step numbers are based on https://fetch.spec.whatwg.org/commit-snapshots/ae716822cb3a61843226cd090eefc6589446c1d2/. - */ - -const supportedSchemas = new Set(['data:', 'http:', 'https:']); - -/** - * Fetch function - * - * @param {string | URL | import('./request').default} url - Absolute url or Request instance - * @param {*} [options_] - Fetch options - * @return {Promise} - */ -async function fetch$1(url, options_) { - return new Promise((resolve, reject) => { - // Build request object - const request = new Request(url, options_); - const {parsedURL, options} = getNodeRequestOptions(request); - if (!supportedSchemas.has(parsedURL.protocol)) { - throw new TypeError(`node-fetch cannot load ${url}. URL scheme "${parsedURL.protocol.replace(/:$/, '')}" is not supported.`); - } - - if (parsedURL.protocol === 'data:') { - const data = dataUriToBuffer(request.url); - const response = new Response(data, {headers: {'Content-Type': data.typeFull}}); - resolve(response); - return; - } - - // Wrap http.request into fetch - const send = (parsedURL.protocol === 'https:' ? https__default["default"] : http__default["default"]).request; - const {signal} = request; - let response = null; - - const abort = () => { - const error = new AbortError('The operation was aborted.'); - reject(error); - if (request.body && request.body instanceof Stream__default["default"].Readable) { - request.body.destroy(error); - } - - if (!response || !response.body) { - return; - } - - response.body.emit('error', error); - }; - - if (signal && signal.aborted) { - abort(); - return; - } - - const abortAndFinalize = () => { - abort(); - finalize(); - }; - - // Send request - const request_ = send(parsedURL.toString(), options); - - if (signal) { - signal.addEventListener('abort', abortAndFinalize); - } - - const finalize = () => { - request_.abort(); - if (signal) { - signal.removeEventListener('abort', abortAndFinalize); - } - }; - - request_.on('error', error => { - reject(new FetchError(`request to ${request.url} failed, reason: ${error.message}`, 'system', error)); - finalize(); - }); - - fixResponseChunkedTransferBadEnding(request_, error => { - if (response && response.body) { - response.body.destroy(error); - } - }); - - /* c8 ignore next 18 */ - if (process.version < 'v14') { - // Before Node.js 14, pipeline() does not fully support async iterators and does not always - // properly handle when the socket close/end events are out of order. - request_.on('socket', s => { - let endedWithEventsCount; - s.prependListener('end', () => { - endedWithEventsCount = s._eventsCount; - }); - s.prependListener('close', hadError => { - // if end happened before close but the socket didn't emit an error, do it now - if (response && endedWithEventsCount < s._eventsCount && !hadError) { - const error = new Error('Premature close'); - error.code = 'ERR_STREAM_PREMATURE_CLOSE'; - response.body.emit('error', error); - } - }); - }); - } - - request_.on('response', response_ => { - request_.setTimeout(0); - const headers = fromRawHeaders(response_.rawHeaders); - - // HTTP fetch step 5 - if (isRedirect(response_.statusCode)) { - // HTTP fetch step 5.2 - const location = headers.get('Location'); - - // HTTP fetch step 5.3 - let locationURL = null; - try { - locationURL = location === null ? null : new URL(location, request.url); - } catch { - // error here can only be invalid URL in Location: header - // do not throw when options.redirect == manual - // let the user extract the errorneous redirect URL - if (request.redirect !== 'manual') { - reject(new FetchError(`uri requested responds with an invalid redirect URL: ${location}`, 'invalid-redirect')); - finalize(); - return; - } - } - - // HTTP fetch step 5.5 - switch (request.redirect) { - case 'error': - reject(new FetchError(`uri requested responds with a redirect, redirect mode is set to error: ${request.url}`, 'no-redirect')); - finalize(); - return; - case 'manual': - // Nothing to do - break; - case 'follow': { - // HTTP-redirect fetch step 2 - if (locationURL === null) { - break; - } - - // HTTP-redirect fetch step 5 - if (request.counter >= request.follow) { - reject(new FetchError(`maximum redirect reached at: ${request.url}`, 'max-redirect')); - finalize(); - return; - } - - // HTTP-redirect fetch step 6 (counter increment) - // Create a new Request object. - const requestOptions = { - headers: new Headers(request.headers), - follow: request.follow, - counter: request.counter + 1, - agent: request.agent, - compress: request.compress, - method: request.method, - body: clone(request), - signal: request.signal, - size: request.size, - referrer: request.referrer, - referrerPolicy: request.referrerPolicy - }; - - // when forwarding sensitive headers like "Authorization", - // "WWW-Authenticate", and "Cookie" to untrusted targets, - // headers will be ignored when following a redirect to a domain - // that is not a subdomain match or exact match of the initial domain. - // For example, a redirect from "foo.com" to either "foo.com" or "sub.foo.com" - // will forward the sensitive headers, but a redirect to "bar.com" will not. - if (!isDomainOrSubdomain(request.url, locationURL)) { - for (const name of ['authorization', 'www-authenticate', 'cookie', 'cookie2']) { - requestOptions.headers.delete(name); - } - } - - // HTTP-redirect fetch step 9 - if (response_.statusCode !== 303 && request.body && options_.body instanceof Stream__default["default"].Readable) { - reject(new FetchError('Cannot follow redirect with body being a readable stream', 'unsupported-redirect')); - finalize(); - return; - } - - // HTTP-redirect fetch step 11 - if (response_.statusCode === 303 || ((response_.statusCode === 301 || response_.statusCode === 302) && request.method === 'POST')) { - requestOptions.method = 'GET'; - requestOptions.body = undefined; - requestOptions.headers.delete('content-length'); - } - - // HTTP-redirect fetch step 14 - const responseReferrerPolicy = parseReferrerPolicyFromHeader(headers); - if (responseReferrerPolicy) { - requestOptions.referrerPolicy = responseReferrerPolicy; - } - - // HTTP-redirect fetch step 15 - resolve(fetch$1(new Request(locationURL, requestOptions))); - finalize(); - return; - } - - default: - return reject(new TypeError(`Redirect option '${request.redirect}' is not a valid value of RequestRedirect`)); - } - } - - // Prepare response - if (signal) { - response_.once('end', () => { - signal.removeEventListener('abort', abortAndFinalize); - }); - } - - let body = Stream.pipeline(response_, new Stream.PassThrough(), error => { - if (error) { - reject(error); - } - }); - // see https://github.com/nodejs/node/pull/29376 - /* c8 ignore next 3 */ - if (process.version < 'v12.10') { - response_.on('aborted', abortAndFinalize); - } - - const responseOptions = { - url: request.url, - status: response_.statusCode, - statusText: response_.statusMessage, - headers, - size: request.size, - counter: request.counter, - highWaterMark: request.highWaterMark - }; - - // HTTP-network fetch step 12.1.1.3 - const codings = headers.get('Content-Encoding'); - - // HTTP-network fetch step 12.1.1.4: handle content codings - - // in following scenarios we ignore compression support - // 1. compression support is disabled - // 2. HEAD request - // 3. no Content-Encoding header - // 4. no content response (204) - // 5. content not modified response (304) - if (!request.compress || request.method === 'HEAD' || codings === null || response_.statusCode === 204 || response_.statusCode === 304) { - response = new Response(body, responseOptions); - resolve(response); - return; - } - - // For Node v6+ - // Be less strict when decoding compressed responses, since sometimes - // servers send slightly invalid responses that are still accepted - // by common browsers. - // Always using Z_SYNC_FLUSH is what cURL does. - const zlibOptions = { - flush: zlib__default["default"].Z_SYNC_FLUSH, - finishFlush: zlib__default["default"].Z_SYNC_FLUSH - }; - - // For gzip - if (codings === 'gzip' || codings === 'x-gzip') { - body = Stream.pipeline(body, zlib__default["default"].createGunzip(zlibOptions), error => { - if (error) { - reject(error); - } - }); - response = new Response(body, responseOptions); - resolve(response); - return; - } - - // For deflate - if (codings === 'deflate' || codings === 'x-deflate') { - // Handle the infamous raw deflate response from old servers - // a hack for old IIS and Apache servers - const raw = Stream.pipeline(response_, new Stream.PassThrough(), error => { - if (error) { - reject(error); - } - }); - raw.once('data', chunk => { - // See http://stackoverflow.com/questions/37519828 - if ((chunk[0] & 0x0F) === 0x08) { - body = Stream.pipeline(body, zlib__default["default"].createInflate(), error => { - if (error) { - reject(error); - } - }); - } else { - body = Stream.pipeline(body, zlib__default["default"].createInflateRaw(), error => { - if (error) { - reject(error); - } - }); - } - - response = new Response(body, responseOptions); - resolve(response); - }); - raw.once('end', () => { - // Some old IIS servers return zero-length OK deflate responses, so - // 'data' is never emitted. See https://github.com/node-fetch/node-fetch/pull/903 - if (!response) { - response = new Response(body, responseOptions); - resolve(response); - } - }); - return; - } - - // For br - if (codings === 'br') { - body = Stream.pipeline(body, zlib__default["default"].createBrotliDecompress(), error => { - if (error) { - reject(error); - } - }); - response = new Response(body, responseOptions); - resolve(response); - return; - } - - // Otherwise, use response as-is - response = new Response(body, responseOptions); - resolve(response); - }); - - // eslint-disable-next-line promise/prefer-await-to-then - writeToStream(request_, request).catch(reject); - }); -} - -function fixResponseChunkedTransferBadEnding(request, errorCallback) { - const LAST_CHUNK = node_buffer.Buffer.from('0\r\n\r\n'); - - let isChunkedTransfer = false; - let properLastChunkReceived = false; - let previousChunk; - - request.on('response', response => { - const {headers} = response; - isChunkedTransfer = headers['transfer-encoding'] === 'chunked' && !headers['content-length']; - }); - - request.on('socket', socket => { - const onSocketClose = () => { - if (isChunkedTransfer && !properLastChunkReceived) { - const error = new Error('Premature close'); - error.code = 'ERR_STREAM_PREMATURE_CLOSE'; - errorCallback(error); - } - }; - - const onData = buf => { - properLastChunkReceived = node_buffer.Buffer.compare(buf.slice(-5), LAST_CHUNK) === 0; - - // Sometimes final 0-length chunk and end of message code are in separate packets - if (!properLastChunkReceived && previousChunk) { - properLastChunkReceived = ( - node_buffer.Buffer.compare(previousChunk.slice(-3), LAST_CHUNK.slice(0, 3)) === 0 && - node_buffer.Buffer.compare(buf.slice(-2), LAST_CHUNK.slice(3)) === 0 - ); - } - - previousChunk = buf; - }; - - socket.prependListener('close', onSocketClose); - socket.on('data', onData); - - request.on('close', () => { - socket.removeListener('close', onSocketClose); - socket.removeListener('data', onData); - }); - }); -} - -// progressiveFetchHelper is the full progressiveFetch function, split out into -// a helper because the inptus/api is more complicated but only necessary for -// internal use. -function progressiveFetchHelper(pfm, resolve, verifyFunction) { - // If we run out of portals, return an error. - if (pfm.remainingPortals.length === 0) { - let newLog = "query failed because all portals have been tried\n" + JSON.stringify(pfm); - pfm.logs.push(newLog); - resolve({ - success: false, - portal: null, - response: null, - portalsFailed: pfm.portalsFailed, - responsesFailed: pfm.responsesFailed, - remainingPortals: null, - logs: pfm.logs, - }); - return; - } - // Grab the portal and query. - let portal = pfm.remainingPortals.shift(); - let query = portal + pfm.endpoint; - // Create a helper function for trying the next portal. - let nextPortal = function (response, log) { - if (response !== null) { - response - .clone() - .text() - .then((t) => { - pfm.logs.push(log); - pfm.portalsFailed.push(portal); - pfm.responsesFailed.push(response); - pfm.messagesFailed.push(t); - progressiveFetchHelper(pfm, resolve, verifyFunction); - }); - } - else { - pfm.logs.push(log); - pfm.portalsFailed.push(portal); - pfm.responsesFailed.push(response); - pfm.messagesFailed.push(""); - progressiveFetchHelper(pfm, resolve, verifyFunction); - } - }; - // Try sending the query to the portal. - fetch$1(query, pfm.fetchOpts) - .then((response) => { - // Check for a 5XX error. - if (!("status" in response) || typeof response.status !== "number") { - nextPortal(response, "portal has returned invalid response\n" + JSON.stringify({ portal, query })); - return; - } - if (response.status < 200 || response.status >= 300) { - nextPortal(response, "portal has returned error status\n" + JSON.stringify({ portal, query })); - return; - } - // Check the result against the verify function. - verifyFunction(response.clone()).then((errVF) => { - if (errVF !== null) { - nextPortal(response, "verify function has returned an error from portal " + portal + " - " + errVF); - return; - } - // Success! Return the response. - resolve({ - success: true, - portal, - response, - portalsFailed: pfm.portalsFailed, - responsesFailed: pfm.responsesFailed, - remainingPortals: pfm.remainingPortals, - messagesFailed: pfm.messagesFailed, - logs: pfm.logs, - }); - }); - }) - .catch((err) => { - // This portal failed, try again with the next portal. - nextPortal(null, "fetch returned an error\n" + JSON.stringify(err) + JSON.stringify(pfm.fetchOpts)); - return; - }); -} -// progressiveFetch will query multiple portals until one returns with a -// non-error response. In the event of a 4XX response, progressiveFetch will -// keep querying additional portals to try and find a working 2XX response. In -// the event that no working 2XX response is found, the first 4XX response will -// be returned. -// -// If progressiveFetch returns a 2XX response, it merely means that the portal -// returned a 2XX response. progressiveFetch cannot be confident that the -// portal has returned a correct/honest message, the verification has to be -// handled by the caller. The response (progressiveFetchResult) contains the -// list of portals that progressiveFetch hasn't tried yet. In the event that -// the 2XX response is not correct, the progressiveFetchResult contains the -// list of failover portals that have not been used yet, allowing -// progressiveFetch to be called again. -// -// This progressive method of querying portals helps prevent queries from -// failing, but if the first portal is not a good portal it introduces -// substantial latency. progressiveFetch does not do anything to make sure the -// portals are the best portals, it just queries them in order. The caller -// should make a best attempt to always have the best, most reliable and -// fastest portal as the first portal in the list. -// -// The reason that we don't blindly accept a 4XX response from a portal is that -// we have no way of verifying that the 4XX is legitimate. We don't trust the -// portal, and we can't give a rogue portal the opportunity to interrupt our -// user experience simply by returning a dishonest 404. So we need to keep -// querying more portals and gain confidence that the 404 a truthful response. -// -// TODO: Would be great if 'verifyFunction' could check the function signature -// of the function being passed in, I don't know how to do this. -function progressiveFetch(endpoint, fetchOpts, portals, verifyFunction) { - let portalsCopy = [...portals]; - return new Promise((resolve) => { - let pfm = { - endpoint, - fetchOpts, - remainingPortals: portalsCopy, - portalsFailed: [], - responsesFailed: [], - messagesFailed: [], - logs: [], - }; - progressiveFetchHelper(pfm, resolve, verifyFunction); - }); -} - -// readRegistryEntry will read and verify a registry entry. The tag strings -// will be hashed with the user's seed to produce the correct entropy. -function readRegistryEntry(pubkey, datakey) { - return new Promise((resolve, reject) => { - let pubkeyHex = bufToHex(pubkey); - let datakeyHex = bufToHex(datakey); - let endpoint = "/skynet/registry?publickey=ed25519%3A" + pubkeyHex + "&datakey=" + datakeyHex; - let verifyFunc = function (response) { - return verifyRegistryReadResponse(response, pubkey, datakey); - }; - progressiveFetch(endpoint, {}, defaultPortalList, verifyFunc).then((result) => { - // Check for a success. - if (result.success === true) { - result.response - .json() - .then((j) => { - resolve({ - exists: true, - data: j.data, - revision: BigInt(j.revision), - }); - }) - .catch((err) => { - reject(addContextToErr$1(err, "unable to parse response despite passing verification")); - }); - return; - } - // Check for 404. - for (let i = 0; i < result.responsesFailed.length; i++) { - if (result.responsesFailed[i].status === 404) { - resolve({ - exists: false, - data: new Uint8Array(0), - revision: 0n, - }); - return; - } - } - reject("unable to read registry entry\n" + JSON.stringify(result)); - }); - }); -} - -// verifyRegistryWrite checks that a response from the portal matches the write -// we attempted to perform. -function verifyRegistryWrite(response) { - return new Promise((resolve) => { - if (!("status" in response)) { - resolve("response did not contain a status"); - return; - } - if (response.status === 204) { - resolve(null); - return; - } - resolve("unrecognized status"); - }); -} -// overwriteRegistryEntry will obliterate an existing registry entry with a new -// value. This function does not have any data safety, and is only recommended -// for uses where the caller is not concerned about wiping existing data. -// Improper use of this function has caused a large number of developers to -// accidentally wipe critical user data, please avoid using this function for -// any sort of incremental data. -function overwriteRegistryEntry(keypair, datakey, data) { - return new Promise((resolve, reject) => { - // Check that the data is small enough to fit in a registry - // entry. The actual limit for a type 2 entry is 90 bytes, but - // we are leaving 4 bytes of room for potential extensions - // later. - if (data.length > 86) { - reject("provided data is too large to fit in a registry entry"); - return; - } - // Fetch the current registry entry so that we know the - // revision number. - // - // TODO: Need special error handling for max revision number, - // which probably also means we need to use bignums as the - // return type. - readRegistryEntry(keypair.publicKey, datakey) - .then((result) => { - let revisionNumber; - if (!result.exists) { - revisionNumber = 0n; - } - else { - revisionNumber = result.revision + 1n; - } - let [encodedRevision, errU64] = encodeU64$1(revisionNumber); - if (errU64 !== null) { - reject(addContextToErr$1(errU64, "unable to encode revision number")); - return; - } - // Compute the signature of the new registry entry. - let datakeyHex = bufToHex(datakey); - let [encodedData, errEPB] = encodePrefixedBytes(data); - if (errEPB !== null) { - reject(addContextToErr$1(errEPB, "unable to encode the registry data")); - return; - } - let dataToSign = new Uint8Array(32 + 8 + data.length + 8); - dataToSign.set(datakey, 0); - dataToSign.set(encodedData, 32); - dataToSign.set(encodedRevision, 32 + 8 + data.length); - let sigHash = blake2b(dataToSign); - let [sig, errS] = ed25519Sign(sigHash, keypair.secretKey); - if (errS !== null) { - reject(addContextToErr$1(errS, "unable to produce signature")); - return; - } - // Compose the registry entry query. - let postBody = { - publickey: { - algorithm: "ed25519", - key: Array.from(keypair.publicKey), - }, - datakey: datakeyHex, - revision: Number(revisionNumber), - data: Array.from(data), - signature: Array.from(sig), - }; - let fetchOpts = { - method: "post", - body: JSON.stringify(postBody), - }; - let endpoint = "/skynet/registry"; - // Perform the fetch call. - progressiveFetch(endpoint, fetchOpts, defaultPortalList, verifyRegistryWrite).then((result) => { - if (result.success === true) { - resolve(null); - return; - } - reject("unable to write registry entry\n" + JSON.stringify(result)); - }); - }) - .catch((err) => { - reject(addContextToErr$1(err, "unable to write registry entry")); - }); - }); -} - -// generateSeedPhraseRandom will randomly generate and verify a seed phrase for the user. -function generateSeedPhraseRandom() { - let buf = Uint8Array.from(require$$6.randomBytes(32)); - let str = bufToB64$1(buf); - let [sp, errGSPD] = generateSeedPhraseDeterministic(str); - if (errGSPD !== null) { - return ["", addContextToErr$1(errGSPD, "unable to generate seed from string")]; - } - return [sp, null]; -} - -// upload will upload the provided fileData to Skynet using the provided -// metadata and then return the resulting skylink. Upload is a secure function -// that computes the skylink of the upload locally, ensuring that the server -// cannot return a malicious skylink and convince a user to run modified code. -function upload$1(fileData, metadata) { - return new Promise((resolve, reject) => { - // Check that this is a small file. - if (fileData.length > 4 * 1000 * 1000) { - reject("currently only small uploads are supported, please use less than 4 MB"); - return; - } - // Encode the metadata after checking that it is valid. - let errVSM = validateSkyfileMetadata(metadata); - if (errVSM !== null) { - reject(addContextToErr$1(errVSM, "upload is using invalid metadata")); - return; - } - let metadataBytes = new TextEncoder().encode(JSON.stringify(metadata)); - // Build the layout of the skyfile. - let layoutBytes = new Uint8Array(99); - let offset = 0; - layoutBytes[offset] = 1; // Set the Version - offset += 1; - let [filesizeBytes, errU641] = encodeU64$1(BigInt(fileData.length)); - if (errU641 !== null) { - reject(addContextToErr$1(errU641, "unable to encode fileData length")); - return; - } - layoutBytes.set(filesizeBytes, offset); - offset += 8; - let [mdSizeBytes, errU642] = encodeU64$1(BigInt(metadataBytes.length)); - if (errU642 !== null) { - reject(addContextToErr$1(errU642, "unable to encode metadata bytes length")); - return; - } - layoutBytes.set(mdSizeBytes, offset); - offset += 8; - let [fanoutSizeBytes, errU643] = encodeU64$1(0n); - if (errU643 !== null) { - reject(addContextToErr$1(errU643, "unable to encode fanout bytes length")); - return; - } - layoutBytes.set(fanoutSizeBytes, offset); - offset += 8; - layoutBytes[offset] = 0; // Set the fanout data pieces - offset += 1; - layoutBytes[offset] = 0; // Set the fanout parity pieces - offset += 1; - layoutBytes[offset + 7] = 1; // Set the cipher type - offset += 8; - if (offset + 64 !== 99) { - reject("error when building the layout bytes, got wrong final offset"); - return; - } - // Build the base sector. - let totalSize = layoutBytes.length + metadataBytes.length + fileData.length; - if (totalSize > 1 << 22) { - reject("error when building the base sector: total sector is too large"); - return; - } - let baseSector = new Uint8Array(1 << 22); - offset = 0; - baseSector.set(layoutBytes, offset); - offset += layoutBytes.length; - baseSector.set(metadataBytes, offset); - offset += metadataBytes.length; - baseSector.set(fileData, offset); - // Compute the Skylink of this file. - let [sectorRoot, errBMR] = blake2bMerkleRoot(baseSector); - if (errBMR !== null) { - reject(addContextToErr$1(errBMR, "unable to create bitfield for skylink")); - return; - } - let skylinkBytes = new Uint8Array(34); - let [bitfield, errSV1B] = skylinkV1Bitfield(BigInt(totalSize)); - if (errSV1B !== null) { - reject(addContextToErr$1(errSV1B, "unable to create bitfield for skylink")); - return; - } - skylinkBytes.set(bitfield, 0); - skylinkBytes.set(sectorRoot, 2); - // Build the header for the upload call. - let header = new Uint8Array(92); - let [headerMetadataPrefix, errU644] = encodeU64$1(15n); - if (errU644 !== null) { - reject(addContextToErr$1(errU644, "unable to encode header metadata length")); - return; - } - let headerMetadata = new TextEncoder().encode("Skyfile Backup\n"); - let [versionPrefix, errU645] = encodeU64$1(7n); - if (errU645 !== null) { - reject(addContextToErr$1(errU645, "unable to encode version prefix length")); - return; - } - let version = new TextEncoder().encode("v1.5.5\n"); - let [skylinkPrefix, errU646] = encodeU64$1(46n); - if (errU646 !== null) { - reject(addContextToErr$1(errU646, "unable to encode skylink length")); - return; - } - let skylink = bufToB64$1(skylinkBytes); - offset = 0; - header.set(headerMetadataPrefix, offset); - offset += 8; - header.set(headerMetadata, offset); - offset += 15; - header.set(versionPrefix, offset); - offset += 8; - header.set(version, offset); - offset += 7; - header.set(skylinkPrefix, offset); - offset += 8; - header.set(new TextEncoder().encode(skylink), offset); - // Build the full request body. - let reqBody = new Uint8Array((1 << 22) + 92); - reqBody.set(header, 0); - reqBody.set(baseSector, 92); - // Call progressiveFetch to perform the upload. - let endpoint = "/skynet/restore"; - let fetchOpts = { - method: "post", - body: reqBody, - }; - // Establish the function that verifies the result is correct. - let verifyFunction = function (response) { - return new Promise((resolve) => { - response - .json() - .then((j) => { - if (!("skylink" in j)) { - resolve("response is missing the skylink field\n" + JSON.stringify(j)); - return; - } - if (j.skylink !== skylink) { - resolve("wrong skylink was returned, expecting " + skylink + " but got " + j.skylink); - return; - } - resolve(null); - }) - .catch((err) => { - resolve(addContextToErr$1(err, "unable to read response body")); - }); - }); - }; - progressiveFetch(endpoint, fetchOpts, defaultPortalList, verifyFunction).then((result) => { - result.response - .json() - .then((j) => { - resolve(j.skylink); - }) - .catch((err) => { - reject(addContextToErr$1(err, "unable to read response body, despite verification of response succeeding")); - }); - }); - }); -} - -var dist$1 = /*#__PURE__*/Object.freeze({ - __proto__: null, - overwriteRegistryEntry: overwriteRegistryEntry, - generateSeedPhraseRandom: generateSeedPhraseRandom, - upload: upload$1 -}); - -var require$$4 = /*@__PURE__*/getAugmentedNamespace(dist$1); - -// log provides a wrapper for console.log that prefixes '[libkernel]' to the -// output. -function log(...inputs) { - console.log("[libkernel]", ...inputs); -} -// logErr provides a wrapper for console.error that prefixes '[libkernel]' to -// the output. -function logErr(...inputs) { - console.error("[libkernel]", ...inputs); -} - -// tryStringify will try to turn the provided input into a string. If the input -// object is already a string, the input object will be returned. If the input -// object has a toString method, the toString method will be called. If that -// fails, we try to call JSON.stringify on the object. And if that fails, we -// set the return value to "[stringify failed]". -function tryStringify(obj) { - // Check for undefined input. - if (obj === undefined || obj === null) { - return "[cannot stringify undefined input]"; - } - // Parse the error into a string. - if (typeof obj === "string") { - return obj; - } - // Check if the object has a custom toString and use that if so. - let hasToString = typeof obj.toString === "function"; - if (hasToString && obj.toString !== Object.prototype.toString) { - return obj.toString(); - } - // If the object does not have a custom toString, attempt to perform a - // JSON.stringify. - try { - return JSON.stringify(obj); - } - catch { - return "[stringify failed]"; - } -} - -// addContextToErr is a helper function that standardizes the formatting of -// adding context to an error. Within the world of go we discovered that being -// persistent about layering context onto errors is helpful when debugging, -// even though it often creates rather verbose error messages. -// -// addContextToErr will return null if the input err is null. -// -// NOTE: To protect against accidental situations where an Error type or some -// other type is provided instead of a string, we wrap both of the inputs with -// tryStringify before returning them. This prevents runtime failures. -function addContextToErr(err, context) { - if (err === null) { - err = "[no error provided]"; - } - return tryStringify(context) + ": " + tryStringify(err); -} -// composeErr takes a series of inputs and composes them into a single string. -// Each element will be separated by a newline. If the input is not a string, -// it will be transformed into a string with JSON.stringify. -// -// Any object that cannot be stringified will be skipped, though an error will -// be logged. -function composeErr(...inputs) { - let result = ""; - let resultEmpty = true; - for (let i = 0; i < inputs.length; i++) { - if (inputs[i] === null) { - continue; - } - if (resultEmpty) { - resultEmpty = false; - } - else { - result += "\n"; - } - result += tryStringify(inputs[i]); - } - if (resultEmpty) { - return null; - } - return result; -} - -// Helper consts to make it easy to return empty values alongside errors. -const nu8 = new Uint8Array(0); -// bufToB64 will convert a Uint8Array to a base64 string with URL encoding and -// no padding characters. -function bufToB64(buf) { - let b64Str = btoa(String.fromCharCode.apply(null, buf)); - return b64Str.replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, ""); -} -// encodeU64 will encode a bigint in the range of a uint64 to an 8 byte -// Uint8Array. -function encodeU64(num) { - // Check the bounds on the bigint. - if (num < 0) { - return [nu8, "expected a positive integer"]; - } - if (num > 18446744073709551615n) { - return [nu8, "expected a number no larger than a uint64"]; - } - // Encode the bigint into a Uint8Array. - let encoded = new Uint8Array(8); - for (let i = 0; i < encoded.length; i++) { - let byte = Number(num & 0xffn); - encoded[i] = byte; - num = num >> 8n; - } - return [encoded, null]; -} - -let gfi = function (init) { - let i, r = new Float64Array(16); - if (init) - for (i = 0; i < init.length; i++) - r[i] = init[i]; - return r; -}; -gfi([1]); gfi([ - 0x78a3, 0x1359, 0x4dca, 0x75eb, 0xd8ab, 0x4141, 0x0a4d, 0x0070, 0xe898, 0x7779, 0x4079, 0x8cc7, 0xfe73, 0x2b6f, - 0x6cee, 0x5203, -]); gfi([ - 0xf159, 0x26b2, 0x9b94, 0xebd6, 0xb156, 0x8283, 0x149a, 0x00e0, 0xd130, 0xeef3, 0x80f2, 0x198e, 0xfce7, 0x56df, - 0xd9dc, 0x2406, -]); gfi([ - 0xd51a, 0x8f25, 0x2d60, 0xc956, 0xa7b2, 0x9525, 0xc760, 0x692c, 0xdc5c, 0xfdd6, 0xe231, 0xc0a4, 0x53fe, 0xcd6e, - 0x36d3, 0x2169, -]); gfi([ - 0x6658, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, - 0x6666, 0x6666, -]); gfi([ - 0xa0b0, 0x4a0e, 0x1b27, 0xc4ee, 0xe478, 0xad2f, 0x1806, 0x2f43, 0xd7a7, 0x3dfb, 0x0099, 0x2b4d, 0xdf0b, 0x4fc1, - 0x2480, 0x2b83, -]); - -// Create the queryMap. -let queries = {}; -// Define the nonce handling. nonceSeed is 16 random bytes that get generated -// at init and serve as the baseline for creating random nonces. nonceCounter -// tracks which messages have been sent. We hash together the nonceSeed and the -// current nonceCounter to get a secure nonce. -// -// We need a secure nonce so that we know which messages from the kernel are -// intended for us. There could be multiple pieces of independent code talking -// to the kernel and using nonces, by having secure random nonces we can -// guarantee that the applications will not use conflicting nonces. -let nonceSeed; -let nonceCounter; -function initNonce() { - nonceSeed = new Uint8Array(16); - nonceCounter = 0; - crypto.getRandomValues(nonceSeed); -} -// nextNonce will combine the nonceCounter with the nonceSeed to produce a -// unique string that can be used as the nonce with the kernel. -// -// Note: the nonce is only ever going to be visible to the kernel and to other -// code running in the same webpage, so we don't need to hash our nonceSeed. We -// just need it to be unique, not undetectable. -function nextNonce() { - let nonceNum = nonceCounter; - nonceCounter += 1; - let [nonceNumBytes, err] = encodeU64(BigInt(nonceNum)); - if (err !== null) { - // encodeU64 only fails if nonceNum is outside the bounds of a - // uint64, which shouldn't happen ever. - logErr("encodeU64 somehow failed", err); - } - let noncePreimage = new Uint8Array(nonceNumBytes.length + nonceSeed.length); - noncePreimage.set(nonceNumBytes, 0); - noncePreimage.set(nonceSeed, nonceNumBytes.length); - return bufToB64(noncePreimage); -} -// Establish the handler for incoming messages. -function handleMessage(event) { - // Ignore all messages that aren't from approved kernel sources. The two - // approved sources are skt.us and the browser extension bridge (which has - // an event.source equal to 'window') - if (event.source !== window && event.origin !== "https://skt.us") { - return; - } - // Ignore any messages that don't have a method and data field. - if (!("method" in event.data) || !("data" in event.data)) { - return; - } - // Handle logging messages. - if (event.data.method === "log") { - // We display the logging message if the kernel is a browser - // extension, so that the kernel's logs appear in the app - // console as well as the extension console. If the kernel is - // in an iframe, its logging messages will already be in the - // app console and therefore don't need to be displayed. - if (kernelOrigin === window.origin) { - if (event.data.data.isErr) { - console.error(event.data.data.message); - } - else { - console.log(event.data.data.message); - } - } - return; - } - // init is complete when the kernel sends us the auth status. If the - // user is logged in, report success, otherwise return an error - // indicating that the user is not logged in. - if (event.data.method === "kernelAuthStatus") { - // If we have received an auth status message, it means the bootloader - // at a minimum is working. - if (initResolved === false) { - initResolved = true; - initResolve(); - } - // If the auth status message says that login is complete, it means - // that the user is logged in. - if (loginResolved === false && event.data.data.loginComplete === true) { - loginResolved = true; - loginResolve(); - } - // If the auth status message says that the kernel loaded, it means - // that the kernel is ready to receive messages. - if (kernelLoadedResolved === false && event.data.data.kernelLoaded !== "not yet") { - kernelLoadedResolved = true; - if (event.data.data.kernelLoaded === "success") { - kernelLoadedResolve(null); - } - else { - kernelLoadedResolve(event.data.data.kernelLoaded); - } - } - // If we have received a message indicating that the user has logged - // out, we need to reload the page and reset the auth process. - if (event.data.data.logoutComplete === true) { - { - logoutResolve(); - } - window.location.reload(); - } - return; - } - // Check that the message sent has a nonce. We don't log - // on failure because the message may have come from 'window', which - // will happen if the app has other messages being sent to the window. - if (!("nonce" in event.data)) { - return; - } - // If we can't locate the nonce in the queries map, there is nothing to do. - // This can happen especially for responseUpdate messages. - if (!(event.data.nonce in queries)) { - return; - } - let query = queries[event.data.nonce]; - // Handle a response. Once the response has been received, it is safe to - // delete the query from the queries map. - if (event.data.method === "response") { - queries[event.data.nonce].resolve([event.data.data, event.data.err]); - delete queries[event.data.nonce]; - return; - } - // Handle a response update. - if (event.data.method === "responseUpdate") { - // If no update handler was provided, there is nothing to do. - if (typeof query.receiveUpdate === "function") { - query.receiveUpdate(event.data.data); - } - return; - } - // Handle a responseNonce. - if (event.data.method === "responseNonce") { - if (typeof query.kernelNonceReceived === "function") { - query.kernelNonceReceived(event.data.data.nonce); - } - return; - } - // Ignore any other messages as they might be from other applications. -} -// launchKernelFrame will launch the skt.us iframe that is used to connect to the -// Skynet kernel if the kernel cannot be reached through the browser extension. -function launchKernelFrame() { - let iframe = document.createElement("iframe"); - iframe.src = "https://skt.us"; - iframe.width = "0"; - iframe.height = "0"; - iframe.style.border = "0"; - iframe.style.position = "absolute"; - document.body.appendChild(iframe); - kernelSource = iframe.contentWindow; - kernelOrigin = "https://skt.us"; - kernelAuthLocation = "https://skt.us/auth.html"; - // Set a timer to fail the login process if the kernel doesn't load in - // time. - setTimeout(() => { - if (initResolved === true) { - return; - } - initResolved = true; - initResolve("tried to open kernel in iframe, but hit a timeout"); - }, 24000); -} -// messageBridge will send a message to the bridge of the skynet extension to -// see if it exists. If it does not respond or if it responds with an error, -// messageBridge will open an iframe to skt.us and use that as the kernel. -let kernelSource; -let kernelOrigin; -let kernelAuthLocation; -function messageBridge() { - // Establish the function that will handle the bridge's response. - let bridgeInitComplete = false; - let bridgeResolve = () => { }; // Need to set bridgeResolve here to make tsc happy - let p = new Promise((resolve) => { - bridgeResolve = resolve; - }); - p.then(([, err]) => { - // Check if the timeout already elapsed. - if (bridgeInitComplete === true) { - logErr("received response from bridge, but init already finished"); - return; - } - bridgeInitComplete = true; - // Deconstruct the input and return if there's an error. - if (err !== null) { - logErr("bridge exists but returned an error", err); - launchKernelFrame(); - return; - } - // Bridge has responded successfully, and there's no error. - kernelSource = window; - kernelOrigin = window.origin; - kernelAuthLocation = "http://kernel.skynet/auth.html"; - console.log("established connection to bridge, using browser extension for kernel"); - }); - // Add the handler to the queries map. - let nonce = nextNonce(); - queries[nonce] = { - resolve: bridgeResolve, - }; - // Send a message to the bridge of the browser extension to determine - // whether the bridge exists. - window.postMessage({ - nonce, - method: "kernelBridgeVersion", - }, window.origin); - // Set a timeout, if we do not hear back from the bridge in 500 - // milliseconds we assume that the bridge is not available. - setTimeout(() => { - // If we've already received and processed a message from the - // bridge, there is nothing to do. - if (bridgeInitComplete === true) { - return; - } - bridgeInitComplete = true; - log("browser extension not found, falling back to skt.us"); - launchKernelFrame(); - }, 500); - return initPromise; -} -// init is a function that returns a promise which will resolve when -// initialization is complete. -// -// The init / auth process has 5 stages. The first stage is that something -// somewhere needs to call init(). It is safe to call init() multiple times, -// thanks to the 'initialized' variable. -let initialized = false; // set to true once 'init()' has been called -let initResolved = false; // set to true once we know the bootloader is working -let initResolve; -let initPromise; -let loginResolved = false; // set to true once we know the user is logged in -let loginResolve; -let loginPromise; -let kernelLoadedResolved = false; // set to true once the user kernel is loaded -let kernelLoadedResolve; -let kernelLoadedPromise; -let logoutResolve; -let logoutPromise; -function init() { - // If init has already been called, just return the init promise. - if (initialized === true) { - return initPromise; - } - initialized = true; - // Run all of the init functions. - initNonce(); - window.addEventListener("message", handleMessage); - messageBridge(); - // Create the promises that resolve at various stages of the auth flow. - initPromise = new Promise((resolve) => { - initResolve = resolve; - }); - loginPromise = new Promise((resolve) => { - loginResolve = resolve; - }); - kernelLoadedPromise = new Promise((resolve) => { - kernelLoadedResolve = resolve; - }); - logoutPromise = new Promise((resolve) => { - logoutResolve = resolve; - }); - // Return the initPromise, which will resolve when bootloader init is - // complete. - return initPromise; -} -// callModule is a generic function to call a module. The first input is the -// module identifier (typically a skylink), the second input is the method -// being called on the module, and the final input is optional and contains -// input data to be passed to the module. The input data will depend on the -// module and the method that is being called. The return value is an errTuple -// that contains the module's response. The format of the response is an -// arbitrary object whose fields depend on the module and method being called. -// -// callModule can only be used for query-response communication, there is no -// support for sending or receiving updates. -function callModule(module, method, data) { - let moduleCallData = { - module, - method, - data, - }; - let [, query] = newKernelQuery("moduleCall", moduleCallData, false); - return query; -} -// connectModule is the standard function to send a query to a module that can -// optionally send and optionally receive updates. The first three inputs match -// the inputs of 'callModule', and the fourth input is a function that will be -// called any time that the module sends a responseUpdate. The receiveUpdate -// function should have the following signature: -// -// `function receiveUpdate(data: any)` -// -// The structure of the data will depend on the module and method that was -// queried. -// -// The first return value is a 'sendUpdate' function that can be called to send -// a queryUpdate to the module. The sendUpdate function has the same signature -// as the receiveUpdate function, it's an arbitrary object whose fields depend -// on the module and method being queried. -// -// The second return value is a promise that returns an errTuple. It will -// resolve when the module sends a response message, and works the same as the -// return value of callModule. -function connectModule(module, method, data, receiveUpdate) { - let moduleCallData = { - module, - method, - data, - }; - return newKernelQuery("moduleCall", moduleCallData, true, receiveUpdate); -} -// newKernelQuery opens a query to the kernel. Details like postMessage -// communication and nonce handling are all abstracted away by newKernelQuery. -// -// The first arg is the method that is being called on the kernel, and the -// second arg is the data that will be sent to the kernel as input to the -// method. -// -// The thrid arg is an optional function that can be passed in to receive -// responseUpdates to the query. Not every query will send responseUpdates, and -// most responseUpdates can be ignored, but sometimes contain useful -// information like download progress. -// -// The first output is a 'sendUpdate' function that can be called to send a -// queryUpdate. The second output is a promise that will resolve when the query -// receives a response message. Once the response message has been received, no -// more updates can be sent or received. -function newKernelQuery(method, data, sendUpdates, receiveUpdate) { - // NOTE: The implementation here is gnarly, because I didn't want to use - // async/await (that decision should be left to the caller) and I also - // wanted this function to work correctly even if init() had not been - // called yet. - // - // This function returns a sendUpdate function along with a promise, so we - // can't simply wrap everything in a basic promise. The sendUpdate function - // has to block internally until all of the setup is complete, and then we - // can't send a query until all of the setup is complete, and the setup - // cylce has multiple dependencies and therefore we get a few promises that - // all depend on each other. - // - // Using async/await here actually breaks certain usage patterns (or at - // least makes them much more difficult to use correctly). The standard way - // to establish duplex communication using connectModule is to define a - // variable 'sendUpdate' before defining the function 'receiveUpdate', and - // then setting 'sendUpdate' equal to the first return value of - // 'connectModue'. It looks like this: - // - // let sendUpdate; - // let receiveUpdate = function(data: any) { - // if (data.needsUpdate) { - // sendUpdate(someUpdate) - // } - // } - // let [sendUpdateFn, response] = connectModule(x, y, z, receiveUpdate) - // sendUpdate = sendUpdateFn - // - // If we use async/await, it's not safe to set sendUpdate after - // connectModule returns because 'receiveUpdate' may be called before - // 'sendUpdate' is set. You can fix that by using a promise, but it's a - // complicated fix and we want this library to be usable by less - // experienced developers. - // - // Therefore, we make an implementation tradeoff here and avoid async/await - // at the cost of having a bunch of complicated promise chaining. - // Create a promise that will resolve once the nonce is available. We - // cannot get the nonce until init() is complete. getNonce therefore - // implies that init is complete. - let getNonce = new Promise((resolve) => { - init().then(() => { - kernelLoadedPromise.then(() => { - resolve(nextNonce()); - }); - }); - }); - // Two promises are being created at once here. Once is 'p', which will be - // returned to the caller of newKernelQuery and will be resolved when the - // kernel provides a 'response' message. The other is for internal use and - // will resolve once the query has been created. - let p; - let queryCreated; - let haveQueryCreated = new Promise((resolve) => { - queryCreated = resolve; - p = new Promise((resolve) => { - getNonce.then((nonce) => { - queries[nonce] = { resolve }; - if (receiveUpdate !== null && receiveUpdate !== undefined) { - queries[nonce]["receiveUpdate"] = receiveUpdate; - } - queryCreated(nonce); - }); - }); - }); - // Create a promise that will be resolved once we are ready to receive the - // kernelNonce. We won't be ready to receive the kernel nonce until after - // the queries[nonce] object has been created. - let readyForKernelNonce; - let getReadyForKernelNonce = new Promise((resolve) => { - readyForKernelNonce = resolve; - }); - // Create the sendUpdate function. It defaults to doing nothing. After the - // sendUpdate function is ready to receive the kernelNonce, resolve the - // promise that blocks until the sendUpdate function is ready to receive - // the kernel nonce. - let sendUpdate; - if (sendUpdates !== true) { - sendUpdate = () => { }; - readyForKernelNonce(); // We won't get a kernel nonce, no reason to block. - } - else { - // sendUpdate will send an update to the kernel. The update can't be - // sent until the kernel nonce is known. Create a promise that will - // resolve when the kernel nonce is known. - // - // This promise cannot itself be created until the queries[nonce] - // object has been created, so block for the query to be created. - let blockForKernelNonce = new Promise((resolve) => { - haveQueryCreated.then((nonce) => { - queries[nonce]["kernelNonceReceived"] = resolve; - readyForKernelNonce(); - }); - }); - // The sendUpdate function needs both the local nonce and also the - // kernel nonce. Block for both. Having the kernel nonce implies that - // the local nonce is ready, therefore start by blocking for the kernel - // nonce. - sendUpdate = function (updateData) { - blockForKernelNonce.then((nonce) => { - kernelSource.postMessage({ - method: "queryUpdate", - nonce, - data: updateData, - }, kernelOrigin); - }); - }; - } - // Prepare to send the query to the kernel. The query cannot be sent until - // the queries object is created and also we are ready to receive the - // kernel nonce. - haveQueryCreated.then((nonce) => { - getReadyForKernelNonce.then(() => { - // There are two types of messages we can send depending on whether - // we are talking to skt.us or the background script. - let kernelMessage = { - method, - nonce, - data, - sendKernelNonce: sendUpdates, - }; - let backgroundMessage = { - method: "newKernelQuery", - nonce, - data: kernelMessage, - }; - // The message structure needs to adjust based on whether we are - // talking directly to the kernel or whether we are talking to the - // background page. - if (kernelOrigin === "https://skt.us") { - kernelSource.postMessage(kernelMessage, kernelOrigin); - } - else { - kernelSource.postMessage(backgroundMessage, kernelOrigin); - } - }); - }); - // Return sendUpdate and the promise. sendUpdate is already set to block - // until all the necessary prereqs are complete. - return [sendUpdate, p]; -} - -// There are 5 stages of auth. -// -// Stage 0: Bootloader is not loaded. -// Stage 1: Bootloader is loaded, user is not logged in. -// Stage 2: Bootloader is loaded, user is logged in. -// Stage 3: Kernel is loaded, user is logged in. -// Stage 4: Kernel is loaded, user is logged out. -// -// init() will block until auth has reached stage 1. If the user is already -// logged in from a previous session, auth will immediately progress to stage -// 2. -// -// loginComplete() will block until auth has reached stage 2. The kernel is not -// ready to receive messages yet, but apps do not need to present users with a -// login dialog. -// -// kernelLoaded() will block until auth has reached stage 3. kernelLoaded() -// returns a promise that can resolve with an error. If there was an error, it -// means the kernel could not be loaded and cannot be used. -// -// logoutComplete() will block until auth has reached stage 4. libkernel does -// not support resetting the auth stages, once stage 4 has been reached the app -// needs to refresh. -// kernelLoaded will resolve when the user has successfully loaded the kernel. -// If there was an error in loading the kernel, the error will be returned. -// -// NOTE: kernelLoaded will not resolve until after loginComplete has resolved. -function kernelLoaded() { - return kernelLoadedPromise; -} -// loginComplete will resolve when the user has successfully logged in. -function loginComplete() { - return loginPromise; -} -// logoutComplete will resolve when the user has logged out. Note that -// logoutComplete will only resolve if the user logged in first - if the user -// was not logged in to begin with, this promise will not resolve. -function logoutComplete() { - return logoutPromise; -} -// openAuthWindow is intended to be used as an onclick target when the user -// clicks the 'login' button on a skynet application. It will block until the -// auth location is known, and then it will pop open the correct auth window -// for the user. -// -// NOTE: openAuthWindow will only open a window if the user is not already -// logged in. If the user is already logged in, this function is a no-op. -// -// NOTE: When using this function, you probably want to have your login button -// faded out or presenting the user with a spinner until init() resolves. In -// the worst case (user has no browser extension, and is on a slow internet -// connection) this could take multiple seconds. -function openAuthWindow() { - // openAuthWindow doesn't care what the auth status is, it's just trying to - // open the right window. - init().then(() => { - window.open(kernelAuthLocation, "_blank"); - }); -} - -// download will take a skylink and return the file data for that skylink. The -// download occurs using a kernel module that verifies the data's integrity and -// prevents the portal from lying about the download. -function download(skylink) { - return new Promise((resolve) => { - let downloadModule = "AQCIaQ0P-r6FwPEDq3auCZiuH_jqrHfqRcY7TjZ136Z_Yw"; - let data = { - skylink, - }; - callModule(downloadModule, "secureDownload", data).then(([result, err]) => { - // Pull the fileData out of the result. - if (err !== null) { - resolve([new Uint8Array(0), addContextToErr(err, "unable to complete download")]); - return; - } - resolve([result.fileData, null]); - }); - }); -} - -// registryRead will perform a registry read on a portal. readEntry does not -// guarantee that the latest revision has been provided, however it does -// guarantee that the provided data has a matching signature. -// -// registryRead returns the full registry entry object provided by the module -// because the object is relatively complex and all of the fields are more or -// less required. -function registryRead(publicKey, dataKey) { - let registryModule = "AQCovesg1AXUzKXLeRzQFILbjYMKr_rvNLsNhdq5GbYb2Q"; - let data = { - publicKey, - dataKey, - }; - return callModule(registryModule, "readEntry", data); -} -// registryWrite will perform a registry write on a portal. -// -// registryWrite is not considered a safe function, there are easy ways to -// misuse registryWrite such that user data will be lost. We recommend using a -// safe set of functions for writing to the registry such as getsetjson. -function registryWrite(keypair, dataKey, entryData, revision) { - return new Promise((resolve) => { - let registryModule = "AQCovesg1AXUzKXLeRzQFILbjYMKr_rvNLsNhdq5GbYb2Q"; - let callData = { - publicKey: keypair.publicKey, - secretKey: keypair.secretKey, - dataKey, - entryData, - revision, - }; - callModule(registryModule, "writeEntry", callData).then(([result, err]) => { - if (err !== null) { - resolve(["", err]); - return; - } - resolve([result.entryID, null]); - }); - }); -} - -// upload will take a filename and some file data and perform a secure upload -// to Skynet. All data is verified and the correct Skylink is returned. This -// function cannot fully guarantee that the data was pinned, but it can fully -// guarantee that the final skylink matches the data that was presented for the -// upload. -function upload(filename, fileData) { - return new Promise((resolve) => { - // Prepare the module call. - let uploadModule = "AQAT_a0MzOInZoJzt1CwBM2U8oQ3GIfP5yKKJu8Un-SfNg"; - let data = { - filename, - fileData, - }; - callModule(uploadModule, "secureUpload", data).then(([result, err]) => { - // Pull the skylink out of the result. - if (err !== null) { - resolve(["", addContextToErr(err, "uable to complete upload")]); - return; - } - resolve([result.skylink, null]); - }); - }); -} - -// kernelVersion will fetch the version number of the kernel. If successful, -// the returned value will be an object containing a field 'version' with a -// version string, and a 'distribtion' field with a string that states the -// distribution of the kernel". -function kernelVersion() { - return new Promise((resolve) => { - let [, query] = newKernelQuery("version", {}, false); - query.then(([result, err]) => { - if (err !== null) { - resolve(["", "", err]); - return; - } - resolve([result.version, result.distribution, err]); - }); - }); -} - -var dist = /*#__PURE__*/Object.freeze({ - __proto__: null, - kernelLoaded: kernelLoaded, - loginComplete: loginComplete, - logoutComplete: logoutComplete, - openAuthWindow: openAuthWindow, - download: download, - registryRead: registryRead, - registryWrite: registryWrite, - upload: upload, - kernelVersion: kernelVersion, - callModule: callModule, - connectModule: connectModule, - init: init, - newKernelQuery: newKernelQuery, - addContextToErr: addContextToErr, - composeErr: composeErr -}); - -var require$$5 = /*@__PURE__*/getAugmentedNamespace(dist); - -var require$$2 = { - "application/andrew-inset": [ - "ez" -], - "application/applixware": [ - "aw" -], - "application/atom+xml": [ - "atom" -], - "application/atomcat+xml": [ - "atomcat" -], - "application/atomsvc+xml": [ - "atomsvc" -], - "application/bdoc": [ - "bdoc" -], - "application/ccxml+xml": [ - "ccxml" -], - "application/cdmi-capability": [ - "cdmia" -], - "application/cdmi-container": [ - "cdmic" -], - "application/cdmi-domain": [ - "cdmid" -], - "application/cdmi-object": [ - "cdmio" -], - "application/cdmi-queue": [ - "cdmiq" -], - "application/cu-seeme": [ - "cu" -], - "application/dash+xml": [ - "mpd" -], - "application/davmount+xml": [ - "davmount" -], - "application/docbook+xml": [ - "dbk" -], - "application/dssc+der": [ - "dssc" -], - "application/dssc+xml": [ - "xdssc" -], - "application/ecmascript": [ - "ecma" -], - "application/emma+xml": [ - "emma" -], - "application/epub+zip": [ - "epub" -], - "application/exi": [ - "exi" -], - "application/font-tdpfr": [ - "pfr" -], - "application/font-woff": [ -], - "application/font-woff2": [ -], - "application/geo+json": [ - "geojson" -], - "application/gml+xml": [ - "gml" -], - "application/gpx+xml": [ - "gpx" -], - "application/gxf": [ - "gxf" -], - "application/gzip": [ - "gz" -], - "application/hyperstudio": [ - "stk" -], - "application/inkml+xml": [ - "ink", - "inkml" -], - "application/ipfix": [ - "ipfix" -], - "application/java-archive": [ - "jar", - "war", - "ear" -], - "application/java-serialized-object": [ - "ser" -], - "application/java-vm": [ - "class" -], - "application/javascript": [ - "js", - "mjs" -], - "application/json": [ - "json", - "map" -], - "application/json5": [ - "json5" -], - "application/jsonml+json": [ - "jsonml" -], - "application/ld+json": [ - "jsonld" -], - "application/lost+xml": [ - "lostxml" -], - "application/mac-binhex40": [ - "hqx" -], - "application/mac-compactpro": [ - "cpt" -], - "application/mads+xml": [ - "mads" -], - "application/manifest+json": [ - "webmanifest" -], - "application/marc": [ - "mrc" -], - "application/marcxml+xml": [ - "mrcx" -], - "application/mathematica": [ - "ma", - "nb", - "mb" -], - "application/mathml+xml": [ - "mathml" -], - "application/mbox": [ - "mbox" -], - "application/mediaservercontrol+xml": [ - "mscml" -], - "application/metalink+xml": [ - "metalink" -], - "application/metalink4+xml": [ - "meta4" -], - "application/mets+xml": [ - "mets" -], - "application/mods+xml": [ - "mods" -], - "application/mp21": [ - "m21", - "mp21" -], - "application/mp4": [ - "mp4s", - "m4p" -], - "application/msword": [ - "doc", - "dot" -], - "application/mxf": [ - "mxf" -], - "application/octet-stream": [ - "bin", - "dms", - "lrf", - "mar", - "so", - "dist", - "distz", - "pkg", - "bpk", - "dump", - "elc", - "deploy", - "exe", - "dll", - "deb", - "dmg", - "iso", - "img", - "msi", - "msp", - "msm", - "buffer" -], - "application/oda": [ - "oda" -], - "application/oebps-package+xml": [ - "opf" -], - "application/ogg": [ - "ogx" -], - "application/omdoc+xml": [ - "omdoc" -], - "application/onenote": [ - "onetoc", - "onetoc2", - "onetmp", - "onepkg" -], - "application/oxps": [ - "oxps" -], - "application/patch-ops-error+xml": [ - "xer" -], - "application/pdf": [ - "pdf" -], - "application/pgp-encrypted": [ - "pgp" -], - "application/pgp-signature": [ - "asc", - "sig" -], - "application/pics-rules": [ - "prf" -], - "application/pkcs10": [ - "p10" -], - "application/pkcs7-mime": [ - "p7m", - "p7c" -], - "application/pkcs7-signature": [ - "p7s" -], - "application/pkcs8": [ - "p8" -], - "application/pkix-attr-cert": [ - "ac" -], - "application/pkix-cert": [ - "cer" -], - "application/pkix-crl": [ - "crl" -], - "application/pkix-pkipath": [ - "pkipath" -], - "application/pkixcmp": [ - "pki" -], - "application/pls+xml": [ - "pls" -], - "application/postscript": [ - "ai", - "eps", - "ps" -], - "application/prs.cww": [ - "cww" -], - "application/pskc+xml": [ - "pskcxml" -], - "application/raml+yaml": [ - "raml" -], - "application/rdf+xml": [ - "rdf" -], - "application/reginfo+xml": [ - "rif" -], - "application/relax-ng-compact-syntax": [ - "rnc" -], - "application/resource-lists+xml": [ - "rl" -], - "application/resource-lists-diff+xml": [ - "rld" -], - "application/rls-services+xml": [ - "rs" -], - "application/rpki-ghostbusters": [ - "gbr" -], - "application/rpki-manifest": [ - "mft" -], - "application/rpki-roa": [ - "roa" -], - "application/rsd+xml": [ - "rsd" -], - "application/rss+xml": [ - "rss" -], - "application/rtf": [ - "rtf" -], - "application/sbml+xml": [ - "sbml" -], - "application/scvp-cv-request": [ - "scq" -], - "application/scvp-cv-response": [ - "scs" -], - "application/scvp-vp-request": [ - "spq" -], - "application/scvp-vp-response": [ - "spp" -], - "application/sdp": [ - "sdp" -], - "application/set-payment-initiation": [ - "setpay" -], - "application/set-registration-initiation": [ - "setreg" -], - "application/shf+xml": [ - "shf" -], - "application/smil+xml": [ - "smi", - "smil" -], - "application/sparql-query": [ - "rq" -], - "application/sparql-results+xml": [ - "srx" -], - "application/srgs": [ - "gram" -], - "application/srgs+xml": [ - "grxml" -], - "application/sru+xml": [ - "sru" -], - "application/ssdl+xml": [ - "ssdl" -], - "application/ssml+xml": [ - "ssml" -], - "application/tei+xml": [ - "tei", - "teicorpus" -], - "application/thraud+xml": [ - "tfi" -], - "application/timestamped-data": [ - "tsd" -], - "application/vnd.3gpp.pic-bw-large": [ - "plb" -], - "application/vnd.3gpp.pic-bw-small": [ - "psb" -], - "application/vnd.3gpp.pic-bw-var": [ - "pvb" -], - "application/vnd.3gpp2.tcap": [ - "tcap" -], - "application/vnd.3m.post-it-notes": [ - "pwn" -], - "application/vnd.accpac.simply.aso": [ - "aso" -], - "application/vnd.accpac.simply.imp": [ - "imp" -], - "application/vnd.acucobol": [ - "acu" -], - "application/vnd.acucorp": [ - "atc", - "acutc" -], - "application/vnd.adobe.air-application-installer-package+zip": [ - "air" -], - "application/vnd.adobe.formscentral.fcdt": [ - "fcdt" -], - "application/vnd.adobe.fxp": [ - "fxp", - "fxpl" -], - "application/vnd.adobe.xdp+xml": [ - "xdp" -], - "application/vnd.adobe.xfdf": [ - "xfdf" -], - "application/vnd.ahead.space": [ - "ahead" -], - "application/vnd.airzip.filesecure.azf": [ - "azf" -], - "application/vnd.airzip.filesecure.azs": [ - "azs" -], - "application/vnd.amazon.ebook": [ - "azw" -], - "application/vnd.americandynamics.acc": [ - "acc" -], - "application/vnd.amiga.ami": [ - "ami" -], - "application/vnd.android.package-archive": [ - "apk" -], - "application/vnd.anser-web-certificate-issue-initiation": [ - "cii" -], - "application/vnd.anser-web-funds-transfer-initiation": [ - "fti" -], - "application/vnd.antix.game-component": [ - "atx" -], - "application/vnd.apple.installer+xml": [ - "mpkg" -], - "application/vnd.apple.mpegurl": [ - "m3u8" -], - "application/vnd.apple.pkpass": [ - "pkpass" -], - "application/vnd.aristanetworks.swi": [ - "swi" -], - "application/vnd.astraea-software.iota": [ - "iota" -], - "application/vnd.audiograph": [ - "aep" -], - "application/vnd.blueice.multipass": [ - "mpm" -], - "application/vnd.bmi": [ - "bmi" -], - "application/vnd.businessobjects": [ - "rep" -], - "application/vnd.chemdraw+xml": [ - "cdxml" -], - "application/vnd.chipnuts.karaoke-mmd": [ - "mmd" -], - "application/vnd.cinderella": [ - "cdy" -], - "application/vnd.claymore": [ - "cla" -], - "application/vnd.cloanto.rp9": [ - "rp9" -], - "application/vnd.clonk.c4group": [ - "c4g", - "c4d", - "c4f", - "c4p", - "c4u" -], - "application/vnd.cluetrust.cartomobile-config": [ - "c11amc" -], - "application/vnd.cluetrust.cartomobile-config-pkg": [ - "c11amz" -], - "application/vnd.commonspace": [ - "csp" -], - "application/vnd.contact.cmsg": [ - "cdbcmsg" -], - "application/vnd.cosmocaller": [ - "cmc" -], - "application/vnd.crick.clicker": [ - "clkx" -], - "application/vnd.crick.clicker.keyboard": [ - "clkk" -], - "application/vnd.crick.clicker.palette": [ - "clkp" -], - "application/vnd.crick.clicker.template": [ - "clkt" -], - "application/vnd.crick.clicker.wordbank": [ - "clkw" -], - "application/vnd.criticaltools.wbs+xml": [ - "wbs" -], - "application/vnd.ctc-posml": [ - "pml" -], - "application/vnd.cups-ppd": [ - "ppd" -], - "application/vnd.curl.car": [ - "car" -], - "application/vnd.curl.pcurl": [ - "pcurl" -], - "application/vnd.dart": [ - "dart" -], - "application/vnd.data-vision.rdz": [ - "rdz" -], - "application/vnd.dece.data": [ - "uvf", - "uvvf", - "uvd", - "uvvd" -], - "application/vnd.dece.ttml+xml": [ - "uvt", - "uvvt" -], - "application/vnd.dece.unspecified": [ - "uvx", - "uvvx" -], - "application/vnd.dece.zip": [ - "uvz", - "uvvz" -], - "application/vnd.denovo.fcselayout-link": [ - "fe_launch" -], - "application/vnd.dna": [ - "dna" -], - "application/vnd.dolby.mlp": [ - "mlp" -], - "application/vnd.dpgraph": [ - "dpg" -], - "application/vnd.dreamfactory": [ - "dfac" -], - "application/vnd.ds-keypoint": [ - "kpxx" -], - "application/vnd.dvb.ait": [ - "ait" -], - "application/vnd.dvb.service": [ - "svc" -], - "application/vnd.dynageo": [ - "geo" -], - "application/vnd.ecowin.chart": [ - "mag" -], - "application/vnd.enliven": [ - "nml" -], - "application/vnd.epson.esf": [ - "esf" -], - "application/vnd.epson.msf": [ - "msf" -], - "application/vnd.epson.quickanime": [ - "qam" -], - "application/vnd.epson.salt": [ - "slt" -], - "application/vnd.epson.ssf": [ - "ssf" -], - "application/vnd.eszigno3+xml": [ - "es3", - "et3" -], - "application/vnd.ezpix-album": [ - "ez2" -], - "application/vnd.ezpix-package": [ - "ez3" -], - "application/vnd.fdf": [ - "fdf" -], - "application/vnd.fdsn.mseed": [ - "mseed" -], - "application/vnd.fdsn.seed": [ - "seed", - "dataless" -], - "application/vnd.flographit": [ - "gph" -], - "application/vnd.fluxtime.clip": [ - "ftc" -], - "application/vnd.framemaker": [ - "fm", - "frame", - "maker", - "book" -], - "application/vnd.frogans.fnc": [ - "fnc" -], - "application/vnd.frogans.ltf": [ - "ltf" -], - "application/vnd.fsc.weblaunch": [ - "fsc" -], - "application/vnd.fujitsu.oasys": [ - "oas" -], - "application/vnd.fujitsu.oasys2": [ - "oa2" -], - "application/vnd.fujitsu.oasys3": [ - "oa3" -], - "application/vnd.fujitsu.oasysgp": [ - "fg5" -], - "application/vnd.fujitsu.oasysprs": [ - "bh2" -], - "application/vnd.fujixerox.ddd": [ - "ddd" -], - "application/vnd.fujixerox.docuworks": [ - "xdw" -], - "application/vnd.fujixerox.docuworks.binder": [ - "xbd" -], - "application/vnd.fuzzysheet": [ - "fzs" -], - "application/vnd.genomatix.tuxedo": [ - "txd" -], - "application/vnd.geogebra.file": [ - "ggb" -], - "application/vnd.geogebra.tool": [ - "ggt" -], - "application/vnd.geometry-explorer": [ - "gex", - "gre" -], - "application/vnd.geonext": [ - "gxt" -], - "application/vnd.geoplan": [ - "g2w" -], - "application/vnd.geospace": [ - "g3w" -], - "application/vnd.gmx": [ - "gmx" -], - "application/vnd.google-apps.document": [ - "gdoc" -], - "application/vnd.google-apps.presentation": [ - "gslides" -], - "application/vnd.google-apps.spreadsheet": [ - "gsheet" -], - "application/vnd.google-earth.kml+xml": [ - "kml" -], - "application/vnd.google-earth.kmz": [ - "kmz" -], - "application/vnd.grafeq": [ - "gqf", - "gqs" -], - "application/vnd.groove-account": [ - "gac" -], - "application/vnd.groove-help": [ - "ghf" -], - "application/vnd.groove-identity-message": [ - "gim" -], - "application/vnd.groove-injector": [ - "grv" -], - "application/vnd.groove-tool-message": [ - "gtm" -], - "application/vnd.groove-tool-template": [ - "tpl" -], - "application/vnd.groove-vcard": [ - "vcg" -], - "application/vnd.hal+xml": [ - "hal" -], - "application/vnd.handheld-entertainment+xml": [ - "zmm" -], - "application/vnd.hbci": [ - "hbci" -], - "application/vnd.hhe.lesson-player": [ - "les" -], - "application/vnd.hp-hpgl": [ - "hpgl" -], - "application/vnd.hp-hpid": [ - "hpid" -], - "application/vnd.hp-hps": [ - "hps" -], - "application/vnd.hp-jlyt": [ - "jlt" -], - "application/vnd.hp-pcl": [ - "pcl" -], - "application/vnd.hp-pclxl": [ - "pclxl" -], - "application/vnd.hydrostatix.sof-data": [ - "sfd-hdstx" -], - "application/vnd.ibm.minipay": [ - "mpy" -], - "application/vnd.ibm.modcap": [ - "afp", - "listafp", - "list3820" -], - "application/vnd.ibm.rights-management": [ - "irm" -], - "application/vnd.ibm.secure-container": [ - "sc" -], - "application/vnd.iccprofile": [ - "icc", - "icm" -], - "application/vnd.igloader": [ - "igl" -], - "application/vnd.immervision-ivp": [ - "ivp" -], - "application/vnd.immervision-ivu": [ - "ivu" -], - "application/vnd.insors.igm": [ - "igm" -], - "application/vnd.intercon.formnet": [ - "xpw", - "xpx" -], - "application/vnd.intergeo": [ - "i2g" -], - "application/vnd.intu.qbo": [ - "qbo" -], - "application/vnd.intu.qfx": [ - "qfx" -], - "application/vnd.ipunplugged.rcprofile": [ - "rcprofile" -], - "application/vnd.irepository.package+xml": [ - "irp" -], - "application/vnd.is-xpr": [ - "xpr" -], - "application/vnd.isac.fcs": [ - "fcs" -], - "application/vnd.jam": [ - "jam" -], - "application/vnd.jcp.javame.midlet-rms": [ - "rms" -], - "application/vnd.jisp": [ - "jisp" -], - "application/vnd.joost.joda-archive": [ - "joda" -], - "application/vnd.kahootz": [ - "ktz", - "ktr" -], - "application/vnd.kde.karbon": [ - "karbon" -], - "application/vnd.kde.kchart": [ - "chrt" -], - "application/vnd.kde.kformula": [ - "kfo" -], - "application/vnd.kde.kivio": [ - "flw" -], - "application/vnd.kde.kontour": [ - "kon" -], - "application/vnd.kde.kpresenter": [ - "kpr", - "kpt" -], - "application/vnd.kde.kspread": [ - "ksp" -], - "application/vnd.kde.kword": [ - "kwd", - "kwt" -], - "application/vnd.kenameaapp": [ - "htke" -], - "application/vnd.kidspiration": [ - "kia" -], - "application/vnd.kinar": [ - "kne", - "knp" -], - "application/vnd.koan": [ - "skp", - "skd", - "skt", - "skm" -], - "application/vnd.kodak-descriptor": [ - "sse" -], - "application/vnd.las.las+xml": [ - "lasxml" -], - "application/vnd.llamagraphics.life-balance.desktop": [ - "lbd" -], - "application/vnd.llamagraphics.life-balance.exchange+xml": [ - "lbe" -], - "application/vnd.lotus-1-2-3": [ - "123" -], - "application/vnd.lotus-approach": [ - "apr" -], - "application/vnd.lotus-freelance": [ - "pre" -], - "application/vnd.lotus-notes": [ - "nsf" -], - "application/vnd.lotus-organizer": [ - "org" -], - "application/vnd.lotus-screencam": [ - "scm" -], - "application/vnd.lotus-wordpro": [ - "lwp" -], - "application/vnd.macports.portpkg": [ - "portpkg" -], - "application/vnd.mcd": [ - "mcd" -], - "application/vnd.medcalcdata": [ - "mc1" -], - "application/vnd.mediastation.cdkey": [ - "cdkey" -], - "application/vnd.mfer": [ - "mwf" -], - "application/vnd.mfmp": [ - "mfm" -], - "application/vnd.micrografx.flo": [ - "flo" -], - "application/vnd.micrografx.igx": [ - "igx" -], - "application/vnd.mif": [ - "mif" -], - "application/vnd.mobius.daf": [ - "daf" -], - "application/vnd.mobius.dis": [ - "dis" -], - "application/vnd.mobius.mbk": [ - "mbk" -], - "application/vnd.mobius.mqy": [ - "mqy" -], - "application/vnd.mobius.msl": [ - "msl" -], - "application/vnd.mobius.plc": [ - "plc" -], - "application/vnd.mobius.txf": [ - "txf" -], - "application/vnd.mophun.application": [ - "mpn" -], - "application/vnd.mophun.certificate": [ - "mpc" -], - "application/vnd.mozilla.xul+xml": [ - "xul" -], - "application/vnd.ms-artgalry": [ - "cil" -], - "application/vnd.ms-cab-compressed": [ - "cab" -], - "application/vnd.ms-excel": [ - "xls", - "xlm", - "xla", - "xlc", - "xlt", - "xlw" -], - "application/vnd.ms-excel.addin.macroenabled.12": [ - "xlam" -], - "application/vnd.ms-excel.sheet.binary.macroenabled.12": [ - "xlsb" -], - "application/vnd.ms-excel.sheet.macroenabled.12": [ - "xlsm" -], - "application/vnd.ms-excel.template.macroenabled.12": [ - "xltm" -], - "application/vnd.ms-fontobject": [ - "eot" -], - "application/vnd.ms-htmlhelp": [ - "chm" -], - "application/vnd.ms-ims": [ - "ims" -], - "application/vnd.ms-lrm": [ - "lrm" -], - "application/vnd.ms-officetheme": [ - "thmx" -], - "application/vnd.ms-outlook": [ - "msg" -], - "application/vnd.ms-pki.seccat": [ - "cat" -], - "application/vnd.ms-pki.stl": [ - "stl" -], - "application/vnd.ms-powerpoint": [ - "ppt", - "pps", - "pot" -], - "application/vnd.ms-powerpoint.addin.macroenabled.12": [ - "ppam" -], - "application/vnd.ms-powerpoint.presentation.macroenabled.12": [ - "pptm" -], - "application/vnd.ms-powerpoint.slide.macroenabled.12": [ - "sldm" -], - "application/vnd.ms-powerpoint.slideshow.macroenabled.12": [ - "ppsm" -], - "application/vnd.ms-powerpoint.template.macroenabled.12": [ - "potm" -], - "application/vnd.ms-project": [ - "mpp", - "mpt" -], - "application/vnd.ms-word.document.macroenabled.12": [ - "docm" -], - "application/vnd.ms-word.template.macroenabled.12": [ - "dotm" -], - "application/vnd.ms-works": [ - "wps", - "wks", - "wcm", - "wdb" -], - "application/vnd.ms-wpl": [ - "wpl" -], - "application/vnd.ms-xpsdocument": [ - "xps" -], - "application/vnd.mseq": [ - "mseq" -], - "application/vnd.musician": [ - "mus" -], - "application/vnd.muvee.style": [ - "msty" -], - "application/vnd.mynfc": [ - "taglet" -], - "application/vnd.neurolanguage.nlu": [ - "nlu" -], - "application/vnd.nitf": [ - "ntf", - "nitf" -], - "application/vnd.noblenet-directory": [ - "nnd" -], - "application/vnd.noblenet-sealer": [ - "nns" -], - "application/vnd.noblenet-web": [ - "nnw" -], - "application/vnd.nokia.n-gage.data": [ - "ngdat" -], - "application/vnd.nokia.n-gage.symbian.install": [ - "n-gage" -], - "application/vnd.nokia.radio-preset": [ - "rpst" -], - "application/vnd.nokia.radio-presets": [ - "rpss" -], - "application/vnd.novadigm.edm": [ - "edm" -], - "application/vnd.novadigm.edx": [ - "edx" -], - "application/vnd.novadigm.ext": [ - "ext" -], - "application/vnd.oasis.opendocument.chart": [ - "odc" -], - "application/vnd.oasis.opendocument.chart-template": [ - "otc" -], - "application/vnd.oasis.opendocument.database": [ - "odb" -], - "application/vnd.oasis.opendocument.formula": [ - "odf" -], - "application/vnd.oasis.opendocument.formula-template": [ - "odft" -], - "application/vnd.oasis.opendocument.graphics": [ - "odg" -], - "application/vnd.oasis.opendocument.graphics-template": [ - "otg" -], - "application/vnd.oasis.opendocument.image": [ - "odi" -], - "application/vnd.oasis.opendocument.image-template": [ - "oti" -], - "application/vnd.oasis.opendocument.presentation": [ - "odp" -], - "application/vnd.oasis.opendocument.presentation-template": [ - "otp" -], - "application/vnd.oasis.opendocument.spreadsheet": [ - "ods" -], - "application/vnd.oasis.opendocument.spreadsheet-template": [ - "ots" -], - "application/vnd.oasis.opendocument.text": [ - "odt" -], - "application/vnd.oasis.opendocument.text-master": [ - "odm" -], - "application/vnd.oasis.opendocument.text-template": [ - "ott" -], - "application/vnd.oasis.opendocument.text-web": [ - "oth" -], - "application/vnd.olpc-sugar": [ - "xo" -], - "application/vnd.oma.dd2+xml": [ - "dd2" -], - "application/vnd.openofficeorg.extension": [ - "oxt" -], - "application/vnd.openxmlformats-officedocument.presentationml.presentation": [ - "pptx" -], - "application/vnd.openxmlformats-officedocument.presentationml.slide": [ - "sldx" -], - "application/vnd.openxmlformats-officedocument.presentationml.slideshow": [ - "ppsx" -], - "application/vnd.openxmlformats-officedocument.presentationml.template": [ - "potx" -], - "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet": [ - "xlsx" -], - "application/vnd.openxmlformats-officedocument.spreadsheetml.template": [ - "xltx" -], - "application/vnd.openxmlformats-officedocument.wordprocessingml.document": [ - "docx" -], - "application/vnd.openxmlformats-officedocument.wordprocessingml.template": [ - "dotx" -], - "application/vnd.osgeo.mapguide.package": [ - "mgp" -], - "application/vnd.osgi.dp": [ - "dp" -], - "application/vnd.osgi.subsystem": [ - "esa" -], - "application/vnd.palm": [ - "pdb", - "pqa", - "oprc" -], - "application/vnd.pawaafile": [ - "paw" -], - "application/vnd.pg.format": [ - "str" -], - "application/vnd.pg.osasli": [ - "ei6" -], - "application/vnd.picsel": [ - "efif" -], - "application/vnd.pmi.widget": [ - "wg" -], - "application/vnd.pocketlearn": [ - "plf" -], - "application/vnd.powerbuilder6": [ - "pbd" -], - "application/vnd.previewsystems.box": [ - "box" -], - "application/vnd.proteus.magazine": [ - "mgz" -], - "application/vnd.publishare-delta-tree": [ - "qps" -], - "application/vnd.pvi.ptid1": [ - "ptid" -], - "application/vnd.quark.quarkxpress": [ - "qxd", - "qxt", - "qwd", - "qwt", - "qxl", - "qxb" -], - "application/vnd.realvnc.bed": [ - "bed" -], - "application/vnd.recordare.musicxml": [ - "mxl" -], - "application/vnd.recordare.musicxml+xml": [ - "musicxml" -], - "application/vnd.rig.cryptonote": [ - "cryptonote" -], - "application/vnd.rim.cod": [ - "cod" -], - "application/vnd.rn-realmedia": [ - "rm" -], - "application/vnd.rn-realmedia-vbr": [ - "rmvb" -], - "application/vnd.route66.link66+xml": [ - "link66" -], - "application/vnd.sailingtracker.track": [ - "st" -], - "application/vnd.seemail": [ - "see" -], - "application/vnd.sema": [ - "sema" -], - "application/vnd.semd": [ - "semd" -], - "application/vnd.semf": [ - "semf" -], - "application/vnd.shana.informed.formdata": [ - "ifm" -], - "application/vnd.shana.informed.formtemplate": [ - "itp" -], - "application/vnd.shana.informed.interchange": [ - "iif" -], - "application/vnd.shana.informed.package": [ - "ipk" -], - "application/vnd.simtech-mindmapper": [ - "twd", - "twds" -], - "application/vnd.smaf": [ - "mmf" -], - "application/vnd.smart.teacher": [ - "teacher" -], - "application/vnd.solent.sdkm+xml": [ - "sdkm", - "sdkd" -], - "application/vnd.spotfire.dxp": [ - "dxp" -], - "application/vnd.spotfire.sfs": [ - "sfs" -], - "application/vnd.stardivision.calc": [ - "sdc" -], - "application/vnd.stardivision.draw": [ - "sda" -], - "application/vnd.stardivision.impress": [ - "sdd" -], - "application/vnd.stardivision.math": [ - "smf" -], - "application/vnd.stardivision.writer": [ - "sdw", - "vor" -], - "application/vnd.stardivision.writer-global": [ - "sgl" -], - "application/vnd.stepmania.package": [ - "smzip" -], - "application/vnd.stepmania.stepchart": [ - "sm" -], - "application/vnd.sun.wadl+xml": [ - "wadl" -], - "application/vnd.sun.xml.calc": [ - "sxc" -], - "application/vnd.sun.xml.calc.template": [ - "stc" -], - "application/vnd.sun.xml.draw": [ - "sxd" -], - "application/vnd.sun.xml.draw.template": [ - "std" -], - "application/vnd.sun.xml.impress": [ - "sxi" -], - "application/vnd.sun.xml.impress.template": [ - "sti" -], - "application/vnd.sun.xml.math": [ - "sxm" -], - "application/vnd.sun.xml.writer": [ - "sxw" -], - "application/vnd.sun.xml.writer.global": [ - "sxg" -], - "application/vnd.sun.xml.writer.template": [ - "stw" -], - "application/vnd.sus-calendar": [ - "sus", - "susp" -], - "application/vnd.svd": [ - "svd" -], - "application/vnd.symbian.install": [ - "sis", - "sisx" -], - "application/vnd.syncml+xml": [ - "xsm" -], - "application/vnd.syncml.dm+wbxml": [ - "bdm" -], - "application/vnd.syncml.dm+xml": [ - "xdm" -], - "application/vnd.tao.intent-module-archive": [ - "tao" -], - "application/vnd.tcpdump.pcap": [ - "pcap", - "cap", - "dmp" -], - "application/vnd.tmobile-livetv": [ - "tmo" -], - "application/vnd.trid.tpt": [ - "tpt" -], - "application/vnd.triscape.mxs": [ - "mxs" -], - "application/vnd.trueapp": [ - "tra" -], - "application/vnd.ufdl": [ - "ufd", - "ufdl" -], - "application/vnd.uiq.theme": [ - "utz" -], - "application/vnd.umajin": [ - "umj" -], - "application/vnd.unity": [ - "unityweb" -], - "application/vnd.uoml+xml": [ - "uoml" -], - "application/vnd.vcx": [ - "vcx" -], - "application/vnd.visio": [ - "vsd", - "vst", - "vss", - "vsw" -], - "application/vnd.visionary": [ - "vis" -], - "application/vnd.vsf": [ - "vsf" -], - "application/vnd.wap.wbxml": [ - "wbxml" -], - "application/vnd.wap.wmlc": [ - "wmlc" -], - "application/vnd.wap.wmlscriptc": [ - "wmlsc" -], - "application/vnd.webturbo": [ - "wtb" -], - "application/vnd.wolfram.player": [ - "nbp" -], - "application/vnd.wordperfect": [ - "wpd" -], - "application/vnd.wqd": [ - "wqd" -], - "application/vnd.wt.stf": [ - "stf" -], - "application/vnd.xara": [ - "xar" -], - "application/vnd.xfdl": [ - "xfdl" -], - "application/vnd.yamaha.hv-dic": [ - "hvd" -], - "application/vnd.yamaha.hv-script": [ - "hvs" -], - "application/vnd.yamaha.hv-voice": [ - "hvp" -], - "application/vnd.yamaha.openscoreformat": [ - "osf" -], - "application/vnd.yamaha.openscoreformat.osfpvg+xml": [ - "osfpvg" -], - "application/vnd.yamaha.smaf-audio": [ - "saf" -], - "application/vnd.yamaha.smaf-phrase": [ - "spf" -], - "application/vnd.yellowriver-custom-menu": [ - "cmp" -], - "application/vnd.zul": [ - "zir", - "zirz" -], - "application/vnd.zzazz.deck+xml": [ - "zaz" -], - "application/voicexml+xml": [ - "vxml" -], - "application/wasm": [ - "wasm" -], - "application/widget": [ - "wgt" -], - "application/winhlp": [ - "hlp" -], - "application/wsdl+xml": [ - "wsdl" -], - "application/wspolicy+xml": [ - "wspolicy" -], - "application/x-7z-compressed": [ - "7z" -], - "application/x-abiword": [ - "abw" -], - "application/x-ace-compressed": [ - "ace" -], - "application/x-apple-diskimage": [ -], - "application/x-arj": [ - "arj" -], - "application/x-authorware-bin": [ - "aab", - "x32", - "u32", - "vox" -], - "application/x-authorware-map": [ - "aam" -], - "application/x-authorware-seg": [ - "aas" -], - "application/x-bcpio": [ - "bcpio" -], - "application/x-bdoc": [ -], - "application/x-bittorrent": [ - "torrent" -], - "application/x-blorb": [ - "blb", - "blorb" -], - "application/x-bzip": [ - "bz" -], - "application/x-bzip2": [ - "bz2", - "boz" -], - "application/x-cbr": [ - "cbr", - "cba", - "cbt", - "cbz", - "cb7" -], - "application/x-cdlink": [ - "vcd" -], - "application/x-cfs-compressed": [ - "cfs" -], - "application/x-chat": [ - "chat" -], - "application/x-chess-pgn": [ - "pgn" -], - "application/x-chrome-extension": [ - "crx" -], - "application/x-cocoa": [ - "cco" -], - "application/x-conference": [ - "nsc" -], - "application/x-cpio": [ - "cpio" -], - "application/x-csh": [ - "csh" -], - "application/x-debian-package": [ - "udeb" -], - "application/x-dgc-compressed": [ - "dgc" -], - "application/x-director": [ - "dir", - "dcr", - "dxr", - "cst", - "cct", - "cxt", - "w3d", - "fgd", - "swa" -], - "application/x-doom": [ - "wad" -], - "application/x-dtbncx+xml": [ - "ncx" -], - "application/x-dtbook+xml": [ - "dtb" -], - "application/x-dtbresource+xml": [ - "res" -], - "application/x-dvi": [ - "dvi" -], - "application/x-envoy": [ - "evy" -], - "application/x-eva": [ - "eva" -], - "application/x-font-bdf": [ - "bdf" -], - "application/x-font-ghostscript": [ - "gsf" -], - "application/x-font-linux-psf": [ - "psf" -], - "application/x-font-pcf": [ - "pcf" -], - "application/x-font-snf": [ - "snf" -], - "application/x-font-type1": [ - "pfa", - "pfb", - "pfm", - "afm" -], - "application/x-freearc": [ - "arc" -], - "application/x-futuresplash": [ - "spl" -], - "application/x-gca-compressed": [ - "gca" -], - "application/x-glulx": [ - "ulx" -], - "application/x-gnumeric": [ - "gnumeric" -], - "application/x-gramps-xml": [ - "gramps" -], - "application/x-gtar": [ - "gtar" -], - "application/x-hdf": [ - "hdf" -], - "application/x-httpd-php": [ - "php" -], - "application/x-install-instructions": [ - "install" -], - "application/x-iso9660-image": [ -], - "application/x-java-archive-diff": [ - "jardiff" -], - "application/x-java-jnlp-file": [ - "jnlp" -], - "application/x-latex": [ - "latex" -], - "application/x-lua-bytecode": [ - "luac" -], - "application/x-lzh-compressed": [ - "lzh", - "lha" -], - "application/x-makeself": [ - "run" -], - "application/x-mie": [ - "mie" -], - "application/x-mobipocket-ebook": [ - "prc", - "mobi" -], - "application/x-ms-application": [ - "application" -], - "application/x-ms-shortcut": [ - "lnk" -], - "application/x-ms-wmd": [ - "wmd" -], - "application/x-ms-wmz": [ - "wmz" -], - "application/x-ms-xbap": [ - "xbap" -], - "application/x-msaccess": [ - "mdb" -], - "application/x-msbinder": [ - "obd" -], - "application/x-mscardfile": [ - "crd" -], - "application/x-msclip": [ - "clp" -], - "application/x-msdos-program": [ -], - "application/x-msdownload": [ - "com", - "bat" -], - "application/x-msmediaview": [ - "mvb", - "m13", - "m14" -], - "application/x-msmetafile": [ - "wmf", - "emf", - "emz" -], - "application/x-msmoney": [ - "mny" -], - "application/x-mspublisher": [ - "pub" -], - "application/x-msschedule": [ - "scd" -], - "application/x-msterminal": [ - "trm" -], - "application/x-mswrite": [ - "wri" -], - "application/x-netcdf": [ - "nc", - "cdf" -], - "application/x-ns-proxy-autoconfig": [ - "pac" -], - "application/x-nzb": [ - "nzb" -], - "application/x-perl": [ - "pl", - "pm" -], - "application/x-pilot": [ -], - "application/x-pkcs12": [ - "p12", - "pfx" -], - "application/x-pkcs7-certificates": [ - "p7b", - "spc" -], - "application/x-pkcs7-certreqresp": [ - "p7r" -], - "application/x-rar-compressed": [ - "rar" -], - "application/x-redhat-package-manager": [ - "rpm" -], - "application/x-research-info-systems": [ - "ris" -], - "application/x-sea": [ - "sea" -], - "application/x-sh": [ - "sh" -], - "application/x-shar": [ - "shar" -], - "application/x-shockwave-flash": [ - "swf" -], - "application/x-silverlight-app": [ - "xap" -], - "application/x-sql": [ - "sql" -], - "application/x-stuffit": [ - "sit" -], - "application/x-stuffitx": [ - "sitx" -], - "application/x-subrip": [ - "srt" -], - "application/x-sv4cpio": [ - "sv4cpio" -], - "application/x-sv4crc": [ - "sv4crc" -], - "application/x-t3vm-image": [ - "t3" -], - "application/x-tads": [ - "gam" -], - "application/x-tar": [ - "tar" -], - "application/x-tcl": [ - "tcl", - "tk" -], - "application/x-tex": [ - "tex" -], - "application/x-tex-tfm": [ - "tfm" -], - "application/x-texinfo": [ - "texinfo", - "texi" -], - "application/x-tgif": [ - "obj" -], - "application/x-ustar": [ - "ustar" -], - "application/x-virtualbox-hdd": [ - "hdd" -], - "application/x-virtualbox-ova": [ - "ova" -], - "application/x-virtualbox-ovf": [ - "ovf" -], - "application/x-virtualbox-vbox": [ - "vbox" -], - "application/x-virtualbox-vbox-extpack": [ - "vbox-extpack" -], - "application/x-virtualbox-vdi": [ - "vdi" -], - "application/x-virtualbox-vhd": [ - "vhd" -], - "application/x-virtualbox-vmdk": [ - "vmdk" -], - "application/x-wais-source": [ - "src" -], - "application/x-web-app-manifest+json": [ - "webapp" -], - "application/x-x509-ca-cert": [ - "der", - "crt", - "pem" -], - "application/x-xfig": [ - "fig" -], - "application/x-xliff+xml": [ - "xlf" -], - "application/x-xpinstall": [ - "xpi" -], - "application/x-xz": [ - "xz" -], - "application/x-zmachine": [ - "z1", - "z2", - "z3", - "z4", - "z5", - "z6", - "z7", - "z8" -], - "application/xaml+xml": [ - "xaml" -], - "application/xcap-diff+xml": [ - "xdf" -], - "application/xenc+xml": [ - "xenc" -], - "application/xhtml+xml": [ - "xhtml", - "xht" -], - "application/xml": [ - "xml", - "xsl", - "xsd", - "rng" -], - "application/xml-dtd": [ - "dtd" -], - "application/xop+xml": [ - "xop" -], - "application/xproc+xml": [ - "xpl" -], - "application/xslt+xml": [ - "xslt" -], - "application/xspf+xml": [ - "xspf" -], - "application/xv+xml": [ - "mxml", - "xhvml", - "xvml", - "xvm" -], - "application/yang": [ - "yang" -], - "application/yin+xml": [ - "yin" -], - "application/zip": [ - "zip" -], - "audio/3gpp": [ -], - "audio/adpcm": [ - "adp" -], - "audio/basic": [ - "au", - "snd" -], - "audio/midi": [ - "mid", - "midi", - "kar", - "rmi" -], - "audio/mp3": [ -], - "audio/mp4": [ - "m4a", - "mp4a" -], - "audio/mpeg": [ - "mpga", - "mp2", - "mp2a", - "mp3", - "m2a", - "m3a" -], - "audio/ogg": [ - "oga", - "ogg", - "spx" -], - "audio/s3m": [ - "s3m" -], - "audio/silk": [ - "sil" -], - "audio/vnd.dece.audio": [ - "uva", - "uvva" -], - "audio/vnd.digital-winds": [ - "eol" -], - "audio/vnd.dra": [ - "dra" -], - "audio/vnd.dts": [ - "dts" -], - "audio/vnd.dts.hd": [ - "dtshd" -], - "audio/vnd.lucent.voice": [ - "lvp" -], - "audio/vnd.ms-playready.media.pya": [ - "pya" -], - "audio/vnd.nuera.ecelp4800": [ - "ecelp4800" -], - "audio/vnd.nuera.ecelp7470": [ - "ecelp7470" -], - "audio/vnd.nuera.ecelp9600": [ - "ecelp9600" -], - "audio/vnd.rip": [ - "rip" -], - "audio/wav": [ - "wav" -], - "audio/wave": [ -], - "audio/webm": [ - "weba" -], - "audio/x-aac": [ - "aac" -], - "audio/x-aiff": [ - "aif", - "aiff", - "aifc" -], - "audio/x-caf": [ - "caf" -], - "audio/x-flac": [ - "flac" -], - "audio/x-m4a": [ -], - "audio/x-matroska": [ - "mka" -], - "audio/x-mpegurl": [ - "m3u" -], - "audio/x-ms-wax": [ - "wax" -], - "audio/x-ms-wma": [ - "wma" -], - "audio/x-pn-realaudio": [ - "ram", - "ra" -], - "audio/x-pn-realaudio-plugin": [ - "rmp" -], - "audio/x-realaudio": [ -], - "audio/x-wav": [ -], - "audio/xm": [ - "xm" -], - "chemical/x-cdx": [ - "cdx" -], - "chemical/x-cif": [ - "cif" -], - "chemical/x-cmdf": [ - "cmdf" -], - "chemical/x-cml": [ - "cml" -], - "chemical/x-csml": [ - "csml" -], - "chemical/x-xyz": [ - "xyz" -], - "font/collection": [ - "ttc" -], - "font/otf": [ - "otf" -], - "font/ttf": [ - "ttf" -], - "font/woff": [ - "woff" -], - "font/woff2": [ - "woff2" -], - "image/apng": [ - "apng" -], - "image/bmp": [ - "bmp" -], - "image/cgm": [ - "cgm" -], - "image/g3fax": [ - "g3" -], - "image/gif": [ - "gif" -], - "image/ief": [ - "ief" -], - "image/jp2": [ - "jp2", - "jpg2" -], - "image/jpeg": [ - "jpeg", - "jpg", - "jpe" -], - "image/jpm": [ - "jpm" -], - "image/jpx": [ - "jpx", - "jpf" -], - "image/ktx": [ - "ktx" -], - "image/png": [ - "png" -], - "image/prs.btif": [ - "btif" -], - "image/sgi": [ - "sgi" -], - "image/svg+xml": [ - "svg", - "svgz" -], - "image/tiff": [ - "tiff", - "tif" -], - "image/vnd.adobe.photoshop": [ - "psd" -], - "image/vnd.dece.graphic": [ - "uvi", - "uvvi", - "uvg", - "uvvg" -], - "image/vnd.djvu": [ - "djvu", - "djv" -], - "image/vnd.dvb.subtitle": [ -], - "image/vnd.dwg": [ - "dwg" -], - "image/vnd.dxf": [ - "dxf" -], - "image/vnd.fastbidsheet": [ - "fbs" -], - "image/vnd.fpx": [ - "fpx" -], - "image/vnd.fst": [ - "fst" -], - "image/vnd.fujixerox.edmics-mmr": [ - "mmr" -], - "image/vnd.fujixerox.edmics-rlc": [ - "rlc" -], - "image/vnd.ms-modi": [ - "mdi" -], - "image/vnd.ms-photo": [ - "wdp" -], - "image/vnd.net-fpx": [ - "npx" -], - "image/vnd.wap.wbmp": [ - "wbmp" -], - "image/vnd.xiff": [ - "xif" -], - "image/webp": [ - "webp" -], - "image/x-3ds": [ - "3ds" -], - "image/x-cmu-raster": [ - "ras" -], - "image/x-cmx": [ - "cmx" -], - "image/x-freehand": [ - "fh", - "fhc", - "fh4", - "fh5", - "fh7" -], - "image/x-icon": [ - "ico" -], - "image/x-jng": [ - "jng" -], - "image/x-mrsid-image": [ - "sid" -], - "image/x-ms-bmp": [ -], - "image/x-pcx": [ - "pcx" -], - "image/x-pict": [ - "pic", - "pct" -], - "image/x-portable-anymap": [ - "pnm" -], - "image/x-portable-bitmap": [ - "pbm" -], - "image/x-portable-graymap": [ - "pgm" -], - "image/x-portable-pixmap": [ - "ppm" -], - "image/x-rgb": [ - "rgb" -], - "image/x-tga": [ - "tga" -], - "image/x-xbitmap": [ - "xbm" -], - "image/x-xpixmap": [ - "xpm" -], - "image/x-xwindowdump": [ - "xwd" -], - "message/rfc822": [ - "eml", - "mime" -], - "model/gltf+json": [ - "gltf" -], - "model/gltf-binary": [ - "glb" -], - "model/iges": [ - "igs", - "iges" -], - "model/mesh": [ - "msh", - "mesh", - "silo" -], - "model/vnd.collada+xml": [ - "dae" -], - "model/vnd.dwf": [ - "dwf" -], - "model/vnd.gdl": [ - "gdl" -], - "model/vnd.gtw": [ - "gtw" -], - "model/vnd.mts": [ - "mts" -], - "model/vnd.vtu": [ - "vtu" -], - "model/vrml": [ - "wrl", - "vrml" -], - "model/x3d+binary": [ - "x3db", - "x3dbz" -], - "model/x3d+vrml": [ - "x3dv", - "x3dvz" -], - "model/x3d+xml": [ - "x3d", - "x3dz" -], - "text/cache-manifest": [ - "appcache", - "manifest" -], - "text/calendar": [ - "ics", - "ifb" -], - "text/coffeescript": [ - "coffee", - "litcoffee" -], - "text/css": [ - "css" -], - "text/csv": [ - "csv" -], - "text/hjson": [ - "hjson" -], - "text/html": [ - "html", - "htm", - "shtml" -], - "text/jade": [ - "jade" -], - "text/jsx": [ - "jsx" -], - "text/less": [ - "less" -], - "text/markdown": [ - "markdown", - "md" -], - "text/mathml": [ - "mml" -], - "text/n3": [ - "n3" -], - "text/plain": [ - "txt", - "text", - "conf", - "def", - "list", - "log", - "in", - "ini" -], - "text/prs.lines.tag": [ - "dsc" -], - "text/richtext": [ - "rtx" -], - "text/rtf": [ -], - "text/sgml": [ - "sgml", - "sgm" -], - "text/slim": [ - "slim", - "slm" -], - "text/stylus": [ - "stylus", - "styl" -], - "text/tab-separated-values": [ - "tsv" -], - "text/troff": [ - "t", - "tr", - "roff", - "man", - "me", - "ms" -], - "text/turtle": [ - "ttl" -], - "text/uri-list": [ - "uri", - "uris", - "urls" -], - "text/vcard": [ - "vcard" -], - "text/vnd.curl": [ - "curl" -], - "text/vnd.curl.dcurl": [ - "dcurl" -], - "text/vnd.curl.mcurl": [ - "mcurl" -], - "text/vnd.curl.scurl": [ - "scurl" -], - "text/vnd.dvb.subtitle": [ - "sub" -], - "text/vnd.fly": [ - "fly" -], - "text/vnd.fmi.flexstor": [ - "flx" -], - "text/vnd.graphviz": [ - "gv" -], - "text/vnd.in3d.3dml": [ - "3dml" -], - "text/vnd.in3d.spot": [ - "spot" -], - "text/vnd.sun.j2me.app-descriptor": [ - "jad" -], - "text/vnd.wap.wml": [ - "wml" -], - "text/vnd.wap.wmlscript": [ - "wmls" -], - "text/vtt": [ - "vtt" -], - "text/x-asm": [ - "s", - "asm" -], - "text/x-c": [ - "c", - "cc", - "cxx", - "cpp", - "h", - "hh", - "dic" -], - "text/x-component": [ - "htc" -], - "text/x-fortran": [ - "f", - "for", - "f77", - "f90" -], - "text/x-handlebars-template": [ - "hbs" -], - "text/x-java-source": [ - "java" -], - "text/x-lua": [ - "lua" -], - "text/x-markdown": [ - "mkd" -], - "text/x-nfo": [ - "nfo" -], - "text/x-opml": [ - "opml" -], - "text/x-org": [ -], - "text/x-pascal": [ - "p", - "pas" -], - "text/x-processing": [ - "pde" -], - "text/x-sass": [ - "sass" -], - "text/x-scss": [ - "scss" -], - "text/x-setext": [ - "etx" -], - "text/x-sfv": [ - "sfv" -], - "text/x-suse-ymp": [ - "ymp" -], - "text/x-uuencode": [ - "uu" -], - "text/x-vcalendar": [ - "vcs" -], - "text/x-vcard": [ - "vcf" -], - "text/xml": [ -], - "text/yaml": [ - "yaml", - "yml" -], - "video/3gpp": [ - "3gp", - "3gpp" -], - "video/3gpp2": [ - "3g2" -], - "video/h261": [ - "h261" -], - "video/h263": [ - "h263" -], - "video/h264": [ - "h264" -], - "video/jpeg": [ - "jpgv" -], - "video/jpm": [ - "jpgm" -], - "video/mj2": [ - "mj2", - "mjp2" -], - "video/mp2t": [ - "ts" -], - "video/mp4": [ - "mp4", - "mp4v", - "mpg4" -], - "video/mpeg": [ - "mpeg", - "mpg", - "mpe", - "m1v", - "m2v" -], - "video/ogg": [ - "ogv" -], - "video/quicktime": [ - "qt", - "mov" -], - "video/vnd.dece.hd": [ - "uvh", - "uvvh" -], - "video/vnd.dece.mobile": [ - "uvm", - "uvvm" -], - "video/vnd.dece.pd": [ - "uvp", - "uvvp" -], - "video/vnd.dece.sd": [ - "uvs", - "uvvs" -], - "video/vnd.dece.video": [ - "uvv", - "uvvv" -], - "video/vnd.dvb.file": [ - "dvb" -], - "video/vnd.fvt": [ - "fvt" -], - "video/vnd.mpegurl": [ - "mxu", - "m4u" -], - "video/vnd.ms-playready.media.pyv": [ - "pyv" -], - "video/vnd.uvvu.mp4": [ - "uvu", - "uvvu" -], - "video/vnd.vivo": [ - "viv" -], - "video/webm": [ - "webm" -], - "video/x-f4v": [ - "f4v" -], - "video/x-fli": [ - "fli" -], - "video/x-flv": [ - "flv" -], - "video/x-m4v": [ - "m4v" -], - "video/x-matroska": [ - "mkv", - "mk3d", - "mks" -], - "video/x-mng": [ - "mng" -], - "video/x-ms-asf": [ - "asf", - "asx" -], - "video/x-ms-vob": [ - "vob" -], - "video/x-ms-wm": [ - "wm" -], - "video/x-ms-wmv": [ - "wmv" -], - "video/x-ms-wmx": [ - "wmx" -], - "video/x-ms-wvx": [ - "wvx" -], - "video/x-msvideo": [ - "avi" -], - "video/x-sgi-movie": [ - "movie" -], - "video/x-smv": [ - "smv" -], - "x-conference/x-cooltalk": [ - "ice" -] -}; - -var fs$2 = require$$1__default["default"]; - -function Mime() { - // Map of extension -> mime type - this.types = Object.create(null); - - // Map of mime type -> extension - this.extensions = Object.create(null); -} - -/** - * Define mimetype -> extension mappings. Each key is a mime-type that maps - * to an array of extensions associated with the type. The first extension is - * used as the default extension for the type. - * - * e.g. mime.define({'audio/ogg', ['oga', 'ogg', 'spx']}); - * - * @param map (Object) type definitions - */ -Mime.prototype.define = function (map) { - for (var type in map) { - var exts = map[type]; - for (var i = 0; i < exts.length; i++) { - if (process.env.DEBUG_MIME && this.types[exts[i]]) { - console.warn((this._loading || "define()").replace(/.*\//, ''), 'changes "' + exts[i] + '" extension type from ' + - this.types[exts[i]] + ' to ' + type); - } - - this.types[exts[i]] = type; - } - - // Default extension is the first one we encounter - if (!this.extensions[type]) { - this.extensions[type] = exts[0]; - } - } -}; - -/** - * Load an Apache2-style ".types" file - * - * This may be called multiple times (it's expected). Where files declare - * overlapping types/extensions, the last file wins. - * - * @param file (String) path of file to load. - */ -Mime.prototype.load = function(file) { - this._loading = file; - // Read file and split into lines - var map = {}, - content = fs$2.readFileSync(file, 'ascii'), - lines = content.split(/[\r\n]+/); - - lines.forEach(function(line) { - // Clean up whitespace/comments, and split into fields - var fields = line.replace(/\s*#.*|^\s*|\s*$/g, '').split(/\s+/); - map[fields.shift()] = fields; - }); - - this.define(map); - - this._loading = null; -}; - -/** - * Lookup a mime type based on extension - */ -Mime.prototype.lookup = function(path, fallback) { - var ext = path.replace(/^.*[\.\/\\]/, '').toLowerCase(); - - return this.types[ext] || fallback || this.default_type; -}; - -/** - * Return file extension associated with a mime type - */ -Mime.prototype.extension = function(mimeType) { - var type = mimeType.match(/^\s*([^;\s]*)(?:;|\s|$)/)[1].toLowerCase(); - return this.extensions[type]; -}; - -// Default instance -var mime$1 = new Mime(); - -// Define built-in types -mime$1.define(require$$2); - -// Default type -mime$1.default_type = mime$1.lookup('bin'); - -// -// Additional API specific to the default instance -// - -mime$1.Mime = Mime; - -/** - * Lookup a charset based on mime type. - */ -mime$1.charsets = { - lookup: function(mimeType, fallback) { - // Assume text types are utf8 - return (/^text\/|^application\/(javascript|json)/).test(mimeType) ? 'UTF-8' : fallback; - } -}; - -var mime_1 = mime$1; - -var isWsl$2 = {exports: {}}; - -const os = require$$0__default["default"]; -const fs$1 = require$$1__default["default"]; - -const isWsl$1 = () => { - if (process.platform !== 'linux') { - return false; - } - - if (os.release().includes('Microsoft')) { - return true; - } - - try { - return fs$1.readFileSync('/proc/version', 'utf8').includes('Microsoft'); - } catch (err) { - return false; - } -}; - -if (process.env.__IS_WSL_TEST__) { - isWsl$2.exports = isWsl$1; -} else { - isWsl$2.exports = isWsl$1(); -} - -const path$1 = require$$0__default$1["default"]; -const childProcess = require$$1__default$1["default"]; -const isWsl = isWsl$2.exports; - -var opn$1 = (target, opts) => { - if (typeof target !== 'string') { - return Promise.reject(new Error('Expected a `target`')); - } - - opts = Object.assign({wait: true}, opts); - - let cmd; - let appArgs = []; - let args = []; - const cpOpts = {}; - - if (Array.isArray(opts.app)) { - appArgs = opts.app.slice(1); - opts.app = opts.app[0]; - } - - if (process.platform === 'darwin') { - cmd = 'open'; - - if (opts.wait) { - args.push('-W'); - } - - if (opts.app) { - args.push('-a', opts.app); - } - } else if (process.platform === 'win32' || isWsl) { - cmd = 'cmd' + (isWsl ? '.exe' : ''); - args.push('/c', 'start', '""', '/b'); - target = target.replace(/&/g, '^&'); - - if (opts.wait) { - args.push('/wait'); - } - - if (opts.app) { - args.push(opts.app); - } - - if (appArgs.length > 0) { - args = args.concat(appArgs); - } - } else { - if (opts.app) { - cmd = opts.app; - } else { - const useSystemXdgOpen = process.versions.electron || process.platform === 'android'; - cmd = useSystemXdgOpen ? 'xdg-open' : path$1.join(__dirname, 'xdg-open'); - } - - if (appArgs.length > 0) { - args = args.concat(appArgs); - } - - if (!opts.wait) { - // `xdg-open` will block the process unless - // stdio is ignored and it's detached from the parent - // even if it's unref'd - cpOpts.stdio = 'ignore'; - cpOpts.detached = true; - } - } - - args.push(target); - - if (process.platform === 'darwin' && appArgs.length > 0) { - args.push('--args'); - args = args.concat(appArgs); - } - - const cp = childProcess.spawn(cmd, args, cpOpts); - - if (opts.wait) { - return new Promise((resolve, reject) => { - cp.once('error', reject); - - cp.once('close', code => { - if (code > 0) { - reject(new Error('Exited with code ' + code)); - return; - } - - resolve(cp); - }); - }); - } - - cp.unref(); - - return Promise.resolve(cp); -}; - -const DEFAULT_INDEX = 'index.html'; - -const HTTP_STATUS_OK = 200; -const HTTP_STATUS_PARTIAL_CONTENT = 206; -const HTTP_STATUS_NOT_MODIFIED = 304; -const HTTP_STATUS_ERR = 500; -const HTTP_STATUS_BAD_REQUEST = 400; -const HTTP_STATUS_FORBIDDEN = 403; -const HTTP_STATUS_NOT_FOUND = 404; -const HTTP_STATUS_INVALID_METHOD = 405; - -const VALID_HTTP_METHODS = ['GET', 'HEAD']; - -const RANGE_REQUEST_HEADER_TEST = /^bytes=/; -const RANGE_REQUEST_HEADER_PATTERN = /\d*-\d*/g; - -const TIME_MS_PRECISION = 3; - -const MULTIPART_SEPARATOR = '--MULTIPARTSEPERATORaufielqbghgzwr'; - -const NEWLINE = '\n'; - - -var EventEmitter = require$$0__default$2["default"].EventEmitter; -var util = require$$1__default$2["default"]; -var http = require$$2__default["default"]; -var url = require$$3__default["default"]; -var mime = mime_1; -var path = require$$0__default$1["default"]; -var fs = require$$1__default["default"]; -var opn = opn$1; - - -/** -Exposes the StaticServer class -*/ -var server_1 = StaticServer; - - -/** -Create a new instance of StaticServer class - -Options are : - - name the server name, what will be sent as "X-Powered-by" - - host the host interface where the server will listen to. If not specified, - the server will listen on any networking interfaces - - cors a cors header, will be sent as "Access-Control-Allow-Origin", - - port the listening port number - - rootPath the serving root path. Any file above that path will be denied - - followSymlink true to follow any symbolic link, false to forbid - - templates - - index the default index file to server for a directory (default 'index.html') - - notFound the 404 error template - - noCache disables 304 responses - - open open server in the local browser - -@param options {Object} -*/ -function StaticServer(options) { - options = options || {}; - - if (!options.rootPath) { - throw new Error('Root path not specified'); - } - - if(!options.templates){ - options.templates = {}; - } - - this.name = options.name; - this.host = options.host; - this.port = options.port; - this.cors = options.cors; - this.rootPath = path.resolve(options.rootPath); - this.followSymlink = !!options.followSymlink; - this.templates = { - 'index': (options.templates.index || DEFAULT_INDEX), - 'notFound': options.templates.notFound - }; - // the arguments parser converts `--no-XXXX` to `XXXX` with a value of false; - this.noCache = !options.cache; - this.open = options.open; - - if (options.index) { - console.log("options.index is now deprecated please use options.templates.index instead."); - this.templates.index = options.index; - } - - Object.defineProperty(this, '_socket', { - configurable: true, - enumerable: false, - writable: true, - value: null - }); - -} -util.inherits(StaticServer, EventEmitter); - -/** -Expose the http.STATUS_CODES object -*/ -StaticServer.STATUS_CODES = http.STATUS_CODES; - - -/** -Start listening on the given host:port - -@param callback {Function} the function to call once the server is ready -*/ -StaticServer.prototype.start = function start(callback) { - this._socket = http.createServer(requestHandler(this)).listen(this.port, this.host, callback); - if(this.open && this.port){ - opn('http://localhost:' + this.port); - } -}; - - -/** -Stop listening -*/ -StaticServer.prototype.stop = function stop() { - if (this._socket) { - this._socket.close(); - this._socket = null; - } -}; - - -/** -Return the server's request handler function - -@param server {StaticServer} server instance -@return {Function} -*/ -function requestHandler(server) { - return function handler(req, res) { - var uri = req.path = decodeURIComponent(url.parse(req.url).pathname); - var filename = path.join(server.rootPath, uri); - var timestamp = process.hrtime(); - - // add a property to get the elapsed time since the request was issued - Object.defineProperty(req, 'elapsedTime', { - get: function getElapsedTime() { - var elapsed = process.hrtime(timestamp); - return (elapsed[0] ? elapsed[0] + 's ' : '') + (elapsed[1] / 1000000).toFixed(TIME_MS_PRECISION) + 'ms'; - } - }); - - res.headers = {}; - if (server.name) { - res.headers['X-Powered-By'] = server.name; - } - - if (server.cors) { - res.headers['Access-Control-Allow-Origin'] = server.cors; - } - - server.emit('request', req, res); - - if (VALID_HTTP_METHODS.indexOf(req.method) === -1) { - return sendError(server, req, res, null, HTTP_STATUS_INVALID_METHOD); - } else if (!validPath(server.rootPath, filename)) { - return sendError(server, req, res, null, HTTP_STATUS_FORBIDDEN); - } - - getFileStats(server, [filename, path.join(filename, server.templates.index)], function (err, stat, file, index) { - if (err) { - handleError(server, req, res); - } else if (stat.isDirectory()) { - // - // TODO : handle directory listing here - // - sendError(server, req, res, null, HTTP_STATUS_FORBIDDEN); - } else { - sendFile(server, req, res, stat, file); - } - }); - }; -} - - -/** -Handle an error - -Currently assumes that the only error would be a 404 error. - -@param server {StaticServer} server instance -@param req {Object} request Object -@param res {Object} response Object -@param err {Object} the error to handle -*/ -function handleError(server, req, res, err){ - if(server.templates.notFound){ - getFileStats(server, [server.templates.notFound], function(err, stat, file, index){ - if (err) { - sendError(server, req, res, null, HTTP_STATUS_NOT_FOUND); - } else { - res.status = HTTP_STATUS_NOT_FOUND; - sendFile(server, req, res, stat, file); - } - }); - }else { - sendError(server, req, res, null, HTTP_STATUS_NOT_FOUND); - } -} - - - -/** -Check that path is valid so we don't access invalid resources - -@param rootPath {String} the server root path -@param file {String} the path to validate -*/ -function validPath(rootPath, file) { - var resolvedPath = path.resolve(rootPath, file); - - // only if we are still in the rootPath of the static site - return resolvedPath.indexOf(rootPath) === 0; -} - - -/** -Get stats for the given file(s). The function will return the stats for the -first valid (i.e. found) file or directory. - - getFile(server, ['file1', 'file2'], callback); - -The callback function receives four arguments; an error if any, a stats object, -the file name matching the stats found, and the actual index of the file from -the provided list of files. - -@param server {StaticServer} the StaticServer instance -@param files {Array} list of files -@param callback {Function} a callback function -*/ -function getFileStats(server, files, callback) { - var dirFound; - var dirStat; - var dirIndex; - - function checkNext(err, index) { - if (files.length) { - next(files.shift(), index + 1); - } else if (dirFound) { - // if a directory was found at some point, return it and ignore the error - callback(null, dirStat, dirFound, dirIndex); - } else { - callback(err || new Error('File not found')); - } - } - - function next(file, index) { - fs.lstat(file, function (err, stat) { - if (err) { - checkNext(err, index); - } else if (stat.isSymbolicLink()) { - if (server.followSymlink) { - fs.readlink(file, function (err, fileRef) { - if (err) { - checkNext(err, index); - } else { - if (!path.isAbsolute(fileRef)) { - fileRef = path.join( path.dirname(file), fileRef ); - } - server.emit('symbolicLink', fileRef); - next(fileRef, index); - } - }); - } else { - callback(new Error('Symbolic link not allowed')); - } - } else if (stat.isDirectory()) { - if (!dirFound) { - dirFound = file; - dirStat = stat; - dirIndex = index; - } - checkNext(null, index); - } else { - callback(null, stat, file, index); - } - }); - } - - checkNext(null, 0); -} - - -/** -Validate that this file is not client cached - -@param req {Object} the request object -@param res {Object} the response object -@return {boolean} true if the file is client cached -*/ -function validateClientCache(server, req, res, stat) { - var mtime = stat.mtime.getTime(); - var clientETag = req.headers['if-none-match']; - var clientMTime = Date.parse(req.headers['if-modified-since']); - - if (server.noCache) return false; - - if ((clientMTime || clientETag) && - (!clientETag || clientETag === res.headers['Etag']) && - (!clientMTime || clientMTime >= mtime)) { - - // NOT MODIFIED responses should not contain entity headers - [ - 'Content-Encoding', - 'Content-Language', - 'Content-Length', - 'Content-Location', - 'Content-MD5', - 'Content-Range', - 'Content-Type', - 'Expires', - 'Last-Modified' - ].forEach(function(entityHeader) { - delete res.headers[entityHeader]; - }); - - res.status = HTTP_STATUS_NOT_MODIFIED; - - res.writeHead(res.status, res.headers); - res.end(); - - server.emit('response', req, res); - - return true; - } else { - return false; - } -} - -function parseRanges(req, res, size) { - var ranges; - var start; - var end; - var i; - var originalSize = size; - - // support range headers - if (req.headers.range) { - // 'bytes=100-200,300-400' --> ['100-200','300-400'] - if (!RANGE_REQUEST_HEADER_TEST.test(req.headers.range)) { - return sendError(req, res, null, HTTP_STATUS_BAD_REQUEST, 'Invalid Range Headers: ' + req.headers.range); - } - - ranges = req.headers.range.match(RANGE_REQUEST_HEADER_PATTERN); - size = 0; - - if (!ranges) { - return sendError(server, req, res, null, HTTP_STATUS_BAD_REQUEST, 'Invalid Range Headers: ' + req.headers.range); - } - - i = ranges.length; - - while (--i >= 0) { - // 100-200 --> [100, 200] = bytes 100 to 200 - // -200 --> [null, 200] = last 100 bytes - // 100- --> [100, null] = bytes 100 to end - range = ranges[i].split('-'); - start = range[0] ? Number(range[0]) : null; - end = range[1] ? Number(range[1]) : null; - - // check if requested range is valid: - // - check it is within file range - // - check that start is smaller than end, if both are set - - if ((start > originalSize) || (end > originalSize) || ((start && end) && start > end)) { - res.headers['Content-Range'] = 'bytes=0-' + originalSize; - return sendError(server, req, res, null, DEFAULT_STATUS_REQUEST_RANGE_NOT_SATISFIABLE); - } - - // update size - if (start !== null && end !== null) { - size += (end - start); - ranges[i] = { start: start, end: end + 1 }; - } else if (start !== null) { - size += (originalSize - start); - ranges[i] = { start: start, end: originalSize + 1 }; - } else if (end !== null) { - size += end; - ranges[i] = { start: originalSize - end, end: originalSize }; - } - } - } - - return { - ranges: ranges, - size: size - }; -} - - -/** -Send error back to the client. If `status` is not specified, a value -of 500 is used. If `message` is not specified, the default message for -the given status is returned. - -@param server {StaticServer} the server instance -@param req {Object} the request object -@param res {Object} the response object -@param err {Object} an Error object, if any -@param status {Number} the status (default 500) -@param message {String} the status message (optional) -*/ -function sendError(server, req, res, err, status, message) { - status = status || res.status || HTTP_STATUS_ERR; - message = message || http.STATUS_CODES[status]; - - if (status >= 400) { - // ERR responses should not contain entity headers - [ - 'Content-Encoding', - 'Content-Language', - 'Content-Length', - 'Content-Location', - 'Content-MD5', - // 'Content-Range', // Error 416 SHOULD contain this header - 'Etag', - 'Expires', - 'Last-Modified' - ].forEach(function(entityHeader) { - delete res.headers[entityHeader]; - }); - - res.status = status; - res.headers['Content-Type'] = mime.lookup('text'); - - res.writeHead(status, res.headers); - res.write(message); - res.end(); - } - - server.emit('response', req, res, err); -} - - -/** -Send a file back at the client. If the file is not found, an error 404 -will be returned. If the file cannot be read, for any reason, an error 500 -will be read and the error will be sent to stderr - -@param server {StaticServer} the server instance -@param req {Object} the request object -@param res {Object} the response object -@param stat {Object} the actual file stat -@param file {String} the absolute file path -*/ -function sendFile(server, req, res, stat, file) { - var headersSent = false; - var contentParts = parseRanges(req, res, stat.size); - var streamOptions = { flags: 'r' }; - var contentType = mime.lookup(file); - var rangeIndex = 0; - - if (!contentParts) { - return; // ranges failed, abort - } - - if (!server.noCache) { - res.headers['Etag'] = JSON.stringify([stat.ino, stat.size, stat.mtime.getTime()].join('-')); - res.headers['Last-Modified'] = new Date(stat.mtime).toUTCString(); - } - - res.headers['Date'] = new Date().toUTCString(); - - if (contentParts.ranges && contentParts.ranges.length > 1) { - res.headers['Content-Type'] = 'multipart/byteranges; boundary=' + MULTIPART_SEPARATOR; - } else { - res.headers['Content-Type'] = contentType; - res.headers['Content-Length'] = contentParts.size; - - if (contentParts.ranges) { - res.headers['Content-Range'] = req.headers.range; - } - } - - // return only headers if request method is HEAD - if (req.method === 'HEAD') { - res.status = HTTP_STATUS_OK; - res.writeHead(HTTP_STATUS_OK, res.headers); - res.end(); - server.emit('response', req, res, null, file, stat); - } else if (!validateClientCache(server, req, res, stat)) { - - (function sendNext() { - var range; - - if (contentParts.ranges) { - range = contentParts.ranges[rangeIndex++]; - - streamOptions.start = range.start; - streamOptions.end = range.end; - } - - fs.createReadStream(file, streamOptions) - .on('close', function () { - // close response when there are no ranges defined - // or when the last range has been read - if (!range || (rangeIndex >= contentParts.ranges.length)) { - res.end(); - server.emit('response', req, res, null, file, stat); - } else { - setImmediate(sendNext); - } - }).on('open', function (fd) { - if (!headersSent) { - if (!res.status){ - if (range) { - res.status = HTTP_STATUS_PARTIAL_CONTENT; - } else { - res.status = HTTP_STATUS_OK; - } - } - res.writeHead(res.status, res.headers); - headersSent = true; - } - - if (range && contentParts.ranges.length > 1) { - res.write(MULTIPART_SEPARATOR + NEWLINE + - 'Content-Type: ' + contentType + NEWLINE + - 'Content-Range: ' + (range.start || '') + '-' + (range.end || '') + NEWLINE + NEWLINE); - } - }).on('error', function (err) { - sendError(server, req, res, err); - }).on('data', function (chunk) { - res.write(chunk); - }); - })(); - } - -} - -(function (exports) { - Object.defineProperty(exports, "__esModule", { value: true }); - exports.tester = exports.loadTester = exports.login = exports.generateSeedPhrase = exports.TEST_KERNEL_SKLINK = exports.KERNEL_HELPER_MODULE = exports.KERNEL_TEST_SUITE = void 0; - const libskynet_1 = require$$0; - const seed_1 = require$$1; - const dictionary_1 = require$$2$1; - const path = require$$0__default$1["default"]; - const libskynetnode_1 = require$$4; - const kernel = require$$5; - const crypto_1 = require$$6__default["default"]; - // @ts-ignore - const StaticServer = server_1; - exports.KERNEL_TEST_SUITE = "AQCPJ9WRzMpKQHIsPo8no3XJpUydcDCjw7VJy8lG1MCZ3g"; - exports.KERNEL_HELPER_MODULE = "AQCoaLP6JexdZshDDZRQaIwN3B7DqFjlY7byMikR7u1IEA"; - exports.TEST_KERNEL_SKLINK = "AQCw2_9rg0Fxuy8ky3pvLiDhcJTmAqthy1Buc7Frl2v2fA"; - const SEED_ENTROPY_WORDS = 13; - const crypto = crypto_1.webcrypto; - function generateSeedPhrase() { - // Get the random numbers for the seed phrase. Typically, you need to - // have code that avoids bias by checking the random results and - // re-rolling the random numbers if the result is outside of the range - // of numbers that would produce no bias. Because the search space - // (1024) evenly divides the random number space (2^16), we can skip - // this step and just use a modulus instead. The result will have no - // bias, but only because the search space is a power of 2. - let randNums = new Uint16Array(SEED_ENTROPY_WORDS); - crypto.getRandomValues(randNums); - // Generate the seed phrase from the randNums. - let seedWords = []; - for (let i = 0; i < SEED_ENTROPY_WORDS; i++) { - let wordIndex = randNums[i] % libskynet_1.dictionary.length; - seedWords.push(libskynet_1.dictionary[wordIndex]); - } - // Convert the seedWords to a seed. - let [seed] = seedWordsToSeed(seedWords); - // Compute the checksum. - let [checksumOne, checksumTwo, err2] = (0, seed_1.seedToChecksumWords)(seed); - // Assemble the final seed phrase and set the text field. - return [...seedWords, checksumOne, checksumTwo].join(" "); - } - exports.generateSeedPhrase = generateSeedPhrase; - function seedWordsToSeed(seedWords) { - // Input checking. - if (seedWords.length !== SEED_ENTROPY_WORDS) { - return [ - new Uint8Array(0), - `Seed words should have length ${SEED_ENTROPY_WORDS} but has length ${seedWords.length}`, - ]; - } - // We are getting 16 bytes of entropy. - let bytes = new Uint8Array(seed_1.SEED_BYTES); - let curByte = 0; - let curBit = 0; - for (let i = 0; i < SEED_ENTROPY_WORDS; i++) { - // Determine which number corresponds to the next word. - let word = -1; - for (let j = 0; j < libskynet_1.dictionary.length; j++) { - if (seedWords[i].slice(0, dictionary_1.DICTIONARY_UNIQUE_PREFIX) === - libskynet_1.dictionary[j].slice(0, dictionary_1.DICTIONARY_UNIQUE_PREFIX)) { - word = j; - break; - } - } - if (word === -1) { - return [ - new Uint8Array(0), - `word '${seedWords[i]}' at index ${i} not found in dictionary`, - ]; - } - let wordBits = 10; - if (i === SEED_ENTROPY_WORDS - 1) { - wordBits = 8; - } - // Iterate over the bits of the 10- or 8-bit word. - for (let j = 0; j < wordBits; j++) { - let bitSet = (word & (1 << (wordBits - j - 1))) > 0; - if (bitSet) { - bytes[curByte] |= 1 << (8 - curBit - 1); - } - curBit += 1; - if (curBit >= 8) { - // Current byte has 8 bits, go to the next byte. - curByte += 1; - curBit = 0; - } - } - } - return [bytes, null]; - } - async function login(page, seed = generateSeedPhrase()) { - await page.goto("http://skt.us"); - let userSeed; - [userSeed] = (0, libskynet_1.seedPhraseToSeed)(seed); - let seedHex = (0, libskynet_1.bufToHex)(userSeed); - await page.evaluate((seed) => { - window.localStorage.setItem("v1-seed", seed); - }, seedHex); - let kernelEntrySeed = (0, libskynet_1.deriveChildSeed)(userSeed, "userPreferredKernel2"); - // Get the registry keys. - let [keypair, dataKey] = (0, libskynet_1.taggedRegistryEntryKeys)(kernelEntrySeed, "user kernel"); - await (0, libskynetnode_1.overwriteRegistryEntry)(keypair, dataKey, (0, libskynet_1.b64ToBuf)(exports.TEST_KERNEL_SKLINK)[0]); - } - exports.login = login; - async function loadTester(page, port = 8080) { - const server = new StaticServer({ - rootPath: path.resolve(__dirname, "..", "public"), - port, - host: "localhost", - }); - await new Promise((resolve) => { - server.start(resolve); - }); - await page.goto(`http://localhost:${port}/`); - await page.evaluate(() => { - return kernel.init(); - }); - } - exports.loadTester = loadTester; - class Tester { - page; - constructor(page) { - this.page = page; - } - async callModule(id, method, data = {}) { - return this.page.evaluate(async (id, method, data) => { - return kernel.callModule(id, method, data); - }, id, method, data); - } - } - const tester = (page) => new Tester(page); - exports.tester = tester; -} (build)); - -var index = /*@__PURE__*/getDefaultExportFromCjs(build); - -let s = 0; -const S = { - START_BOUNDARY: s++, - HEADER_FIELD_START: s++, - HEADER_FIELD: s++, - HEADER_VALUE_START: s++, - HEADER_VALUE: s++, - HEADER_VALUE_ALMOST_DONE: s++, - HEADERS_ALMOST_DONE: s++, - PART_DATA_START: s++, - PART_DATA: s++, - END: s++ -}; - -let f = 1; -const F = { - PART_BOUNDARY: f, - LAST_BOUNDARY: f *= 2 -}; - -const LF = 10; -const CR = 13; -const SPACE = 32; -const HYPHEN = 45; -const COLON = 58; -const A = 97; -const Z = 122; - -const lower = c => c | 0x20; - -const noop = () => {}; - -class MultipartParser { - /** - * @param {string} boundary - */ - constructor(boundary) { - this.index = 0; - this.flags = 0; - - this.onHeaderEnd = noop; - this.onHeaderField = noop; - this.onHeadersEnd = noop; - this.onHeaderValue = noop; - this.onPartBegin = noop; - this.onPartData = noop; - this.onPartEnd = noop; - - this.boundaryChars = {}; - - boundary = '\r\n--' + boundary; - const ui8a = new Uint8Array(boundary.length); - for (let i = 0; i < boundary.length; i++) { - ui8a[i] = boundary.charCodeAt(i); - this.boundaryChars[ui8a[i]] = true; - } - - this.boundary = ui8a; - this.lookbehind = new Uint8Array(this.boundary.length + 8); - this.state = S.START_BOUNDARY; - } - - /** - * @param {Uint8Array} data - */ - write(data) { - let i = 0; - const length_ = data.length; - let previousIndex = this.index; - let {lookbehind, boundary, boundaryChars, index, state, flags} = this; - const boundaryLength = this.boundary.length; - const boundaryEnd = boundaryLength - 1; - const bufferLength = data.length; - let c; - let cl; - - const mark = name => { - this[name + 'Mark'] = i; - }; - - const clear = name => { - delete this[name + 'Mark']; - }; - - const callback = (callbackSymbol, start, end, ui8a) => { - if (start === undefined || start !== end) { - this[callbackSymbol](ui8a && ui8a.subarray(start, end)); - } - }; - - const dataCallback = (name, clear) => { - const markSymbol = name + 'Mark'; - if (!(markSymbol in this)) { - return; - } - - if (clear) { - callback(name, this[markSymbol], i, data); - delete this[markSymbol]; - } else { - callback(name, this[markSymbol], data.length, data); - this[markSymbol] = 0; - } - }; - - for (i = 0; i < length_; i++) { - c = data[i]; - - switch (state) { - case S.START_BOUNDARY: - if (index === boundary.length - 2) { - if (c === HYPHEN) { - flags |= F.LAST_BOUNDARY; - } else if (c !== CR) { - return; - } - - index++; - break; - } else if (index - 1 === boundary.length - 2) { - if (flags & F.LAST_BOUNDARY && c === HYPHEN) { - state = S.END; - flags = 0; - } else if (!(flags & F.LAST_BOUNDARY) && c === LF) { - index = 0; - callback('onPartBegin'); - state = S.HEADER_FIELD_START; - } else { - return; - } - - break; - } - - if (c !== boundary[index + 2]) { - index = -2; - } - - if (c === boundary[index + 2]) { - index++; - } - - break; - case S.HEADER_FIELD_START: - state = S.HEADER_FIELD; - mark('onHeaderField'); - index = 0; - // falls through - case S.HEADER_FIELD: - if (c === CR) { - clear('onHeaderField'); - state = S.HEADERS_ALMOST_DONE; - break; - } - - index++; - if (c === HYPHEN) { - break; - } - - if (c === COLON) { - if (index === 1) { - // empty header field - return; - } - - dataCallback('onHeaderField', true); - state = S.HEADER_VALUE_START; - break; - } - - cl = lower(c); - if (cl < A || cl > Z) { - return; - } - - break; - case S.HEADER_VALUE_START: - if (c === SPACE) { - break; - } - - mark('onHeaderValue'); - state = S.HEADER_VALUE; - // falls through - case S.HEADER_VALUE: - if (c === CR) { - dataCallback('onHeaderValue', true); - callback('onHeaderEnd'); - state = S.HEADER_VALUE_ALMOST_DONE; - } - - break; - case S.HEADER_VALUE_ALMOST_DONE: - if (c !== LF) { - return; - } - - state = S.HEADER_FIELD_START; - break; - case S.HEADERS_ALMOST_DONE: - if (c !== LF) { - return; - } - - callback('onHeadersEnd'); - state = S.PART_DATA_START; - break; - case S.PART_DATA_START: - state = S.PART_DATA; - mark('onPartData'); - // falls through - case S.PART_DATA: - previousIndex = index; - - if (index === 0) { - // boyer-moore derrived algorithm to safely skip non-boundary data - i += boundaryEnd; - while (i < bufferLength && !(data[i] in boundaryChars)) { - i += boundaryLength; - } - - i -= boundaryEnd; - c = data[i]; - } - - if (index < boundary.length) { - if (boundary[index] === c) { - if (index === 0) { - dataCallback('onPartData', true); - } - - index++; - } else { - index = 0; - } - } else if (index === boundary.length) { - index++; - if (c === CR) { - // CR = part boundary - flags |= F.PART_BOUNDARY; - } else if (c === HYPHEN) { - // HYPHEN = end boundary - flags |= F.LAST_BOUNDARY; - } else { - index = 0; - } - } else if (index - 1 === boundary.length) { - if (flags & F.PART_BOUNDARY) { - index = 0; - if (c === LF) { - // unset the PART_BOUNDARY flag - flags &= ~F.PART_BOUNDARY; - callback('onPartEnd'); - callback('onPartBegin'); - state = S.HEADER_FIELD_START; - break; - } - } else if (flags & F.LAST_BOUNDARY) { - if (c === HYPHEN) { - callback('onPartEnd'); - state = S.END; - flags = 0; - } else { - index = 0; - } - } else { - index = 0; - } - } - - if (index > 0) { - // when matching a possible boundary, keep a lookbehind reference - // in case it turns out to be a false lead - lookbehind[index - 1] = c; - } else if (previousIndex > 0) { - // if our boundary turned out to be rubbish, the captured lookbehind - // belongs to partData - const _lookbehind = new Uint8Array(lookbehind.buffer, lookbehind.byteOffset, lookbehind.byteLength); - callback('onPartData', 0, previousIndex, _lookbehind); - previousIndex = 0; - mark('onPartData'); - - // reconsider the current character even so it interrupted the sequence - // it could be the beginning of a new sequence - i--; - } - - break; - case S.END: - break; - default: - throw new Error(`Unexpected state entered: ${state}`); - } - } - - dataCallback('onHeaderField'); - dataCallback('onHeaderValue'); - dataCallback('onPartData'); - - // Update properties for the next call - this.index = index; - this.state = state; - this.flags = flags; - } - - end() { - if ((this.state === S.HEADER_FIELD_START && this.index === 0) || - (this.state === S.PART_DATA && this.index === this.boundary.length)) { - this.onPartEnd(); - } else if (this.state !== S.END) { - throw new Error('MultipartParser.end(): stream ended unexpectedly'); - } - } -} - -function _fileName(headerValue) { - // matches either a quoted-string or a token (RFC 2616 section 19.5.1) - const m = headerValue.match(/\bfilename=("(.*?)"|([^()<>@,;:\\"/[\]?={}\s\t]+))($|;\s)/i); - if (!m) { - return; - } - - const match = m[2] || m[3] || ''; - let filename = match.slice(match.lastIndexOf('\\') + 1); - filename = filename.replace(/%22/g, '"'); - filename = filename.replace(/&#(\d{4});/g, (m, code) => { - return String.fromCharCode(code); - }); - return filename; -} - -async function toFormData(Body, ct) { - if (!/multipart/i.test(ct)) { - throw new TypeError('Failed to fetch'); - } - - const m = ct.match(/boundary=(?:"([^"]+)"|([^;]+))/i); - - if (!m) { - throw new TypeError('no or bad content-type header, no multipart boundary'); - } - - const parser = new MultipartParser(m[1] || m[2]); - - let headerField; - let headerValue; - let entryValue; - let entryName; - let contentType; - let filename; - const entryChunks = []; - const formData = new FormData(); - - const onPartData = ui8a => { - entryValue += decoder.decode(ui8a, {stream: true}); - }; - - const appendToFile = ui8a => { - entryChunks.push(ui8a); - }; - - const appendFileToFormData = () => { - const file = new File(entryChunks, filename, {type: contentType}); - formData.append(entryName, file); - }; - - const appendEntryToFormData = () => { - formData.append(entryName, entryValue); - }; - - const decoder = new TextDecoder('utf-8'); - decoder.decode(); - - parser.onPartBegin = function () { - parser.onPartData = onPartData; - parser.onPartEnd = appendEntryToFormData; - - headerField = ''; - headerValue = ''; - entryValue = ''; - entryName = ''; - contentType = ''; - filename = null; - entryChunks.length = 0; - }; - - parser.onHeaderField = function (ui8a) { - headerField += decoder.decode(ui8a, {stream: true}); - }; - - parser.onHeaderValue = function (ui8a) { - headerValue += decoder.decode(ui8a, {stream: true}); - }; - - parser.onHeaderEnd = function () { - headerValue += decoder.decode(); - headerField = headerField.toLowerCase(); - - if (headerField === 'content-disposition') { - // matches either a quoted-string or a token (RFC 2616 section 19.5.1) - const m = headerValue.match(/\bname=("([^"]*)"|([^()<>@,;:\\"/[\]?={}\s\t]+))/i); - - if (m) { - entryName = m[2] || m[3] || ''; - } - - filename = _fileName(headerValue); - - if (filename) { - parser.onPartData = appendToFile; - parser.onPartEnd = appendFileToFormData; - } - } else if (headerField === 'content-type') { - contentType = headerValue; - } - - headerValue = ''; - headerField = ''; - }; - - for await (const chunk of Body) { - parser.write(chunk); - } - - parser.end(); - - return formData; -} - -var multipartParser = /*#__PURE__*/Object.freeze({ - __proto__: null, - toFormData: toFormData -}); - -module.exports = index; +const tester = (page) => new Tester(page); +exports.tester = tester; diff --git a/dist/tester.d.ts b/dist/tester.d.ts deleted file mode 100644 index cb0ff5c..0000000 --- a/dist/tester.d.ts +++ /dev/null @@ -1 +0,0 @@ -export {}; diff --git a/public/tester.js b/public/tester.js index c6650fa..92cbf94 100644 --- a/public/tester.js +++ b/public/tester.js @@ -37,108 +37,109 @@ console.error("[libkernel]", ...inputs); } - // tryStringify will try to turn the provided input into a string. If the input - // object is already a string, the input object will be returned. If the input - // object has a toString method, the toString method will be called. If that - // fails, we try to call JSON.stringify on the object. And if that fails, we - // set the return value to "[stringify failed]". - function tryStringify$1(obj) { + // objAsString will try to return the provided object as a string. If the + // object is already a string, it will be returned without modification. If the + // object is an 'Error', the message of the error will be returned. If the object + // has a toString method, the toString method will be called and the result + // will be returned. If the object is null or undefined, a special string will + // be returned indicating that the undefined/null object cannot be converted to + // a string. In all other cases, JSON.stringify is used. If JSON.stringify + // throws an exception, a message "[could not provide object as string]" will + // be returned. + // + // NOTE: objAsString is intended to produce human readable output. It is lossy, + // and it is not intended to be used for serialization. + function objAsString(obj) { // Check for undefined input. - if (obj === undefined || obj === null) { - return "[cannot stringify undefined input]"; + if (obj === undefined) { + return "[cannot convert undefined to string]"; + } + if (obj === null) { + return "[cannot convert null to string]"; } // Parse the error into a string. if (typeof obj === "string") { return obj; } - // Check if the object has a custom toString and use that if so. - let hasToString = typeof obj.toString === "function"; - if (hasToString && obj.toString !== Object.prototype.toString) { - return obj.toString(); + // Check if the object is an error, and return the message of the error if + // so. + if (obj instanceof Error) { + return obj.message; + } + // Check if the object has a 'toString' method defined on it. To ensure + // that we don't crash or throw, check that the toString is a function, and + // also that the return value of toString is a string. + if (Object.prototype.hasOwnProperty.call(obj, "toString")) { + if (typeof obj.toString === "function") { + const str = obj.toString(); + if (typeof str === "string") { + return str; + } + } } // If the object does not have a custom toString, attempt to perform a - // JSON.stringify. + // JSON.stringify. We use a lot of bigints in libskynet, and calling + // JSON.stringify on an object with a bigint will cause a throw, so we add + // some custom handling to allow bigint objects to still be encoded. try { - return JSON.stringify(obj); + return JSON.stringify(obj, (_, v) => { + if (typeof v === "bigint") { + return v.toString(); + } + return v; + }); } - catch { + catch (err) { + if (err !== undefined && typeof err.message === "string") { + return `[stringify failed]: ${err.message}`; + } return "[stringify failed]"; } } // addContextToErr is a helper function that standardizes the formatting of - // adding context to an error. Within the world of go we discovered that being - // persistent about layering context onto errors is helpful when debugging, - // even though it often creates rather verbose error messages. - // - // addContextToErr will return null if the input err is null. + // adding context to an error. // // NOTE: To protect against accidental situations where an Error type or some // other type is provided instead of a string, we wrap both of the inputs with - // tryStringify before returning them. This prevents runtime failures. + // objAsString before returning them. This prevents runtime failures. function addContextToErr$1(err, context) { - if (err === null) { + if (err === null || err === undefined) { err = "[no error provided]"; } - return tryStringify$1(context) + ": " + tryStringify$1(err); - } - // composeErr takes a series of inputs and composes them into a single string. - // Each element will be separated by a newline. If the input is not a string, - // it will be transformed into a string with JSON.stringify. - // - // Any object that cannot be stringified will be skipped, though an error will - // be logged. - function composeErr$1(...inputs) { - let result = ""; - let resultEmpty = true; - for (let i = 0; i < inputs.length; i++) { - if (inputs[i] === null) { - continue; - } - if (resultEmpty) { - resultEmpty = false; - } - else { - result += "\n"; - } - result += tryStringify$1(inputs[i]); - } - if (resultEmpty) { - return null; - } - return result; + return objAsString(context) + ": " + objAsString(err); } - // Helper consts to make it easy to return empty values alongside errors. - const nu8$7 = new Uint8Array(0); + const MAX_UINT_64 = 18446744073709551615n; // bufToB64 will convert a Uint8Array to a base64 string with URL encoding and // no padding characters. function bufToB64$1(buf) { - let b64Str = btoa(String.fromCharCode.apply(null, buf)); - return b64Str.replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, ""); + const b64Str = btoa(String.fromCharCode(...buf)); + return b64Str.replaceAll("+", "-").replaceAll("/", "_").replaceAll("=", ""); } // encodeU64 will encode a bigint in the range of a uint64 to an 8 byte // Uint8Array. function encodeU64$1(num) { // Check the bounds on the bigint. if (num < 0) { - return [nu8$7, "expected a positive integer"]; + return [new Uint8Array(0), "expected a positive integer"]; } - if (num > 18446744073709551615n) { - return [nu8$7, "expected a number no larger than a uint64"]; + if (num > MAX_UINT_64) { + return [new Uint8Array(0), "expected a number no larger than a uint64"]; } // Encode the bigint into a Uint8Array. - let encoded = new Uint8Array(8); + const encoded = new Uint8Array(8); for (let i = 0; i < encoded.length; i++) { - let byte = Number(num & 0xffn); + const byte = Number(num & 0xffn); encoded[i] = byte; num = num >> 8n; } return [encoded, null]; } - let gfi$1 = function (init) { - let i, r = new Float64Array(16); + const gfi$1 = function (init) { + let i; + const r = new Float64Array(16); if (init) for (i = 0; i < init.length; i++) r[i] = init[i]; @@ -161,6 +162,38 @@ 0x2480, 0x2b83, ]); + // checkObj take an untrusted object and a list of typechecks to perform and + // will check that the object adheres to the typechecks. If a type is missing + // or has the wrong type, an error will be returned. This is intended to be + // used to check untrusted objects after they get decoded from JSON. This is + // particularly useful when receiving objects from untrusted entities over the + // network or over postMessage. + // + // Below is an example object, followed by the call that you would make to + // checkObj to verify the object. + // + // const expectedObj = { + // aNum: 35, + // aStr: "hi", + // aBig: 10n, + // }; + // + // const err = checkObj(expectedObj, [ + // ["aNum", "number"], + // ["aStr", "string"], + // ["aBig", "bigint"], + // ]); + function checkObj(obj, checks) { + for (let i = 0; i < checks.length; i++) { + const check = checks[i]; + const type = typeof obj[check[0]]; + if (type !== check[1]) { + return "check failed, expecting " + check[1] + " got " + type; + } + } + return null; + } + // Create the queryMap. let queries = {}; // Define the nonce handling. nonceSeed is 16 random bytes that get generated @@ -236,7 +269,12 @@ // at a minimum is working. if (initResolved === false) { initResolved = true; - initResolve(); + // We can't actually establish that init is complete until the + // kernel source has been set. This happens async and might happen + // after we receive the auth message. + sourcePromise.then(() => { + initResolve(); + }); } // If the auth status message says that login is complete, it means // that the user is logged in. @@ -314,6 +352,7 @@ kernelSource = iframe.contentWindow; kernelOrigin = "https://skt.us"; kernelAuthLocation = "https://skt.us/auth.html"; + sourceResolve(); // Set a timer to fail the login process if the kernel doesn't load in // time. setTimeout(() => { @@ -355,6 +394,7 @@ kernelOrigin = window.origin; kernelAuthLocation = "http://kernel.skynet/auth.html"; console.log("established connection to bridge, using browser extension for kernel"); + sourceResolve(); }); // Add the handler to the queries map. let nonce = nextNonce(); @@ -399,6 +439,8 @@ let kernelLoadedPromise; let logoutResolve; let logoutPromise; + let sourceResolve; + let sourcePromise; // resolves when the source is known and set function init() { // If init has already been called, just return the init promise. if (initialized === true) { @@ -422,6 +464,9 @@ logoutPromise = new Promise((resolve) => { logoutResolve = resolve; }); + sourcePromise = new Promise((resolve) => { + sourceResolve = resolve; + }); // Return the initPromise, which will resolve when bootloader init is // complete. return initPromise; @@ -430,7 +475,7 @@ // module identifier (typically a skylink), the second input is the method // being called on the module, and the final input is optional and contains // input data to be passed to the module. The input data will depend on the - // module and the method that is being called. The return value is an errTuple + // module and the method that is being called. The return value is an ErrTuple // that contains the module's response. The format of the response is an // arbitrary object whose fields depend on the module and method being called. // @@ -461,7 +506,7 @@ // as the receiveUpdate function, it's an arbitrary object whose fields depend // on the module and method being queried. // - // The second return value is a promise that returns an errTuple. It will + // The second return value is a promise that returns an ErrTuple. It will // resolve when the module sends a response message, and works the same as the // return value of callModule. function connectModule(module, method, data, receiveUpdate) { @@ -540,16 +585,14 @@ // kernel provides a 'response' message. The other is for internal use and // will resolve once the query has been created. let p; - let queryCreated; - let haveQueryCreated = new Promise((resolve) => { - queryCreated = resolve; + let haveQueryCreated = new Promise((queryCreatedResolve) => { p = new Promise((resolve) => { getNonce.then((nonce) => { queries[nonce] = { resolve }; if (receiveUpdate !== null && receiveUpdate !== undefined) { queries[nonce]["receiveUpdate"] = receiveUpdate; } - queryCreated(nonce); + queryCreatedResolve(nonce); }); }); }); @@ -653,6 +696,10 @@ // logoutComplete() will block until auth has reached stage 4. libkernel does // not support resetting the auth stages, once stage 4 has been reached the app // needs to refresh. + // loginComplete will resolve when the user has successfully logged in. + function loginComplete() { + return loginPromise; + } // kernelLoaded will resolve when the user has successfully loaded the kernel. // If there was an error in loading the kernel, the error will be returned. // @@ -660,10 +707,6 @@ function kernelLoaded() { return kernelLoadedPromise; } - // loginComplete will resolve when the user has successfully logged in. - function loginComplete() { - return loginPromise; - } // logoutComplete will resolve when the user has logged out. Note that // logoutComplete will only resolve if the user logged in first - if the user // was not logged in to begin with, this promise will not resolve. @@ -718,12 +761,27 @@ // because the object is relatively complex and all of the fields are more or // less required. function registryRead(publicKey, dataKey) { - let registryModule = "AQCovesg1AXUzKXLeRzQFILbjYMKr_rvNLsNhdq5GbYb2Q"; - let data = { - publicKey, - dataKey, - }; - return callModule(registryModule, "readEntry", data); + return new Promise((resolve) => { + let registryModule = "AQCovesg1AXUzKXLeRzQFILbjYMKr_rvNLsNhdq5GbYb2Q"; + let data = { + publicKey, + dataKey, + }; + callModule(registryModule, "readEntry", data).then(([result, err]) => { + if (err !== null) { + resolve([{}, addContextToErr$1(err, "readEntry module call failed")]); + return; + } + resolve([ + { + exists: result.exists, + entryData: result.entryData, + revision: result.revision, + }, + null, + ]); + }); + }); } // registryWrite will perform a registry write on a portal. // @@ -807,7 +865,7 @@ init: init, newKernelQuery: newKernelQuery, addContextToErr: addContextToErr$1, - composeErr: composeErr$1 + checkObj: checkObj }); var require$$0 = /*@__PURE__*/getAugmentedNamespace(dist$1);