toiljs 0.0.90 → 0.0.91

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,10 @@
1
1
  # Changelog
2
2
 
3
+ ## [v0.0.89] - 2026-07-04
4
+
5
+ - No changes
6
+
7
+
3
8
  ## [v0.0.87] - 2026-07-03
4
9
 
5
10
  - No changes
@@ -1 +1 @@
1
- {"fileNames":["../../node_modules/typescript/lib/lib.es5.d.ts","../../node_modules/typescript/lib/lib.es2015.d.ts","../../node_modules/typescript/lib/lib.es2016.d.ts","../../node_modules/typescript/lib/lib.es2017.d.ts","../../node_modules/typescript/lib/lib.es2018.d.ts","../../node_modules/typescript/lib/lib.es2019.d.ts","../../node_modules/typescript/lib/lib.es2020.d.ts","../../node_modules/typescript/lib/lib.es2021.d.ts","../../node_modules/typescript/lib/lib.es2022.d.ts","../../node_modules/typescript/lib/lib.es2023.d.ts","../../node_modules/typescript/lib/lib.es2024.d.ts","../../node_modules/typescript/lib/lib.es2025.d.ts","../../node_modules/typescript/lib/lib.esnext.d.ts","../../node_modules/typescript/lib/lib.dom.d.ts","../../node_modules/typescript/lib/lib.dom.iterable.d.ts","../../node_modules/typescript/lib/lib.es2015.core.d.ts","../../node_modules/typescript/lib/lib.es2015.collection.d.ts","../../node_modules/typescript/lib/lib.es2015.generator.d.ts","../../node_modules/typescript/lib/lib.es2015.iterable.d.ts","../../node_modules/typescript/lib/lib.es2015.promise.d.ts","../../node_modules/typescript/lib/lib.es2015.proxy.d.ts","../../node_modules/typescript/lib/lib.es2015.reflect.d.ts","../../node_modules/typescript/lib/lib.es2015.symbol.d.ts","../../node_modules/typescript/lib/lib.es2015.symbol.wellknown.d.ts","../../node_modules/typescript/lib/lib.es2016.array.include.d.ts","../../node_modules/typescript/lib/lib.es2016.intl.d.ts","../../node_modules/typescript/lib/lib.es2017.arraybuffer.d.ts","../../node_modules/typescript/lib/lib.es2017.date.d.ts","../../node_modules/typescript/lib/lib.es2017.object.d.ts","../../node_modules/typescript/lib/lib.es2017.sharedmemory.d.ts","../../node_modules/typescript/lib/lib.es2017.string.d.ts","../../node_modules/typescript/lib/lib.es2017.intl.d.ts","../../node_modules/typescript/lib/lib.es2017.typedarrays.d.ts","../../node_modules/typescript/lib/lib.es2018.asyncgenerator.d.ts","../../node_modules/typescript/lib/lib.es2018.asynciterable.d.ts","../../node_modules/typescript/lib/lib.es2018.intl.d.ts","../../node_modules/typescript/lib/lib.es2018.promise.d.ts","../../node_modules/typescript/lib/lib.es2018.regexp.d.ts","../../node_modules/typescript/lib/lib.es2019.array.d.ts","../../node_modules/typescript/lib/lib.es2019.object.d.ts","../../node_modules/typescript/lib/lib.es2019.string.d.ts","../../node_modules/typescript/lib/lib.es2019.symbol.d.ts","../../node_modules/typescript/lib/lib.es2019.intl.d.ts","../../node_modules/typescript/lib/lib.es2020.bigint.d.ts","../../node_modules/typescript/lib/lib.es2020.date.d.ts","../../node_modules/typescript/lib/lib.es2020.promise.d.ts","../../node_modules/typescript/lib/lib.es2020.sharedmemory.d.ts","../../node_modules/typescript/lib/lib.es2020.string.d.ts","../../node_modules/typescript/lib/lib.es2020.symbol.wellknown.d.ts","../../node_modules/typescript/lib/lib.es2020.intl.d.ts","../../node_modules/typescript/lib/lib.es2020.number.d.ts","../../node_modules/typescript/lib/lib.es2021.promise.d.ts","../../node_modules/typescript/lib/lib.es2021.string.d.ts","../../node_modules/typescript/lib/lib.es2021.weakref.d.ts","../../node_modules/typescript/lib/lib.es2021.intl.d.ts","../../node_modules/typescript/lib/lib.es2022.array.d.ts","../../node_modules/typescript/lib/lib.es2022.error.d.ts","../../node_modules/typescript/lib/lib.es2022.intl.d.ts","../../node_modules/typescript/lib/lib.es2022.object.d.ts","../../node_modules/typescript/lib/lib.es2022.string.d.ts","../../node_modules/typescript/lib/lib.es2022.regexp.d.ts","../../node_modules/typescript/lib/lib.es2023.array.d.ts","../../node_modules/typescript/lib/lib.es2023.collection.d.ts","../../node_modules/typescript/lib/lib.es2023.intl.d.ts","../../node_modules/typescript/lib/lib.es2024.arraybuffer.d.ts","../../node_modules/typescript/lib/lib.es2024.collection.d.ts","../../node_modules/typescript/lib/lib.es2024.object.d.ts","../../node_modules/typescript/lib/lib.es2024.promise.d.ts","../../node_modules/typescript/lib/lib.es2024.regexp.d.ts","../../node_modules/typescript/lib/lib.es2024.sharedmemory.d.ts","../../node_modules/typescript/lib/lib.es2024.string.d.ts","../../node_modules/typescript/lib/lib.es2025.collection.d.ts","../../node_modules/typescript/lib/lib.es2025.float16.d.ts","../../node_modules/typescript/lib/lib.es2025.intl.d.ts","../../node_modules/typescript/lib/lib.es2025.iterator.d.ts","../../node_modules/typescript/lib/lib.es2025.promise.d.ts","../../node_modules/typescript/lib/lib.es2025.regexp.d.ts","../../node_modules/typescript/lib/lib.esnext.array.d.ts","../../node_modules/typescript/lib/lib.esnext.collection.d.ts","../../node_modules/typescript/lib/lib.esnext.date.d.ts","../../node_modules/typescript/lib/lib.esnext.decorators.d.ts","../../node_modules/typescript/lib/lib.esnext.disposable.d.ts","../../node_modules/typescript/lib/lib.esnext.error.d.ts","../../node_modules/typescript/lib/lib.esnext.intl.d.ts","../../node_modules/typescript/lib/lib.esnext.sharedmemory.d.ts","../../node_modules/typescript/lib/lib.esnext.temporal.d.ts","../../node_modules/typescript/lib/lib.esnext.typedarrays.d.ts","../../node_modules/typescript/lib/lib.decorators.d.ts","../../node_modules/typescript/lib/lib.decorators.legacy.d.ts","../../node_modules/@types/react/global.d.ts","../../node_modules/csstype/index.d.ts","../../node_modules/@types/react/index.d.ts","../../node_modules/@types/react/jsx-runtime.d.ts","../../node_modules/hash-wasm/dist/lib/util.d.ts","../../node_modules/hash-wasm/dist/lib/WASMInterface.d.ts","../../node_modules/hash-wasm/dist/lib/adler32.d.ts","../../node_modules/hash-wasm/dist/lib/argon2.d.ts","../../node_modules/hash-wasm/dist/lib/blake2b.d.ts","../../node_modules/hash-wasm/dist/lib/blake2s.d.ts","../../node_modules/hash-wasm/dist/lib/blake3.d.ts","../../node_modules/hash-wasm/dist/lib/crc32.d.ts","../../node_modules/hash-wasm/dist/lib/crc64.d.ts","../../node_modules/hash-wasm/dist/lib/md4.d.ts","../../node_modules/hash-wasm/dist/lib/md5.d.ts","../../node_modules/hash-wasm/dist/lib/sha1.d.ts","../../node_modules/hash-wasm/dist/lib/sha3.d.ts","../../node_modules/hash-wasm/dist/lib/keccak.d.ts","../../node_modules/hash-wasm/dist/lib/sha224.d.ts","../../node_modules/hash-wasm/dist/lib/sha256.d.ts","../../node_modules/hash-wasm/dist/lib/sha384.d.ts","../../node_modules/hash-wasm/dist/lib/sha512.d.ts","../../node_modules/hash-wasm/dist/lib/xxhash32.d.ts","../../node_modules/hash-wasm/dist/lib/xxhash64.d.ts","../../node_modules/hash-wasm/dist/lib/xxhash3.d.ts","../../node_modules/hash-wasm/dist/lib/xxhash128.d.ts","../../node_modules/hash-wasm/dist/lib/ripemd160.d.ts","../../node_modules/hash-wasm/dist/lib/hmac.d.ts","../../node_modules/hash-wasm/dist/lib/pbkdf2.d.ts","../../node_modules/hash-wasm/dist/lib/scrypt.d.ts","../../node_modules/hash-wasm/dist/lib/bcrypt.d.ts","../../node_modules/hash-wasm/dist/lib/whirlpool.d.ts","../../node_modules/hash-wasm/dist/lib/sm3.d.ts","../../node_modules/hash-wasm/dist/lib/index.d.ts","../../node_modules/@noble/hashes/utils.d.ts","../../node_modules/@dacely/noble-post-quantum/utils.d.ts","../../node_modules/@dacely/noble-post-quantum/ml-dsa.d.ts","../../node_modules/@dacely/noble-post-quantum/ml-kem.d.ts","../../node_modules/@noble/curves/utils.d.ts","../../node_modules/@noble/curves/abstract/modular.d.ts","../../node_modules/@noble/curves/abstract/curve.d.ts","../../node_modules/@noble/curves/abstract/edwards.d.ts","../../node_modules/@noble/curves/abstract/hash-to-curve.d.ts","../../node_modules/@noble/curves/abstract/frost.d.ts","../../node_modules/@noble/curves/abstract/montgomery.d.ts","../../node_modules/@noble/curves/abstract/oprf.d.ts","../../node_modules/@noble/curves/ed25519.d.ts","../io/FastMap.d.ts","../io/FastSet.d.ts","../io/codec.d.ts","../io/types.d.ts","../io/index.d.ts","../../src/client/auth.ts","../../src/client/errors.ts","../../node_modules/@types/react-dom/client.d.ts","../../node_modules/@types/react-dom/index.d.ts","../../src/client/navigation/scroll.ts","../../src/client/types.ts","../../src/client/navigation/navigation.ts","../../src/client/ssr/markers.tsx","../../src/client/head/head.ts","../../src/client/routing/match.ts","../../src/client/head/metadata.ts","../../src/client/routing/loader.ts","../../src/client/navigation/prefetch.ts","../../src/client/routing/error-boundary.tsx","../../src/client/routing/params-context.ts","../../src/client/routing/hooks.ts","../../src/client/routing/lazy.ts","../../src/client/routing/slot-context.ts","../../src/client/routing/Router.tsx","../../src/client/dev/error-overlay.tsx","../../src/client/search/search.ts","../../src/client/dev/devtools.tsx","../../src/client/routing/mount.tsx","../../src/client/navigation/Link.tsx","../../src/client/navigation/NavLink.tsx","../../src/client/routing/action.ts","../../src/client/channel/channel.ts","../../src/client/stream/client.ts","../../src/client/search/use-page-search.ts","../../src/client/components/Image.tsx","../../src/client/components/Script.tsx","../../src/client/components/Form.tsx","../../src/client/components/Slot.tsx","../../src/client/rpc.ts","../../src/client/index.ts"],"fileIdsList":[[137],[137,138,139,140],[125],[124],[128,129],[128,129,130],[128,129,130,132],[128],[128,130],[128,130,132],[128,129,130,131,132,133,134,135],[92],[90,91],[94],[94,95],[94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122],[93,123,126,127,136,141],[92,93],[92,93,167],[92,93,159],[92,93,147,148,151,153,161,162],[93],[92,93,149],[93,150,151],[93,142,143,147,148,149,150,151,152,153,154,157,160,162,164,165,166,167,168,169,170,171,172,173,174,175],[92,93,147,148,154],[92,93,157,165],[92,93,145,146,147],[93,147,151,153],[92,93,146,147,148,150,151,153,155,156,157,158,159],[92,93,147,148,153],[92,93,147],[92,93,147,148,151,153,154,156],[92,93,147,148,150,151,152],[93,144,147,148,154,160,161,163],[92,93,151],[93,152],[92,93,147,148,162]],"fileInfos":[{"version":"bcd24271a113971ba9eb71ff8cb01bc6b0f872a85c23fdbe5d93065b375933cd","affectsGlobalScope":true,"impliedFormat":1},{"version":"3f88bedbeb09c6f5a6645cb24c7c55f1aa22d19ae96c8e6959cbd8b85a707bc6","impliedFormat":1},{"version":"7fe93b39b810eadd916be8db880dd7f0f7012a5cc6ffb62de8f62a2117fa6f1f","impliedFormat":1},{"version":"bb0074cc08b84a2374af33d8bf044b80851ccc9e719a5e202eacf40db2c31600","impliedFormat":1},{"version":"1a7daebe4f45fb03d9ec53d60008fbf9ac45a697fdc89e4ce218bc94b94f94d6","impliedFormat":1},{"version":"f94b133a3cb14a288803be545ac2683e0d0ff6661bcd37e31aaaec54fc382aed","impliedFormat":1},{"version":"f59d0650799f8782fd74cf73c19223730c6d1b9198671b1c5b3a38e1188b5953","impliedFormat":1},{"version":"8a15b4607d9a499e2dbeed9ec0d3c0d7372c850b2d5f1fb259e8f6d41d468a84","impliedFormat":1},{"version":"26e0fe14baee4e127f4365d1ae0b276f400562e45e19e35fd2d4c296684715e6","impliedFormat":1},{"version":"1e9332c23e9a907175e0ffc6a49e236f97b48838cc8aec9ce7e4cec21e544b65","impliedFormat":1},{"version":"3753fbc1113dc511214802a2342280a8b284ab9094f6420e7aa171e868679f91","impliedFormat":1},{"version":"999ca32883495a866aa5737fe1babc764a469e4cde6ee6b136a4b9ae68853e4b","impliedFormat":1},{"version":"17f13ecb98cbc39243f2eee1f16d45cd8ec4706b03ee314f1915f1a8b42f6984","impliedFormat":1},{"version":"d6b1eba8496bdd0eed6fc8a685768fe01b2da4a0388b5fe7df558290bffcf32f","affectsGlobalScope":true,"impliedFormat":1},{"version":"7f57fc4404ff020bc45b9c620aff2b40f700b95fe31164024c453a5e3c163c54","impliedFormat":1},{"version":"eadcffda2aa84802c73938e589b9e58248d74c59cb7fcbca6474e3435ac15504","affectsGlobalScope":true,"impliedFormat":1},{"version":"105ba8ff7ba746404fe1a2e189d1d3d2e0eb29a08c18dded791af02f29fb4711","affectsGlobalScope":true,"impliedFormat":1},{"version":"00343ca5b2e3d48fa5df1db6e32ea2a59afab09590274a6cccb1dbae82e60c7c","affectsGlobalScope":true,"impliedFormat":1},{"version":"ebd9f816d4002697cb2864bea1f0b70a103124e18a8cd9645eeccc09bdf80ab4","affectsGlobalScope":true,"impliedFormat":1},{"version":"2c1afac30a01772cd2a9a298a7ce7706b5892e447bb46bdbeef720f7b5da77ad","affectsGlobalScope":true,"impliedFormat":1},{"version":"7b0225f483e4fa685625ebe43dd584bb7973bbd84e66a6ba7bbe175ee1048b4f","affectsGlobalScope":true,"impliedFormat":1},{"version":"c0a4b8ac6ce74679c1da2b3795296f5896e31c38e888469a8e0f99dc3305de60","affectsGlobalScope":true,"impliedFormat":1},{"version":"3084a7b5f569088e0146533a00830e206565de65cae2239509168b11434cd84f","affectsGlobalScope":true,"impliedFormat":1},{"version":"c5079c53f0f141a0698faa903e76cb41cd664e3efb01cc17a5c46ec2eb0bef42","affectsGlobalScope":true,"impliedFormat":1},{"version":"32cafbc484dea6b0ab62cf8473182bbcb23020d70845b406f80b7526f38ae862","affectsGlobalScope":true,"impliedFormat":1},{"version":"fca4cdcb6d6c5ef18a869003d02c9f0fd95df8cfaf6eb431cd3376bc034cad36","affectsGlobalScope":true,"impliedFormat":1},{"version":"b93ec88115de9a9dc1b602291b85baf825c85666bf25985cc5f698073892b467","affectsGlobalScope":true,"impliedFormat":1},{"version":"f5c06dcc3fe849fcb297c247865a161f995cc29de7aa823afdd75aaaddc1419b","affectsGlobalScope":true,"impliedFormat":1},{"version":"b77e16112127a4b169ef0b8c3a4d730edf459c5f25fe52d5e436a6919206c4d7","affectsGlobalScope":true,"impliedFormat":1},{"version":"fbffd9337146eff822c7c00acbb78b01ea7ea23987f6c961eba689349e744f8c","affectsGlobalScope":true,"impliedFormat":1},{"version":"a995c0e49b721312f74fdfb89e4ba29bd9824c770bbb4021d74d2bf560e4c6bd","affectsGlobalScope":true,"impliedFormat":1},{"version":"c7b3542146734342e440a84b213384bfa188835537ddbda50d30766f0593aff9","affectsGlobalScope":true,"impliedFormat":1},{"version":"ce6180fa19b1cccd07ee7f7dbb9a367ac19c0ed160573e4686425060b6df7f57","affectsGlobalScope":true,"impliedFormat":1},{"version":"3f02e2476bccb9dbe21280d6090f0df17d2f66b74711489415a8aa4df73c9675","affectsGlobalScope":true,"impliedFormat":1},{"version":"45e3ab34c1c013c8ab2dc1ba4c80c780744b13b5676800ae2e3be27ae862c40c","affectsGlobalScope":true,"impliedFormat":1},{"version":"805c86f6cca8d7702a62a844856dbaa2a3fd2abef0536e65d48732441dde5b5b","affectsGlobalScope":true,"impliedFormat":1},{"version":"e42e397f1a5a77994f0185fd1466520691456c772d06bf843e5084ceb879a0ad","affectsGlobalScope":true,"impliedFormat":1},{"version":"f4c2b41f90c95b1c532ecc874bd3c111865793b23aebcc1c3cbbabcd5d76ffb0","affectsGlobalScope":true,"impliedFormat":1},{"version":"ab26191cfad5b66afa11b8bf935ef1cd88fabfcb28d30b2dfa6fad877d050332","affectsGlobalScope":true,"impliedFormat":1},{"version":"2088bc26531e38fb05eedac2951480db5309f6be3fa4a08d2221abb0f5b4200d","affectsGlobalScope":true,"impliedFormat":1},{"version":"cb9d366c425fea79716a8fb3af0d78e6b22ebbab3bd64d25063b42dc9f531c1e","affectsGlobalScope":true,"impliedFormat":1},{"version":"500934a8089c26d57ebdb688fc9757389bb6207a3c8f0674d68efa900d2abb34","affectsGlobalScope":true,"impliedFormat":1},{"version":"689da16f46e647cef0d64b0def88910e818a5877ca5379ede156ca3afb780ac3","affectsGlobalScope":true,"impliedFormat":1},{"version":"bc21cc8b6fee4f4c2440d08035b7ea3c06b3511314c8bab6bef7a92de58a2593","affectsGlobalScope":true,"impliedFormat":1},{"version":"7ca53d13d2957003abb47922a71866ba7cb2068f8d154877c596d63c359fed25","affectsGlobalScope":true,"impliedFormat":1},{"version":"54725f8c4df3d900cb4dac84b64689ce29548da0b4e9b7c2de61d41c79293611","affectsGlobalScope":true,"impliedFormat":1},{"version":"e5594bc3076ac29e6c1ebda77939bc4c8833de72f654b6e376862c0473199323","affectsGlobalScope":true,"impliedFormat":1},{"version":"2f3eb332c2d73e729f3364fcc0c2b375e72a121e8157d25a82d67a138c83a95c","affectsGlobalScope":true,"impliedFormat":1},{"version":"6f4427f9642ce8d500970e4e69d1397f64072ab73b97e476b4002a646ac743b1","affectsGlobalScope":true,"impliedFormat":1},{"version":"48915f327cd1dea4d7bd358d9dc7732f58f9e1626a29cc0c05c8c692419d9bb7","affectsGlobalScope":true,"impliedFormat":1},{"version":"b7bf9377723203b5a6a4b920164df22d56a43f593269ba6ae1fdc97774b68855","affectsGlobalScope":true,"impliedFormat":1},{"version":"db9709688f82c9e5f65a119c64d835f906efe5f559d08b11642d56eb85b79357","affectsGlobalScope":true,"impliedFormat":1},{"version":"4b25b8c874acd1a4cf8444c3617e037d444d19080ac9f634b405583fd10ce1f7","affectsGlobalScope":true,"impliedFormat":1},{"version":"37be57d7c90cf1f8112ee2636a068d8fd181289f82b744160ec56a7dc158a9f5","affectsGlobalScope":true,"impliedFormat":1},{"version":"a917a49ac94cd26b754ab84e113369a75d1a47a710661d7cd25e961cc797065f","affectsGlobalScope":true,"impliedFormat":1},{"version":"6d3261badeb7843d157ef3e6f5d1427d0eeb0af0cf9df84a62cfd29fd47ac86e","affectsGlobalScope":true,"impliedFormat":1},{"version":"195daca651dde22f2167ac0d0a05e215308119a3100f5e6268e8317d05a92526","affectsGlobalScope":true,"impliedFormat":1},{"version":"8b11e4285cd2bb164a4dc09248bdec69e9842517db4ca47c1ba913011e44ff2f","affectsGlobalScope":true,"impliedFormat":1},{"version":"0508571a52475e245b02bc50fa1394065a0a3d05277fbf5120c3784b85651799","affectsGlobalScope":true,"impliedFormat":1},{"version":"8f9af488f510c3015af3cc8c267a9e9d96c4dd38a1fdff0e11dc5a544711415b","affectsGlobalScope":true,"impliedFormat":1},{"version":"fc611fea8d30ea72c6bbfb599c9b4d393ce22e2f5bfef2172534781e7d138104","affectsGlobalScope":true,"impliedFormat":1},{"version":"0bd714129fca875f7d4c477a1a392200b0bcd13fb2e80928cd334b63830ea047","affectsGlobalScope":true,"impliedFormat":1},{"version":"e2c9037ae6cd2c52d80ceef0b3c5ffdb488627d71529cf4f63776daf11161c9a","affectsGlobalScope":true,"impliedFormat":1},{"version":"135d5cf4d345f59f1a9caadfafcd858d3d9cc68290db616cc85797224448cccc","affectsGlobalScope":true,"impliedFormat":1},{"version":"bc238c3f81c2984751932b6aab223cd5b830e0ac6cad76389e5e9d2ffc03287d","affectsGlobalScope":true,"impliedFormat":1},{"version":"4a07f9b76d361f572620927e5735b77d6d2101c23cdd94383eb5b706e7b36357","affectsGlobalScope":true,"impliedFormat":1},{"version":"7c4e8dc6ab834cc6baa0227e030606d29e3e8449a9f67cdf5605ea5493c4db29","affectsGlobalScope":true,"impliedFormat":1},{"version":"de7ba0fd02e06cd9a5bd4ab441ed0e122735786e67dde1e849cced1cd8b46b78","affectsGlobalScope":true,"impliedFormat":1},{"version":"6148e4e88d720a06855071c3db02069434142a8332cf9c182cda551adedf3156","affectsGlobalScope":true,"impliedFormat":1},{"version":"d63dba625b108316a40c95a4425f8d4294e0deeccfd6c7e59d819efa19e23409","affectsGlobalScope":true,"impliedFormat":1},{"version":"0568d6befee03dd435bed4fc25c4e46865b24bdcb8c563fdc21f580a2c301904","affectsGlobalScope":true,"impliedFormat":1},{"version":"30d62269b05b584741f19a5369852d5d34895aa2ac4fd948956f886d15f9cc0d","affectsGlobalScope":true,"impliedFormat":1},{"version":"f128dae7c44d8f35ee42e0a437000a57c9f06cc04f8b4fb42eebf44954d53dc8","affectsGlobalScope":true,"impliedFormat":1},{"version":"ffbe6d7b295306b2ba88030f65b74c107d8d99bdcf596ea99c62a02f606108b0","affectsGlobalScope":true,"impliedFormat":1},{"version":"996fb27b15277369c68a4ba46ed138b4e9e839a02fb4ec756f7997629242fd9f","affectsGlobalScope":true,"impliedFormat":1},{"version":"79b712591b270d4778c89706ca2cfc56ddb8c3f895840e477388f1710dc5eda9","affectsGlobalScope":true,"impliedFormat":1},{"version":"20884846cef428b992b9bd032e70a4ef88e349263f63aeddf04dda837a7dba26","affectsGlobalScope":true,"impliedFormat":1},{"version":"5fcab789c73a97cd43828ee3cc94a61264cf24d4c44472ce64ced0e0f148bdb2","affectsGlobalScope":true,"impliedFormat":1},{"version":"db59a81f070c1880ad645b2c0275022baa6a0c4f0acdc58d29d349c6efcf0903","affectsGlobalScope":true,"impliedFormat":1},{"version":"673294292640f5722b700e7d814e17aaf7d93f83a48a2c9b38f33cbc940ad8b0","affectsGlobalScope":true,"impliedFormat":1},{"version":"d786b48f934cbca483b3c6d0a798cb43bbb4ada283e76fb22c28e53ae05b9e69","affectsGlobalScope":true,"impliedFormat":1},{"version":"1ecb8e347cb6b2a8927c09b86263663289418df375f5e68e11a0ae683776978f","affectsGlobalScope":true,"impliedFormat":1},{"version":"142efd4ce210576f777dc34df121777be89eda476942d6d6663b03dcb53be3ff","affectsGlobalScope":true,"impliedFormat":1},{"version":"379bc41580c2d774f82e828c70308f24a005b490c25ba34d679d84bcf05c3d9d","affectsGlobalScope":true,"impliedFormat":1},{"version":"ed484fb2aa8a1a23d0277056ec3336e0a0b52f9b8d6a961f338a642faf43235d","affectsGlobalScope":true,"impliedFormat":1},{"version":"4ffedae1d1c2d53fdbca1c96d3c7dda544281f7d262f99b6880634f8fd8d9820","affectsGlobalScope":true,"impliedFormat":1},{"version":"83a730b125d477dd264df8ba479afab27a3dae7152b005c214ab94dc7ee44fd3","affectsGlobalScope":true,"impliedFormat":1},{"version":"1ce14b81c5cc821994aa8ec1d42b220dd41b27fcc06373bce3958af7421b77d4","affectsGlobalScope":true,"impliedFormat":1},{"version":"b3a048b3e9302ef9a34ef4ebb9aecfb28b66abb3bce577206a79fee559c230da","affectsGlobalScope":true,"impliedFormat":1},{"version":"7e29f41b158de217f94cb9676bf9cbd0cd9b5a46e1985141ed36e075c52bf6ad","affectsGlobalScope":true,"impliedFormat":1},{"version":"ac51dd7d31333793807a6abaa5ae168512b6131bd41d9c5b98477fc3b7800f9f","impliedFormat":1},{"version":"dc782ff85b2cb10075ecffc158af7bfb27ff97bf8491c917efea0c3d622d5ac4","impliedFormat":1},{"version":"b838d4c72740eb0afd284bf7575b74c624b105eff2e8c7b4aeead57e7ac320ff","impliedFormat":1},{"version":"a957a1395986cd6863bae5a42c58d66886df90f1931c911fbe406f8321335e6f","impliedFormat":1},{"version":"a2bc59da4f44ff533bd0b7ea20946f8c52eae8895531746dee71603e3b7d5578","impliedFormat":1},{"version":"9828342b073c3d2a51680d84be6e8693c15209142d4c3c49f9af9ad3e8a9dacc","impliedFormat":1},{"version":"7cabf9ff89f3a1de0524b3a50265ba1294a88e495e114dcae8da0cbc50fc92f2","impliedFormat":1},{"version":"9d7a70722e17134d5eab42d3dd710eacbe42fd1210d80287f6639c29ee2a7c10","impliedFormat":1},{"version":"165409ea4281fef67eea472050347967441004e84d22a8977a94e1976823d5be","impliedFormat":1},{"version":"505abecc03fe091b97b747dc320fff4679344de28c922564193151c0cefb3180","impliedFormat":1},{"version":"0f90009e6c417c9336b260496ea53729a9c70933895e2ce545fff272b9301bb2","impliedFormat":1},{"version":"c0a488e0b571aec7a957ecad80792af284c357b48ba6d2d8b4444aa2be6c5a2f","impliedFormat":1},{"version":"ff2ce6f20d8c9346ab61a3444f5bca603f327d26352eb0ab6f40cb1f48e84c84","impliedFormat":1},{"version":"7c9fc8fbe28c6fe364d78be412d8467619b87dc828f2cf5ef525db7d7837c9f7","impliedFormat":1},{"version":"c824d703f55424408de202f826ff50eced9ad4c07edf12ff99fef7a7ca820f5b","impliedFormat":1},{"version":"6efbf9b08c3e5a48b93858e7b96eb61f9ca6d5c5d27709dc16f806e0ba1067cc","impliedFormat":1},{"version":"1b6d8a8926e323af55c6777a6f6561191ea3da6beabe8e7d91c152df3c693bac","impliedFormat":1},{"version":"587173d12395c6996972afd696425044d322eb0174e76d7d5888caf35d88831d","impliedFormat":1},{"version":"de5ba33082f9ac12bd6a9e44c530a5dd708d145fff6cc2dd7cb30321a8882a6b","impliedFormat":1},{"version":"a50a03f03f65f3cc4e012c86464f310755462c7059f1581a9c666b5457d102e1","impliedFormat":1},{"version":"89b954bd9c00a77ce3d889e1cc78b034779e2593fe0adfa14b6e56baafeb5de2","impliedFormat":1},{"version":"9935b6341ac96a5027526efc1ec75114ccf2009b6ed602f65bc82e75ac2089b1","impliedFormat":1},{"version":"f8776dc3e57237b3de45b8ab5f224adc00dd90fe217f1a34ed6442606807c122","impliedFormat":1},{"version":"b0c8c7af35a444fd4054c12d971eabcd7ec4be2e840fc60f8897b5732cb3a20b","impliedFormat":1},{"version":"4f9bd8f00fe9f0ae8b5d2fffed8d47915b61b428e33b2ee9aa3ef159e98e305c","impliedFormat":1},{"version":"bbe6c08cefd08a23dc36eca9dae8aeb30895debf15387ab6904b591e3b6b3217","impliedFormat":1},{"version":"0c3880ad1eee5252b7f02c6ff10bd2666cb9a59ae698d552ec5b0a4a7b9611d8","impliedFormat":1},{"version":"d5d71ded265f144dec6604983fbfaf201844d7cd8614aadab8ad5227e99545d3","impliedFormat":1},{"version":"907d2ea3b3fed567fe2dff6747f7642f57aa8b3c288becf4843113ac98331ee3","impliedFormat":1},{"version":"33da6d63dbab160960cdd6e1dba0716bbc2f60af4aeb229ea9b318303c2015e1","impliedFormat":1},{"version":"6dc0148fe65a487db8bd552670f0fe87498c0a8e644c38092a185a05030282bf","impliedFormat":1},{"version":"6bd476fd8a150f5211488cc1d58d412dabec0da0977295ea1f06957b1d28ed13","impliedFormat":1},{"version":"5e134f083c46ea016764a484ac86f664564303f87bc3ca7cfd4b74ccbacad282","impliedFormat":1},{"version":"5d01f288556ba56b803dfbd9b207502aaaa831afddd9e71b2b5ce250dc395152","impliedFormat":99},{"version":"7b9d4f3cc667e8896241f6c95d2824ced607ce7f2858cedf04058ddd23287602","impliedFormat":99},{"version":"371e624178bb67607b2c63e1f8ec3e5d9585455b39bac8f0816eba540072383f","impliedFormat":99},{"version":"c468447508a5ca66c0a2523ed935cf5cb1d768d890c991e20397df618db741d1","impliedFormat":99},{"version":"b8c741cb7cd15e89b24af6c25b6d95a581b2d79f7c0d959552220743f7269c7f","impliedFormat":99},{"version":"1b65eaf896a59cf1904bae76e68bc64941671555a3b1ee4190bcd6d3b16d5b61","impliedFormat":99},{"version":"2cea0605228c4357d9f57b6d13fd607752579a0a70995ccf70179110b098435b","impliedFormat":99},{"version":"edc4a14bf998e6512257766b4f291c940b5e88fe8bea8aec0c499e2e41da1d34","impliedFormat":99},{"version":"74853f56c2d22c7794408839dc106c4c412818fbd2e855b1d7dc4a70447f8387","impliedFormat":99},{"version":"61d04e1fb8987919928a5c4982fe4b32ec4147bd39491b4da9720bb518fd77ce","impliedFormat":99},{"version":"c1d730d8774ef9d198a2f8ecedd6806b1efd9e00a502ba7e28969f5a2c550ae1","impliedFormat":99},{"version":"9155fc738cfdd9a8dbeb7a9657998407101fc278c1649d8bb24b24b4fc7e5ad4","impliedFormat":99},{"version":"aa9a3b2c5d46f501a49ebde65cbdd59a7c05122f4f15785467bc30b6d8956751","impliedFormat":99},"6a4c287c863003342a42d8bf876c7df4c2e82e95f556af5ade71f05255845200","272e7bc3a3734cc9e7419625f04cff7095131e315e51a83fa992a5134763df49","b9f2341c8b486561706db362b6f89ee6b149ef08fb4fa6aaea1041bce04fe1c5","3952955b5e83c1164fc78d7d54377fd4d09d2c11b79763cba53a7ff4b27a0601","48d0d0bebe2ccfd875953713d746fe4adae81b1e3a91ffafae29ead23fd5c39b",{"version":"e940f4c8d46e3c778bdc3ca33620728b2a49540bd998811f9ba94a86d049b715","signature":"5dd87edc1a272a3f093635f78daaa539d6fbd858e22fc90496b52e3577010e2e"},{"version":"cbc4073fb15a767ab8787ce067b3266807ea2ef8456aa85e3a55ff5a62c33bdd","signature":"7cf224e300294bcb276cf440125703dd0da90e1b5aa8070a3f7ca043475979c1"},{"version":"bc03c3c352f689e38c0ddd50c39b1e65d59273991bfc8858a9e3c0ebb79c023b","impliedFormat":1},{"version":"be1cc4d94ea60cbe567bc29ed479d42587bf1e6cba490f123d329976b0fe4ee5","impliedFormat":1},{"version":"dbafe5664a764167d089a3ecce720259c6f4837696f2cf5e0adb199de6a9150c","signature":"2b2db01796f774852b44cacad054f31b9e63a3c4ed787d12c1dd75c75e602bef"},{"version":"43c268c58c28f2f6f80bc2a42104a2e8ce3891d1c8a2b8767e2a52606e61952b","signature":"d86aae3a61fb2a3734379428044eefd6b048996f3a1a1cd7e57bb94d3d36b02b"},{"version":"31946b8cd45a08d2f4d3be4e8b31b5896e5f0fb24840cc53e6d9a45d71e24506","signature":"50c12b83406070a98041a222f49db12395234ac00db0f16d18d01d8fccfe9d9d"},{"version":"2a0b3b70eae3ac89e80870431490787f00d5b450b6c9767df4daf6aee7eb0978","signature":"dd11f115ef46b611836fe84d45fb6f7889711397a69aad6cc147739cbe5a4072"},{"version":"1f97d3daade701681d6c89a1904123b009db72bdf95ec5fd563076769da2339c","signature":"c12ee6242f6e1108c7cfac4089b422a742417d50a70cbb03d0d24b7217271376"},{"version":"f6eaf207ae99ba6778460fa1d857e80c870be1533e9b1668060f0f53e6aa6b41","signature":"b9f112f8e9a593f362dd5f434f8f997385dd62f15e2d2fb6d316e5d0d9942a51"},{"version":"6647f68fcaa6a2a028711abf7288cd95d8625d0efff1315b5ad3536bf2de9e2b","signature":"919e52d8be47dbe1be9f86aff4b897c9801b8d6d0bf49f68fc321a4dc9251ad4"},{"version":"ef23db21116b6651538dbcb7df065b8340d6b2514bce598087309f5f435a2bcb","signature":"ba8cda0a8ef4aaa88a574d7e25ea6eaac5e6b9a25c862afdd948d8b6780014b6"},{"version":"26a4fb1b862a479d7a5d90aa1745f070d44bc351e79c6e4f8a6481b206a1655b","signature":"ad70244d75add3a5819000694ceb8f6ffca2fff2bd49acbd6786e1457c9d1d82","affectsGlobalScope":true},{"version":"abdc0918e0afd85d5495c618d95ea69c667d1cd095452cc73617168c784904a4","signature":"9382f138465c4775c54940f2a3d4334a083a6fc9a622a7c926c5f8233228cbae"},{"version":"336f74bb2ca217a8b08f3c146c41295de7597a86d52ca333fac5634561261846","signature":"c8525f0be940a19f3d03f06b6e43d4bea21ba910db62fb5024ecc671bcc23932"},{"version":"eb5c9b96b9b90a2c7abd1dd62be278b51ef4fcc1a7181fb7294ae1554b5d2409","signature":"90b4955becdfa8d37df7a1fdd1c93d847cdbea6bb3a113bd3baa6134291531a2"},{"version":"bdf04d4dd9ed94c85da1be565643ef5fad4212b7a545da8f4792deb4cf426665","signature":"c6384012cac726d5b05237d2bd2c9c9da0893feaf54ab1dd0042fe141b9e5bd8"},{"version":"1ac886967a62c940d61ab89f3411f64893d779d69e1435f15215547ba50fa03b","signature":"994bfb8326dca5c985462ba74b5c64146aef0e3ea7bbbbf265ad426d884fbc9e"},{"version":"314ad9d994327a7e9cc1367c1c56fb3f28737fc85716317e01f7649a02e6303b","signature":"00dd4ce0458ebf64e2e0617d4bc04f3a9a569bc388f3a20c1c4416d465e99245"},{"version":"b7a6fa2ad0bbeb531d9fc2a4003d5cc4a6e8142c18914fb2d034ca8b32b760fc","signature":"61814a0254524d3e14d405795a649b8b838386ff0f82caf50a0b7d4c72008c3d"},{"version":"3fcfd875b042c0855e76061aae81b0d8333c1990c1e4ca4d1f3141652b988b06","signature":"b43c263b28c6f20a6d7066e22f6906fe51605b6a4b7709a3c47d7cf6c0ccf93e"},{"version":"1e54ebe6806cac6a9b2ce78a54863cd75732cc68901256507042e3d8cd399224","signature":"58d2bb278ba2b594a3b664571b357e10388c6a1eef2c27e2946d3ee447fb4e16"},{"version":"f40083b8ea073895257a2f5ef2bfc9b8cf031d471744fe76185ecc259847d49b","signature":"e5f0e0e21621bb3e87958857cc9695abf011fb257bd249abd42ae97b3b61e1d0"},{"version":"91df3defe1f0907af6b80d1b7849615c72b36340404efb0bbf6f9fb1f99727fc","signature":"5cf43ceac60fba7927af9ce9b27fb6031854fc923263b78c353fb986857218b9"},{"version":"64837fd5187d6a3c2abc6a265251be66c4a9961c369e5cf647ac87511d328d90","signature":"0caa217adbbdb001facd9aeb363fa2a446eabbeb4e5af2c1f2c3d1ef4bbffc6e"},{"version":"40896dfcdeafc76e4d85bfd4acca390f542032e613c6f5b7c5c8e1e99bb3b63d","signature":"63bfd9f3fbbcb2dc649dd7303b9fdcf5680c25e217228a5abe005674bfc8bed5"},{"version":"f79040aab08b6460794739412f2f175f902517183e6a5196e4aec528d4634347","signature":"bbaa85a96900ee24d770ce38f7807d2d3cc2ca203e223cd4080447680910992e"},{"version":"d8d719cbe4f408a189f1b35d8183e10e8972d238f7df4eeb0c8cb48a365518b6","signature":"497761089898de53e02d017b84843a99061b782b9b0c6d987b1595a31b0260f7"},{"version":"69a362101efd9d9fe1a4d2d246ae3ac1d76ffc26e222817d13146f7a07bfe5cd","signature":"ea9768ee8ae2400a4352956f0937ff7ce12640c4de3c69d6e71e8a2f954ad58a"},{"version":"6ba703e0059aab893149bff3e9d4ab11e61342ca6914bad738f9e79eacb9fe3b","signature":"fe072e91b615ffa8bccb04dcc43149d4095fc5f6e56677346250901a692f4568"},{"version":"5e36c20b72b953b78f812d6d5c5b74f5789a8139870654e38a8fa065aea4575a","signature":"d9ce1372a43589027af010d0293b17099bf27089071c6d12ce30eb94b70191af"},{"version":"f9d363bd3045f41be125a5653330811c52b4849321a4fd6f580ed0d7344d72bf","signature":"dbb3eab27a108491f80873c1031ddc0b1a16c47f4c32e2ec2e70b83e9cee161b"},{"version":"574db92fbafc03af54f69b1a10735093ec1c047ac3480a7bba3cf427ff48d3be","signature":"8aec088c8b901c6fe9e7fe22785892138849af77a640d12b7015ec52a95aa27c"},{"version":"3717d410e1140d12aff0a8459792feda0fc49a0bbdd485bbb359ed7ac8aae3cc","signature":"d358bf9f604d2d3ac588fc908565f9c8a60bcb8e6993461b20ef5ca60e9a8f57"},{"version":"e51c2f73371682e7e7143c40764c5d5121ab8b3d5e9e2d33141d740ced6951b9","signature":"dcc953172cebbbf423013663b3bdc82d2ef9151cd09115a88cfac633d7d7a036"}],"root":[142,143,[146,176]],"options":{"allowJs":true,"allowSyntheticDefaultImports":true,"alwaysStrict":true,"declaration":true,"esModuleInterop":true,"experimentalDecorators":true,"jsx":4,"module":99,"noImplicitAny":true,"outDir":"./","preserveConstEnums":true,"removeComments":true,"rootDir":"../../src/client","skipLibCheck":true,"sourceMap":false,"strict":true,"strictBindCallApply":true,"strictFunctionTypes":true,"strictNullChecks":true,"strictPropertyInitialization":true,"suppressImplicitAnyIndexErrors":false,"target":99,"tsBuildInfoFile":"./.tsbuildinfo"},"referencedMap":[[138,1],[141,2],[126,3],[127,3],[125,4],[130,5],[131,6],[133,7],[132,6],[129,8],[134,9],[135,10],[136,11],[128,4],[144,12],[145,12],[92,13],[93,12],[95,14],[96,15],[97,14],[120,14],[98,15],[99,15],[100,15],[101,15],[102,15],[117,15],[123,16],[107,15],[103,15],[104,15],[118,15],[116,15],[119,14],[105,15],[108,15],[109,15],[106,15],[110,15],[111,15],[122,15],[121,15],[115,15],[114,15],[112,15],[113,15],[142,17],[168,18],[173,19],[171,18],[172,18],[174,20],[163,21],[161,18],[143,22],[150,23],[152,24],[176,25],[165,26],[166,27],[148,28],[154,29],[146,22],[160,30],[167,31],[155,32],[157,33],[158,32],[153,34],[151,22],[164,35],[156,36],[159,18],[175,22],[162,37],[170,38],[149,18],[169,22],[147,18]],"version":"6.0.3"}
1
+ {"fileNames":["../../node_modules/typescript/lib/lib.es5.d.ts","../../node_modules/typescript/lib/lib.es2015.d.ts","../../node_modules/typescript/lib/lib.es2016.d.ts","../../node_modules/typescript/lib/lib.es2017.d.ts","../../node_modules/typescript/lib/lib.es2018.d.ts","../../node_modules/typescript/lib/lib.es2019.d.ts","../../node_modules/typescript/lib/lib.es2020.d.ts","../../node_modules/typescript/lib/lib.es2021.d.ts","../../node_modules/typescript/lib/lib.es2022.d.ts","../../node_modules/typescript/lib/lib.es2023.d.ts","../../node_modules/typescript/lib/lib.es2024.d.ts","../../node_modules/typescript/lib/lib.es2025.d.ts","../../node_modules/typescript/lib/lib.esnext.d.ts","../../node_modules/typescript/lib/lib.dom.d.ts","../../node_modules/typescript/lib/lib.dom.iterable.d.ts","../../node_modules/typescript/lib/lib.es2015.core.d.ts","../../node_modules/typescript/lib/lib.es2015.collection.d.ts","../../node_modules/typescript/lib/lib.es2015.generator.d.ts","../../node_modules/typescript/lib/lib.es2015.iterable.d.ts","../../node_modules/typescript/lib/lib.es2015.promise.d.ts","../../node_modules/typescript/lib/lib.es2015.proxy.d.ts","../../node_modules/typescript/lib/lib.es2015.reflect.d.ts","../../node_modules/typescript/lib/lib.es2015.symbol.d.ts","../../node_modules/typescript/lib/lib.es2015.symbol.wellknown.d.ts","../../node_modules/typescript/lib/lib.es2016.array.include.d.ts","../../node_modules/typescript/lib/lib.es2016.intl.d.ts","../../node_modules/typescript/lib/lib.es2017.arraybuffer.d.ts","../../node_modules/typescript/lib/lib.es2017.date.d.ts","../../node_modules/typescript/lib/lib.es2017.object.d.ts","../../node_modules/typescript/lib/lib.es2017.sharedmemory.d.ts","../../node_modules/typescript/lib/lib.es2017.string.d.ts","../../node_modules/typescript/lib/lib.es2017.intl.d.ts","../../node_modules/typescript/lib/lib.es2017.typedarrays.d.ts","../../node_modules/typescript/lib/lib.es2018.asyncgenerator.d.ts","../../node_modules/typescript/lib/lib.es2018.asynciterable.d.ts","../../node_modules/typescript/lib/lib.es2018.intl.d.ts","../../node_modules/typescript/lib/lib.es2018.promise.d.ts","../../node_modules/typescript/lib/lib.es2018.regexp.d.ts","../../node_modules/typescript/lib/lib.es2019.array.d.ts","../../node_modules/typescript/lib/lib.es2019.object.d.ts","../../node_modules/typescript/lib/lib.es2019.string.d.ts","../../node_modules/typescript/lib/lib.es2019.symbol.d.ts","../../node_modules/typescript/lib/lib.es2019.intl.d.ts","../../node_modules/typescript/lib/lib.es2020.bigint.d.ts","../../node_modules/typescript/lib/lib.es2020.date.d.ts","../../node_modules/typescript/lib/lib.es2020.promise.d.ts","../../node_modules/typescript/lib/lib.es2020.sharedmemory.d.ts","../../node_modules/typescript/lib/lib.es2020.string.d.ts","../../node_modules/typescript/lib/lib.es2020.symbol.wellknown.d.ts","../../node_modules/typescript/lib/lib.es2020.intl.d.ts","../../node_modules/typescript/lib/lib.es2020.number.d.ts","../../node_modules/typescript/lib/lib.es2021.promise.d.ts","../../node_modules/typescript/lib/lib.es2021.string.d.ts","../../node_modules/typescript/lib/lib.es2021.weakref.d.ts","../../node_modules/typescript/lib/lib.es2021.intl.d.ts","../../node_modules/typescript/lib/lib.es2022.array.d.ts","../../node_modules/typescript/lib/lib.es2022.error.d.ts","../../node_modules/typescript/lib/lib.es2022.intl.d.ts","../../node_modules/typescript/lib/lib.es2022.object.d.ts","../../node_modules/typescript/lib/lib.es2022.string.d.ts","../../node_modules/typescript/lib/lib.es2022.regexp.d.ts","../../node_modules/typescript/lib/lib.es2023.array.d.ts","../../node_modules/typescript/lib/lib.es2023.collection.d.ts","../../node_modules/typescript/lib/lib.es2023.intl.d.ts","../../node_modules/typescript/lib/lib.es2024.arraybuffer.d.ts","../../node_modules/typescript/lib/lib.es2024.collection.d.ts","../../node_modules/typescript/lib/lib.es2024.object.d.ts","../../node_modules/typescript/lib/lib.es2024.promise.d.ts","../../node_modules/typescript/lib/lib.es2024.regexp.d.ts","../../node_modules/typescript/lib/lib.es2024.sharedmemory.d.ts","../../node_modules/typescript/lib/lib.es2024.string.d.ts","../../node_modules/typescript/lib/lib.es2025.collection.d.ts","../../node_modules/typescript/lib/lib.es2025.float16.d.ts","../../node_modules/typescript/lib/lib.es2025.intl.d.ts","../../node_modules/typescript/lib/lib.es2025.iterator.d.ts","../../node_modules/typescript/lib/lib.es2025.promise.d.ts","../../node_modules/typescript/lib/lib.es2025.regexp.d.ts","../../node_modules/typescript/lib/lib.esnext.array.d.ts","../../node_modules/typescript/lib/lib.esnext.collection.d.ts","../../node_modules/typescript/lib/lib.esnext.date.d.ts","../../node_modules/typescript/lib/lib.esnext.decorators.d.ts","../../node_modules/typescript/lib/lib.esnext.disposable.d.ts","../../node_modules/typescript/lib/lib.esnext.error.d.ts","../../node_modules/typescript/lib/lib.esnext.intl.d.ts","../../node_modules/typescript/lib/lib.esnext.sharedmemory.d.ts","../../node_modules/typescript/lib/lib.esnext.temporal.d.ts","../../node_modules/typescript/lib/lib.esnext.typedarrays.d.ts","../../node_modules/typescript/lib/lib.decorators.d.ts","../../node_modules/typescript/lib/lib.decorators.legacy.d.ts","../../node_modules/@types/react/global.d.ts","../../node_modules/csstype/index.d.ts","../../node_modules/@types/react/index.d.ts","../../node_modules/@types/react/jsx-runtime.d.ts","../../node_modules/hash-wasm/dist/lib/util.d.ts","../../node_modules/hash-wasm/dist/lib/WASMInterface.d.ts","../../node_modules/hash-wasm/dist/lib/adler32.d.ts","../../node_modules/hash-wasm/dist/lib/argon2.d.ts","../../node_modules/hash-wasm/dist/lib/blake2b.d.ts","../../node_modules/hash-wasm/dist/lib/blake2s.d.ts","../../node_modules/hash-wasm/dist/lib/blake3.d.ts","../../node_modules/hash-wasm/dist/lib/crc32.d.ts","../../node_modules/hash-wasm/dist/lib/crc64.d.ts","../../node_modules/hash-wasm/dist/lib/md4.d.ts","../../node_modules/hash-wasm/dist/lib/md5.d.ts","../../node_modules/hash-wasm/dist/lib/sha1.d.ts","../../node_modules/hash-wasm/dist/lib/sha3.d.ts","../../node_modules/hash-wasm/dist/lib/keccak.d.ts","../../node_modules/hash-wasm/dist/lib/sha224.d.ts","../../node_modules/hash-wasm/dist/lib/sha256.d.ts","../../node_modules/hash-wasm/dist/lib/sha384.d.ts","../../node_modules/hash-wasm/dist/lib/sha512.d.ts","../../node_modules/hash-wasm/dist/lib/xxhash32.d.ts","../../node_modules/hash-wasm/dist/lib/xxhash64.d.ts","../../node_modules/hash-wasm/dist/lib/xxhash3.d.ts","../../node_modules/hash-wasm/dist/lib/xxhash128.d.ts","../../node_modules/hash-wasm/dist/lib/ripemd160.d.ts","../../node_modules/hash-wasm/dist/lib/hmac.d.ts","../../node_modules/hash-wasm/dist/lib/pbkdf2.d.ts","../../node_modules/hash-wasm/dist/lib/scrypt.d.ts","../../node_modules/hash-wasm/dist/lib/bcrypt.d.ts","../../node_modules/hash-wasm/dist/lib/whirlpool.d.ts","../../node_modules/hash-wasm/dist/lib/sm3.d.ts","../../node_modules/hash-wasm/dist/lib/index.d.ts","../../node_modules/@noble/hashes/utils.d.ts","../../node_modules/@dacely/noble-post-quantum/utils.d.ts","../../node_modules/@dacely/noble-post-quantum/ml-dsa.d.ts","../../node_modules/@dacely/noble-post-quantum/ml-kem.d.ts","../../node_modules/@noble/curves/utils.d.ts","../../node_modules/@noble/curves/abstract/modular.d.ts","../../node_modules/@noble/curves/abstract/curve.d.ts","../../node_modules/@noble/curves/abstract/edwards.d.ts","../../node_modules/@noble/curves/abstract/hash-to-curve.d.ts","../../node_modules/@noble/curves/abstract/frost.d.ts","../../node_modules/@noble/curves/abstract/montgomery.d.ts","../../node_modules/@noble/curves/abstract/oprf.d.ts","../../node_modules/@noble/curves/ed25519.d.ts","../io/FastMap.d.ts","../io/FastSet.d.ts","../io/codec.d.ts","../io/types.d.ts","../io/index.d.ts","../../src/client/auth.ts","../../src/client/errors.ts","../../node_modules/@types/react-dom/client.d.ts","../../node_modules/@types/react-dom/index.d.ts","../../src/client/navigation/scroll.ts","../../src/client/types.ts","../../src/client/navigation/navigation.ts","../../src/client/ssr/markers.tsx","../../src/client/head/head.ts","../../src/client/routing/match.ts","../../src/client/head/metadata.ts","../../src/client/routing/loader.ts","../../src/client/navigation/prefetch.ts","../../src/client/routing/error-boundary.tsx","../../src/client/routing/params-context.ts","../../src/client/routing/hooks.ts","../../src/client/routing/lazy.ts","../../src/client/routing/slot-context.ts","../../src/client/routing/Router.tsx","../../src/client/dev/error-overlay.tsx","../../src/client/search/search.ts","../../src/client/dev/devtools.tsx","../../src/client/routing/mount.tsx","../../src/client/navigation/Link.tsx","../../src/client/navigation/NavLink.tsx","../../src/client/routing/action.ts","../../src/client/channel/channel.ts","../../src/client/stream/client.ts","../../src/client/search/use-page-search.ts","../../src/client/components/Image.tsx","../../src/client/components/Script.tsx","../../src/client/components/Form.tsx","../../src/client/components/Slot.tsx","../../src/client/rpc.ts","../../src/client/index.ts"],"fileIdsList":[[137],[137,138,139,140],[125],[124],[128,129],[128,129,130],[128,129,130,132],[128],[128,130],[128,130,132],[128,129,130,131,132,133,134,135],[92],[90,91],[94],[94,95],[94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122],[93,123,126,127,136,141],[92,93],[92,93,167],[92,93,159],[92,93,147,148,151,153,161,162],[93],[92,93,149],[93,150,151],[93,142,143,147,148,149,150,151,152,153,154,157,160,162,164,165,166,167,168,169,170,171,172,173,174,175],[92,93,147,148,154],[92,93,157,165],[92,93,145,146,147],[93,147,151,153],[92,93,146,147,148,150,151,153,155,156,157,158,159],[92,93,147,148,153],[92,93,147],[92,93,147,148,151,153,154,156],[92,93,147,148,150,151,152],[93,144,147,148,154,160,161,163],[92,93,151],[93,152],[92,93,147,148,162]],"fileInfos":[{"version":"bcd24271a113971ba9eb71ff8cb01bc6b0f872a85c23fdbe5d93065b375933cd","affectsGlobalScope":true,"impliedFormat":1},{"version":"3f88bedbeb09c6f5a6645cb24c7c55f1aa22d19ae96c8e6959cbd8b85a707bc6","impliedFormat":1},{"version":"7fe93b39b810eadd916be8db880dd7f0f7012a5cc6ffb62de8f62a2117fa6f1f","impliedFormat":1},{"version":"bb0074cc08b84a2374af33d8bf044b80851ccc9e719a5e202eacf40db2c31600","impliedFormat":1},{"version":"1a7daebe4f45fb03d9ec53d60008fbf9ac45a697fdc89e4ce218bc94b94f94d6","impliedFormat":1},{"version":"f94b133a3cb14a288803be545ac2683e0d0ff6661bcd37e31aaaec54fc382aed","impliedFormat":1},{"version":"f59d0650799f8782fd74cf73c19223730c6d1b9198671b1c5b3a38e1188b5953","impliedFormat":1},{"version":"8a15b4607d9a499e2dbeed9ec0d3c0d7372c850b2d5f1fb259e8f6d41d468a84","impliedFormat":1},{"version":"26e0fe14baee4e127f4365d1ae0b276f400562e45e19e35fd2d4c296684715e6","impliedFormat":1},{"version":"1e9332c23e9a907175e0ffc6a49e236f97b48838cc8aec9ce7e4cec21e544b65","impliedFormat":1},{"version":"3753fbc1113dc511214802a2342280a8b284ab9094f6420e7aa171e868679f91","impliedFormat":1},{"version":"999ca32883495a866aa5737fe1babc764a469e4cde6ee6b136a4b9ae68853e4b","impliedFormat":1},{"version":"17f13ecb98cbc39243f2eee1f16d45cd8ec4706b03ee314f1915f1a8b42f6984","impliedFormat":1},{"version":"d6b1eba8496bdd0eed6fc8a685768fe01b2da4a0388b5fe7df558290bffcf32f","affectsGlobalScope":true,"impliedFormat":1},{"version":"7f57fc4404ff020bc45b9c620aff2b40f700b95fe31164024c453a5e3c163c54","impliedFormat":1},{"version":"eadcffda2aa84802c73938e589b9e58248d74c59cb7fcbca6474e3435ac15504","affectsGlobalScope":true,"impliedFormat":1},{"version":"105ba8ff7ba746404fe1a2e189d1d3d2e0eb29a08c18dded791af02f29fb4711","affectsGlobalScope":true,"impliedFormat":1},{"version":"00343ca5b2e3d48fa5df1db6e32ea2a59afab09590274a6cccb1dbae82e60c7c","affectsGlobalScope":true,"impliedFormat":1},{"version":"ebd9f816d4002697cb2864bea1f0b70a103124e18a8cd9645eeccc09bdf80ab4","affectsGlobalScope":true,"impliedFormat":1},{"version":"2c1afac30a01772cd2a9a298a7ce7706b5892e447bb46bdbeef720f7b5da77ad","affectsGlobalScope":true,"impliedFormat":1},{"version":"7b0225f483e4fa685625ebe43dd584bb7973bbd84e66a6ba7bbe175ee1048b4f","affectsGlobalScope":true,"impliedFormat":1},{"version":"c0a4b8ac6ce74679c1da2b3795296f5896e31c38e888469a8e0f99dc3305de60","affectsGlobalScope":true,"impliedFormat":1},{"version":"3084a7b5f569088e0146533a00830e206565de65cae2239509168b11434cd84f","affectsGlobalScope":true,"impliedFormat":1},{"version":"c5079c53f0f141a0698faa903e76cb41cd664e3efb01cc17a5c46ec2eb0bef42","affectsGlobalScope":true,"impliedFormat":1},{"version":"32cafbc484dea6b0ab62cf8473182bbcb23020d70845b406f80b7526f38ae862","affectsGlobalScope":true,"impliedFormat":1},{"version":"fca4cdcb6d6c5ef18a869003d02c9f0fd95df8cfaf6eb431cd3376bc034cad36","affectsGlobalScope":true,"impliedFormat":1},{"version":"b93ec88115de9a9dc1b602291b85baf825c85666bf25985cc5f698073892b467","affectsGlobalScope":true,"impliedFormat":1},{"version":"f5c06dcc3fe849fcb297c247865a161f995cc29de7aa823afdd75aaaddc1419b","affectsGlobalScope":true,"impliedFormat":1},{"version":"b77e16112127a4b169ef0b8c3a4d730edf459c5f25fe52d5e436a6919206c4d7","affectsGlobalScope":true,"impliedFormat":1},{"version":"fbffd9337146eff822c7c00acbb78b01ea7ea23987f6c961eba689349e744f8c","affectsGlobalScope":true,"impliedFormat":1},{"version":"a995c0e49b721312f74fdfb89e4ba29bd9824c770bbb4021d74d2bf560e4c6bd","affectsGlobalScope":true,"impliedFormat":1},{"version":"c7b3542146734342e440a84b213384bfa188835537ddbda50d30766f0593aff9","affectsGlobalScope":true,"impliedFormat":1},{"version":"ce6180fa19b1cccd07ee7f7dbb9a367ac19c0ed160573e4686425060b6df7f57","affectsGlobalScope":true,"impliedFormat":1},{"version":"3f02e2476bccb9dbe21280d6090f0df17d2f66b74711489415a8aa4df73c9675","affectsGlobalScope":true,"impliedFormat":1},{"version":"45e3ab34c1c013c8ab2dc1ba4c80c780744b13b5676800ae2e3be27ae862c40c","affectsGlobalScope":true,"impliedFormat":1},{"version":"805c86f6cca8d7702a62a844856dbaa2a3fd2abef0536e65d48732441dde5b5b","affectsGlobalScope":true,"impliedFormat":1},{"version":"e42e397f1a5a77994f0185fd1466520691456c772d06bf843e5084ceb879a0ad","affectsGlobalScope":true,"impliedFormat":1},{"version":"f4c2b41f90c95b1c532ecc874bd3c111865793b23aebcc1c3cbbabcd5d76ffb0","affectsGlobalScope":true,"impliedFormat":1},{"version":"ab26191cfad5b66afa11b8bf935ef1cd88fabfcb28d30b2dfa6fad877d050332","affectsGlobalScope":true,"impliedFormat":1},{"version":"2088bc26531e38fb05eedac2951480db5309f6be3fa4a08d2221abb0f5b4200d","affectsGlobalScope":true,"impliedFormat":1},{"version":"cb9d366c425fea79716a8fb3af0d78e6b22ebbab3bd64d25063b42dc9f531c1e","affectsGlobalScope":true,"impliedFormat":1},{"version":"500934a8089c26d57ebdb688fc9757389bb6207a3c8f0674d68efa900d2abb34","affectsGlobalScope":true,"impliedFormat":1},{"version":"689da16f46e647cef0d64b0def88910e818a5877ca5379ede156ca3afb780ac3","affectsGlobalScope":true,"impliedFormat":1},{"version":"bc21cc8b6fee4f4c2440d08035b7ea3c06b3511314c8bab6bef7a92de58a2593","affectsGlobalScope":true,"impliedFormat":1},{"version":"7ca53d13d2957003abb47922a71866ba7cb2068f8d154877c596d63c359fed25","affectsGlobalScope":true,"impliedFormat":1},{"version":"54725f8c4df3d900cb4dac84b64689ce29548da0b4e9b7c2de61d41c79293611","affectsGlobalScope":true,"impliedFormat":1},{"version":"e5594bc3076ac29e6c1ebda77939bc4c8833de72f654b6e376862c0473199323","affectsGlobalScope":true,"impliedFormat":1},{"version":"2f3eb332c2d73e729f3364fcc0c2b375e72a121e8157d25a82d67a138c83a95c","affectsGlobalScope":true,"impliedFormat":1},{"version":"6f4427f9642ce8d500970e4e69d1397f64072ab73b97e476b4002a646ac743b1","affectsGlobalScope":true,"impliedFormat":1},{"version":"48915f327cd1dea4d7bd358d9dc7732f58f9e1626a29cc0c05c8c692419d9bb7","affectsGlobalScope":true,"impliedFormat":1},{"version":"b7bf9377723203b5a6a4b920164df22d56a43f593269ba6ae1fdc97774b68855","affectsGlobalScope":true,"impliedFormat":1},{"version":"db9709688f82c9e5f65a119c64d835f906efe5f559d08b11642d56eb85b79357","affectsGlobalScope":true,"impliedFormat":1},{"version":"4b25b8c874acd1a4cf8444c3617e037d444d19080ac9f634b405583fd10ce1f7","affectsGlobalScope":true,"impliedFormat":1},{"version":"37be57d7c90cf1f8112ee2636a068d8fd181289f82b744160ec56a7dc158a9f5","affectsGlobalScope":true,"impliedFormat":1},{"version":"a917a49ac94cd26b754ab84e113369a75d1a47a710661d7cd25e961cc797065f","affectsGlobalScope":true,"impliedFormat":1},{"version":"6d3261badeb7843d157ef3e6f5d1427d0eeb0af0cf9df84a62cfd29fd47ac86e","affectsGlobalScope":true,"impliedFormat":1},{"version":"195daca651dde22f2167ac0d0a05e215308119a3100f5e6268e8317d05a92526","affectsGlobalScope":true,"impliedFormat":1},{"version":"8b11e4285cd2bb164a4dc09248bdec69e9842517db4ca47c1ba913011e44ff2f","affectsGlobalScope":true,"impliedFormat":1},{"version":"0508571a52475e245b02bc50fa1394065a0a3d05277fbf5120c3784b85651799","affectsGlobalScope":true,"impliedFormat":1},{"version":"8f9af488f510c3015af3cc8c267a9e9d96c4dd38a1fdff0e11dc5a544711415b","affectsGlobalScope":true,"impliedFormat":1},{"version":"fc611fea8d30ea72c6bbfb599c9b4d393ce22e2f5bfef2172534781e7d138104","affectsGlobalScope":true,"impliedFormat":1},{"version":"0bd714129fca875f7d4c477a1a392200b0bcd13fb2e80928cd334b63830ea047","affectsGlobalScope":true,"impliedFormat":1},{"version":"e2c9037ae6cd2c52d80ceef0b3c5ffdb488627d71529cf4f63776daf11161c9a","affectsGlobalScope":true,"impliedFormat":1},{"version":"135d5cf4d345f59f1a9caadfafcd858d3d9cc68290db616cc85797224448cccc","affectsGlobalScope":true,"impliedFormat":1},{"version":"bc238c3f81c2984751932b6aab223cd5b830e0ac6cad76389e5e9d2ffc03287d","affectsGlobalScope":true,"impliedFormat":1},{"version":"4a07f9b76d361f572620927e5735b77d6d2101c23cdd94383eb5b706e7b36357","affectsGlobalScope":true,"impliedFormat":1},{"version":"7c4e8dc6ab834cc6baa0227e030606d29e3e8449a9f67cdf5605ea5493c4db29","affectsGlobalScope":true,"impliedFormat":1},{"version":"de7ba0fd02e06cd9a5bd4ab441ed0e122735786e67dde1e849cced1cd8b46b78","affectsGlobalScope":true,"impliedFormat":1},{"version":"6148e4e88d720a06855071c3db02069434142a8332cf9c182cda551adedf3156","affectsGlobalScope":true,"impliedFormat":1},{"version":"d63dba625b108316a40c95a4425f8d4294e0deeccfd6c7e59d819efa19e23409","affectsGlobalScope":true,"impliedFormat":1},{"version":"0568d6befee03dd435bed4fc25c4e46865b24bdcb8c563fdc21f580a2c301904","affectsGlobalScope":true,"impliedFormat":1},{"version":"30d62269b05b584741f19a5369852d5d34895aa2ac4fd948956f886d15f9cc0d","affectsGlobalScope":true,"impliedFormat":1},{"version":"f128dae7c44d8f35ee42e0a437000a57c9f06cc04f8b4fb42eebf44954d53dc8","affectsGlobalScope":true,"impliedFormat":1},{"version":"ffbe6d7b295306b2ba88030f65b74c107d8d99bdcf596ea99c62a02f606108b0","affectsGlobalScope":true,"impliedFormat":1},{"version":"996fb27b15277369c68a4ba46ed138b4e9e839a02fb4ec756f7997629242fd9f","affectsGlobalScope":true,"impliedFormat":1},{"version":"79b712591b270d4778c89706ca2cfc56ddb8c3f895840e477388f1710dc5eda9","affectsGlobalScope":true,"impliedFormat":1},{"version":"20884846cef428b992b9bd032e70a4ef88e349263f63aeddf04dda837a7dba26","affectsGlobalScope":true,"impliedFormat":1},{"version":"5fcab789c73a97cd43828ee3cc94a61264cf24d4c44472ce64ced0e0f148bdb2","affectsGlobalScope":true,"impliedFormat":1},{"version":"db59a81f070c1880ad645b2c0275022baa6a0c4f0acdc58d29d349c6efcf0903","affectsGlobalScope":true,"impliedFormat":1},{"version":"673294292640f5722b700e7d814e17aaf7d93f83a48a2c9b38f33cbc940ad8b0","affectsGlobalScope":true,"impliedFormat":1},{"version":"d786b48f934cbca483b3c6d0a798cb43bbb4ada283e76fb22c28e53ae05b9e69","affectsGlobalScope":true,"impliedFormat":1},{"version":"1ecb8e347cb6b2a8927c09b86263663289418df375f5e68e11a0ae683776978f","affectsGlobalScope":true,"impliedFormat":1},{"version":"142efd4ce210576f777dc34df121777be89eda476942d6d6663b03dcb53be3ff","affectsGlobalScope":true,"impliedFormat":1},{"version":"379bc41580c2d774f82e828c70308f24a005b490c25ba34d679d84bcf05c3d9d","affectsGlobalScope":true,"impliedFormat":1},{"version":"ed484fb2aa8a1a23d0277056ec3336e0a0b52f9b8d6a961f338a642faf43235d","affectsGlobalScope":true,"impliedFormat":1},{"version":"4ffedae1d1c2d53fdbca1c96d3c7dda544281f7d262f99b6880634f8fd8d9820","affectsGlobalScope":true,"impliedFormat":1},{"version":"83a730b125d477dd264df8ba479afab27a3dae7152b005c214ab94dc7ee44fd3","affectsGlobalScope":true,"impliedFormat":1},{"version":"1ce14b81c5cc821994aa8ec1d42b220dd41b27fcc06373bce3958af7421b77d4","affectsGlobalScope":true,"impliedFormat":1},{"version":"b3a048b3e9302ef9a34ef4ebb9aecfb28b66abb3bce577206a79fee559c230da","affectsGlobalScope":true,"impliedFormat":1},{"version":"7e29f41b158de217f94cb9676bf9cbd0cd9b5a46e1985141ed36e075c52bf6ad","affectsGlobalScope":true,"impliedFormat":1},{"version":"ac51dd7d31333793807a6abaa5ae168512b6131bd41d9c5b98477fc3b7800f9f","impliedFormat":1},{"version":"dc782ff85b2cb10075ecffc158af7bfb27ff97bf8491c917efea0c3d622d5ac4","impliedFormat":1},{"version":"b838d4c72740eb0afd284bf7575b74c624b105eff2e8c7b4aeead57e7ac320ff","impliedFormat":1},{"version":"a957a1395986cd6863bae5a42c58d66886df90f1931c911fbe406f8321335e6f","impliedFormat":1},{"version":"a2bc59da4f44ff533bd0b7ea20946f8c52eae8895531746dee71603e3b7d5578","impliedFormat":1},{"version":"9828342b073c3d2a51680d84be6e8693c15209142d4c3c49f9af9ad3e8a9dacc","impliedFormat":1},{"version":"7cabf9ff89f3a1de0524b3a50265ba1294a88e495e114dcae8da0cbc50fc92f2","impliedFormat":1},{"version":"9d7a70722e17134d5eab42d3dd710eacbe42fd1210d80287f6639c29ee2a7c10","impliedFormat":1},{"version":"165409ea4281fef67eea472050347967441004e84d22a8977a94e1976823d5be","impliedFormat":1},{"version":"505abecc03fe091b97b747dc320fff4679344de28c922564193151c0cefb3180","impliedFormat":1},{"version":"0f90009e6c417c9336b260496ea53729a9c70933895e2ce545fff272b9301bb2","impliedFormat":1},{"version":"c0a488e0b571aec7a957ecad80792af284c357b48ba6d2d8b4444aa2be6c5a2f","impliedFormat":1},{"version":"ff2ce6f20d8c9346ab61a3444f5bca603f327d26352eb0ab6f40cb1f48e84c84","impliedFormat":1},{"version":"7c9fc8fbe28c6fe364d78be412d8467619b87dc828f2cf5ef525db7d7837c9f7","impliedFormat":1},{"version":"c824d703f55424408de202f826ff50eced9ad4c07edf12ff99fef7a7ca820f5b","impliedFormat":1},{"version":"6efbf9b08c3e5a48b93858e7b96eb61f9ca6d5c5d27709dc16f806e0ba1067cc","impliedFormat":1},{"version":"1b6d8a8926e323af55c6777a6f6561191ea3da6beabe8e7d91c152df3c693bac","impliedFormat":1},{"version":"587173d12395c6996972afd696425044d322eb0174e76d7d5888caf35d88831d","impliedFormat":1},{"version":"de5ba33082f9ac12bd6a9e44c530a5dd708d145fff6cc2dd7cb30321a8882a6b","impliedFormat":1},{"version":"a50a03f03f65f3cc4e012c86464f310755462c7059f1581a9c666b5457d102e1","impliedFormat":1},{"version":"89b954bd9c00a77ce3d889e1cc78b034779e2593fe0adfa14b6e56baafeb5de2","impliedFormat":1},{"version":"9935b6341ac96a5027526efc1ec75114ccf2009b6ed602f65bc82e75ac2089b1","impliedFormat":1},{"version":"f8776dc3e57237b3de45b8ab5f224adc00dd90fe217f1a34ed6442606807c122","impliedFormat":1},{"version":"b0c8c7af35a444fd4054c12d971eabcd7ec4be2e840fc60f8897b5732cb3a20b","impliedFormat":1},{"version":"4f9bd8f00fe9f0ae8b5d2fffed8d47915b61b428e33b2ee9aa3ef159e98e305c","impliedFormat":1},{"version":"bbe6c08cefd08a23dc36eca9dae8aeb30895debf15387ab6904b591e3b6b3217","impliedFormat":1},{"version":"0c3880ad1eee5252b7f02c6ff10bd2666cb9a59ae698d552ec5b0a4a7b9611d8","impliedFormat":1},{"version":"d5d71ded265f144dec6604983fbfaf201844d7cd8614aadab8ad5227e99545d3","impliedFormat":1},{"version":"907d2ea3b3fed567fe2dff6747f7642f57aa8b3c288becf4843113ac98331ee3","impliedFormat":1},{"version":"33da6d63dbab160960cdd6e1dba0716bbc2f60af4aeb229ea9b318303c2015e1","impliedFormat":1},{"version":"6dc0148fe65a487db8bd552670f0fe87498c0a8e644c38092a185a05030282bf","impliedFormat":1},{"version":"6bd476fd8a150f5211488cc1d58d412dabec0da0977295ea1f06957b1d28ed13","impliedFormat":1},{"version":"5e134f083c46ea016764a484ac86f664564303f87bc3ca7cfd4b74ccbacad282","impliedFormat":1},{"version":"5d01f288556ba56b803dfbd9b207502aaaa831afddd9e71b2b5ce250dc395152","impliedFormat":99},{"version":"7b9d4f3cc667e8896241f6c95d2824ced607ce7f2858cedf04058ddd23287602","impliedFormat":99},{"version":"371e624178bb67607b2c63e1f8ec3e5d9585455b39bac8f0816eba540072383f","impliedFormat":99},{"version":"c468447508a5ca66c0a2523ed935cf5cb1d768d890c991e20397df618db741d1","impliedFormat":99},{"version":"b8c741cb7cd15e89b24af6c25b6d95a581b2d79f7c0d959552220743f7269c7f","impliedFormat":99},{"version":"1b65eaf896a59cf1904bae76e68bc64941671555a3b1ee4190bcd6d3b16d5b61","impliedFormat":99},{"version":"2cea0605228c4357d9f57b6d13fd607752579a0a70995ccf70179110b098435b","impliedFormat":99},{"version":"edc4a14bf998e6512257766b4f291c940b5e88fe8bea8aec0c499e2e41da1d34","impliedFormat":99},{"version":"74853f56c2d22c7794408839dc106c4c412818fbd2e855b1d7dc4a70447f8387","impliedFormat":99},{"version":"61d04e1fb8987919928a5c4982fe4b32ec4147bd39491b4da9720bb518fd77ce","impliedFormat":99},{"version":"c1d730d8774ef9d198a2f8ecedd6806b1efd9e00a502ba7e28969f5a2c550ae1","impliedFormat":99},{"version":"9155fc738cfdd9a8dbeb7a9657998407101fc278c1649d8bb24b24b4fc7e5ad4","impliedFormat":99},{"version":"aa9a3b2c5d46f501a49ebde65cbdd59a7c05122f4f15785467bc30b6d8956751","impliedFormat":99},"6a4c287c863003342a42d8bf876c7df4c2e82e95f556af5ade71f05255845200","272e7bc3a3734cc9e7419625f04cff7095131e315e51a83fa992a5134763df49","b9f2341c8b486561706db362b6f89ee6b149ef08fb4fa6aaea1041bce04fe1c5","3952955b5e83c1164fc78d7d54377fd4d09d2c11b79763cba53a7ff4b27a0601","48d0d0bebe2ccfd875953713d746fe4adae81b1e3a91ffafae29ead23fd5c39b",{"version":"5661655283f1c6f9bad2d382fdf2a09b7216f1ee2b0ce18d0b08f72ffb17342f","signature":"d0b36193cdceaefd1a09c44714a7e6ffa9362c1dfb0190351a104a9967d2d0ed"},{"version":"cbc4073fb15a767ab8787ce067b3266807ea2ef8456aa85e3a55ff5a62c33bdd","signature":"7cf224e300294bcb276cf440125703dd0da90e1b5aa8070a3f7ca043475979c1"},{"version":"bc03c3c352f689e38c0ddd50c39b1e65d59273991bfc8858a9e3c0ebb79c023b","impliedFormat":1},{"version":"be1cc4d94ea60cbe567bc29ed479d42587bf1e6cba490f123d329976b0fe4ee5","impliedFormat":1},{"version":"dbafe5664a764167d089a3ecce720259c6f4837696f2cf5e0adb199de6a9150c","signature":"2b2db01796f774852b44cacad054f31b9e63a3c4ed787d12c1dd75c75e602bef"},{"version":"43c268c58c28f2f6f80bc2a42104a2e8ce3891d1c8a2b8767e2a52606e61952b","signature":"d86aae3a61fb2a3734379428044eefd6b048996f3a1a1cd7e57bb94d3d36b02b"},{"version":"31946b8cd45a08d2f4d3be4e8b31b5896e5f0fb24840cc53e6d9a45d71e24506","signature":"50c12b83406070a98041a222f49db12395234ac00db0f16d18d01d8fccfe9d9d"},{"version":"2a0b3b70eae3ac89e80870431490787f00d5b450b6c9767df4daf6aee7eb0978","signature":"dd11f115ef46b611836fe84d45fb6f7889711397a69aad6cc147739cbe5a4072"},{"version":"1f97d3daade701681d6c89a1904123b009db72bdf95ec5fd563076769da2339c","signature":"c12ee6242f6e1108c7cfac4089b422a742417d50a70cbb03d0d24b7217271376"},{"version":"f6eaf207ae99ba6778460fa1d857e80c870be1533e9b1668060f0f53e6aa6b41","signature":"b9f112f8e9a593f362dd5f434f8f997385dd62f15e2d2fb6d316e5d0d9942a51"},{"version":"6647f68fcaa6a2a028711abf7288cd95d8625d0efff1315b5ad3536bf2de9e2b","signature":"919e52d8be47dbe1be9f86aff4b897c9801b8d6d0bf49f68fc321a4dc9251ad4"},{"version":"ef23db21116b6651538dbcb7df065b8340d6b2514bce598087309f5f435a2bcb","signature":"ba8cda0a8ef4aaa88a574d7e25ea6eaac5e6b9a25c862afdd948d8b6780014b6"},{"version":"26a4fb1b862a479d7a5d90aa1745f070d44bc351e79c6e4f8a6481b206a1655b","signature":"ad70244d75add3a5819000694ceb8f6ffca2fff2bd49acbd6786e1457c9d1d82","affectsGlobalScope":true},{"version":"abdc0918e0afd85d5495c618d95ea69c667d1cd095452cc73617168c784904a4","signature":"9382f138465c4775c54940f2a3d4334a083a6fc9a622a7c926c5f8233228cbae"},{"version":"336f74bb2ca217a8b08f3c146c41295de7597a86d52ca333fac5634561261846","signature":"c8525f0be940a19f3d03f06b6e43d4bea21ba910db62fb5024ecc671bcc23932"},{"version":"eb5c9b96b9b90a2c7abd1dd62be278b51ef4fcc1a7181fb7294ae1554b5d2409","signature":"90b4955becdfa8d37df7a1fdd1c93d847cdbea6bb3a113bd3baa6134291531a2"},{"version":"bdf04d4dd9ed94c85da1be565643ef5fad4212b7a545da8f4792deb4cf426665","signature":"c6384012cac726d5b05237d2bd2c9c9da0893feaf54ab1dd0042fe141b9e5bd8"},{"version":"1ac886967a62c940d61ab89f3411f64893d779d69e1435f15215547ba50fa03b","signature":"994bfb8326dca5c985462ba74b5c64146aef0e3ea7bbbbf265ad426d884fbc9e"},{"version":"314ad9d994327a7e9cc1367c1c56fb3f28737fc85716317e01f7649a02e6303b","signature":"00dd4ce0458ebf64e2e0617d4bc04f3a9a569bc388f3a20c1c4416d465e99245"},{"version":"b7a6fa2ad0bbeb531d9fc2a4003d5cc4a6e8142c18914fb2d034ca8b32b760fc","signature":"61814a0254524d3e14d405795a649b8b838386ff0f82caf50a0b7d4c72008c3d"},{"version":"3fcfd875b042c0855e76061aae81b0d8333c1990c1e4ca4d1f3141652b988b06","signature":"b43c263b28c6f20a6d7066e22f6906fe51605b6a4b7709a3c47d7cf6c0ccf93e"},{"version":"1e54ebe6806cac6a9b2ce78a54863cd75732cc68901256507042e3d8cd399224","signature":"58d2bb278ba2b594a3b664571b357e10388c6a1eef2c27e2946d3ee447fb4e16"},{"version":"f40083b8ea073895257a2f5ef2bfc9b8cf031d471744fe76185ecc259847d49b","signature":"e5f0e0e21621bb3e87958857cc9695abf011fb257bd249abd42ae97b3b61e1d0"},{"version":"91df3defe1f0907af6b80d1b7849615c72b36340404efb0bbf6f9fb1f99727fc","signature":"5cf43ceac60fba7927af9ce9b27fb6031854fc923263b78c353fb986857218b9"},{"version":"64837fd5187d6a3c2abc6a265251be66c4a9961c369e5cf647ac87511d328d90","signature":"0caa217adbbdb001facd9aeb363fa2a446eabbeb4e5af2c1f2c3d1ef4bbffc6e"},{"version":"40896dfcdeafc76e4d85bfd4acca390f542032e613c6f5b7c5c8e1e99bb3b63d","signature":"63bfd9f3fbbcb2dc649dd7303b9fdcf5680c25e217228a5abe005674bfc8bed5"},{"version":"f79040aab08b6460794739412f2f175f902517183e6a5196e4aec528d4634347","signature":"bbaa85a96900ee24d770ce38f7807d2d3cc2ca203e223cd4080447680910992e"},{"version":"d8d719cbe4f408a189f1b35d8183e10e8972d238f7df4eeb0c8cb48a365518b6","signature":"497761089898de53e02d017b84843a99061b782b9b0c6d987b1595a31b0260f7"},{"version":"69a362101efd9d9fe1a4d2d246ae3ac1d76ffc26e222817d13146f7a07bfe5cd","signature":"ea9768ee8ae2400a4352956f0937ff7ce12640c4de3c69d6e71e8a2f954ad58a"},{"version":"6ba703e0059aab893149bff3e9d4ab11e61342ca6914bad738f9e79eacb9fe3b","signature":"fe072e91b615ffa8bccb04dcc43149d4095fc5f6e56677346250901a692f4568"},{"version":"5e36c20b72b953b78f812d6d5c5b74f5789a8139870654e38a8fa065aea4575a","signature":"d9ce1372a43589027af010d0293b17099bf27089071c6d12ce30eb94b70191af"},{"version":"f9d363bd3045f41be125a5653330811c52b4849321a4fd6f580ed0d7344d72bf","signature":"dbb3eab27a108491f80873c1031ddc0b1a16c47f4c32e2ec2e70b83e9cee161b"},{"version":"574db92fbafc03af54f69b1a10735093ec1c047ac3480a7bba3cf427ff48d3be","signature":"8aec088c8b901c6fe9e7fe22785892138849af77a640d12b7015ec52a95aa27c"},{"version":"3717d410e1140d12aff0a8459792feda0fc49a0bbdd485bbb359ed7ac8aae3cc","signature":"d358bf9f604d2d3ac588fc908565f9c8a60bcb8e6993461b20ef5ca60e9a8f57"},{"version":"e51c2f73371682e7e7143c40764c5d5121ab8b3d5e9e2d33141d740ced6951b9","signature":"dcc953172cebbbf423013663b3bdc82d2ef9151cd09115a88cfac633d7d7a036"}],"root":[142,143,[146,176]],"options":{"allowJs":true,"allowSyntheticDefaultImports":true,"alwaysStrict":true,"declaration":true,"esModuleInterop":true,"experimentalDecorators":true,"jsx":4,"module":99,"noImplicitAny":true,"outDir":"./","preserveConstEnums":true,"removeComments":true,"rootDir":"../../src/client","skipLibCheck":true,"sourceMap":false,"strict":true,"strictBindCallApply":true,"strictFunctionTypes":true,"strictNullChecks":true,"strictPropertyInitialization":true,"suppressImplicitAnyIndexErrors":false,"target":99,"tsBuildInfoFile":"./.tsbuildinfo"},"referencedMap":[[138,1],[141,2],[126,3],[127,3],[125,4],[130,5],[131,6],[133,7],[132,6],[129,8],[134,9],[135,10],[136,11],[128,4],[144,12],[145,12],[92,13],[93,12],[95,14],[96,15],[97,14],[120,14],[98,15],[99,15],[100,15],[101,15],[102,15],[117,15],[123,16],[107,15],[103,15],[104,15],[118,15],[116,15],[119,14],[105,15],[108,15],[109,15],[106,15],[110,15],[111,15],[122,15],[121,15],[115,15],[114,15],[112,15],[113,15],[142,17],[168,18],[173,19],[171,18],[172,18],[174,20],[163,21],[161,18],[143,22],[150,23],[152,24],[176,25],[165,26],[166,27],[148,28],[154,29],[146,22],[160,30],[167,31],[155,32],[157,33],[158,32],[153,34],[151,22],[164,35],[156,36],[159,18],[175,22],[162,37],[170,38],[149,18],[169,22],[147,18]],"version":"6.0.3"}
@@ -26,6 +26,18 @@ export declare function login(username: string, password: string, opts?: AuthOpt
26
26
  export declare class EmailNotConfirmedError extends Error {
27
27
  constructor();
28
28
  }
29
+ export declare class TwoFactorRequiredError extends Error {
30
+ readonly twoFaId: string;
31
+ constructor(twoFaId: string);
32
+ }
33
+ export declare const TwoFactorMethod: {
34
+ readonly None: 0;
35
+ readonly Email: 1;
36
+ };
37
+ export declare function verifyTwoFactor(twoFaId: string, code: string, opts?: AuthOptions): Promise<Uint8Array>;
38
+ export declare function setupTwoFactor(method: number, opts?: AuthOptions): Promise<void>;
39
+ export declare function confirmTwoFactorSetup(code: string, opts?: AuthOptions): Promise<void>;
40
+ export declare function twoFactorStatus(opts?: AuthOptions): Promise<number>;
29
41
  export declare function confirmEmail(token: string, opts?: AuthOptions): Promise<void>;
30
42
  export declare function resendConfirmation(email: string, opts?: AuthOptions): Promise<void>;
31
43
  export declare function requestPasswordReset(email: string, opts?: AuthOptions): Promise<void>;
@@ -37,6 +49,14 @@ export declare const Auth: {
37
49
  readonly resendConfirmation: typeof resendConfirmation;
38
50
  readonly requestPasswordReset: typeof requestPasswordReset;
39
51
  readonly resetPassword: typeof resetPassword;
52
+ readonly verifyTwoFactor: typeof verifyTwoFactor;
53
+ readonly setupTwoFactor: typeof setupTwoFactor;
54
+ readonly confirmTwoFactorSetup: typeof confirmTwoFactorSetup;
55
+ readonly twoFactorStatus: typeof twoFactorStatus;
56
+ readonly TwoFactorMethod: {
57
+ readonly None: 0;
58
+ readonly Email: 1;
59
+ };
40
60
  readonly buildLoginMessage: typeof buildLoginMessage;
41
61
  readonly LOGIN_CONTEXT: "qauth:login:v1";
42
62
  };
@@ -16,6 +16,12 @@ function fromHex(hex) {
16
16
  out[i] = parseInt(hex.slice(i * 2, i * 2 + 2), 16);
17
17
  return out;
18
18
  }
19
+ function toHex(bytes) {
20
+ let s = '';
21
+ for (let i = 0; i < bytes.length; i++)
22
+ s += bytes[i].toString(16).padStart(2, '0');
23
+ return s;
24
+ }
19
25
  export const SERVER_KEM_PUBLIC_KEY = fromHex('29d765e8083182891302569b3712a856e564fdd484b0706b0c68568d5ab7edc742cf74459d64595455a60f267973aa55e43c5be61925a3822eafcca445e36dc4655636e31e6fc9bec338b253f94290008ef7f40dbddb49c15c690f6755a23a1b3c85cfd5207e71a607086a6fc6d74a05080f43276901a19cafdb8de7771d58ea07f0f1056b905127b22223d08e75173199f13ab13c5dcd3b51ac784f84e520484a262b845a897c41cf27324ab6ba545c78c9ccab361051e0bba53498af26240fa0d566d1572684f4b42e253e6d052c848650915063c35641e1121ef8d9cfd17b667b351103c56d195007c9376d0c08aa268396814490eab4c364175a94533267a1933862cc4c33bcf0a13d1fa2b9d6c5082eeca1480672f2526cbe013beff14dc908a386e0b633c8761023cbed760deac6709bc328d865ac82e12307b673d96711dbb27a4d939230d25b53d594169a318be0200fa33550e9418e2a3b30e9719edc09d5fc4306f1abfd021eab14637a8a72c5931d25dc9b56db0e6ab677522b10f25307dbb804a6774ce05b87b0976a4b227bfe6caf20a79e64004fbd27b1eea018b3ab8ffa629f2dc87f19278f95168e94e44660a3370c537795678eb2f056260609769740583b51b291862927a1938737c6a37f40b78f00671cccbcb88ac3427b37915ed58782998f84051647707d48995472baad3f64a7cca54e1c0734db08751c614a34f28b84f2c1b5a6817355ab61957c486b7acffbc092bc8a7b46387f33b53ed372f7168d31a71cd008539928b0cdf91e835aa97f6a2be6d327b87a6ae478701d75a59a25179cb14997bb2552853014724170a1c49b82c2bcebc3279024e1fa44c53c7afdc43f0bd22116490f3b74c90e7296be58b9a91168f2fa0c3d378a3bcac959f357825c9976a8c9ee944f29b45e96d7345d9b478431a20cf1c5d3a3227c717fd204619777636c0cb140db5c50d2a3302334461030bee34e4eb1a6f02b733f9ccda4290fa168bc039568373241542728d00030d1f251e83737cb215adbdc1de75978675a0cd0d75b12748abdda7a9852629c63697d145af2c69854b06e03f37c4b064e4c9a4c03f2ad4d081e70180e9547247921918118086b62b4f7727f46b24e3e79ba3f28209f32b5102035bf935856232f83642268c0292ec6bf8e9462382163d30a20b4bcb7b4439310ec9d0a148193907fc07697342967cf1a16c6b3c71558951fa915400736cf699262b54b723abb2ecc27b74b68ee494287595ef818388adb49e883c67bfa5c226c0eef037a0851a29d34675912c1ea1068310b6dfcd017c809c8fbfc2c3ae78dfef07299960eeefba182662a90fa422c1790f356a2ea909012b15623a9b9e450a282cb530589a68368b3583159d9010ac3e52cc974753c342e58279516339dfb691df94b13a223ad97eb6a09c21dafe6304a3642d6d2067b5238497661fe88ad1227ca3557be2a576b6e17c5a7f997ea07929e76407e376aba74c44cd8504804776f39bbb8327624188a63501e83b404d9438cade0b11dc3ac61856447fb072b91761c228878f01b2eb6b4b21ba664c2c75882431603b25a449ffeb8410b910558581777562aa9b2181fd9c04713ad9326462d3e842121c4997f9aa932417c67851625816de66e0d65637434629f39');
20
26
  export const PUBLIC_KEY_LEN = 1312;
21
27
  export const SECRET_KEY_LEN = 2560;
@@ -194,11 +200,11 @@ export async function login(username, password, opts = {}) {
194
200
  wipe(sharedSecret);
195
201
  throw new EmailNotConfirmedError();
196
202
  }
197
- if (loginStatus !== 0) {
203
+ if (loginStatus !== 0 && loginStatus !== 3) {
198
204
  wipe(sharedSecret);
199
205
  throw new Error('auth: login failed');
200
206
  }
201
- const session = res.readBytes();
207
+ const first = res.readBytes();
202
208
  const serverConfirm = res.readBytes();
203
209
  const transcriptHash = await sha256Bytes(message);
204
210
  const sessionKey = await hmacSha256(sharedSecret, concatBytes(utf8(SESSION_KEY_LABEL), transcriptHash));
@@ -206,7 +212,10 @@ export async function login(username, password, opts = {}) {
206
212
  const expected = await hmacSha256(sessionKey, concatBytes(utf8(SERVER_CONFIRM_LABEL), transcriptHash));
207
213
  if (!bytesEqual(expected, serverConfirm))
208
214
  throw new Error('auth: server authentication failed');
209
- return session;
215
+ if (loginStatus === 3) {
216
+ throw new TwoFactorRequiredError(toHex(first));
217
+ }
218
+ return first;
210
219
  }
211
220
  export class EmailNotConfirmedError extends Error {
212
221
  constructor() {
@@ -214,6 +223,44 @@ export class EmailNotConfirmedError extends Error {
214
223
  this.name = 'EmailNotConfirmedError';
215
224
  }
216
225
  }
226
+ export class TwoFactorRequiredError extends Error {
227
+ twoFaId;
228
+ constructor(twoFaId) {
229
+ super('auth: two-factor authentication required');
230
+ this.name = 'TwoFactorRequiredError';
231
+ this.twoFaId = twoFaId;
232
+ }
233
+ }
234
+ export const TwoFactorMethod = { None: 0, Email: 1 };
235
+ export async function verifyTwoFactor(twoFaId, code, opts = {}) {
236
+ const baseUrl = opts.baseUrl ?? '/auth';
237
+ const res = await postBinary(baseUrl, '/2fa/verify', new DataWriter().writeBytes(fromHex(twoFaId)).writeString(code).toBytes());
238
+ if (res.readU8() !== 0)
239
+ throw new Error('auth: two-factor code invalid or expired');
240
+ return res.readBytes();
241
+ }
242
+ export async function setupTwoFactor(method, opts = {}) {
243
+ const baseUrl = opts.baseUrl ?? '/auth';
244
+ const res = await postBinary(baseUrl, '/2fa/setup', new DataWriter().writeU8(method).toBytes());
245
+ if (res.readU8() !== 0)
246
+ throw new Error('auth: two-factor setup failed');
247
+ }
248
+ export async function confirmTwoFactorSetup(code, opts = {}) {
249
+ const baseUrl = opts.baseUrl ?? '/auth';
250
+ const res = await postBinary(baseUrl, '/2fa/setup/verify', new DataWriter().writeString(code).toBytes());
251
+ if (res.readU8() !== 0)
252
+ throw new Error('auth: two-factor setup confirmation failed');
253
+ }
254
+ export async function twoFactorStatus(opts = {}) {
255
+ const baseUrl = opts.baseUrl ?? '/auth';
256
+ const res = await fetch(baseUrl + '/2fa/status', {
257
+ method: 'GET',
258
+ credentials: 'same-origin',
259
+ });
260
+ if (!res.ok)
261
+ throw new Error('auth: request failed');
262
+ return new DataReader(new Uint8Array(await res.arrayBuffer())).readU8();
263
+ }
217
264
  export async function confirmEmail(token, opts = {}) {
218
265
  const baseUrl = opts.baseUrl ?? '/auth';
219
266
  const res = await postBinary(baseUrl, '/confirm', new DataWriter().writeBytes(fromHex(token)).toBytes());
@@ -272,6 +319,11 @@ export const Auth = {
272
319
  resendConfirmation,
273
320
  requestPasswordReset,
274
321
  resetPassword,
322
+ verifyTwoFactor,
323
+ setupTwoFactor,
324
+ confirmTwoFactorSetup,
325
+ twoFactorStatus,
326
+ TwoFactorMethod,
275
327
  buildLoginMessage,
276
328
  LOGIN_CONTEXT,
277
329
  };
@@ -37,5 +37,7 @@ export class SeriesData {
37
37
  metric: i32 = 0;
38
38
  bucketSecs: u32 = 0;
39
39
  headMs: u64 = 0;
40
- points: i64[] = [];
40
+ // `u64` to match `Analytics.series(...).points` (per-bucket totals are
41
+ // non-negative). Was `i64[]`, which the toilscript analytics API rejects.
42
+ points: u64[] = [];
41
43
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "toiljs",
3
3
  "type": "module",
4
- "version": "0.0.90",
4
+ "version": "0.0.91",
5
5
  "author": "Dacely",
6
6
  "description": "The modern React framework: a file-based React frontend and a ToilScript-compiled WebAssembly backend.",
7
7
  "repository": {
@@ -70,6 +70,44 @@ const ST_OK: u8 = 0;
70
70
  const ST_TAKEN: u8 = 1; // username already registered
71
71
  const ST_EMAIL_TAKEN: u8 = 2; // email already in use (register)
72
72
  const ST_UNCONFIRMED: u8 = 2; // email not confirmed (login) — distinct endpoint, reuses the value
73
+ // login/finish 2FA status: the credential verified but a SECOND factor is
74
+ // required; no session is minted (see loginFinish). Distinct from ST_OK(0) /
75
+ // ST_UNCONFIRMED(2) so the client can branch.
76
+ const ST_TWOFA_REQUIRED: u8 = 3;
77
+
78
+ // Two-factor METHOD enum (append-only; the value is stored in AuthAccount and in
79
+ // every challenge, so NEVER renumber). 0 = 2FA off. Adding a method is one new
80
+ // value here plus a deliver arm + a verify arm (see the `switch (method)` sites);
81
+ // the challenge lifecycle and the login wiring do NOT change.
82
+ const TWOFA_NONE: u8 = 0;
83
+ const TWOFA_EMAIL: u8 = 1;
84
+ // Future (reserved, not yet implemented): TWOFA_TOTP: u8 = 2; TWOFA_SMS: u8 = 3;
85
+
86
+ // 2FA challenge tuning. The code is single-use, TTL'd, and attempt-limited (all
87
+ // enforced against the stored challenge, independent of the per-IP @ratelimit).
88
+ const TWOFA_TTL_SECS: u64 = 300; // a login/setup code is valid 5 minutes
89
+ const TWOFA_MAX_ATTEMPTS: u32 = 5; // wrong-code guesses before the challenge dies
90
+ const TWOFA_DIGITS: i32 = 6; // digits in an emailed numeric code
91
+
92
+ // RACE-FREE per-challenge attempt cap. The `ch.attempts` counter below is a
93
+ // non-atomic get+patch across two host calls, so on the edge (a fresh wasm
94
+ // instance per request across 14 workers) N concurrent verifies for ONE
95
+ // challenge can each read attempts=0 and all guess before any patch lands -- a
96
+ // lost-update TOCTOU that lifts the intended 5-guess cap to the attacker's
97
+ // in-flight concurrency. The per-IP @ratelimit does NOT backstop a many-IP
98
+ // attacker. So we ALSO count each verify against a host-side EXACT limiter keyed
99
+ // on the CHALLENGE itself (twoFaId / setup username), never the peer IP: the
100
+ // count is atomic and shared across all workers, so total guesses per challenge
101
+ // are hard-capped regardless of source IP or request concurrency. `ch.attempts`
102
+ // stays as the primary (UX-friendly, burns-the-row) sequential path; this is the
103
+ // concurrency backstop. The routeIds sit just under i32::MAX so they can never
104
+ // collide with the `@ratelimit` decorator's monotonic-from-0 routeIds.
105
+ const TWOFA_VERIFY_RL_ROUTE: i32 = 2147483001;
106
+ const TWOFA_SETUP_RL_ROUTE: i32 = 2147483002;
107
+ // The host strategy tag for SlidingWindow (matches `RateLimit.SlidingWindow` and
108
+ // what the @ratelimit decorator lowers to). Used as a raw int because `RateLimit`
109
+ // is a type-only ambient enum with no runtime backing in a handler body.
110
+ const TWOFA_RL_STRATEGY: i32 = 1;
73
111
 
74
112
  // Resolved-and-cached per instance; the audience id (server config, never
75
113
  // client-echoed). Read lazily (not at module top level) so the env host import
@@ -244,6 +282,49 @@ function mintToken(): Uint8Array {
244
282
  return randomBytes(32);
245
283
  }
246
284
 
285
+ /**
286
+ * A CSPRNG numeric code of `digits` decimal digits (leading zeros kept), using
287
+ * REJECTION SAMPLING so there is NO modulo bias: a byte in [250,256) is rejected
288
+ * (250 = the largest multiple of 10 that is <= 256), so every accepted byte maps
289
+ * uniformly onto 0-9. Each digit is drawn independently until accepted.
290
+ */
291
+ function randomCode(digits: i32): string {
292
+ const buf = new Uint8Array(1);
293
+ let s = '';
294
+ for (let i = 0; i < digits; i++) {
295
+ let b: i32 = 255;
296
+ do {
297
+ crypto.getRandomValues(buf);
298
+ b = <i32>buf[0];
299
+ } while (b >= 250); // reject the biased tail
300
+ s += (b % 10).toString();
301
+ }
302
+ return s;
303
+ }
304
+
305
+ /** The stored 2FA verifier: SHA-256 of `username || 0x00 || code`. The username
306
+ * is bound INTO the hash (a null separator, unambiguous), so a code is only ever
307
+ * valid for the account it was issued to; the plaintext code is NEVER stored. */
308
+ function twoFaCodeHash(username: string, code: string): Uint8Array {
309
+ return crypto.sha256Text(username + '\x00' + code);
310
+ }
311
+
312
+ /** Constant-time equality of two fixed 32-byte SHA-256 hashes (XOR-accumulate,
313
+ * no early exit on the first differing byte). Mirrors the client `bytesEqual`. */
314
+ function ctEqual(a: Uint8Array, b: Uint8Array): bool {
315
+ if (a.length != b.length) return false;
316
+ let diff: i32 = 0;
317
+ for (let i = 0; i < a.length; i++) diff |= (<i32>a[i]) ^ (<i32>b[i]);
318
+ return diff == 0;
319
+ }
320
+
321
+ /** Whether `m` is a 2FA method this build understands (TWOFA_NONE or a supported
322
+ * method). ADD A METHOD: also accept its enum value here. */
323
+ function isKnownTwoFaMethod(m: u8): bool {
324
+ return m == TWOFA_NONE || m == TWOFA_EMAIL;
325
+ // >>> e.g. `|| m == TWOFA_TOTP || m == TWOFA_SMS` <<<
326
+ }
327
+
247
328
  @data
248
329
  class Username {
249
330
  name: string = '';
@@ -306,6 +387,11 @@ class AuthAccount {
306
387
  parallelism: u32 = 0;
307
388
  email: string = '';
308
389
  emailConfirmed: bool = false;
390
+ // APPENDED (append-only, forward-compatible like `email` above): the account's
391
+ // second-factor method (see the TWOFA_* enum). An old row decodes as 0 =
392
+ // TWOFA_NONE (2FA off), the safe default, so existing accounts stay logged in
393
+ // by password alone until they opt in via /auth/2fa/setup.
394
+ twoFactorMethod: u8 = 0;
309
395
  }
310
396
 
311
397
  @data
@@ -317,6 +403,35 @@ class Challenge {
317
403
  exp: u64 = 0;
318
404
  }
319
405
 
406
+ /** The lookup key for a login 2FA challenge: 16 random bytes minted per login.
407
+ * Lives in its OWN collection (twoFaLogins), a SEPARATE NAMESPACE from
408
+ * confirm/reset TokenId, so a confirm/reset token can never resolve here. */
409
+ @data
410
+ class TwoFaId {
411
+ id: Uint8Array = new Uint8Array(0);
412
+ constructor(id: Uint8Array = new Uint8Array(0)) {
413
+ this.id = id;
414
+ }
415
+ }
416
+
417
+ /**
418
+ * A pending second-factor challenge (login OR setup). METHOD-AGNOSTIC lifecycle
419
+ * fields (username / exp / attempts) plus the per-method `codeHash`; `method` is
420
+ * which factor was delivered and `targetMethod` is used ONLY by the setup flow
421
+ * (what to set `account.twoFactorMethod` to on success). Login challenges leave
422
+ * `targetMethod` at 0. `codeHash = SHA-256(username || 0x00 || code)`; the
423
+ * plaintext code is never stored.
424
+ */
425
+ @data
426
+ class TwoFaChallenge {
427
+ username: string = '';
428
+ method: u8 = 0;
429
+ codeHash: Uint8Array = new Uint8Array(0);
430
+ exp: u64 = 0;
431
+ attempts: u32 = 0;
432
+ targetMethod: u8 = 0;
433
+ }
434
+
320
435
  @database
321
436
  class AuthDb {
322
437
  @collection static accounts: Documents<Username, AuthAccount>;
@@ -329,6 +444,14 @@ class AuthDb {
329
444
  // user per kind (O(users)), not one per request (unbounded storage-griefing).
330
445
  @collection static confirmTokenOf: Documents<Username, TokenId>;
331
446
  @collection static resetTokenOf: Documents<Username, TokenId>;
447
+ // SECOND-FACTOR challenges live in their OWN collections, a namespace fully
448
+ // disjoint from confirm/reset tokens (above). A reset/confirm token looked up
449
+ // here finds nothing (wrong collection); a 2FA code/id looked up in the token
450
+ // collections finds nothing. The separation is STRUCTURAL, not a purpose
451
+ // string. `twoFaLogins` is keyed by a random per-login id; `twoFaSetup` is
452
+ // keyed by username = one outstanding setup challenge per user.
453
+ @collection static twoFaLogins: Documents<TwoFaId, TwoFaChallenge>;
454
+ @collection static twoFaSetup: Documents<Username, TwoFaChallenge>;
332
455
  }
333
456
 
334
457
  @rest('auth')
@@ -565,6 +688,40 @@ class Auth {
565
688
  const sessionKey = AuthService.deriveSessionKey(sharedSecret, transcriptHash);
566
689
  const confirm = AuthService.serverConfirmTag(sessionKey, transcriptHash);
567
690
 
691
+ // 3c. SECOND-FACTOR GATE. If this account has 2FA enabled, DO NOT mint a
692
+ // session here. Mint a login 2FA challenge (method-agnostic lifecycle)
693
+ // and deliver the code (per-method), then return ST_TWOFA_REQUIRED
694
+ // WITH the serverConfirm tag (so the client still completes mutual auth
695
+ // and knows the server is genuine BEFORE it prompts for a code) and NO
696
+ // cookie. The challenge is stored in `twoFaLogins` (its own namespace,
697
+ // never resetTokens/confirmTokens). This runs AFTER the signature
698
+ // verify above, so it is not an oracle, and the login `Challenge` was
699
+ // already consumed (getDelete) at the top of this handler.
700
+ if (acct.twoFactorMethod != TWOFA_NONE) {
701
+ const raw = randomBytes(16); // the twoFaId the client echoes to /2fa/verify
702
+ const codeHash = this.twoFaDeliver(
703
+ acct.twoFactorMethod,
704
+ ch.username,
705
+ acct.email,
706
+ 'Your login code',
707
+ );
708
+ if (codeHash.length == 0) return fail(); // unsupported/misconfigured method
709
+ const c2 = new TwoFaChallenge();
710
+ c2.username = ch.username;
711
+ c2.method = acct.twoFactorMethod;
712
+ c2.codeHash = codeHash;
713
+ c2.exp = nowSecs() + TWOFA_TTL_SECS;
714
+ c2.attempts = 0;
715
+ c2.targetMethod = TWOFA_NONE; // a LOGIN challenge changes no method on success
716
+ AuthDb.twoFaLogins.create(new TwoFaId(raw), c2);
717
+
718
+ const w2 = new DataWriter();
719
+ w2.writeU8(ST_TWOFA_REQUIRED);
720
+ w2.writeBytes(raw);
721
+ w2.writeBytes(confirm); // mutual-auth tag: the client verifies the server first
722
+ return Response.bytes(w2.toBytes()); // NO Set-Cookie: no session until 2FA verifies
723
+ }
724
+
568
725
  // 4. Success: mint the session for whatever `@user` this program has (built-in or the app's own
569
726
  // extended one). `__toilEncodeAuthUser` is injected by `--authUser`: it constructs the `@user`
570
727
  // (app fields at their defaults), sets the reserved identity, and encodes it. The stable
@@ -707,6 +864,239 @@ class Auth {
707
864
  return resp;
708
865
  }
709
866
 
867
+ /** POST /auth/2fa/verify body: bytes(twoFaId) str(code)
868
+ * resp: u8(status) [+ bytes(userData)] + Set-Cookie on success.
869
+ * The SECOND factor of a 2FA login: consumes the login challenge minted by
870
+ * login/finish and, on success, mints the session (the FIRST point a cookie
871
+ * is set for a 2FA account). NOT @auth (there is no session yet). The
872
+ * challenge is looked up in `twoFaLogins` ONLY, so a reset/confirm token can
873
+ * never be presented here. Single-use, attempt-limited, TTL'd, rate-limited. */
874
+ @ratelimit(RateLimit.SlidingWindow, 5, 60)
875
+ @post('/2fa/verify')
876
+ public twoFaVerify(ctx: RouteContext): Response {
877
+ const r = new DataReader(ctx.request.body);
878
+ const id = r.readBytes();
879
+ const code = r.readString();
880
+ if (!r.ok || id.length == 0) return fail();
881
+
882
+ // RACE-FREE attempt cap: count this guess against a host-side EXACT
883
+ // limiter keyed on THIS challenge (the twoFaId), not the peer IP. Unlike
884
+ // the `ch.attempts` get+patch below, this is atomic across all workers,
885
+ // so a concurrent many-IP attacker cannot exceed TWOFA_MAX_ATTEMPTS
886
+ // guesses against one code. Denied -> 429 (Retry-After); the challenge is
887
+ // left for its TTL to reap. Keyed on the hex so the key is stable ASCII.
888
+ const rl = RateLimitService.guardKeyed(
889
+ TWOFA_VERIFY_RL_ROUTE,
890
+ TWOFA_RL_STRATEGY,
891
+ TWOFA_MAX_ATTEMPTS as i32,
892
+ TWOFA_TTL_SECS as i32,
893
+ crypto.toHex(id),
894
+ );
895
+ if (rl != null) return rl;
896
+
897
+ const key = new TwoFaId(id);
898
+ // PEEK (not consume): a wrong guess must NOT burn the challenge (a typo
899
+ // would otherwise lock the user out) until the attempt cap is reached.
900
+ const ch = AuthDb.twoFaLogins.get(key);
901
+ if (ch == null) return fail();
902
+ if (nowSecs() >= ch.exp || ch.attempts >= TWOFA_MAX_ATTEMPTS) {
903
+ AuthDb.twoFaLogins.delete(key); // burn an expired / exhausted challenge
904
+ return fail();
905
+ }
906
+ if (!this.twoFaVerifyCode(ch.username, code, ch)) {
907
+ // Wrong code: count the attempt; delete the challenge once the cap is
908
+ // hit so a burned-out challenge cannot be ground further.
909
+ ch.attempts = ch.attempts + 1;
910
+ if (ch.attempts >= TWOFA_MAX_ATTEMPTS) AuthDb.twoFaLogins.delete(key);
911
+ else AuthDb.twoFaLogins.patch(key, ch);
912
+ return fail();
913
+ }
914
+
915
+ // SUCCESS: consume-once, then mint the session EXACTLY like login/finish.
916
+ AuthDb.twoFaLogins.getDelete(key);
917
+ const acct = AuthDb.accounts.get(new Username(ch.username));
918
+ if (acct == null) return fail();
919
+ const domain = authDomain(ctx);
920
+ const toilUserId = ToilUserId.derive(acct.publicKey, ch.username, domain).toBytes();
921
+ const userData = __toilEncodeAuthUser(toilUserId, ch.username);
922
+ const w = new DataWriter();
923
+ w.writeU8(ST_OK);
924
+ w.writeBytes(userData);
925
+ const resp = Response.bytes(w.toBytes());
926
+ resp.setCookie(AuthService.mintSession(userData, SESSION_TTL_SECS));
927
+ resp.setCookie(AuthService.userCookie(userData, SESSION_TTL_SECS));
928
+ return resp;
929
+ }
930
+
931
+ /** POST /auth/2fa/setup (@auth) body: u8(targetMethod) resp: u8(ST_OK)
932
+ * Begin enabling or disabling 2FA for the SESSION user. Delivers a proof code
933
+ * and stores a setup challenge in `twoFaSetup` (keyed by username = one
934
+ * outstanding per user); /auth/2fa/setup/verify confirms it. ENABLE proves
935
+ * control of the NEW method (deliver via targetMethod). DISABLE proves control
936
+ * of the CURRENT method (deliver via account.twoFactorMethod) before the
937
+ * factor is removed - anti-hijack. Always a generic ST_OK. */
938
+ @auth
939
+ @ratelimit(RateLimit.SlidingWindow, 5, 60)
940
+ @post('/2fa/setup')
941
+ public twoFaSetup(_ctx: RouteContext): Response {
942
+ const r = new DataReader(_ctx.request.body);
943
+ const targetMethod = r.readU8();
944
+ if (!r.ok) return fail();
945
+ if (!isKnownTwoFaMethod(targetMethod)) return fail();
946
+ const u = AuthService.getUser();
947
+ if (u == null) return fail();
948
+ const acct = AuthDb.accounts.get(new Username(u.username));
949
+ if (acct == null) return fail();
950
+
951
+ // Disabling when 2FA is already off: nothing to prove; generic ST_OK.
952
+ if (targetMethod == TWOFA_NONE && acct.twoFactorMethod == TWOFA_NONE) {
953
+ return Response.bytes(new DataWriter().writeU8(ST_OK).toBytes());
954
+ }
955
+
956
+ // Which method delivers the PROOF code:
957
+ // ENABLE (targetMethod != NONE): the NEW method (prove you control it).
958
+ // DISABLE (targetMethod == NONE): the CURRENT method (prove you still
959
+ // hold the existing factor before it is removed).
960
+ const deliverMethod: u8 = targetMethod != TWOFA_NONE ? targetMethod : acct.twoFactorMethod;
961
+ const codeHash = this.twoFaDeliver(
962
+ deliverMethod,
963
+ u.username,
964
+ acct.email,
965
+ 'Your verification code',
966
+ );
967
+ if (codeHash.length == 0) return fail(); // unsupported deliver method
968
+
969
+ const c = new TwoFaChallenge();
970
+ c.username = u.username;
971
+ c.method = deliverMethod;
972
+ c.codeHash = codeHash;
973
+ c.exp = nowSecs() + TWOFA_TTL_SECS;
974
+ c.attempts = 0;
975
+ c.targetMethod = targetMethod; // what to set account.twoFactorMethod to on success
976
+ // One outstanding setup challenge per user: overwrite any prior.
977
+ AuthDb.twoFaSetup.delete(new Username(u.username));
978
+ AuthDb.twoFaSetup.create(new Username(u.username), c);
979
+ return Response.bytes(new DataWriter().writeU8(ST_OK).toBytes());
980
+ }
981
+
982
+ /** POST /auth/2fa/setup/verify (@auth) body: str(code) resp: u8(ST_OK)
983
+ * Confirms a pending /auth/2fa/setup challenge for the SESSION user: on a
984
+ * correct code, sets account.twoFactorMethod = challenge.targetMethod (enable
985
+ * OR disable) and consumes the challenge. Same single-use + attempt-limit +
986
+ * TTL as /auth/2fa/verify. */
987
+ @auth
988
+ @ratelimit(RateLimit.SlidingWindow, 5, 60)
989
+ @post('/2fa/setup/verify')
990
+ public twoFaSetupVerify(_ctx: RouteContext): Response {
991
+ const r = new DataReader(_ctx.request.body);
992
+ const code = r.readString();
993
+ if (!r.ok) return fail();
994
+ const u = AuthService.getUser();
995
+ if (u == null) return fail();
996
+
997
+ // RACE-FREE attempt cap for the setup challenge (same rationale as
998
+ // /2fa/verify): an atomic host-side limiter keyed on the session user, so
999
+ // the `ch.attempts` get+patch below cannot be out-raced by concurrent
1000
+ // submissions. @auth-gated, so lower risk than login, but fixed alike.
1001
+ const srl = RateLimitService.guardKeyed(
1002
+ TWOFA_SETUP_RL_ROUTE,
1003
+ TWOFA_RL_STRATEGY,
1004
+ TWOFA_MAX_ATTEMPTS as i32,
1005
+ TWOFA_TTL_SECS as i32,
1006
+ u.username,
1007
+ );
1008
+ if (srl != null) return srl;
1009
+
1010
+ const key = new Username(u.username);
1011
+ const ch = AuthDb.twoFaSetup.get(key);
1012
+ if (ch == null) return fail();
1013
+ if (nowSecs() >= ch.exp || ch.attempts >= TWOFA_MAX_ATTEMPTS) {
1014
+ AuthDb.twoFaSetup.delete(key);
1015
+ return fail();
1016
+ }
1017
+ if (!this.twoFaVerifyCode(ch.username, code, ch)) {
1018
+ ch.attempts = ch.attempts + 1;
1019
+ if (ch.attempts >= TWOFA_MAX_ATTEMPTS) AuthDb.twoFaSetup.delete(key);
1020
+ else AuthDb.twoFaSetup.patch(key, ch);
1021
+ return fail();
1022
+ }
1023
+
1024
+ // SUCCESS: consume-once + apply the method change.
1025
+ AuthDb.twoFaSetup.getDelete(key);
1026
+ const acct = AuthDb.accounts.get(key);
1027
+ if (acct == null) return fail();
1028
+ acct.twoFactorMethod = ch.targetMethod;
1029
+ AuthDb.accounts.patch(key, acct);
1030
+ return Response.bytes(new DataWriter().writeU8(ST_OK).toBytes());
1031
+ }
1032
+
1033
+ /** GET /auth/2fa/status (@auth) resp: u8(method) (0 = off, 1 = email, ...)
1034
+ * The session user's current 2FA method, so the UI can show state. */
1035
+ @auth
1036
+ @get('/2fa/status')
1037
+ public twoFaStatus(_ctx: RouteContext): Response {
1038
+ const u = AuthService.getUser();
1039
+ if (u == null) return fail();
1040
+ const acct = AuthDb.accounts.get(new Username(u.username));
1041
+ if (acct == null) return fail();
1042
+ return Response.bytes(new DataWriter().writeU8(acct.twoFactorMethod).toBytes());
1043
+ }
1044
+
1045
+ /**
1046
+ * PER-METHOD 2FA DELIVERY. Generates and delivers a fresh code for `method`
1047
+ * and returns the codeHash to persist for the later verify; returns an EMPTY
1048
+ * array for an unsupported method (the caller fails closed). The plaintext
1049
+ * code never leaves this method.
1050
+ *
1051
+ * >>> ADD A METHOD HERE: a new `case TWOFA_TOTP:` returns the codeHash/secret
1052
+ * binding WITHOUT emailing (the code is the authenticator's own output),
1053
+ * and pairs with a `case TWOFA_TOTP` in {@link twoFaVerifyCode}. The
1054
+ * lifecycle and the login/setup wiring do NOT change. <<<
1055
+ */
1056
+ private twoFaDeliver(method: u8, username: string, email: string, subject: string): Uint8Array {
1057
+ switch (method) {
1058
+ case TWOFA_EMAIL: {
1059
+ const code = randomCode(TWOFA_DIGITS);
1060
+ const text =
1061
+ 'Your verification code is ' +
1062
+ code +
1063
+ '.\nIt expires in a few minutes. If you did not request it, ignore this email.\n';
1064
+ const html =
1065
+ '<p>Your verification code is:</p>' +
1066
+ '<p style="font-size:28px;font-weight:bold;letter-spacing:4px">' +
1067
+ code +
1068
+ '</p>' +
1069
+ '<p>It expires in a few minutes. If you did not request it, ignore this email.</p>';
1070
+ // DETACHED (non-suspending) send: constant-time, no provider-RTT
1071
+ // parking (matches the confirm/reset anti-enumeration posture).
1072
+ EmailService.sendDetached(email, subject, text, '2fa', html);
1073
+ return twoFaCodeHash(username, code);
1074
+ }
1075
+ // >>> case TWOFA_TOTP: { return twoFaSecretBinding(username); } <<<
1076
+ default:
1077
+ return new Uint8Array(0);
1078
+ }
1079
+ }
1080
+
1081
+ /**
1082
+ * PER-METHOD 2FA VERIFICATION: `true` iff `code` satisfies `challenge` for its
1083
+ * method. The method-agnostic lifecycle (peek / attempt-limit / TTL / consume)
1084
+ * lives in the endpoints; only the CODE CHECK is per-method here.
1085
+ *
1086
+ * >>> ADD A METHOD HERE: a new `case TWOFA_TOTP:` runs a TOTP check against the
1087
+ * stored secret binding. <<<
1088
+ */
1089
+ private twoFaVerifyCode(username: string, code: string, challenge: TwoFaChallenge): bool {
1090
+ switch (challenge.method) {
1091
+ case TWOFA_EMAIL:
1092
+ // Constant-time compare of the two 32-byte SHA-256 hashes.
1093
+ return ctEqual(twoFaCodeHash(username, code), challenge.codeHash);
1094
+ // >>> case TWOFA_TOTP: return totpVerify(challenge.codeHash, code); <<<
1095
+ default:
1096
+ return false;
1097
+ }
1098
+ }
1099
+
710
1100
  /** Mint a confirm token for `username`/`email` and email the confirm link.
711
1101
  * Best-effort: a failed send is not fatal (the user can resend).
712
1102
  *
@@ -39,6 +39,13 @@ function fromHex(hex: string): Uint8Array {
39
39
  return out;
40
40
  }
41
41
 
42
+ /** bytes -> lowercase-hex. */
43
+ function toHex(bytes: Uint8Array): string {
44
+ let s = '';
45
+ for (let i = 0; i < bytes.length; i++) s += bytes[i].toString(16).padStart(2, '0');
46
+ return s;
47
+ }
48
+
42
49
  /**
43
50
  * The server's PINNED static ML-KEM-768 public key. The client encapsulates to
44
51
  * it; only the genuine server (holder of the matching secret key) can
@@ -353,17 +360,23 @@ export async function login(
353
360
  wipe(sharedSecret);
354
361
  throw new EmailNotConfirmedError();
355
362
  }
356
- if (loginStatus !== 0) {
363
+ // status 3 = 2FA required: the credential verified but the account has a second
364
+ // factor. The server ALSO returns its serverConfirm tag (so we still complete
365
+ // mutual auth below) but mints NO session/cookie. Both the success (0) and the
366
+ // 2FA (3) responses are `bytes(first) bytes(serverConfirm)` -- `first` is the
367
+ // session token on 0 and the twoFaId on 3.
368
+ if (loginStatus !== 0 && loginStatus !== 3) {
357
369
  wipe(sharedSecret);
358
370
  throw new Error('auth: login failed');
359
371
  }
360
- const session = res.readBytes();
372
+ const first = res.readBytes();
361
373
  const serverConfirm = res.readBytes();
362
374
 
363
375
  // 5. Mutual auth: derive the session key K = HMAC(sharedSecret, label || H(M)),
364
376
  // then check the server's tag = HMAC(K, label || H(M)). Only a server that
365
377
  // decapsulated correctly derives the same K, so a valid tag proves its
366
- // identity. Verify before returning the session.
378
+ // identity. Runs for BOTH statuses, so a 2FA prompt only ever appears AFTER
379
+ // the server has authenticated itself.
367
380
  const transcriptHash = await sha256Bytes(message);
368
381
  const sessionKey = await hmacSha256(
369
382
  sharedSecret,
@@ -376,7 +389,14 @@ export async function login(
376
389
  );
377
390
  if (!bytesEqual(expected, serverConfirm)) throw new Error('auth: server authentication failed');
378
391
 
379
- return session; // session token
392
+ if (loginStatus === 3) {
393
+ // The server authenticated itself, but a second factor is required. Surface
394
+ // the twoFaId (hex) so the caller can collect a code and call
395
+ // verifyTwoFactor. NO session exists yet.
396
+ throw new TwoFactorRequiredError(toHex(first));
397
+ }
398
+
399
+ return first; // session token
380
400
  }
381
401
 
382
402
  /** Thrown by {@link login} when the credential is valid but the account's email
@@ -389,6 +409,91 @@ export class EmailNotConfirmedError extends Error {
389
409
  }
390
410
  }
391
411
 
412
+ /** Thrown by {@link login} when the password verified AND the server authenticated
413
+ * itself (mutual auth passed) but the account requires a SECOND FACTOR. No session
414
+ * exists yet. Catch it, collect the delivered code, and call
415
+ * {@link verifyTwoFactor} with `err.twoFaId`. */
416
+ export class TwoFactorRequiredError extends Error {
417
+ /** The opaque login-challenge id (hex) to echo to {@link verifyTwoFactor}. */
418
+ readonly twoFaId: string;
419
+ constructor(twoFaId: string) {
420
+ super('auth: two-factor authentication required');
421
+ this.name = 'TwoFactorRequiredError';
422
+ this.twoFaId = twoFaId;
423
+ }
424
+ }
425
+
426
+ /** The 2FA method values, mirroring the server enum (append-only). */
427
+ export const TwoFactorMethod = { None: 0, Email: 1 } as const;
428
+
429
+ /**
430
+ * Complete a 2FA login: submit the delivered `code` for the challenge `twoFaId`
431
+ * (from {@link TwoFactorRequiredError}). On success the server mints the session
432
+ * (sets the cookies) and returns the opaque session token. Throws one generic
433
+ * error ("code invalid or expired") on any failure -- the code is single-use and
434
+ * attempt-limited server-side.
435
+ */
436
+ export async function verifyTwoFactor(
437
+ twoFaId: string,
438
+ code: string,
439
+ opts: AuthOptions = {},
440
+ ): Promise<Uint8Array> {
441
+ const baseUrl = opts.baseUrl ?? '/auth';
442
+ const res = await postBinary(
443
+ baseUrl,
444
+ '/2fa/verify',
445
+ new DataWriter().writeBytes(fromHex(twoFaId)).writeString(code).toBytes(),
446
+ );
447
+ if (res.readU8() !== 0) throw new Error('auth: two-factor code invalid or expired');
448
+ return res.readBytes(); // opaque session token
449
+ }
450
+
451
+ /**
452
+ * Begin enabling or disabling 2FA for the CURRENT session user. Pass a
453
+ * {@link TwoFactorMethod} value (`Email` to enable email 2FA, `None` to disable).
454
+ * The server delivers a proof code (to the new method when enabling, or the
455
+ * CURRENT method when disabling - anti-hijack); confirm it with
456
+ * {@link confirmTwoFactorSetup}. Requires a valid session.
457
+ */
458
+ export async function setupTwoFactor(method: number, opts: AuthOptions = {}): Promise<void> {
459
+ const baseUrl = opts.baseUrl ?? '/auth';
460
+ const res = await postBinary(
461
+ baseUrl,
462
+ '/2fa/setup',
463
+ new DataWriter().writeU8(method).toBytes(),
464
+ );
465
+ if (res.readU8() !== 0) throw new Error('auth: two-factor setup failed');
466
+ }
467
+
468
+ /**
469
+ * Confirm a pending {@link setupTwoFactor} by submitting the delivered `code`.
470
+ * On success the account's 2FA method is switched (enabled or disabled). Requires
471
+ * a valid session. Throws (generic) if the code is wrong or expired.
472
+ */
473
+ export async function confirmTwoFactorSetup(code: string, opts: AuthOptions = {}): Promise<void> {
474
+ const baseUrl = opts.baseUrl ?? '/auth';
475
+ const res = await postBinary(
476
+ baseUrl,
477
+ '/2fa/setup/verify',
478
+ new DataWriter().writeString(code).toBytes(),
479
+ );
480
+ if (res.readU8() !== 0) throw new Error('auth: two-factor setup confirmation failed');
481
+ }
482
+
483
+ /**
484
+ * The current session user's 2FA method (a {@link TwoFactorMethod} value; `0` =
485
+ * off). Requires a valid session. For the UI to reflect enabled/disabled state.
486
+ */
487
+ export async function twoFactorStatus(opts: AuthOptions = {}): Promise<number> {
488
+ const baseUrl = opts.baseUrl ?? '/auth';
489
+ const res = await fetch(baseUrl + '/2fa/status', {
490
+ method: 'GET',
491
+ credentials: 'same-origin',
492
+ });
493
+ if (!res.ok) throw new Error('auth: request failed');
494
+ return new DataReader(new Uint8Array(await res.arrayBuffer())).readU8();
495
+ }
496
+
392
497
  /** Confirm an account from the one-time token in the emailed link
393
498
  * (`/confirm?token=<hex>`). Throws if the token is invalid or expired. */
394
499
  export async function confirmEmail(token: string, opts: AuthOptions = {}): Promise<void> {
@@ -489,6 +594,11 @@ export const Auth = {
489
594
  resendConfirmation,
490
595
  requestPasswordReset,
491
596
  resetPassword,
597
+ verifyTwoFactor,
598
+ setupTwoFactor,
599
+ confirmTwoFactorSetup,
600
+ twoFactorStatus,
601
+ TwoFactorMethod,
492
602
  buildLoginMessage,
493
603
  LOGIN_CONTEXT,
494
604
  } as const;
@@ -24,7 +24,7 @@ import { __resetDbForTests } from '../src/devserver/db/index.js';
24
24
  import { __resetRatelimitForTests } from '../src/devserver/config/ratelimit.js';
25
25
  import { clearEnvCache } from '../src/devserver/config/dotenv.js';
26
26
  import { __sentEmails, __clearSentEmails } from '../src/devserver/email/index.js';
27
- import { Auth, EmailNotConfirmedError } from '../src/client/auth.js';
27
+ import { Auth, EmailNotConfirmedError, TwoFactorRequiredError } from '../src/client/auth.js';
28
28
  import { DataReader, DataWriter } from '../src/io/codec.js';
29
29
 
30
30
  const EXAMPLE_WASM = path.resolve(
@@ -117,6 +117,21 @@ function tokenFromEmail(kind: 'confirm' | 'reset', to: string): string {
117
117
  );
118
118
  }
119
119
 
120
+ /** Pull the 6-digit code out of the most-recent captured 2FA email (purpose `2fa`) to `to`. */
121
+ function codeFromEmail(to: string): string {
122
+ for (let i = __sentEmails.length - 1; i >= 0; i--) {
123
+ const msg = __sentEmails[i];
124
+ if (msg.to !== to || msg.purpose !== '2fa') continue;
125
+ const hit = /\b(\d{6})\b/.exec(msg.text) ?? /\b(\d{6})\b/.exec(msg.html);
126
+ if (hit) return hit[1];
127
+ }
128
+ throw new Error(
129
+ `no 2fa code emailed to ${to}; captured=${JSON.stringify(
130
+ __sentEmails.map((e) => ({ to: e.to, purpose: e.purpose })),
131
+ )}`,
132
+ );
133
+ }
134
+
120
135
  describe.skipIf(!haveWasm)('built-in auth: email verification + password reset (client <-> example wasm)', () => {
121
136
  let restoreFetch: () => void;
122
137
  let mod: WasmServerModule;
@@ -330,4 +345,293 @@ describe.skipIf(!haveWasm)('built-in auth: email verification + password reset (
330
345
  },
331
346
  60_000,
332
347
  );
348
+
349
+ // ---- multi-method 2FA (email) ----
350
+
351
+ it(
352
+ '(a) full email-2FA login round-trip: enable, login requires a code, verify mints the session',
353
+ async () => {
354
+ await Auth.register('dave', 'dave-pw-strong', 'dave@x.com');
355
+ await Auth.login('dave', 'dave-pw-strong'); // 2FA off -> session
356
+
357
+ // Enable email 2FA: setup delivers a code, confirm switches the method on.
358
+ await Auth.setupTwoFactor(Auth.TwoFactorMethod.Email);
359
+ await Auth.confirmTwoFactorSetup(codeFromEmail('dave@x.com'));
360
+ expect(await Auth.twoFactorStatus()).toBe(Auth.TwoFactorMethod.Email);
361
+
362
+ __clearSentEmails();
363
+ jar.clear(); // drop the existing session so login is a clean 2FA challenge
364
+
365
+ // Login now demands a second factor: mutual auth still passes (login()
366
+ // verifies serverConfirm before throwing), but NO session is minted.
367
+ let err: unknown;
368
+ try {
369
+ await Auth.login('dave', 'dave-pw-strong');
370
+ } catch (e) {
371
+ err = e;
372
+ }
373
+ expect(err).toBeInstanceOf(TwoFactorRequiredError);
374
+ const twoFaId = (err as TwoFactorRequiredError).twoFaId;
375
+ expect(twoFaId.length).toBeGreaterThan(0);
376
+ expect(jar.get('toil_sess')).toBeUndefined(); // no session at login/finish
377
+
378
+ // Read the login code out of the captured email and verify -> session.
379
+ const session = await Auth.verifyTwoFactor(twoFaId, codeFromEmail('dave@x.com'));
380
+ expect(session.length).toBeGreaterThan(0);
381
+
382
+ // /auth/me now returns the user.
383
+ const meRes = await fetch('/auth/me');
384
+ expect(meRes.status).toBe(200);
385
+ const me = new DataReader(new Uint8Array(await meRes.arrayBuffer()));
386
+ expect(me.readBytes().length).toBeGreaterThan(0); // toilUserId
387
+ expect(me.readString()).toBe('dave');
388
+ },
389
+ 90_000,
390
+ );
391
+
392
+ it(
393
+ '(b) 2FA code security: wrong code rejected + attempt-limited to death, correct code single-use',
394
+ async () => {
395
+ await Auth.register('eve', 'eve-pw-strong', 'eve@x.com');
396
+ await Auth.login('eve', 'eve-pw-strong');
397
+ await Auth.setupTwoFactor(Auth.TwoFactorMethod.Email);
398
+ await Auth.confirmTwoFactorSetup(codeFromEmail('eve@x.com'));
399
+
400
+ // ---- wrong code is rejected, and after TWOFA_MAX_ATTEMPTS the challenge dies ----
401
+ __clearSentEmails();
402
+ jar.clear();
403
+ let err: unknown;
404
+ try {
405
+ await Auth.login('eve', 'eve-pw-strong');
406
+ } catch (e) {
407
+ err = e;
408
+ }
409
+ const twoFaId = (err as TwoFactorRequiredError).twoFaId;
410
+ const code = codeFromEmail('eve@x.com');
411
+ const wrong = code === '000000' ? '111111' : '000000';
412
+
413
+ // 5 (TWOFA_MAX_ATTEMPTS) wrong guesses. Reset the per-IP limiter between
414
+ // each so this exercises the CHALLENGE's own attempt cap, not @ratelimit.
415
+ for (let i = 0; i < 5; i++) {
416
+ __resetRatelimitForTests();
417
+ await expect(Auth.verifyTwoFactor(twoFaId, wrong)).rejects.toThrow();
418
+ }
419
+ // The challenge is now destroyed: even the CORRECT code fails.
420
+ __resetRatelimitForTests();
421
+ await expect(Auth.verifyTwoFactor(twoFaId, code)).rejects.toThrow();
422
+
423
+ // ---- a correct code is single-use: replay fails ----
424
+ __clearSentEmails();
425
+ jar.clear();
426
+ __resetRatelimitForTests();
427
+ let err2: unknown;
428
+ try {
429
+ await Auth.login('eve', 'eve-pw-strong');
430
+ } catch (e) {
431
+ err2 = e;
432
+ }
433
+ const twoFaId2 = (err2 as TwoFactorRequiredError).twoFaId;
434
+ const code2 = codeFromEmail('eve@x.com');
435
+ const session = await Auth.verifyTwoFactor(twoFaId2, code2); // consumes
436
+ expect(session.length).toBeGreaterThan(0);
437
+ __resetRatelimitForTests();
438
+ await expect(Auth.verifyTwoFactor(twoFaId2, code2)).rejects.toThrow(); // replay dead
439
+ },
440
+ 120_000,
441
+ );
442
+
443
+ it(
444
+ '(c) cross-flow: reset tokens and 2FA codes are NOT interchangeable (namespace separation)',
445
+ async () => {
446
+ await Auth.register('frank', 'frank-pw-strong', 'frank@x.com');
447
+
448
+ // ---- direction 1: a LIVE reset token is useless at /auth/2fa/verify ----
449
+ await Auth.requestPasswordReset('frank@x.com');
450
+ const resetToken = tokenFromEmail('reset', 'frank@x.com'); // live resetTokens entry
451
+ __resetRatelimitForTests();
452
+ // Present the reset token as BOTH the twoFaId AND the code: /2fa/verify
453
+ // looks in `twoFaLogins` (a different collection) -> nothing -> rejected.
454
+ await expect(Auth.verifyTwoFactor(resetToken, resetToken)).rejects.toThrow();
455
+
456
+ // ---- direction 2: a LIVE 2FA login challenge id is useless at /auth/reset/finish ----
457
+ await Auth.login('frank', 'frank-pw-strong'); // session (2FA still off here)
458
+ __clearSentEmails();
459
+ await Auth.setupTwoFactor(Auth.TwoFactorMethod.Email);
460
+ await Auth.confirmTwoFactorSetup(codeFromEmail('frank@x.com'));
461
+ __clearSentEmails();
462
+ jar.clear();
463
+ __resetRatelimitForTests();
464
+ let err: unknown;
465
+ try {
466
+ await Auth.login('frank', 'frank-pw-strong');
467
+ } catch (e) {
468
+ err = e;
469
+ }
470
+ const twoFaId = (err as TwoFactorRequiredError).twoFaId; // live twoFaLogins key
471
+ const loginCode = codeFromEmail('frank@x.com');
472
+
473
+ // Submit the live 2FA challenge id AND the live 2FA code to
474
+ // /auth/reset/finish as the reset token: reset/finish looks in
475
+ // `resetTokens` -> nothing -> non-200. A live 2FA challenge is NOT a
476
+ // reset token.
477
+ const probes: Uint8Array[] = [hexToBytes(twoFaId), new TextEncoder().encode(loginCode)];
478
+ for (const raw of probes) {
479
+ __resetRatelimitForTests();
480
+ const body = new DataWriter()
481
+ .writeBytes(raw)
482
+ .writeBytes(new Uint8Array(1312)) // valid-length pk (reach the consume step)
483
+ .writeBytes(new Uint8Array(2420)) // valid-length proof
484
+ .toBytes();
485
+ const r = mod.dispatch({
486
+ method: 'POST',
487
+ path: '/auth/reset/finish',
488
+ headers: [
489
+ ['host', 'localhost:3000'],
490
+ ['content-type', 'application/octet-stream'],
491
+ ],
492
+ body,
493
+ });
494
+ expect(r.status).not.toBe(200);
495
+ }
496
+
497
+ // The cross-flow probes touched NOTHING: the real 2FA login still
498
+ // completes with its real (twoFaId, code).
499
+ __resetRatelimitForTests();
500
+ const session = await Auth.verifyTwoFactor(twoFaId, loginCode);
501
+ expect(session.length).toBeGreaterThan(0);
502
+ },
503
+ 120_000,
504
+ );
505
+
506
+ it(
507
+ '(d) NO session cookie is set on the ST_TWOFA_REQUIRED login response',
508
+ async () => {
509
+ await Auth.register('gwen', 'gwen-pw-strong', 'gwen@x.com');
510
+ await Auth.login('gwen', 'gwen-pw-strong');
511
+ await Auth.setupTwoFactor(Auth.TwoFactorMethod.Email);
512
+ await Auth.confirmTwoFactorSetup(codeFromEmail('gwen@x.com'));
513
+
514
+ jar.clear(); // drop every cookie
515
+ __clearSentEmails();
516
+ __resetRatelimitForTests();
517
+
518
+ let err: unknown;
519
+ try {
520
+ await Auth.login('gwen', 'gwen-pw-strong');
521
+ } catch (e) {
522
+ err = e;
523
+ }
524
+ expect(err).toBeInstanceOf(TwoFactorRequiredError);
525
+ // The shim folds any Set-Cookie into the jar; login/finish set NONE.
526
+ expect(jar.get('toil_sess')).toBeUndefined();
527
+ expect(jar.get('toil_user')).toBeUndefined();
528
+ // With no session cookie, the @auth-gated /auth/me is 401.
529
+ const meRes = await fetch('/auth/me');
530
+ expect(meRes.status).toBe(401);
531
+ },
532
+ 60_000,
533
+ );
534
+
535
+ it(
536
+ '(e) login<->setup 2FA challenges are separate: a setup code cannot mint a login session, and setup/verify never silently disables 2FA',
537
+ async () => {
538
+ await Auth.register('ivy', 'ivy-pw-strong', 'ivy@x.com');
539
+ await Auth.login('ivy', 'ivy-pw-strong'); // session; 2FA still off
540
+
541
+ // Begin a 2FA SETUP: writes a challenge into `twoFaSetup` (keyed by
542
+ // username), NOT a login challenge into `twoFaLogins`.
543
+ __clearSentEmails();
544
+ __resetRatelimitForTests();
545
+ await Auth.setupTwoFactor(Auth.TwoFactorMethod.Email);
546
+ const setupCode = codeFromEmail('ivy@x.com');
547
+
548
+ // Present the LIVE setup code at /auth/2fa/verify with a fabricated
549
+ // twoFaId: /2fa/verify consults ONLY `twoFaLogins`, so the id misses and
550
+ // a setup code can never mint a login session.
551
+ __resetRatelimitForTests();
552
+ const fakeId = 'ab'.repeat(16); // 16-byte hex, not a real twoFaLogins key
553
+ await expect(Auth.verifyTwoFactor(fakeId, setupCode)).rejects.toThrow();
554
+
555
+ // The probe consumed NOTHING: the real setup still completes with the code.
556
+ __resetRatelimitForTests();
557
+ await Auth.confirmTwoFactorSetup(setupCode);
558
+ expect(await Auth.twoFactorStatus()).toBe(Auth.TwoFactorMethod.Email);
559
+
560
+ // With 2FA now ON but NO pending setup challenge, /auth/2fa/setup/verify is
561
+ // a no-op: a stray code cannot flip (disable) the method. A login challenge
562
+ // (targetMethod=NONE) has no wire path here and can never be routed in to
563
+ // silently disable 2FA.
564
+ __resetRatelimitForTests();
565
+ await expect(Auth.confirmTwoFactorSetup('000000')).rejects.toThrow();
566
+ expect(await Auth.twoFactorStatus()).toBe(Auth.TwoFactorMethod.Email);
567
+ },
568
+ 120_000,
569
+ );
570
+
571
+ it(
572
+ '(f) cross-flow: confirm tokens and 2FA codes are NOT interchangeable (namespace separation)',
573
+ async () => {
574
+ setConfirmation(true);
575
+ await Auth.register('jade', 'jade-pw-strong', 'jade@x.com'); // unconfirmed -> confirm token emailed
576
+ const confirmToken = tokenFromEmail('confirm', 'jade@x.com'); // live confirmTokens entry
577
+
578
+ // ---- direction 1: a LIVE confirm token is useless at /auth/2fa/verify ----
579
+ __resetRatelimitForTests();
580
+ // Present the confirm token as BOTH the twoFaId AND the code: /2fa/verify
581
+ // reads `twoFaLogins` (a different collection) -> nothing -> rejected.
582
+ await expect(Auth.verifyTwoFactor(confirmToken, confirmToken)).rejects.toThrow();
583
+
584
+ // The probe consumed NOTHING: the confirm token still confirms the account,
585
+ // and login then succeeds (email now confirmed).
586
+ __resetRatelimitForTests();
587
+ await Auth.confirmEmail(confirmToken);
588
+ __resetRatelimitForTests();
589
+ expect((await Auth.login('jade', 'jade-pw-strong')).length).toBeGreaterThan(0);
590
+
591
+ // ---- direction 2: a LIVE 2FA login id/code is useless at /auth/confirm ----
592
+ // Enable 2FA (jade is confirmed + has a session from the login above).
593
+ __clearSentEmails();
594
+ __resetRatelimitForTests();
595
+ await Auth.setupTwoFactor(Auth.TwoFactorMethod.Email);
596
+ await Auth.confirmTwoFactorSetup(codeFromEmail('jade@x.com'));
597
+
598
+ // Fresh login -> a live `twoFaLogins` challenge (id + emailed code).
599
+ __clearSentEmails();
600
+ jar.clear();
601
+ __resetRatelimitForTests();
602
+ let err: unknown;
603
+ try {
604
+ await Auth.login('jade', 'jade-pw-strong');
605
+ } catch (e) {
606
+ err = e;
607
+ }
608
+ const twoFaId = (err as TwoFactorRequiredError).twoFaId;
609
+ const loginCode = codeFromEmail('jade@x.com');
610
+
611
+ // Submit the live 2FA id AND the live code to /auth/confirm as the confirm
612
+ // token: /auth/confirm consumes from `confirmTokens` (sha256(raw)) -> nothing
613
+ // -> non-200. A 2FA credential is NOT a confirm token.
614
+ const probes: Uint8Array[] = [hexToBytes(twoFaId), new TextEncoder().encode(loginCode)];
615
+ for (const raw of probes) {
616
+ __resetRatelimitForTests();
617
+ const body = new DataWriter().writeBytes(raw).toBytes();
618
+ const r = mod.dispatch({
619
+ method: 'POST',
620
+ path: '/auth/confirm',
621
+ headers: [
622
+ ['host', 'localhost:3000'],
623
+ ['content-type', 'application/octet-stream'],
624
+ ],
625
+ body,
626
+ });
627
+ expect(r.status).not.toBe(200);
628
+ }
629
+
630
+ // The probes touched NOTHING: the real 2FA login still completes.
631
+ __resetRatelimitForTests();
632
+ const session = await Auth.verifyTwoFactor(twoFaId, loginCode);
633
+ expect(session.length).toBeGreaterThan(0);
634
+ },
635
+ 120_000,
636
+ );
333
637
  });