From 2adb25e913196d9505b9a561f0af141cd1d8909d Mon Sep 17 00:00:00 2001 From: Steven Vandevelde Date: Thu, 24 Aug 2023 20:40:13 +0200 Subject: [PATCH] feat: implement authority transfer --- DESIGN.md | 2 + package-lock.json | 1000 ++++++----------- package.json | 63 +- src/accessKey.ts | 7 + src/auth.ts | 4 +- src/authority/query.ts | 76 +- src/channel.ts | 6 +- src/channel/websocket.ts | 13 +- src/components.ts | 10 +- .../account/fission/implementations/common.ts | 61 +- .../fission/implementations/delegated.ts | 11 +- .../fission/implementations/standard.ts | 10 +- src/components/account/implementation.ts | 17 +- src/components/account/local.ts | 2 +- src/components/agent/implementation.ts | 4 +- src/components/authority/browser-url.ts | 25 + .../authority/browser-url/common.ts | 180 +++ .../authority/browser-url/provider.ts | 348 ++++++ .../authority/browser-url/requestor.ts | 284 +++++ .../authority/browser-url/session.ts | 103 ++ .../{ts-ucan.ts => clerk/default.ts} | 32 +- src/components/authority/implementation.ts | 55 +- src/components/channel/fission.ts | 12 +- src/components/channel/implementation.ts | 4 +- src/components/channel/local.ts | 10 +- .../depot/ipfs-bitswap-websockets.ts | 2 +- src/compositions/fission.ts | 36 +- src/compositions/local.ts | 11 +- src/events/authority.ts | 22 +- src/fileSystem.ts | 12 +- src/fs/class.node.test.ts | 32 +- src/fs/class.ts | 30 +- src/fs/transaction.ts | 19 +- src/identifier/did.ts | 30 + src/index.ts | 121 +- src/inventory.ts | 129 +++ src/repositories/cabinet.ts | 19 +- src/ticket/index.ts | 21 + src/ticket/inventory.ts | 124 -- src/ticket/types.ts | 7 + tests/helpers/components.ts | 19 +- tsconfig.json | 2 +- 42 files changed, 1939 insertions(+), 1036 deletions(-) create mode 100644 src/accessKey.ts create mode 100644 src/components/authority/browser-url.ts create mode 100644 src/components/authority/browser-url/common.ts create mode 100644 src/components/authority/browser-url/provider.ts create mode 100644 src/components/authority/browser-url/requestor.ts create mode 100644 src/components/authority/browser-url/session.ts rename src/components/authority/{ts-ucan.ts => clerk/default.ts} (76%) create mode 100644 src/identifier/did.ts create mode 100644 src/inventory.ts delete mode 100644 src/ticket/inventory.ts diff --git a/DESIGN.md b/DESIGN.md index adc5df09..2fea7d86 100644 --- a/DESIGN.md +++ b/DESIGN.md @@ -86,6 +86,8 @@ The reason we have two components here is so the `Identifier` doesn't need to si Typically the `Agent` will use a temporary session key pair and the `Identifier` is the more permanent identifier. Example flow: Identifier delegates to agent, agent contacts remote account service, account service issues UCANs addressed to identifier. Those UCANs are then used throughout the SDK to check for capabilities, etc. +The storage DID used for the file system is always the identifier DID. + ### Authority This component is responsible for providing and requesting authority, which technically means providing and requesting UCANs and file system secrets (access keys). diff --git a/package-lock.json b/package-lock.json index 9730e7ee..078d5abf 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,68 +9,69 @@ "version": "0.40.0-prerelease", "license": "Apache-2.0", "dependencies": { - "@chainsafe/libp2p-noise": "^13.0.0", - "@chainsafe/libp2p-yamux": "^5.0.0", "@ipld/dag-cbor": "^9.0.4", "@ipld/dag-pb": "^4.0.5", - "@libp2p/mplex": "^9.0.4", - "@libp2p/peer-id": "^3.0.2", - "@libp2p/websockets": "^7.0.4", - "@libp2p/webtransport": "^3.0.6", - "@multiformats/multiaddr": "^12.1.7", - "@ucans/core": "^0.12.0", - "blockstore-level": "^1.1.3", "debounce-promise": "^3.1.2", "emittery": "^1.0.1", - "events": "^3.3.0", - "fission-bloom-filters": "1.7.1", "interface-blockstore": "^5.2.5", - "interface-datastore": "^8.2.4", - "ipfs-bitswap": "^19.0.0", - "ipfs-unixfs": "^11.0.1", - "ipfs-unixfs-exporter": "^13.1.6", - "ipfs-unixfs-importer": "^15.1.7", + "ipfs-unixfs": "^11.1.0", + "ipfs-unixfs-exporter": "^13.2.1", + "ipfs-unixfs-importer": "^15.2.1", "iso-base": "^2.0.0", - "iso-did": "^1.3.1", + "iso-did": "^1.3.2", "iso-signatures": "^0.1.9", "it-all": "^3.0.3", - "libp2p": "^0.46.6", - "localforage": "^1.10.0", "multiformats": "^12.0.1", - "one-webcrypto": "^1.0.3", "uint8arrays": "^4.0.6", - "wnfs": "0.1.24" + "wnfs": "0.1.26" }, "devDependencies": { "@esbuild-plugins/node-globals-polyfill": "^0.2.3", - "@ipld/car": "^5.2.0", + "@ipld/car": "^5.2.2", "@types/debounce-promise": "^3.1.6", "@types/expect": "^24.3.0", "@types/mocha": "^10.0.1", - "@types/node": "^20.5.0", - "@typescript-eslint/eslint-plugin": "^6.4.0", - "@typescript-eslint/parser": "^6.4.0", + "@types/node": "^20.5.7", + "@typescript-eslint/eslint-plugin": "^6.5.0", + "@typescript-eslint/parser": "^6.5.0", "assert": "^2.0.0", "copyfiles": "^2.4.1", "dprint": "^0.40.2", "esbuild": "^0.19.2", "esbuild-plugin-wasm": "^1.1.0", - "eslint": "^8.47.0", + "eslint": "^8.48.0", "fast-check": "^3.12.0", "globby": "^13.2.2", "madge": "^6.1.0", "mocha": "^10.2.0", "rimraf": "^5.0.1", "ts-node": "^10.9.1", - "tslib": "^2.6.1", - "typedoc": "^0.24.8", - "typedoc-plugin-missing-exports": "^2.0.1", - "typedoc-plugin-rename-defaults": "^0.6.5", - "typescript": "^5.1.6", + "tslib": "^2.6.2", + "typedoc": "^0.25.0", + "typedoc-plugin-missing-exports": "^2.1.0", + "typedoc-plugin-rename-defaults": "^0.6.6", + "typescript": "^5.2.2", "util": "^0.12.4" }, "engines": { "node": ">=16" + }, + "peerDependencies": { + "@chainsafe/libp2p-noise": "^13.0.0", + "@chainsafe/libp2p-yamux": "^5.0.0", + "@libp2p/mplex": "^9.0.5", + "@libp2p/peer-id": "^3.0.2", + "@libp2p/websockets": "^7.0.5", + "@libp2p/webtransport": "^3.0.7", + "@multiformats/multiaddr": "^12.1.7", + "@noble/ciphers": "^0.3.0", + "@noble/curves": "^1.2.0", + "@noble/hashes": "^1.3.2", + "@ucans/core": "^0.12.0", + "blockstore-level": "^1.1.3", + "ipfs-bitswap": "^19.0.0", + "libp2p": "^0.46.7", + "localforage": "^1.10.0" } }, "node_modules/@aashutoshrathi/word-wrap": { @@ -86,6 +87,7 @@ "version": "1.0.11", "resolved": "https://registry.npmjs.org/@achingbrain/nat-port-mapper/-/nat-port-mapper-1.0.11.tgz", "integrity": "sha512-Y2lwx0zmrwEl+IGu+V/QiVBdcdsWscYq1PMMEjvyuuaXnmnppbLWilO8LK1yoLdncxwJBuS0zZtHbpFeWBusRg==", + "peer": true, "dependencies": { "@achingbrain/ssdp": "^4.0.1", "@libp2p/logger": "^3.0.0", @@ -105,6 +107,7 @@ "version": "4.0.4", "resolved": "https://registry.npmjs.org/@achingbrain/ssdp/-/ssdp-4.0.4.tgz", "integrity": "sha512-fY/ShiYJmhLdr45Vn2+f88xTqZjBSH3X3F+EJu/89cjB1JIkMCVtD5CQaaS38YknIL8cEcNhjMZM4cdE3ckSSQ==", + "peer": true, "dependencies": { "event-iterator": "^2.0.0", "freeport-promise": "^2.0.0", @@ -120,6 +123,7 @@ "version": "0.5.0", "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.5.0.tgz", "integrity": "sha512-drPFnkQJik/O+uPKpqSgr22mpuFHqKdbS835iAQrUC73L2F5WkboIRd63ai/2Yg6I1jzifPFKH2NTK+cfglkIA==", + "peer": true, "dependencies": { "sax": ">=0.6.0", "xmlbuilder": "~11.0.0" @@ -254,12 +258,14 @@ "node_modules/@chainsafe/is-ip": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/@chainsafe/is-ip/-/is-ip-2.0.2.tgz", - "integrity": "sha512-ndGqEMG1W5WkGagaqOZHpPU172AGdxr+LD15sv3WIUvT5oCFUrG1Y0CW/v2Egwj4JXEvSibaIIIqImsm98y1nA==" + "integrity": "sha512-ndGqEMG1W5WkGagaqOZHpPU172AGdxr+LD15sv3WIUvT5oCFUrG1Y0CW/v2Egwj4JXEvSibaIIIqImsm98y1nA==", + "peer": true }, "node_modules/@chainsafe/libp2p-noise": { "version": "13.0.0", "resolved": "https://registry.npmjs.org/@chainsafe/libp2p-noise/-/libp2p-noise-13.0.0.tgz", "integrity": "sha512-+kRW5GSTGYB42WjFa1f7Wc/1+VWLffOhwChi+CbPceidMHM5pbOQNb+xQM2/aqLre+A+WnBOKEopME7dnoqLNQ==", + "peer": true, "dependencies": { "@libp2p/crypto": "^2.0.0", "@libp2p/interface": "^0.1.0", @@ -283,10 +289,20 @@ "npm": ">=7.0.0" } }, + "node_modules/@chainsafe/libp2p-noise/node_modules/@noble/ciphers": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/@noble/ciphers/-/ciphers-0.1.4.tgz", + "integrity": "sha512-d3ZR8vGSpy3v/nllS+bD/OMN5UZqusWiQqkyj7AwzTnhXFH72pF5oB4Ach6DQ50g5kXxC28LdaYBEpsyv9KOUQ==", + "peer": true, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, "node_modules/@chainsafe/libp2p-yamux": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/@chainsafe/libp2p-yamux/-/libp2p-yamux-5.0.0.tgz", "integrity": "sha512-aWTnBPR2hJt0A2y579sMtZVB6IqgSSHlZ6Eg+WDxNZQ0zcexafuruZQDj+z3FUTNPz+E8IeuyCi7tjI4IEehjw==", + "peer": true, "dependencies": { "@libp2p/interface": "^0.1.0", "@libp2p/logger": "^3.0.0", @@ -305,6 +321,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/@chainsafe/netmask/-/netmask-2.0.0.tgz", "integrity": "sha512-I3Z+6SWUoaljh3TBzCnCxjlUyN8tA+NAk5L6m9IxvCf1BENQTePzPMis97CoN/iMW1St3WN+AWCCRp+TTBRiDg==", + "peer": true, "dependencies": { "@chainsafe/is-ip": "^2.0.1" } @@ -343,54 +360,6 @@ "esbuild": "*" } }, - "node_modules/@esbuild/android-arm": { - "version": "0.19.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.19.2.tgz", - "integrity": "sha512-tM8yLeYVe7pRyAu9VMi/Q7aunpLwD139EY1S99xbQkT4/q2qa6eA4ige/WJQYdJ8GBL1K33pPFhPfPdJ/WzT8Q==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/android-arm64": { - "version": "0.19.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.19.2.tgz", - "integrity": "sha512-lsB65vAbe90I/Qe10OjkmrdxSX4UJDjosDgb8sZUKcg3oefEuW2OT2Vozz8ef7wrJbMcmhvCC+hciF8jY/uAkw==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/android-x64": { - "version": "0.19.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.19.2.tgz", - "integrity": "sha512-qK/TpmHt2M/Hg82WXHRc/W/2SGo/l1thtDHZWqFq7oi24AjZ4O/CpPSu6ZuYKFkEgmZlFoa7CooAyYmuvnaG8w==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, "node_modules/@esbuild/darwin-arm64": { "version": "0.19.2", "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.19.2.tgz", @@ -407,294 +376,6 @@ "node": ">=12" } }, - "node_modules/@esbuild/darwin-x64": { - "version": "0.19.2", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.19.2.tgz", - "integrity": "sha512-tP+B5UuIbbFMj2hQaUr6EALlHOIOmlLM2FK7jeFBobPy2ERdohI4Ka6ZFjZ1ZYsrHE/hZimGuU90jusRE0pwDw==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/freebsd-arm64": { - "version": "0.19.2", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.19.2.tgz", - "integrity": "sha512-YbPY2kc0acfzL1VPVK6EnAlig4f+l8xmq36OZkU0jzBVHcOTyQDhnKQaLzZudNJQyymd9OqQezeaBgkTGdTGeQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/freebsd-x64": { - "version": "0.19.2", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.19.2.tgz", - "integrity": "sha512-nSO5uZT2clM6hosjWHAsS15hLrwCvIWx+b2e3lZ3MwbYSaXwvfO528OF+dLjas1g3bZonciivI8qKR/Hm7IWGw==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-arm": { - "version": "0.19.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.19.2.tgz", - "integrity": "sha512-Odalh8hICg7SOD7XCj0YLpYCEc+6mkoq63UnExDCiRA2wXEmGlK5JVrW50vZR9Qz4qkvqnHcpH+OFEggO3PgTg==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-arm64": { - "version": "0.19.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.19.2.tgz", - "integrity": "sha512-ig2P7GeG//zWlU0AggA3pV1h5gdix0MA3wgB+NsnBXViwiGgY77fuN9Wr5uoCrs2YzaYfogXgsWZbm+HGr09xg==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-ia32": { - "version": "0.19.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.19.2.tgz", - "integrity": "sha512-mLfp0ziRPOLSTek0Gd9T5B8AtzKAkoZE70fneiiyPlSnUKKI4lp+mGEnQXcQEHLJAcIYDPSyBvsUbKUG2ri/XQ==", - "cpu": [ - "ia32" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-loong64": { - "version": "0.19.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.19.2.tgz", - "integrity": "sha512-hn28+JNDTxxCpnYjdDYVMNTR3SKavyLlCHHkufHV91fkewpIyQchS1d8wSbmXhs1fiYDpNww8KTFlJ1dHsxeSw==", - "cpu": [ - "loong64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-mips64el": { - "version": "0.19.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.19.2.tgz", - "integrity": "sha512-KbXaC0Sejt7vD2fEgPoIKb6nxkfYW9OmFUK9XQE4//PvGIxNIfPk1NmlHmMg6f25x57rpmEFrn1OotASYIAaTg==", - "cpu": [ - "mips64el" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-ppc64": { - "version": "0.19.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.19.2.tgz", - "integrity": "sha512-dJ0kE8KTqbiHtA3Fc/zn7lCd7pqVr4JcT0JqOnbj4LLzYnp+7h8Qi4yjfq42ZlHfhOCM42rBh0EwHYLL6LEzcw==", - "cpu": [ - "ppc64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-riscv64": { - "version": "0.19.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.19.2.tgz", - "integrity": "sha512-7Z/jKNFufZ/bbu4INqqCN6DDlrmOTmdw6D0gH+6Y7auok2r02Ur661qPuXidPOJ+FSgbEeQnnAGgsVynfLuOEw==", - "cpu": [ - "riscv64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-s390x": { - "version": "0.19.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.19.2.tgz", - "integrity": "sha512-U+RinR6aXXABFCcAY4gSlv4CL1oOVvSSCdseQmGO66H+XyuQGZIUdhG56SZaDJQcLmrSfRmx5XZOWyCJPRqS7g==", - "cpu": [ - "s390x" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-x64": { - "version": "0.19.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.19.2.tgz", - "integrity": "sha512-oxzHTEv6VPm3XXNaHPyUTTte+3wGv7qVQtqaZCrgstI16gCuhNOtBXLEBkBREP57YTd68P0VgDgG73jSD8bwXQ==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/netbsd-x64": { - "version": "0.19.2", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.19.2.tgz", - "integrity": "sha512-WNa5zZk1XpTTwMDompZmvQLHszDDDN7lYjEHCUmAGB83Bgs20EMs7ICD+oKeT6xt4phV4NDdSi/8OfjPbSbZfQ==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/openbsd-x64": { - "version": "0.19.2", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.19.2.tgz", - "integrity": "sha512-S6kI1aT3S++Dedb7vxIuUOb3oAxqxk2Rh5rOXOTYnzN8JzW1VzBd+IqPiSpgitu45042SYD3HCoEyhLKQcDFDw==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/sunos-x64": { - "version": "0.19.2", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.19.2.tgz", - "integrity": "sha512-VXSSMsmb+Z8LbsQGcBMiM+fYObDNRm8p7tkUDMPG/g4fhFX5DEFmjxIEa3N8Zr96SjsJ1woAhF0DUnS3MF3ARw==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "sunos" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/win32-arm64": { - "version": "0.19.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.19.2.tgz", - "integrity": "sha512-5NayUlSAyb5PQYFAU9x3bHdsqB88RC3aM9lKDAz4X1mo/EchMIT1Q+pSeBXNgkfNmRecLXA0O8xP+x8V+g/LKg==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/win32-ia32": { - "version": "0.19.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.19.2.tgz", - "integrity": "sha512-47gL/ek1v36iN0wL9L4Q2MFdujR0poLZMJwhO2/N3gA89jgHp4MR8DKCmwYtGNksbfJb9JoTtbkoe6sDhg2QTA==", - "cpu": [ - "ia32" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/win32-x64": { - "version": "0.19.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.19.2.tgz", - "integrity": "sha512-tcuhV7ncXBqbt/Ybf0IyrMcwVOAPDckMK9rXNHtF17UTK18OKLpg08glminN06pt2WCoALhXdLfSPbVvK/6fxw==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, "node_modules/@eslint-community/eslint-utils": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", @@ -743,9 +424,9 @@ } }, "node_modules/@eslint/js": { - "version": "8.47.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.47.0.tgz", - "integrity": "sha512-P6omY1zv5MItm93kLM8s2vr1HICJH8v0dvddDhysbIuZ+vcjOHg5Zbkf1mTkcmi2JA9oBG2anOkRnW8WJTS8Og==", + "version": "8.48.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.48.0.tgz", + "integrity": "sha512-ZSjtmelB7IJfWD2Fvb7+Z+ChTIKWq6kjda95fLcQKNS5aheVHn4IkfgRQE3sIIzTcSLwLcLZUD9UBt+V7+h+Pw==", "dev": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -785,14 +466,14 @@ "dev": true }, "node_modules/@ipld/car": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/@ipld/car/-/car-5.2.0.tgz", - "integrity": "sha512-Y4DiyVoPaeGxY6gKV/0A/73SlIIuDu7fl25NdlrO6BYhyTN6v59KqcilmMXbiBA/zcf7cZr1GZVPHRyG2+nmAw==", + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/@ipld/car/-/car-5.2.2.tgz", + "integrity": "sha512-8IapvzPNB1Z2VwtA7n6olB3quhrLMbFxk4JaENIT4OlQ6YQNz1peY00qb2iJTC/kCDir7yb3TuNHkbdDzSKiXA==", "dev": true, "dependencies": { "@ipld/dag-cbor": "^9.0.0", - "cborg": "^1.9.0", - "multiformats": "^11.0.0", + "cborg": "^2.0.5", + "multiformats": "^12.1.0", "varint": "^6.0.0" }, "engines": { @@ -800,16 +481,6 @@ "npm": ">=7.0.0" } }, - "node_modules/@ipld/car/node_modules/multiformats": { - "version": "11.0.2", - "resolved": "https://registry.npmjs.org/multiformats/-/multiformats-11.0.2.tgz", - "integrity": "sha512-b5mYMkOkARIuVZCpvijFj9a6m5wMVLC7cf/jIPd5D/ARDOfLC5+IFkbgDXQgcU2goIsTD/O9NY4DI/Mt4OGvlg==", - "dev": true, - "engines": { - "node": ">=16.0.0", - "npm": ">=7.0.0" - } - }, "node_modules/@ipld/dag-cbor": { "version": "9.0.4", "resolved": "https://registry.npmjs.org/@ipld/dag-cbor/-/dag-cbor-9.0.4.tgz", @@ -823,14 +494,6 @@ "npm": ">=7.0.0" } }, - "node_modules/@ipld/dag-cbor/node_modules/cborg": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/cborg/-/cborg-2.0.3.tgz", - "integrity": "sha512-f1IbyqgRLQK4ruNM+V3WikfYfXQg/f/zC1oneOw1P7F/Dn2OJX6MaXIdei3JMpz361IjY7OENBKcE53nkJFVCQ==", - "bin": { - "cborg": "cli.js" - } - }, "node_modules/@ipld/dag-pb": { "version": "4.0.5", "resolved": "https://registry.npmjs.org/@ipld/dag-pb/-/dag-pb-4.0.5.tgz", @@ -984,6 +647,7 @@ "version": "2.0.3", "resolved": "https://registry.npmjs.org/@libp2p/crypto/-/crypto-2.0.3.tgz", "integrity": "sha512-VLhjdkJe8b/vedHp7SosDs62Yxq1i05Ej/YdVaEdWQdJsBRHCwbRlS4hPg3vm21U5hLF0g958r/927Vd/wamZw==", + "peer": true, "dependencies": { "@libp2p/interface": "^0.1.2", "@noble/curves": "^1.1.0", @@ -999,6 +663,7 @@ "version": "0.1.2", "resolved": "https://registry.npmjs.org/@libp2p/interface/-/interface-0.1.2.tgz", "integrity": "sha512-Q5t27434Mvn+R6AUJlRH+q/jSXarDpP+KXVkyGY7S1fKPI2berqoFPqT61bRRBYsCH2OPZiKBB53VUzxL9uEvg==", + "peer": true, "dependencies": { "@multiformats/multiaddr": "^12.1.5", "abortable-iterator": "^5.0.1", @@ -1013,6 +678,7 @@ "version": "0.1.4", "resolved": "https://registry.npmjs.org/@libp2p/interface-internal/-/interface-internal-0.1.4.tgz", "integrity": "sha512-fRa8AUeCVOqfjgJgpIWupOsc7nAnJuI/VjWL2ZfRqbz7CPLD9c/ZAKXC140THSxlNdNQ9kGpo/C2z/yCGLy4ig==", + "peer": true, "dependencies": { "@libp2p/interface": "^0.1.2", "@libp2p/peer-collections": "^4.0.3", @@ -1024,6 +690,7 @@ "version": "3.0.3", "resolved": "https://registry.npmjs.org/@libp2p/keychain/-/keychain-3.0.3.tgz", "integrity": "sha512-mt3Pq8pPUDchoYlTXyNFMSIZ2/gbGZUJIr1qDQGphLZKxZ3Ejsqps2Dgo0t6yBxvJQ0581tXfptAXzw75Y2LIA==", + "peer": true, "dependencies": { "@libp2p/crypto": "^2.0.3", "@libp2p/interface": "^0.1.2", @@ -1039,6 +706,7 @@ "version": "3.0.2", "resolved": "https://registry.npmjs.org/@libp2p/logger/-/logger-3.0.2.tgz", "integrity": "sha512-2JtRGBXiGfm1t5XneUIXQ2JusW7QwyYmxsW7hSAYS5J73RQJUicpt5le5obVRt7+OM39ei+nWEuC6Xvm1ugHkw==", + "peer": true, "dependencies": { "@libp2p/interface": "^0.1.2", "@multiformats/multiaddr": "^12.1.5", @@ -1048,9 +716,10 @@ } }, "node_modules/@libp2p/mplex": { - "version": "9.0.4", - "resolved": "https://registry.npmjs.org/@libp2p/mplex/-/mplex-9.0.4.tgz", - "integrity": "sha512-vUoj4XJtQJocN4ZdokfoMXVlATeBmnHDUtk1CtluimwAPhHkIhO9IhzIWEYmb8C5j7Yim+824tPj+TJ6vfBYlQ==", + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/@libp2p/mplex/-/mplex-9.0.5.tgz", + "integrity": "sha512-cwg8ueB7xzwQbWt2da/Q5oPsm/6wk1GwNiGBiUsvy75h3qr6b1RNDuFJYkCSySI4mLvdTrkvthJCXHQMAW4Tvg==", + "peer": true, "dependencies": { "@libp2p/interface": "^0.1.2", "@libp2p/logger": "^3.0.2", @@ -1069,6 +738,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/uint8-varint/-/uint8-varint-2.0.1.tgz", "integrity": "sha512-euvmpuulJstK5+xNuI4S1KfnxJnbI5QP52RXIR3GZ3/ZMkOsEK2AgCtFpNvEQLXMxMx2o0qcyevK1fJwOZJagQ==", + "peer": true, "dependencies": { "uint8arraylist": "^2.0.0", "uint8arrays": "^4.0.2" @@ -1078,6 +748,7 @@ "version": "4.0.2", "resolved": "https://registry.npmjs.org/@libp2p/multistream-select/-/multistream-select-4.0.2.tgz", "integrity": "sha512-Ss3kPD+1Z8RFLUT+oN9I2ynEtp/Yj2+rOngU1XjIxustg1nt5lq0kk9hvWJyBexzmuML0xCknNjUXovpRbFPgQ==", + "peer": true, "dependencies": { "@libp2p/interface": "^0.1.2", "@libp2p/logger": "^3.0.2", @@ -1098,6 +769,7 @@ "version": "4.0.3", "resolved": "https://registry.npmjs.org/@libp2p/peer-collections/-/peer-collections-4.0.3.tgz", "integrity": "sha512-ahfZFdRhApN4dulnzAvkzQsPVJVX7UID3QMKC/cduK5FYWqm7zbtW6bpwDilhZY3wvjvaQYs4R0KKSysvTPiQQ==", + "peer": true, "dependencies": { "@libp2p/interface": "^0.1.2", "@libp2p/peer-id": "^3.0.2" @@ -1107,6 +779,7 @@ "version": "3.0.2", "resolved": "https://registry.npmjs.org/@libp2p/peer-id/-/peer-id-3.0.2.tgz", "integrity": "sha512-133qGXu9UBiqsYm7nBDJaAh4eiKe79DPLKF+/aRu0Z7gKcX7I0+LewEky4kBt3olhYQSF1CAnJIzD8Dmsn40Yw==", + "peer": true, "dependencies": { "@libp2p/interface": "^0.1.2", "multiformats": "^12.0.1", @@ -1117,6 +790,7 @@ "version": "3.0.3", "resolved": "https://registry.npmjs.org/@libp2p/peer-id-factory/-/peer-id-factory-3.0.3.tgz", "integrity": "sha512-RsE1GbK0w4LxiGr9sU2fm23IHOGzCtCfmUD8LC9V8LwLgt+z62oNKbWzwbko+CeromngURDimdv3JpH9jw5OUA==", + "peer": true, "dependencies": { "@libp2p/crypto": "^2.0.3", "@libp2p/interface": "^0.1.2", @@ -1131,6 +805,7 @@ "version": "6.0.3", "resolved": "https://registry.npmjs.org/@libp2p/peer-record/-/peer-record-6.0.3.tgz", "integrity": "sha512-S5C4Df2uyX1vNsnduZ6RVjB7T+dUEhqnaSNhiv82VCoqMoniHQBf2ftvXlv/UqqssW9or1x4UwgFU+sL7kObkw==", + "peer": true, "dependencies": { "@libp2p/crypto": "^2.0.3", "@libp2p/interface": "^0.1.2", @@ -1147,6 +822,7 @@ "version": "9.0.3", "resolved": "https://registry.npmjs.org/@libp2p/peer-store/-/peer-store-9.0.3.tgz", "integrity": "sha512-7vSAUvKAzzWRwcMxOUvyGNw8V59t9l9l1Ugxa+VHCKKhvAEn9eXjf8We8BLGT3KnUG6aJ5HpODPK4RbW6BNGfA==", + "peer": true, "dependencies": { "@libp2p/interface": "^0.1.2", "@libp2p/logger": "^3.0.2", @@ -1168,6 +844,7 @@ "version": "4.0.2", "resolved": "https://registry.npmjs.org/@libp2p/utils/-/utils-4.0.2.tgz", "integrity": "sha512-M6ARf4NhzFqpw15BOG0FQVXanjWdnta/s91OzhtdZhsp1A/FmUDlxwdIeshs2x/6TfNhyrMtR8Wid/BYsPpBow==", + "peer": true, "dependencies": { "@chainsafe/is-ip": "^2.0.2", "@libp2p/interface": "^0.1.2", @@ -1180,9 +857,10 @@ } }, "node_modules/@libp2p/websockets": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/@libp2p/websockets/-/websockets-7.0.4.tgz", - "integrity": "sha512-DtwsZhYH//3bIMtzBpzi7ZWPeHtfEgbDOCaoVORcb4152ZvC68C7u+c3k7S2TyXY1ceqLTAt9LI9hDMM0WNfcQ==", + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/@libp2p/websockets/-/websockets-7.0.5.tgz", + "integrity": "sha512-2Dz4ETRk+ecF2nj1S/G5vSBrhXhuBrXIMAzpqzTM6L0TrEraGrJYyoYB15A+u7kA8xMbdRodyguB6ZLVatL5nw==", + "peer": true, "dependencies": { "@libp2p/interface": "^0.1.2", "@libp2p/logger": "^3.0.2", @@ -1199,9 +877,10 @@ } }, "node_modules/@libp2p/webtransport": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/@libp2p/webtransport/-/webtransport-3.0.6.tgz", - "integrity": "sha512-JNr5oIimsuVNwChdnkMtyLeEQy49Y3qTvVroVoVznczGDDC08xmrDhd7DyIjIs7kfRKzMY5Wftu8TjzKXtC3aw==", + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@libp2p/webtransport/-/webtransport-3.0.7.tgz", + "integrity": "sha512-nZEza/sWqiAm0yc+SFmu1iOQgGp0zAhOmQlnuymK450Bmm+PcWw6+1MuV+y48WpweivwEzE3adU+PLPsfo3rOA==", + "peer": true, "dependencies": { "@chainsafe/libp2p-noise": "^13.0.0", "@libp2p/interface": "^0.1.2", @@ -1218,6 +897,7 @@ "version": "12.1.6", "resolved": "https://registry.npmjs.org/@multiformats/mafmt/-/mafmt-12.1.6.tgz", "integrity": "sha512-tlJRfL21X+AKn9b5i5VnaTD6bNttpSpcqwKVmDmSHLwxoz97fAHaepqFOk/l1fIu94nImIXneNbhsJx/RQNIww==", + "peer": true, "dependencies": { "@multiformats/multiaddr": "^12.0.0" } @@ -1226,6 +906,7 @@ "version": "12.1.7", "resolved": "https://registry.npmjs.org/@multiformats/multiaddr/-/multiaddr-12.1.7.tgz", "integrity": "sha512-MZRj+uUrtF2WqgByrsPolrdyPDSFstw7Fe0ewabWgWl27fcOmfDOSrEt2aUVkSzapXbyCG7JQh0QvimmTF4aMA==", + "peer": true, "dependencies": { "@chainsafe/is-ip": "^2.0.1", "@chainsafe/netmask": "^2.0.0", @@ -1244,6 +925,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/@multiformats/multiaddr-matcher/-/multiaddr-matcher-1.0.1.tgz", "integrity": "sha512-ZzqwTH8tP5Py/k8eNKprO0i6tuwgrbp7KWz+ttxvzkPl43BlU9Yd5joq+M5grCt158rpAc2uhPobzfXgPxW5XQ==", + "peer": true, "dependencies": { "@chainsafe/is-ip": "^2.0.1", "@multiformats/multiaddr": "^12.0.0", @@ -1254,6 +936,7 @@ "version": "9.0.2", "resolved": "https://registry.npmjs.org/@multiformats/multiaddr-to-uri/-/multiaddr-to-uri-9.0.2.tgz", "integrity": "sha512-vrWmfFadmix5Ab9l//oRQdQ7O3J5bGJpJRMSm21bHlQB0XV4xtNU6vMZBVXeu3Su79LgflEp37cjTFE3yKf3Hw==", + "peer": true, "dependencies": { "@multiformats/multiaddr": "^11.0.0" }, @@ -1266,6 +949,7 @@ "version": "11.6.1", "resolved": "https://registry.npmjs.org/@multiformats/multiaddr/-/multiaddr-11.6.1.tgz", "integrity": "sha512-doST0+aB7/3dGK9+U5y3mtF3jq85KGbke1QiH0KE1F5mGQ9y56mFebTeu2D9FNOm+OT6UHb8Ss8vbSnpGjeLNw==", + "peer": true, "dependencies": { "@chainsafe/is-ip": "^2.0.1", "dns-over-http-resolver": "^2.1.0", @@ -1283,6 +967,7 @@ "version": "11.0.2", "resolved": "https://registry.npmjs.org/multiformats/-/multiformats-11.0.2.tgz", "integrity": "sha512-b5mYMkOkARIuVZCpvijFj9a6m5wMVLC7cf/jIPd5D/ARDOfLC5+IFkbgDXQgcU2goIsTD/O9NY4DI/Mt4OGvlg==", + "peer": true, "engines": { "node": ">=16.0.0", "npm": ">=7.0.0" @@ -1292,6 +977,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/uint8-varint/-/uint8-varint-2.0.1.tgz", "integrity": "sha512-euvmpuulJstK5+xNuI4S1KfnxJnbI5QP52RXIR3GZ3/ZMkOsEK2AgCtFpNvEQLXMxMx2o0qcyevK1fJwOZJagQ==", + "peer": true, "dependencies": { "uint8arraylist": "^2.0.0", "uint8arrays": "^4.0.2" @@ -1320,19 +1006,21 @@ } }, "node_modules/@noble/ciphers": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/@noble/ciphers/-/ciphers-0.1.4.tgz", - "integrity": "sha512-d3ZR8vGSpy3v/nllS+bD/OMN5UZqusWiQqkyj7AwzTnhXFH72pF5oB4Ach6DQ50g5kXxC28LdaYBEpsyv9KOUQ==", + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@noble/ciphers/-/ciphers-0.3.0.tgz", + "integrity": "sha512-ldbrnOjmNRwFdXcTM6uXDcxpMIFrbzAWNnpBPp4oTJTFF0XByGD6vf45WrehZGXRQTRVV+Zm8YP+EgEf+e4cWA==", + "peer": true, "funding": { "url": "https://paulmillr.com/funding/" } }, "node_modules/@noble/curves": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.1.0.tgz", - "integrity": "sha512-091oBExgENk/kGj3AZmtBDMpxQPDtxQABR2B9lb1JbVTs6ytdzZNwvhxQ4MWasRNEzlbEH8jCWFCwhF/Obj5AA==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.2.0.tgz", + "integrity": "sha512-oYclrNgRaM9SsBUBVbb8M6DTV7ZHRTKugureoYEncY5c65HOmRzvSiTE3y5CYaPYJA/GVkrhXEoF0M3Ya9PMnw==", + "peer": true, "dependencies": { - "@noble/hashes": "1.3.1" + "@noble/hashes": "1.3.2" }, "funding": { "url": "https://paulmillr.com/funding/" @@ -1350,9 +1038,10 @@ ] }, "node_modules/@noble/hashes": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.1.tgz", - "integrity": "sha512-EbqwksQwz9xDRGfDST86whPBgM65E0OH/pCgqW0GBVzO22bNE+NuIbeTb714+IfSjU3aRk47EUvXIb5bTsenKA==", + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.2.tgz", + "integrity": "sha512-MVC8EAQp7MvEcm30KWENFjgR+Mkmf+D189XJTkFIlwohU5hcBbn1ZkKq7KVTi2Hme3PMGF390DaL52beVrIihQ==", + "peer": true, "engines": { "node": ">= 16" }, @@ -1542,19 +1231,20 @@ "dev": true }, "node_modules/@types/node": { - "version": "20.5.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.5.0.tgz", - "integrity": "sha512-Mgq7eCtoTjT89FqNoTzzXg2XvCi5VMhRV6+I2aYanc6kQCBImeNaAYRs/DyoVqk1YEUJK5gN9VO7HRIdz4Wo3Q==" + "version": "20.5.7", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.5.7.tgz", + "integrity": "sha512-dP7f3LdZIysZnmvP3ANJYTSwg+wLLl8p7RqniVlV7j+oXSXAbt9h0WIBFmJy5inWZoX9wZN6eXx+YXd9Rh3RBA==" }, "node_modules/@types/retry": { "version": "0.12.1", "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.1.tgz", - "integrity": "sha512-xoDlM2S4ortawSWORYqsdU+2rxdh4LRW9ytc3zmT37RIKQh6IHyKwwtKhKis9ah8ol07DCkZxPt8BBvPjC6v4g==" + "integrity": "sha512-xoDlM2S4ortawSWORYqsdU+2rxdh4LRW9ytc3zmT37RIKQh6IHyKwwtKhKis9ah8ol07DCkZxPt8BBvPjC6v4g==", + "peer": true }, "node_modules/@types/semver": { - "version": "7.5.0", - "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.0.tgz", - "integrity": "sha512-G8hZ6XJiHnuhQKR7ZmysCeJWE08o8T0AXtk5darsCaTVsYZhhgUrq53jizaR2FvsoeCwJhlmwTjkXBY5Pn/ZHw==", + "version": "7.5.1", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.1.tgz", + "integrity": "sha512-cJRQXpObxfNKkFAZbJl2yjWtJCqELQIdShsogr1d2MilP8dKD9TE/nEKHkJgUNHdGKCQaf9HbIynuV2csLGVLg==", "dev": true }, "node_modules/@types/stack-utils": { @@ -1567,6 +1257,7 @@ "version": "8.5.5", "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.5.tgz", "integrity": "sha512-lwhs8hktwxSjf9UaZ9tG5M03PGogvFaH8gUgLNbN9HKIg0dvv6q+gkSuJ8HN4/VbyxkuLzCjlN7GquQ0gUJfIg==", + "peer": true, "dependencies": { "@types/node": "*" } @@ -1587,16 +1278,16 @@ "dev": true }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "6.4.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.4.0.tgz", - "integrity": "sha512-62o2Hmc7Gs3p8SLfbXcipjWAa6qk2wZGChXG2JbBtYpwSRmti/9KHLqfbLs9uDigOexG+3PaQ9G2g3201FWLKg==", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.5.0.tgz", + "integrity": "sha512-2pktILyjvMaScU6iK3925uvGU87E+N9rh372uGZgiMYwafaw9SXq86U04XPq3UH6tzRvNgBsub6x2DacHc33lw==", "dev": true, "dependencies": { "@eslint-community/regexpp": "^4.5.1", - "@typescript-eslint/scope-manager": "6.4.0", - "@typescript-eslint/type-utils": "6.4.0", - "@typescript-eslint/utils": "6.4.0", - "@typescript-eslint/visitor-keys": "6.4.0", + "@typescript-eslint/scope-manager": "6.5.0", + "@typescript-eslint/type-utils": "6.5.0", + "@typescript-eslint/utils": "6.5.0", + "@typescript-eslint/visitor-keys": "6.5.0", "debug": "^4.3.4", "graphemer": "^1.4.0", "ignore": "^5.2.4", @@ -1622,9 +1313,9 @@ } }, "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/types": { - "version": "6.4.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.4.0.tgz", - "integrity": "sha512-+FV9kVFrS7w78YtzkIsNSoYsnOtrYVnKWSTVXoL1761CsCRv5wpDOINgsXpxD67YCLZtVQekDDyaxfjVWUJmmg==", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.5.0.tgz", + "integrity": "sha512-eqLLOEF5/lU8jW3Bw+8auf4lZSbbljHR2saKnYqON12G/WsJrGeeDHWuQePoEf9ro22+JkbPfWQwKEC5WwLQ3w==", "dev": true, "engines": { "node": "^16.0.0 || >=18.0.0" @@ -1635,12 +1326,12 @@ } }, "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/visitor-keys": { - "version": "6.4.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.4.0.tgz", - "integrity": "sha512-yJSfyT+uJm+JRDWYRYdCm2i+pmvXJSMtPR9Cq5/XQs4QIgNoLcoRtDdzsLbLsFM/c6um6ohQkg/MLxWvoIndJA==", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.5.0.tgz", + "integrity": "sha512-yCB/2wkbv3hPsh02ZS8dFQnij9VVQXJMN/gbQsaaY+zxALkZnxa/wagvLEFsAWMPv7d7lxQmNsIzGU1w/T/WyA==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.4.0", + "@typescript-eslint/types": "6.5.0", "eslint-visitor-keys": "^3.4.1" }, "engines": { @@ -1652,15 +1343,15 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "6.4.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.4.0.tgz", - "integrity": "sha512-I1Ah1irl033uxjxO9Xql7+biL3YD7w9IU8zF+xlzD/YxY6a4b7DYA08PXUUCbm2sEljwJF6ERFy2kTGAGcNilg==", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.5.0.tgz", + "integrity": "sha512-LMAVtR5GN8nY0G0BadkG0XIe4AcNMeyEy3DyhKGAh9k4pLSMBO7rF29JvDBpZGCmp5Pgz5RLHP6eCpSYZJQDuQ==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "6.4.0", - "@typescript-eslint/types": "6.4.0", - "@typescript-eslint/typescript-estree": "6.4.0", - "@typescript-eslint/visitor-keys": "6.4.0", + "@typescript-eslint/scope-manager": "6.5.0", + "@typescript-eslint/types": "6.5.0", + "@typescript-eslint/typescript-estree": "6.5.0", + "@typescript-eslint/visitor-keys": "6.5.0", "debug": "^4.3.4" }, "engines": { @@ -1680,9 +1371,9 @@ } }, "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/types": { - "version": "6.4.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.4.0.tgz", - "integrity": "sha512-+FV9kVFrS7w78YtzkIsNSoYsnOtrYVnKWSTVXoL1761CsCRv5wpDOINgsXpxD67YCLZtVQekDDyaxfjVWUJmmg==", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.5.0.tgz", + "integrity": "sha512-eqLLOEF5/lU8jW3Bw+8auf4lZSbbljHR2saKnYqON12G/WsJrGeeDHWuQePoEf9ro22+JkbPfWQwKEC5WwLQ3w==", "dev": true, "engines": { "node": "^16.0.0 || >=18.0.0" @@ -1693,13 +1384,13 @@ } }, "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/typescript-estree": { - "version": "6.4.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.4.0.tgz", - "integrity": "sha512-iDPJArf/K2sxvjOR6skeUCNgHR/tCQXBsa+ee1/clRKr3olZjZ/dSkXPZjG6YkPtnW6p5D1egeEPMCW6Gn4yLA==", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.5.0.tgz", + "integrity": "sha512-q0rGwSe9e5Kk/XzliB9h2LBc9tmXX25G0833r7kffbl5437FPWb2tbpIV9wAATebC/018pGa9fwPDuvGN+LxWQ==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.4.0", - "@typescript-eslint/visitor-keys": "6.4.0", + "@typescript-eslint/types": "6.5.0", + "@typescript-eslint/visitor-keys": "6.5.0", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -1720,12 +1411,12 @@ } }, "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/visitor-keys": { - "version": "6.4.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.4.0.tgz", - "integrity": "sha512-yJSfyT+uJm+JRDWYRYdCm2i+pmvXJSMtPR9Cq5/XQs4QIgNoLcoRtDdzsLbLsFM/c6um6ohQkg/MLxWvoIndJA==", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.5.0.tgz", + "integrity": "sha512-yCB/2wkbv3hPsh02ZS8dFQnij9VVQXJMN/gbQsaaY+zxALkZnxa/wagvLEFsAWMPv7d7lxQmNsIzGU1w/T/WyA==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.4.0", + "@typescript-eslint/types": "6.5.0", "eslint-visitor-keys": "^3.4.1" }, "engines": { @@ -1766,13 +1457,13 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "6.4.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.4.0.tgz", - "integrity": "sha512-TUS7vaKkPWDVvl7GDNHFQMsMruD+zhkd3SdVW0d7b+7Zo+bd/hXJQ8nsiUZMi1jloWo6c9qt3B7Sqo+flC1nig==", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.5.0.tgz", + "integrity": "sha512-A8hZ7OlxURricpycp5kdPTH3XnjG85UpJS6Fn4VzeoH4T388gQJ/PGP4ole5NfKt4WDVhmLaQ/dBLNDC4Xl/Kw==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.4.0", - "@typescript-eslint/visitor-keys": "6.4.0" + "@typescript-eslint/types": "6.5.0", + "@typescript-eslint/visitor-keys": "6.5.0" }, "engines": { "node": "^16.0.0 || >=18.0.0" @@ -1783,9 +1474,9 @@ } }, "node_modules/@typescript-eslint/scope-manager/node_modules/@typescript-eslint/types": { - "version": "6.4.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.4.0.tgz", - "integrity": "sha512-+FV9kVFrS7w78YtzkIsNSoYsnOtrYVnKWSTVXoL1761CsCRv5wpDOINgsXpxD67YCLZtVQekDDyaxfjVWUJmmg==", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.5.0.tgz", + "integrity": "sha512-eqLLOEF5/lU8jW3Bw+8auf4lZSbbljHR2saKnYqON12G/WsJrGeeDHWuQePoEf9ro22+JkbPfWQwKEC5WwLQ3w==", "dev": true, "engines": { "node": "^16.0.0 || >=18.0.0" @@ -1796,12 +1487,12 @@ } }, "node_modules/@typescript-eslint/scope-manager/node_modules/@typescript-eslint/visitor-keys": { - "version": "6.4.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.4.0.tgz", - "integrity": "sha512-yJSfyT+uJm+JRDWYRYdCm2i+pmvXJSMtPR9Cq5/XQs4QIgNoLcoRtDdzsLbLsFM/c6um6ohQkg/MLxWvoIndJA==", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.5.0.tgz", + "integrity": "sha512-yCB/2wkbv3hPsh02ZS8dFQnij9VVQXJMN/gbQsaaY+zxALkZnxa/wagvLEFsAWMPv7d7lxQmNsIzGU1w/T/WyA==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.4.0", + "@typescript-eslint/types": "6.5.0", "eslint-visitor-keys": "^3.4.1" }, "engines": { @@ -1813,13 +1504,13 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "6.4.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.4.0.tgz", - "integrity": "sha512-TvqrUFFyGY0cX3WgDHcdl2/mMCWCDv/0thTtx/ODMY1QhEiyFtv/OlLaNIiYLwRpAxAtOLOY9SUf1H3Q3dlwAg==", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.5.0.tgz", + "integrity": "sha512-f7OcZOkRivtujIBQ4yrJNIuwyCQO1OjocVqntl9dgSIZAdKqicj3xFDqDOzHDlGCZX990LqhLQXWRnQvsapq8A==", "dev": true, "dependencies": { - "@typescript-eslint/typescript-estree": "6.4.0", - "@typescript-eslint/utils": "6.4.0", + "@typescript-eslint/typescript-estree": "6.5.0", + "@typescript-eslint/utils": "6.5.0", "debug": "^4.3.4", "ts-api-utils": "^1.0.1" }, @@ -1840,9 +1531,9 @@ } }, "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/types": { - "version": "6.4.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.4.0.tgz", - "integrity": "sha512-+FV9kVFrS7w78YtzkIsNSoYsnOtrYVnKWSTVXoL1761CsCRv5wpDOINgsXpxD67YCLZtVQekDDyaxfjVWUJmmg==", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.5.0.tgz", + "integrity": "sha512-eqLLOEF5/lU8jW3Bw+8auf4lZSbbljHR2saKnYqON12G/WsJrGeeDHWuQePoEf9ro22+JkbPfWQwKEC5WwLQ3w==", "dev": true, "engines": { "node": "^16.0.0 || >=18.0.0" @@ -1853,13 +1544,13 @@ } }, "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/typescript-estree": { - "version": "6.4.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.4.0.tgz", - "integrity": "sha512-iDPJArf/K2sxvjOR6skeUCNgHR/tCQXBsa+ee1/clRKr3olZjZ/dSkXPZjG6YkPtnW6p5D1egeEPMCW6Gn4yLA==", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.5.0.tgz", + "integrity": "sha512-q0rGwSe9e5Kk/XzliB9h2LBc9tmXX25G0833r7kffbl5437FPWb2tbpIV9wAATebC/018pGa9fwPDuvGN+LxWQ==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.4.0", - "@typescript-eslint/visitor-keys": "6.4.0", + "@typescript-eslint/types": "6.5.0", + "@typescript-eslint/visitor-keys": "6.5.0", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -1880,12 +1571,12 @@ } }, "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/visitor-keys": { - "version": "6.4.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.4.0.tgz", - "integrity": "sha512-yJSfyT+uJm+JRDWYRYdCm2i+pmvXJSMtPR9Cq5/XQs4QIgNoLcoRtDdzsLbLsFM/c6um6ohQkg/MLxWvoIndJA==", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.5.0.tgz", + "integrity": "sha512-yCB/2wkbv3hPsh02ZS8dFQnij9VVQXJMN/gbQsaaY+zxALkZnxa/wagvLEFsAWMPv7d7lxQmNsIzGU1w/T/WyA==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.4.0", + "@typescript-eslint/types": "6.5.0", "eslint-visitor-keys": "^3.4.1" }, "engines": { @@ -2016,17 +1707,17 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "6.4.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.4.0.tgz", - "integrity": "sha512-BvvwryBQpECPGo8PwF/y/q+yacg8Hn/2XS+DqL/oRsOPK+RPt29h5Ui5dqOKHDlbXrAeHUTnyG3wZA0KTDxRZw==", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.5.0.tgz", + "integrity": "sha512-9nqtjkNykFzeVtt9Pj6lyR9WEdd8npPhhIPM992FWVkZuS6tmxHfGVnlUcjpUP2hv8r4w35nT33mlxd+Be1ACQ==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", "@types/json-schema": "^7.0.12", "@types/semver": "^7.5.0", - "@typescript-eslint/scope-manager": "6.4.0", - "@typescript-eslint/types": "6.4.0", - "@typescript-eslint/typescript-estree": "6.4.0", + "@typescript-eslint/scope-manager": "6.5.0", + "@typescript-eslint/types": "6.5.0", + "@typescript-eslint/typescript-estree": "6.5.0", "semver": "^7.5.4" }, "engines": { @@ -2041,9 +1732,9 @@ } }, "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/types": { - "version": "6.4.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.4.0.tgz", - "integrity": "sha512-+FV9kVFrS7w78YtzkIsNSoYsnOtrYVnKWSTVXoL1761CsCRv5wpDOINgsXpxD67YCLZtVQekDDyaxfjVWUJmmg==", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.5.0.tgz", + "integrity": "sha512-eqLLOEF5/lU8jW3Bw+8auf4lZSbbljHR2saKnYqON12G/WsJrGeeDHWuQePoEf9ro22+JkbPfWQwKEC5WwLQ3w==", "dev": true, "engines": { "node": "^16.0.0 || >=18.0.0" @@ -2054,13 +1745,13 @@ } }, "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/typescript-estree": { - "version": "6.4.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.4.0.tgz", - "integrity": "sha512-iDPJArf/K2sxvjOR6skeUCNgHR/tCQXBsa+ee1/clRKr3olZjZ/dSkXPZjG6YkPtnW6p5D1egeEPMCW6Gn4yLA==", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.5.0.tgz", + "integrity": "sha512-q0rGwSe9e5Kk/XzliB9h2LBc9tmXX25G0833r7kffbl5437FPWb2tbpIV9wAATebC/018pGa9fwPDuvGN+LxWQ==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.4.0", - "@typescript-eslint/visitor-keys": "6.4.0", + "@typescript-eslint/types": "6.5.0", + "@typescript-eslint/visitor-keys": "6.5.0", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -2081,12 +1772,12 @@ } }, "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/visitor-keys": { - "version": "6.4.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.4.0.tgz", - "integrity": "sha512-yJSfyT+uJm+JRDWYRYdCm2i+pmvXJSMtPR9Cq5/XQs4QIgNoLcoRtDdzsLbLsFM/c6um6ohQkg/MLxWvoIndJA==", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.5.0.tgz", + "integrity": "sha512-yCB/2wkbv3hPsh02ZS8dFQnij9VVQXJMN/gbQsaaY+zxALkZnxa/wagvLEFsAWMPv7d7lxQmNsIzGU1w/T/WyA==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.4.0", + "@typescript-eslint/types": "6.5.0", "eslint-visitor-keys": "^3.4.1" }, "engines": { @@ -2147,6 +1838,7 @@ "version": "0.12.0", "resolved": "https://registry.npmjs.org/@ucans/core/-/core-0.12.0.tgz", "integrity": "sha512-PWk9LDyuUdyGeucqenmG2BRo4bPUJDgxuYZidKD/OKTggyfFlcE/9UK1qpg1gJiS4HpGbm40gsvCmKgLUt0Smg==", + "peer": true, "dependencies": { "uint8arrays": "3.0.0" }, @@ -2157,12 +1849,14 @@ "node_modules/@ucans/core/node_modules/multiformats": { "version": "9.9.0", "resolved": "https://registry.npmjs.org/multiformats/-/multiformats-9.9.0.tgz", - "integrity": "sha512-HoMUjhH9T8DDBNT+6xzkrd9ga/XiBI4xLr58LJACwK6G3HTOPeMz4nB4KJs33L2BelrIJa7P0VuNaVF3hMYfjg==" + "integrity": "sha512-HoMUjhH9T8DDBNT+6xzkrd9ga/XiBI4xLr58LJACwK6G3HTOPeMz4nB4KJs33L2BelrIJa7P0VuNaVF3hMYfjg==", + "peer": true }, "node_modules/@ucans/core/node_modules/uint8arrays": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/uint8arrays/-/uint8arrays-3.0.0.tgz", "integrity": "sha512-HRCx0q6O9Bfbp+HHSfQQKD7wU70+lydKVt4EghkdOvlK/NlrF90z+eXV34mUd48rNvVJXwkrMSPpCATkct8fJA==", + "peer": true, "dependencies": { "multiformats": "^9.4.2" } @@ -2170,12 +1864,14 @@ "node_modules/@vascosantos/moving-average": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@vascosantos/moving-average/-/moving-average-1.1.0.tgz", - "integrity": "sha512-MVEJ4vWAPNbrGLjz7ITnHYg+YXZ6ijAqtH5/cHwSoCpbvuJ98aLXwFfPKAUfZpJMQR5uXB58UJajbY130IRF/w==" + "integrity": "sha512-MVEJ4vWAPNbrGLjz7ITnHYg+YXZ6ijAqtH5/cHwSoCpbvuJ98aLXwFfPKAUfZpJMQR5uXB58UJajbY130IRF/w==", + "peer": true }, "node_modules/abortable-iterator": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/abortable-iterator/-/abortable-iterator-5.0.1.tgz", "integrity": "sha512-hlZ5Z8UwqrKsJcelVPEqDduZowJPBQJ9ZhBC2FXpja3lXy8X6MoI5uMzIgmrA8+3jcVnp8TF/tx+IBBqYJNUrg==", + "peer": true, "dependencies": { "get-iterator": "^2.0.0", "it-stream-types": "^2.0.1" @@ -2189,6 +1885,7 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/abstract-level/-/abstract-level-1.0.3.tgz", "integrity": "sha512-t6jv+xHy+VYwc4xqZMn2Pa9DjcdzvzZmQGRjTFc8spIbRGHgBrEKbPq+rYXc7CCo0lxgYvSgKVg9qZAhpVQSjA==", + "peer": true, "dependencies": { "buffer": "^6.0.3", "catering": "^2.1.0", @@ -2297,6 +1994,7 @@ "version": "4.1.1", "resolved": "https://registry.npmjs.org/any-signal/-/any-signal-4.1.1.tgz", "integrity": "sha512-iADenERppdC+A2YKbOXXB2WUeABLaM6qnpZ70kZbPZ1cZMMJ7eF+3CaYm+/PhBizgkzlvssC7QuHS30oOiQYWA==", + "peer": true, "engines": { "node": ">=16.0.0", "npm": ">=7.0.0" @@ -2409,6 +2107,7 @@ "version": "2.1.4", "resolved": "https://registry.npmjs.org/benchmark/-/benchmark-2.1.4.tgz", "integrity": "sha512-l9MlfN4M1K/H2fbhfMy3B7vJd6AGKJVQn2h6Sg/Yx+KckoUA7ewS5Vv6TjSq18ooE1kS9hhAlQRH3AkXIh/aOQ==", + "peer": true, "dependencies": { "lodash": "^4.17.4", "platform": "^1.3.3" @@ -2445,6 +2144,7 @@ "version": "4.3.3", "resolved": "https://registry.npmjs.org/blockstore-core/-/blockstore-core-4.3.3.tgz", "integrity": "sha512-+CyaLkkI7fUKCV/zTQTUmRjejgl1cyynjMZtoeYMXzp/024oy7HlUQZbcoLjxiqzlejMq2S4LD0iyRae2k67+g==", + "peer": true, "dependencies": { "@libp2p/logger": "^3.0.0", "err-code": "^3.0.1", @@ -2466,6 +2166,7 @@ "version": "1.1.3", "resolved": "https://registry.npmjs.org/blockstore-level/-/blockstore-level-1.1.3.tgz", "integrity": "sha512-wRfxExp3VH5JiLPjq67nmPy2tydhDmxrMB/NIcydgjmK5T66v5bRTkRDP6bfK2tqi26GP8WkwXpfxr0tSOaRbA==", + "peer": true, "dependencies": { "blockstore-core": "^4.0.0", "interface-blockstore": "^5.0.0", @@ -2504,6 +2205,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/browser-level/-/browser-level-1.0.1.tgz", "integrity": "sha512-XECYKJ+Dbzw0lbydyQuJzwNXtOpbMSq737qxJN11sIRTErOMShvDpbzTlgju7orJKvx4epULolZAuJGLzCmWRQ==", + "peer": true, "dependencies": { "abstract-level": "^1.0.2", "catering": "^2.1.1", @@ -2556,6 +2258,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/byte-access/-/byte-access-1.0.1.tgz", "integrity": "sha512-GKYa+lvxnzhgHWj9X+LCsQ4s2/C5uvib573eAOiQKywXMkzFFErY2+yQdzmdE5iWVpmqecsRx3bOtOY4/1eINw==", + "peer": true, "dependencies": { "uint8arraylist": "^2.0.0" }, @@ -2602,15 +2305,15 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/catering/-/catering-2.1.1.tgz", "integrity": "sha512-K7Qy8O9p76sL3/3m7/zLKbRkyOlSZAgzEaLhyj2mXS8PsCud2Eo4hAb8aLtZqHh0QGqLcb9dlJSu6lHRVENm1w==", + "peer": true, "engines": { "node": ">=6" } }, "node_modules/cborg": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/cborg/-/cborg-1.10.0.tgz", - "integrity": "sha512-/eM0JCaL99HDHxjySNQJLaolZFVdl6VA0/hEKIoiQPcQzE5LrG5QHdml0HaBt31brgB9dNe1zMr3f8IVrpotRQ==", - "dev": true, + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/cborg/-/cborg-2.0.5.tgz", + "integrity": "sha512-xVW1rSIw1ZXbkwl2XhJ7o/jAv0vnVoQv/QlfQxV8a7V5PlA4UU/AcIiXqmpyybwNWy/GPQU1m/aBVNIWr7/T0w==", "bin": { "cborg": "cli.js" } @@ -2675,6 +2378,7 @@ "resolved": "https://registry.npmjs.org/classic-level/-/classic-level-1.2.0.tgz", "integrity": "sha512-qw5B31ANxSluWz9xBzklRWTUAJ1SXIdaVKTVS7HcTGKOAmExx65Wo5BUICW+YGORe2FOUaDghoI9ZDxj82QcFg==", "hasInstallScript": true, + "peer": true, "dependencies": { "abstract-level": "^1.0.2", "catering": "^2.1.0", @@ -2813,15 +2517,11 @@ "node": ">= 8" } }, - "node_modules/cuint": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/cuint/-/cuint-0.2.2.tgz", - "integrity": "sha512-d4ZVpCW31eWwCMe1YT3ur7mUDnTXbgwyzaL320DrcRT45rfjYxkt5QWLrmOJ+/UEAI2+fQgKe/fCjR8l4TpRgw==" - }, "node_modules/datastore-core": { "version": "9.2.2", "resolved": "https://registry.npmjs.org/datastore-core/-/datastore-core-9.2.2.tgz", "integrity": "sha512-WFB1wVlD3Tr2yBZpJutPedBc18A4t0HvLOSksokYr/2nHBapplgnwkg2esI6xxctma+76FghhXx7G26khx2Uxg==", + "peer": true, "dependencies": { "@libp2p/logger": "^3.0.0", "err-code": "^3.0.1", @@ -2894,6 +2594,7 @@ "version": "7.2.2", "resolved": "https://registry.npmjs.org/default-gateway/-/default-gateway-7.2.2.tgz", "integrity": "sha512-AD7TrdNNPXRZIGw63dw+lnGmT4v7ggZC5NHNJgAYWm5njrwoze1q5JSAW9YuLy2tjnoLUG/r8FEB93MCh9QJPg==", + "peer": true, "dependencies": { "execa": "^7.1.1" }, @@ -2933,6 +2634,7 @@ "version": "6.0.0", "resolved": "https://registry.npmjs.org/delay/-/delay-6.0.0.tgz", "integrity": "sha512-2NJozoOHQ4NuZuVIr5CWd0iiLVIRSDepakaovIN+9eIDHEhdCAEvSy2cuf1DCrPPQLvHmbqTHODlhHg8UCy4zw==", + "peer": true, "engines": { "node": ">=16" }, @@ -3214,6 +2916,7 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/dns-over-http-resolver/-/dns-over-http-resolver-2.1.0.tgz", "integrity": "sha512-eb8RGy6k54JdD7Rjw8g65y1MyA4z3m3IIYh7uazkgZuKIdFn8gYt8dydMm3op+2UshDdk9EexrXcDluKNY/CDg==", + "peer": true, "dependencies": { "debug": "^4.3.1", "native-fetch": "^4.0.2", @@ -3510,15 +3213,15 @@ } }, "node_modules/eslint": { - "version": "8.47.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.47.0.tgz", - "integrity": "sha512-spUQWrdPt+pRVP1TTJLmfRNJJHHZryFmptzcafwSvHsceV81djHOdnEeDmkdotZyLNjDhrOasNK8nikkoG1O8Q==", + "version": "8.48.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.48.0.tgz", + "integrity": "sha512-sb6DLeIuRXxeM1YljSe1KEx9/YYeZFQWcV8Rq9HfigmdDEugjLEVEa1ozDjL6YDjBpQHPJxJzze+alxi4T3OLg==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.6.1", "@eslint/eslintrc": "^2.1.2", - "@eslint/js": "^8.47.0", + "@eslint/js": "8.48.0", "@humanwhocodes/config-array": "^0.11.10", "@humanwhocodes/module-importer": "^1.0.1", "@nodelib/fs.walk": "^1.2.8", @@ -3684,7 +3387,8 @@ "node_modules/event-iterator": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/event-iterator/-/event-iterator-2.0.0.tgz", - "integrity": "sha512-KGft0ldl31BZVV//jj+IAIGCxkvvUkkON+ScH6zfoX+l+omX6001ggyRSpI0Io2Hlro0ThXotswCtfzS8UkIiQ==" + "integrity": "sha512-KGft0ldl31BZVV//jj+IAIGCxkvvUkkON+ScH6zfoX+l+omX6001ggyRSpI0Io2Hlro0ThXotswCtfzS8UkIiQ==", + "peer": true }, "node_modules/eventemitter3": { "version": "4.0.7", @@ -3695,6 +3399,7 @@ "version": "3.3.0", "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "peer": true, "engines": { "node": ">=0.8.x" } @@ -3703,6 +3408,7 @@ "version": "7.2.0", "resolved": "https://registry.npmjs.org/execa/-/execa-7.2.0.tgz", "integrity": "sha512-UduyVP7TLB5IcAQl+OzLyLcS/l32W/GLg+AhHJ+ow40FOk2U3SAllPwR44v4vmdFwIWqpdwxxpQbF1n5ta9seA==", + "peer": true, "dependencies": { "cross-spawn": "^7.0.3", "get-stream": "^6.0.1", @@ -3725,6 +3431,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz", "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==", + "peer": true, "engines": { "node": ">=12" }, @@ -3736,6 +3443,7 @@ "version": "6.0.0", "resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz", "integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==", + "peer": true, "dependencies": { "mimic-fn": "^4.0.0" }, @@ -3924,21 +3632,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/fission-bloom-filters": { - "version": "1.7.1", - "resolved": "https://registry.npmjs.org/fission-bloom-filters/-/fission-bloom-filters-1.7.1.tgz", - "integrity": "sha512-AAVWxwqgSDK+/3Tn2kx+a9j/ND/pyVNVZgn/rL5pfQaX7w0qfP81PlLCNKhM4XKOhcg1kFXNcoWkQKg3MyyULw==", - "dependencies": { - "buffer": "^6.0.3", - "is-buffer": "^2.0.4", - "lodash": "^4.17.15", - "lodash.eq": "^4.0.0", - "lodash.indexof": "^4.0.5", - "reflect-metadata": "^0.1.13", - "seedrandom": "^3.0.5", - "xxhashjs": "^0.2.2" - } - }, "node_modules/flat": { "version": "5.0.2", "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", @@ -4030,6 +3723,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/freeport-promise/-/freeport-promise-2.0.0.tgz", "integrity": "sha512-dwWpT1DdQcwrhmRwnDnPM/ZFny+FtzU+k50qF2eid3KxaQDsMiBrwo1i0G3qSugkN5db6Cb0zgfc68QeTOpEFg==", + "peer": true, "engines": { "node": ">=16.0.0", "npm": ">=7.0.0" @@ -4127,7 +3821,8 @@ "node_modules/get-iterator": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/get-iterator/-/get-iterator-2.0.0.tgz", - "integrity": "sha512-BDJawD5PU2gZv6Vlp8O28H4GnZcsr3h9gZUvnAP5xXP3WOy/QAoOsyMepSkw21jur+4t5Vppde72ChjhTIzxzg==" + "integrity": "sha512-BDJawD5PU2gZv6Vlp8O28H4GnZcsr3h9gZUvnAP5xXP3WOy/QAoOsyMepSkw21jur+4t5Vppde72ChjhTIzxzg==", + "peer": true }, "node_modules/get-own-enumerable-property-symbols": { "version": "3.0.2", @@ -4139,6 +3834,7 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "peer": true, "engines": { "node": ">=10" }, @@ -4350,6 +4046,7 @@ "version": "4.3.1", "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-4.3.1.tgz", "integrity": "sha512-nZXjEF2nbo7lIw3mgYjItAfgQXog3OjJogSbKa2CQIIvSGWcKgeJnQlNXip6NglNzYH45nSRiEVimMvYL8DDqQ==", + "peer": true, "engines": { "node": ">=14.18.0" } @@ -4385,7 +4082,8 @@ "node_modules/immediate": { "version": "3.0.6", "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz", - "integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==" + "integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==", + "peer": true }, "node_modules/import-fresh": { "version": "3.3.0", @@ -4456,6 +4154,7 @@ "version": "8.2.4", "resolved": "https://registry.npmjs.org/interface-datastore/-/interface-datastore-8.2.4.tgz", "integrity": "sha512-5ng8eSfuynvywa6/5FHbYdyBMrzMdRqcH+xk48hZMr1F+wmLM5Qkh9QuLtYIlTkpUn5INB4vNBONC+swHiLgpA==", + "peer": true, "dependencies": { "interface-store": "^5.0.0", "nanoid": "^4.0.0", @@ -4493,6 +4192,7 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/ip-regex/-/ip-regex-5.0.0.tgz", "integrity": "sha512-fOCG6lhoKKakwv+C6KdsOnGvgXnmgfmp0myi3bcNwj3qfwPAxRKWEuFhvEFF7ceYIz6+1jRZ+yguLFAmUNPEfw==", + "peer": true, "engines": { "node": "^12.20.0 || ^14.13.1 || >=16.0.0" }, @@ -4504,6 +4204,7 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.1.0.tgz", "integrity": "sha512-LlbxQ7xKzfBusov6UMi4MFpEg0m+mAm9xyNGEduwXMEDuf4WfzB/RZwMVYEd7IKGvh4IUkEXYxtAVu9T3OelJQ==", + "peer": true, "engines": { "node": ">= 10" } @@ -4512,6 +4213,7 @@ "version": "19.0.0", "resolved": "https://registry.npmjs.org/ipfs-bitswap/-/ipfs-bitswap-19.0.0.tgz", "integrity": "sha512-X0u7Y9dnRlP57EGNOF+RUtm2UkB3Nrx/NLLeUZ/VEEMWBC5iOFpBDvTxSNdEK366khbG8mXk2NJ1ko8jcKXETw==", + "peer": true, "dependencies": { "@libp2p/interface": "^0.1.1", "@libp2p/logger": "^3.0.1", @@ -4539,9 +4241,9 @@ } }, "node_modules/ipfs-unixfs": { - "version": "11.0.1", - "resolved": "https://registry.npmjs.org/ipfs-unixfs/-/ipfs-unixfs-11.0.1.tgz", - "integrity": "sha512-SD9dqn14bfgMfkPstsR/2Av3zCzYMj2ntQJab4HZucgX4nNV6K7guZh4Hf3kiL8ONff1Ogft1ekFU083DIKEdQ==", + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/ipfs-unixfs/-/ipfs-unixfs-11.1.0.tgz", + "integrity": "sha512-Lq37nKLJOpRFjx3rcg3y+ZwUxBX7jluKfIt5UPp6wb1L3dP0sj1yaLR0Yg2CdGYvHWyUpZD1iTnT8upL0ToDOw==", "dependencies": { "err-code": "^3.0.1", "protons-runtime": "^5.0.0", @@ -4553,9 +4255,9 @@ } }, "node_modules/ipfs-unixfs-exporter": { - "version": "13.1.6", - "resolved": "https://registry.npmjs.org/ipfs-unixfs-exporter/-/ipfs-unixfs-exporter-13.1.6.tgz", - "integrity": "sha512-pfFQThwa4/mbnLriHQso3wt25xcx5V0mBAOBPWx2jQv0QhgDtJSASyQrwwA2xE8F9zn0N3CWn7WDHhmM+EQ3sg==", + "version": "13.2.1", + "resolved": "https://registry.npmjs.org/ipfs-unixfs-exporter/-/ipfs-unixfs-exporter-13.2.1.tgz", + "integrity": "sha512-sR0zA05VVXbRjslZ6PTQFxqVvvC6XXD0qkIo/RQb4VH+t13fbQhvhItn3PtFOETaUsUhUBi8tgH/LlqSeXsplA==", "dependencies": { "@ipld/dag-cbor": "^9.0.0", "@ipld/dag-pb": "^4.0.0", @@ -4570,7 +4272,7 @@ "it-parallel": "^3.0.0", "it-pipe": "^3.0.1", "it-pushable": "^3.1.0", - "multiformats": "^11.0.0", + "multiformats": "^12.0.1", "p-queue": "^7.3.0", "progress-events": "^1.0.0", "uint8arrays": "^4.0.2" @@ -4580,19 +4282,10 @@ "npm": ">=7.0.0" } }, - "node_modules/ipfs-unixfs-exporter/node_modules/multiformats": { - "version": "11.0.2", - "resolved": "https://registry.npmjs.org/multiformats/-/multiformats-11.0.2.tgz", - "integrity": "sha512-b5mYMkOkARIuVZCpvijFj9a6m5wMVLC7cf/jIPd5D/ARDOfLC5+IFkbgDXQgcU2goIsTD/O9NY4DI/Mt4OGvlg==", - "engines": { - "node": ">=16.0.0", - "npm": ">=7.0.0" - } - }, "node_modules/ipfs-unixfs-importer": { - "version": "15.1.7", - "resolved": "https://registry.npmjs.org/ipfs-unixfs-importer/-/ipfs-unixfs-importer-15.1.7.tgz", - "integrity": "sha512-dhcgfW5tigCcL3GhCCzEnNliU2M35mj23KYlcAHh7SCEMOHjNPZjm7kT8prrV24lJLite1QvS//BdcFS/yYY4Q==", + "version": "15.2.1", + "resolved": "https://registry.npmjs.org/ipfs-unixfs-importer/-/ipfs-unixfs-importer-15.2.1.tgz", + "integrity": "sha512-9ArBh7Xfz8gUSe8pq9c9ilBOXd1bbT3L+4xnI6w/usWLwnNT14p8WbFZjDD0MO1/PrD0PTUZuHNDS2l4EO+wPg==", "dependencies": { "@ipld/dag-pb": "^4.0.0", "@multiformats/murmur3": "^2.0.0", @@ -4605,7 +4298,7 @@ "it-batch": "^3.0.2", "it-first": "^3.0.2", "it-parallel-batch": "^3.0.1", - "multiformats": "^11.0.0", + "multiformats": "^12.0.1", "progress-events": "^1.0.0", "rabin-wasm": "^0.1.4", "uint8arraylist": "^2.4.3", @@ -4616,15 +4309,6 @@ "npm": ">=7.0.0" } }, - "node_modules/ipfs-unixfs-importer/node_modules/multiformats": { - "version": "11.0.2", - "resolved": "https://registry.npmjs.org/multiformats/-/multiformats-11.0.2.tgz", - "integrity": "sha512-b5mYMkOkARIuVZCpvijFj9a6m5wMVLC7cf/jIPd5D/ARDOfLC5+IFkbgDXQgcU2goIsTD/O9NY4DI/Mt4OGvlg==", - "engines": { - "node": ">=16.0.0", - "npm": ">=7.0.0" - } - }, "node_modules/is-arguments": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", @@ -4699,6 +4383,7 @@ "url": "https://feross.org/support" } ], + "peer": true, "engines": { "node": ">=4" } @@ -4745,7 +4430,8 @@ "node_modules/is-electron": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/is-electron/-/is-electron-2.2.1.tgz", - "integrity": "sha512-r8EEQQsqT+Gn0aXFx7lTFygYQhILLCB+wn0WCDL5LZRINeLH/Rvw1j2oKodELLXYNImQ3CRlVsY8wW4cGOsyuw==" + "integrity": "sha512-r8EEQQsqT+Gn0aXFx7lTFygYQhILLCB+wn0WCDL5LZRINeLH/Rvw1j2oKodELLXYNImQ3CRlVsY8wW4cGOsyuw==", + "peer": true }, "node_modules/is-extglob": { "version": "2.1.1", @@ -4804,7 +4490,8 @@ "node_modules/is-loopback-addr": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/is-loopback-addr/-/is-loopback-addr-2.0.2.tgz", - "integrity": "sha512-26POf2KRCno/KTNL5Q0b/9TYnL00xEsSaLfiFRmjM7m7Lw7ZMmFybzzuX4CcsLAluZGd+niLUiMRxEooVE3aqg==" + "integrity": "sha512-26POf2KRCno/KTNL5Q0b/9TYnL00xEsSaLfiFRmjM7m7Lw7ZMmFybzzuX4CcsLAluZGd+niLUiMRxEooVE3aqg==", + "peer": true }, "node_modules/is-nan": { "version": "1.3.2", @@ -4931,6 +4618,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==", + "peer": true, "engines": { "node": "^12.20.0 || ^14.13.1 || >=16.0.0" }, @@ -5050,9 +4738,9 @@ } }, "node_modules/iso-did": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/iso-did/-/iso-did-1.3.1.tgz", - "integrity": "sha512-M+TMjOpfnlz2ZpQsEmHJJPkDwsI7klPU4eXa9re6bhRr8nAdFnnBTyCNb8xr28rAJk1OfpUN5c4ZRlnawKW5fA==", + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/iso-did/-/iso-did-1.3.2.tgz", + "integrity": "sha512-xDpTtrzYFWu+Kd4Xix+FJUdXkUDEyv5tuLBG7bu2bBYysZqpf/3sj63zw1PRXS/4RTOtkXZIu8VQKDKYgPlRDA==", "dependencies": { "did-resolver": "^4.1.0", "iso-base": "^1.1.2", @@ -5091,6 +4779,7 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/iso-url/-/iso-url-1.2.1.tgz", "integrity": "sha512-9JPDgCN4B7QPkLtYAAOrEuAWvP9rWvR5offAr0/SeF046wIkglqH3VXgYYP6NcsKslH80UIVgmPqNe3j7tG2ng==", + "peer": true, "engines": { "node": ">=12" } @@ -5113,6 +4802,7 @@ "version": "2.0.3", "resolved": "https://registry.npmjs.org/it-batched-bytes/-/it-batched-bytes-2.0.3.tgz", "integrity": "sha512-vUhr1K6NerlrSbSKpBGW9bDd3s64GPUQePWUzoUF0zkYw2ufFpCXEYCZAtJMP45n6BJNChWDYTYwxAZvQG0b0g==", + "peer": true, "dependencies": { "p-defer": "^4.0.0", "uint8arraylist": "^2.4.1" @@ -5126,6 +4816,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/it-byte-stream/-/it-byte-stream-1.0.0.tgz", "integrity": "sha512-zQjgsP5kWTnMrchFOMAiiA9FcO9xSdkTdpBvdsvuqwwSNCZ8eVeyHGlc9lE3gUUSeZzzwk5OSd/18y2A4GaREg==", + "peer": true, "dependencies": { "it-pushable": "^3.2.0", "it-stream-types": "^2.0.1", @@ -5136,6 +4827,7 @@ "version": "3.0.2", "resolved": "https://registry.npmjs.org/it-drain/-/it-drain-3.0.2.tgz", "integrity": "sha512-0hJvS/4Ktt9wT/bktmovjjMAY8r6FCsXqpL3zjqBBNwoL21VgQfguEnwbLSGuCip9Zq1vfU43cbHkmaRZdBfOg==", + "peer": true, "engines": { "node": ">=16.0.0", "npm": ">=7.0.0" @@ -5166,6 +4858,7 @@ "version": "2.0.3", "resolved": "https://registry.npmjs.org/it-foreach/-/it-foreach-2.0.3.tgz", "integrity": "sha512-rpkhyHMSSe9pkmTtPcDoA5+NKhMUDqddwdXakUzNn/aOIp3vNnGBH4P4xncefxZM29iwzKBnK7AGcYVYoIG8gQ==", + "peer": true, "dependencies": { "it-peekable": "^3.0.0" }, @@ -5178,6 +4871,7 @@ "version": "4.1.3", "resolved": "https://registry.npmjs.org/it-handshake/-/it-handshake-4.1.3.tgz", "integrity": "sha512-V6Lt9A9usox9iduOX+edU1Vo94E6v9Lt9dOvg3ubFaw1qf5NCxXLi93Ao4fyCHWDYd8Y+DUhadwNtWVyn7qqLg==", + "peer": true, "dependencies": { "it-pushable": "^3.1.0", "it-reader": "^6.0.1", @@ -5203,6 +4897,7 @@ "version": "9.0.1", "resolved": "https://registry.npmjs.org/it-length-prefixed/-/it-length-prefixed-9.0.1.tgz", "integrity": "sha512-ZBD8ZFLERj8d1q9CeBtk0eJ4EpeI3qwnkmWtemBSm3ZI2dM8PUweNVk5haZ2vw3EIq2uYQiabV9YwNm6EASM4A==", + "peer": true, "dependencies": { "err-code": "^3.0.1", "it-stream-types": "^2.0.1", @@ -5219,6 +4914,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/it-length-prefixed-stream/-/it-length-prefixed-stream-1.0.0.tgz", "integrity": "sha512-d+WJC2AkQRENrWr0XoZ0Tm+NBFpMiC/hQ1ZhhBhpq/L8/zFh4XNBv/28ticXVdgA2u33N69k43zJ+ZbAophNyg==", + "peer": true, "dependencies": { "it-byte-stream": "^1.0.0", "it-length-prefixed": "^9.0.1", @@ -5255,6 +4951,7 @@ "version": "2.0.6", "resolved": "https://registry.npmjs.org/it-pair/-/it-pair-2.0.6.tgz", "integrity": "sha512-5M0t5RAcYEQYNG5BV7d7cqbdwbCAp5yLdzvkxsZmkuZsLbTdZzah6MQySYfaAQjNDCq6PUnDt0hqBZ4NwMfW6g==", + "peer": true, "dependencies": { "it-stream-types": "^2.0.1", "p-defer": "^4.0.0" @@ -5315,6 +5012,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/it-protobuf-stream/-/it-protobuf-stream-1.0.0.tgz", "integrity": "sha512-y3FfOQ+u2xY3DLs5FH8xXz1YH/50WJx40a9zWEk73DhNSpaLaLHjZqEiTyHa5mKjP0NaYgum+Ne6wo8yFPeoNw==", + "peer": true, "dependencies": { "it-length-prefixed-stream": "^1.0.0", "it-stream-types": "^2.0.1", @@ -5343,6 +5041,7 @@ "version": "6.0.4", "resolved": "https://registry.npmjs.org/it-reader/-/it-reader-6.0.4.tgz", "integrity": "sha512-XCWifEcNFFjjBHtor4Sfaj8rcpt+FkY0L6WdhD578SCDhV4VUm7fCkF3dv5a+fTcfQqvN9BsxBTvWbYO6iCjTg==", + "peer": true, "dependencies": { "it-stream-types": "^2.0.1", "uint8arraylist": "^2.0.0" @@ -5356,6 +5055,7 @@ "version": "3.0.2", "resolved": "https://registry.npmjs.org/it-sort/-/it-sort-3.0.2.tgz", "integrity": "sha512-gRvHyXkn13hyXIoiGkvg7Mf1Yg8JUB+ArKjMrGCYfd/4MQ8mQlMCOE6H8itjshwdVEAUDrppb786zODndYyjSg==", + "peer": true, "dependencies": { "it-all": "^3.0.0" }, @@ -5377,6 +5077,7 @@ "version": "3.0.2", "resolved": "https://registry.npmjs.org/it-take/-/it-take-3.0.2.tgz", "integrity": "sha512-HgtnQYW45iV+lOJIk54dhKWNi+puAeutUehIWQE9tRkM91nlCn0abbDU2xG/FZV3cVnEG4hGwxOEImnMMKwhmg==", + "peer": true, "engines": { "node": ">=16.0.0", "npm": ">=7.0.0" @@ -5386,6 +5087,7 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/it-ws/-/it-ws-6.0.1.tgz", "integrity": "sha512-tWsIEN/hYlBGgvikP3B/afBBR0nZesw6mwQjyeBfpOK69mKYNMOqWn/OxurQaK3TLhxTmbAoy/yLX6jYEqcQVw==", + "peer": true, "dependencies": { "event-iterator": "^2.0.0", "iso-url": "^1.1.2", @@ -5535,12 +5237,14 @@ "node_modules/just-debounce-it": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/just-debounce-it/-/just-debounce-it-3.1.1.tgz", - "integrity": "sha512-oPsuRyWp99LJaQ4KXC3A42tQNqkRTcPy0A8BCkRZ5cPCgsx81upB2KUrmHZvDUNhnCDKe7MshfTuWFQB9iXwDg==" + "integrity": "sha512-oPsuRyWp99LJaQ4KXC3A42tQNqkRTcPy0A8BCkRZ5cPCgsx81upB2KUrmHZvDUNhnCDKe7MshfTuWFQB9iXwDg==", + "peer": true }, "node_modules/level": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/level/-/level-8.0.0.tgz", "integrity": "sha512-ypf0jjAk2BWI33yzEaaotpq7fkOPALKAgDBxggO6Q9HGX2MRXn0wbP1Jn/tJv1gtL867+YOjOB49WaUF3UoJNQ==", + "peer": true, "dependencies": { "browser-level": "^1.0.1", "classic-level": "^1.2.0" @@ -5557,6 +5261,7 @@ "version": "4.0.1", "resolved": "https://registry.npmjs.org/level-supports/-/level-supports-4.0.1.tgz", "integrity": "sha512-PbXpve8rKeNcZ9C1mUicC9auIYFyGpkV9/i6g76tLgANwWhtG2v7I4xNBUlkn3lE2/dZF3Pi0ygYGtLc4RXXdA==", + "peer": true, "engines": { "node": ">=12" } @@ -5565,6 +5270,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/level-transcoder/-/level-transcoder-1.0.1.tgz", "integrity": "sha512-t7bFwFtsQeD8cl8NIoQ2iwxA0CL/9IFw7/9gAjOonH0PWTTiRfY7Hq+Ejbsxh86tXobDQ6IOiddjNYIfOBs06w==", + "peer": true, "dependencies": { "buffer": "^6.0.3", "module-error": "^1.0.1" @@ -5587,9 +5293,10 @@ } }, "node_modules/libp2p": { - "version": "0.46.6", - "resolved": "https://registry.npmjs.org/libp2p/-/libp2p-0.46.6.tgz", - "integrity": "sha512-5zDUpi4Foj30s+I/f6UC+wrO2u1CMLVFXby+AnCl1cEt4r+z92rLlN1Td0gUQjiAw1I3EL9yI+ASt3/Pts5IPw==", + "version": "0.46.7", + "resolved": "https://registry.npmjs.org/libp2p/-/libp2p-0.46.7.tgz", + "integrity": "sha512-m4QaIjGLAMPk5n6bSP254NhHko1OMX1cx0UIghpPCWZDErMhroYTTqlhLCRiBFvIx7P0FLdQv0Y03W4bGmL+NA==", + "peer": true, "dependencies": { "@achingbrain/nat-port-mapper": "^1.0.9", "@libp2p/crypto": "^2.0.3", @@ -5643,6 +5350,7 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/lie/-/lie-3.1.1.tgz", "integrity": "sha512-RiNhHysUjhrDQntfYSfY4MU24coXXdEOgw9WGcKHNeEwffDYbF//u87M1EWaMGzuFoSbqW0C9C6lEEhDOAswfw==", + "peer": true, "dependencies": { "immediate": "~3.0.5" } @@ -5651,6 +5359,7 @@ "version": "1.10.0", "resolved": "https://registry.npmjs.org/localforage/-/localforage-1.10.0.tgz", "integrity": "sha512-14/H1aX7hzBBmmh7sGPd+AOMkkIrHM3Z1PAyGgZigA1H1p5O5ANnMyWzvpAETtG68/dC4pC0ncy3+PPGzXZHPg==", + "peer": true, "dependencies": { "lie": "3.1.1" } @@ -5673,17 +5382,8 @@ "node_modules/lodash": { "version": "4.17.21", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" - }, - "node_modules/lodash.eq": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/lodash.eq/-/lodash.eq-4.0.0.tgz", - "integrity": "sha512-vbrJpXL6kQNG6TkInxX12DZRfuYVllSxhwYqjYB78g2zF3UI15nFO/0AgmZnZRnaQ38sZtjCiVjGr2rnKt4v0g==" - }, - "node_modules/lodash.indexof": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/lodash.indexof/-/lodash.indexof-4.0.5.tgz", - "integrity": "sha512-t9wLWMQsawdVmf6/IcAgVGqAJkNzYVcn4BHYZKTPW//l7N5Oq7Bq138BaVk19agcsPZePcidSgTTw4NqS1nUAw==" + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "peer": true }, "node_modules/lodash.merge": { "version": "4.6.2", @@ -5716,6 +5416,7 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/longbits/-/longbits-1.1.0.tgz", "integrity": "sha512-22U2exkkYy7sr7nuQJYx2NEZ2kEMsC69+BxM5h8auLvkVIJa+LwAB5mFIExnuW2dFuYXFOWsFMKXjaWiq/htYQ==", + "peer": true, "dependencies": { "byte-access": "^1.0.1", "uint8arraylist": "^2.0.0" @@ -5813,6 +5514,7 @@ "version": "3.0.4", "resolved": "https://registry.npmjs.org/merge-options/-/merge-options-3.0.4.tgz", "integrity": "sha512-2Sug1+knBjkaMsMgf1ctR1Ujx+Ayku4EdJN4Z+C2+JzoeF7A3OZ9KM2GY0CpQS51NR61LTurMJrRKPhSs3ZRTQ==", + "peer": true, "dependencies": { "is-plain-obj": "^2.1.0" }, @@ -5823,7 +5525,8 @@ "node_modules/merge-stream": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==" + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "peer": true }, "node_modules/merge2": { "version": "1.4.1", @@ -6055,6 +5758,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/module-error/-/module-error-1.0.2.tgz", "integrity": "sha512-0yuvsqSCv8LbaOKhnsQ/T5JhyFlCYLPXK3U2sgV10zoKQwzs/MyfuQUOZQ1V/6OCOJsK/TRgNVrPuPDqtdMFtA==", + "peer": true, "engines": { "node": ">=10" } @@ -6088,6 +5792,7 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/mortice/-/mortice-3.0.1.tgz", "integrity": "sha512-eyDUsl1nCR9+JtNksKnaESLP9MgAXCA4w1LTtsmOSQNsThnv++f36rrBu5fC/fdGIwTJZmbiaR/QewptH93pYA==", + "peer": true, "dependencies": { "nanoid": "^4.0.0", "observable-webworkers": "^2.0.1", @@ -6105,9 +5810,9 @@ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, "node_modules/multiformats": { - "version": "12.0.1", - "resolved": "https://registry.npmjs.org/multiformats/-/multiformats-12.0.1.tgz", - "integrity": "sha512-s01wijBJoDUqESWSzePY0lvTw7J3PVO9x2Cc6ASI5AMZM2Gnhh7BC17+nlFhHKU7dDzaCaRfb+NiqNzOsgPUoQ==", + "version": "12.1.0", + "resolved": "https://registry.npmjs.org/multiformats/-/multiformats-12.1.0.tgz", + "integrity": "sha512-/qTOKKnU8nwcVURjRcS+UN0QYgdS5BPZzY10Aiciu2SqncyCVMGV8KtD83EBFmsuJDsSEmT4sGvzcTkCoMw0sQ==", "engines": { "node": ">=16.0.0", "npm": ">=7.0.0" @@ -6125,6 +5830,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-4.0.0.tgz", "integrity": "sha512-IgBP8piMxe/gf73RTQx7hmnhwz0aaEXYakvqZyE302IXW3HyVNhdNGC+O2MwMAVhLEnvXlvKtGbtJf6wvHihCg==", + "peer": true, "bin": { "nanoid": "bin/nanoid.js" }, @@ -6135,12 +5841,14 @@ "node_modules/napi-macros": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/napi-macros/-/napi-macros-2.0.0.tgz", - "integrity": "sha512-A0xLykHtARfueITVDernsAWdtIMbOJgKgcluwENp3AlsKN/PloyO10HtmoqnFAQAcxPkgZN7wdfPfEd0zNGxbg==" + "integrity": "sha512-A0xLykHtARfueITVDernsAWdtIMbOJgKgcluwENp3AlsKN/PloyO10HtmoqnFAQAcxPkgZN7wdfPfEd0zNGxbg==", + "peer": true }, "node_modules/native-fetch": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/native-fetch/-/native-fetch-4.0.2.tgz", "integrity": "sha512-4QcVlKFtv2EYVS5MBgsGX5+NWKtbDbIECdUXDBGDMAZXq3Jkv9zf+y8iS7Ub8fEdga3GpYeazp9gauNqXHJOCg==", + "peer": true, "peerDependencies": { "undici": "*" } @@ -6155,6 +5863,7 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/netmask/-/netmask-2.0.2.tgz", "integrity": "sha512-dBpDMdxv9Irdq66304OLfEmQ9tbNRFnFTuZiLo+bD+r332bBmMJ8GBLXklIXXgxd3+v9+KUnZaUR5PJMa75Gsg==", + "peer": true, "engines": { "node": ">= 0.4.0" } @@ -6182,6 +5891,7 @@ "version": "1.3.1", "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", "integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==", + "peer": true, "engines": { "node": ">= 6.13.0" } @@ -6190,6 +5900,7 @@ "version": "4.5.0", "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.5.0.tgz", "integrity": "sha512-2iGbaQBV+ITgCz76ZEjmhUKAKVf7xfY1sRl4UiKQspfZMH2h06SyhNsnSVy50cwkFQDGLyif6m/6uFXHkOZ6rg==", + "peer": true, "bin": { "node-gyp-build": "bin.js", "node-gyp-build-optional": "optional.js", @@ -6249,6 +5960,7 @@ "version": "5.1.0", "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.1.0.tgz", "integrity": "sha512-sJOdmRGrY2sjNTRMbSvluQqg+8X7ZK61yvzBEIDhz4f8z1TZFYABsqjjCBd/0PUNE9M6QDgHJXQkGUEm7Q+l9Q==", + "peer": true, "dependencies": { "path-key": "^4.0.0" }, @@ -6263,6 +5975,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", + "peer": true, "engines": { "node": ">=12" }, @@ -6326,6 +6039,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/observable-webworkers/-/observable-webworkers-2.0.1.tgz", "integrity": "sha512-JI1vB0u3pZjoQKOK1ROWzp0ygxSi7Yb0iR+7UNsw4/Zn4cQ0P3R7XL38zac/Dy2tEA7Lg88/wIJTjF8vYXZ0uw==", + "peer": true, "engines": { "node": ">=16.0.0", "npm": ">=7.0.0" @@ -6340,11 +6054,6 @@ "wrappy": "1" } }, - "node_modules/one-webcrypto": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/one-webcrypto/-/one-webcrypto-1.0.3.tgz", - "integrity": "sha512-fu9ywBVBPx0gS9K0etIROTiCkvI5S1TDjFsYFb3rC1ewFxeOqsbzq7aIMBHsYfrTHBcGXJaONXXjTl8B01cW1Q==" - }, "node_modules/onetime": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", @@ -6506,6 +6215,7 @@ "version": "5.1.1", "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-5.1.1.tgz", "integrity": "sha512-i69WkEU5ZAL8mrmdmVviWwU+DN+IUF8f4sSJThoJ3z5A7Nn5iuO5ROX3Boye0u+uYQLOSfgFl7SuFZCjlAVbQA==", + "peer": true, "dependencies": { "@types/retry": "0.12.1", "retry": "^0.13.1" @@ -6521,6 +6231,7 @@ "version": "6.1.2", "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-6.1.2.tgz", "integrity": "sha512-UbD77BuZ9Bc9aABo74gfXhNvzC9Tx7SxtHSh1fxvx3jTLLYvmVhiQZZrJzqqU0jKbN32kb5VOKiLEQI/3bIjgQ==", + "peer": true, "engines": { "node": ">=14.16" }, @@ -6636,7 +6347,8 @@ "node_modules/platform": { "version": "1.3.6", "resolved": "https://registry.npmjs.org/platform/-/platform-1.3.6.tgz", - "integrity": "sha512-fnWVljUchTro6RiCFvCXBbNhJc2NijN7oIQxbwsyL0buWJPG85v81ehlHI9fXrJsMNgTofEoWIQeClKpgxFLrg==" + "integrity": "sha512-fnWVljUchTro6RiCFvCXBbNhJc2NijN7oIQxbwsyL0buWJPG85v81ehlHI9fXrJsMNgTofEoWIQeClKpgxFLrg==", + "peer": true }, "node_modules/pluralize": { "version": "8.0.0", @@ -7076,6 +6788,7 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/private-ip/-/private-ip-3.0.1.tgz", "integrity": "sha512-Ezc16ANuhSHmWAE6lbXUKburNzGpR0J5X0Zh5Um/PZ/s57Fp+HYqYe6BYPH2QbqKr/5WebfzJQ1jq6Kj5dbRmA==", + "peer": true, "dependencies": { "@chainsafe/is-ip": "^2.0.1", "ip-regex": "^5.0.0", @@ -7214,7 +6927,8 @@ "node_modules/rate-limiter-flexible": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/rate-limiter-flexible/-/rate-limiter-flexible-2.4.1.tgz", - "integrity": "sha512-dgH4T44TzKVO9CLArNto62hJOwlWJMLUjVVr/ii0uUzZXEXthDNr7/yefW5z/1vvHAfycc1tnuiYyNJ8CTRB3g==" + "integrity": "sha512-dgH4T44TzKVO9CLArNto62hJOwlWJMLUjVVr/ii0uUzZXEXthDNr7/yefW5z/1vvHAfycc1tnuiYyNJ8CTRB3g==", + "peer": true }, "node_modules/rc": { "version": "1.2.8", @@ -7275,15 +6989,11 @@ "version": "1.3.2", "resolved": "https://registry.npmjs.org/receptacle/-/receptacle-1.3.2.tgz", "integrity": "sha512-HrsFvqZZheusncQRiEE7GatOAETrARKV/lnfYicIm8lbvp/JQOdADOfhjBd2DajvoszEyxSM6RlAAIZgEoeu/A==", + "peer": true, "dependencies": { "ms": "^2.1.1" } }, - "node_modules/reflect-metadata": { - "version": "0.1.13", - "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.13.tgz", - "integrity": "sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg==" - }, "node_modules/regexp.prototype.flags": { "version": "1.4.3", "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz", @@ -7387,12 +7097,14 @@ "node_modules/retimer": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/retimer/-/retimer-3.0.0.tgz", - "integrity": "sha512-WKE0j11Pa0ZJI5YIk0nflGI7SQsfl2ljihVy7ogh7DeQSeYAUi0ubZ/yEueGtDfUPk6GH5LRw1hBdLq4IwUBWA==" + "integrity": "sha512-WKE0j11Pa0ZJI5YIk0nflGI7SQsfl2ljihVy7ogh7DeQSeYAUi0ubZ/yEueGtDfUPk6GH5LRw1hBdLq4IwUBWA==", + "peer": true }, "node_modules/retry": { "version": "0.13.1", "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==", + "peer": true, "engines": { "node": ">= 4" } @@ -7512,6 +7224,7 @@ "url": "https://feross.org/support" } ], + "peer": true, "dependencies": { "queue-microtask": "^1.2.2" } @@ -7553,6 +7266,7 @@ "version": "1.6.3", "resolved": "https://registry.npmjs.org/sanitize-filename/-/sanitize-filename-1.6.3.tgz", "integrity": "sha512-y/52Mcy7aw3gRm7IrcGDFx/bCk4AhRh2eI9luHOQM86nZsqwiRkkq2GekHXBBD+SmPidc8i2PqtYZl+pWJ8Oeg==", + "peer": true, "dependencies": { "truncate-utf8-bytes": "^1.0.0" } @@ -7581,12 +7295,8 @@ "node_modules/sax": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", - "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==" - }, - "node_modules/seedrandom": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/seedrandom/-/seedrandom-3.0.5.tgz", - "integrity": "sha512-8OwmbklUNzwezjGInmZ+2clQmExQPvomqjL7LFqOYqtmuxRgQYqOD3mHaU+MvZn5FLUeVxVfQjwLZW/n/JFuqg==" + "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", + "peer": true }, "node_modules/semver": { "version": "7.5.4", @@ -7854,6 +7564,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz", "integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==", + "peer": true, "engines": { "node": ">=12" }, @@ -7984,6 +7695,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/timeout-abort-controller/-/timeout-abort-controller-3.0.0.tgz", "integrity": "sha512-O3e+2B8BKrQxU2YRyEjC/2yFdb33slI22WRdUaDx6rvysfi9anloNZyR2q0l6LnePo5qH7gSM7uZtvvwZbc2yA==", + "peer": true, "dependencies": { "retimer": "^3.0.0" } @@ -8009,6 +7721,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/truncate-utf8-bytes/-/truncate-utf8-bytes-1.0.2.tgz", "integrity": "sha512-95Pu1QXQvruGEhv62XCMO3Mm90GscOCClvrIUwCM0PYOXK3kaF3l3sIHxx71ThJfcbM2O5Au6SO3AWCSEfW4mQ==", + "peer": true, "dependencies": { "utf8-byte-length": "^1.0.1" } @@ -8103,9 +7816,9 @@ } }, "node_modules/tslib": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.1.tgz", - "integrity": "sha512-t0hLfiEKfMUoqhG+U1oid7Pva4bbDPHYfJNiB7BiIjRkj1pyC++4N3huJfqY6aRH6VTB0rvtzQwjM4K6qpfOig==", + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", "dev": true }, "node_modules/type-check": { @@ -8133,42 +7846,42 @@ } }, "node_modules/typedoc": { - "version": "0.24.8", - "resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.24.8.tgz", - "integrity": "sha512-ahJ6Cpcvxwaxfu4KtjA8qZNqS43wYt6JL27wYiIgl1vd38WW/KWX11YuAeZhuz9v+ttrutSsgK+XO1CjL1kA3w==", + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.25.0.tgz", + "integrity": "sha512-FvCYWhO1n5jACE0C32qg6b3dSfQ8f2VzExnnRboowHtqUD6ARzM2r8YJeZFYXhcm2hI4C2oCRDgNPk/yaQUN9g==", "dev": true, "dependencies": { "lunr": "^2.3.9", "marked": "^4.3.0", - "minimatch": "^9.0.0", + "minimatch": "^9.0.3", "shiki": "^0.14.1" }, "bin": { "typedoc": "bin/typedoc" }, "engines": { - "node": ">= 14.14" + "node": ">= 16" }, "peerDependencies": { - "typescript": "4.6.x || 4.7.x || 4.8.x || 4.9.x || 5.0.x || 5.1.x" + "typescript": "4.6.x || 4.7.x || 4.8.x || 4.9.x || 5.0.x || 5.1.x || 5.2.x" } }, "node_modules/typedoc-plugin-missing-exports": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/typedoc-plugin-missing-exports/-/typedoc-plugin-missing-exports-2.0.1.tgz", - "integrity": "sha512-+A78kT78uC0Dbv2EFB9RXHO3iywJ5x89jd4z0bLL7Z8DlOSQjJxhRHf8otXsHZbgRUWAuYqYMA9LzxfuSOc87A==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/typedoc-plugin-missing-exports/-/typedoc-plugin-missing-exports-2.1.0.tgz", + "integrity": "sha512-+1DhqZCEu7Vu5APnrqpPwl31D+hXpt1fV0Le9ycCRL1eLVdatdl6KVt4SEVwPxnEpKwgOn2dNX6I9+0F1aO2aA==", "dev": true, "peerDependencies": { - "typedoc": "0.24.x" + "typedoc": "0.24.x || 0.25.x" } }, "node_modules/typedoc-plugin-rename-defaults": { - "version": "0.6.5", - "resolved": "https://registry.npmjs.org/typedoc-plugin-rename-defaults/-/typedoc-plugin-rename-defaults-0.6.5.tgz", - "integrity": "sha512-DwkgwRMxgu3UrDR3VUAdnF9jYzM6p7rw6UcVIh4MD7yjEmFDR8WWyOlk6oYgELmRYHxTDx0f0GK6iSgoxSh/Qw==", + "version": "0.6.6", + "resolved": "https://registry.npmjs.org/typedoc-plugin-rename-defaults/-/typedoc-plugin-rename-defaults-0.6.6.tgz", + "integrity": "sha512-8TCDrxMG8cR0IRhMZbxMCXlmQrEwFFH0she4eHsaUGd1TPfrkk8GLO4n2qlSISd66OtT28e17ysiVZPbQnLGMg==", "dev": true, "peerDependencies": { - "typedoc": "0.22.x || 0.23.x || 0.24.x" + "typedoc": "0.22.x || 0.23.x || 0.24.x || 0.25.x" } }, "node_modules/typedoc/node_modules/brace-expansion": { @@ -8181,9 +7894,9 @@ } }, "node_modules/typedoc/node_modules/minimatch": { - "version": "9.0.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.2.tgz", - "integrity": "sha512-PZOT9g5v2ojiTL7r1xF6plNHLtOeTpSlDI007As2NlA2aYBMfVom17yqa6QzhmDP8QOhn7LjHTg7DFCVSSa6yg==", + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", + "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", "dev": true, "dependencies": { "brace-expansion": "^2.0.1" @@ -8196,9 +7909,9 @@ } }, "node_modules/typescript": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.1.6.tgz", - "integrity": "sha512-zaWCozRZ6DLEWAWFrVDz1H6FVXzUSfTy5FUMWsQlU8Ym5JP9eO4xkTIROFCQvhQf61z6O/G6ugw3SgAnvvm+HA==", + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.2.2.tgz", + "integrity": "sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==", "dev": true, "bin": { "tsc": "bin/tsc", @@ -8212,6 +7925,7 @@ "version": "1.0.6", "resolved": "https://registry.npmjs.org/uint8-varint/-/uint8-varint-1.0.6.tgz", "integrity": "sha512-Z0ujO4rxPwxTdLsSI5ke+bdl9hjJ1xiOakBPZeWUI/u6YBGCEGTW6b90SMlhxSGButKVPkL9fMFUDnqThQYTGg==", + "peer": true, "dependencies": { "byte-access": "^1.0.0", "longbits": "^1.1.0", @@ -8297,7 +8011,8 @@ "node_modules/utf8-byte-length": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/utf8-byte-length/-/utf8-byte-length-1.0.4.tgz", - "integrity": "sha512-4+wkEYLBbWxqTahEsWrhxepcoVOJ+1z5PGIjPZxRkytcdSUaNjIjBM7Xn8E+pdSuV7SzvWovBFA54FO0JSoqhA==" + "integrity": "sha512-4+wkEYLBbWxqTahEsWrhxepcoVOJ+1z5PGIjPZxRkytcdSUaNjIjBM7Xn8E+pdSuV7SzvWovBFA54FO0JSoqhA==", + "peer": true }, "node_modules/util": { "version": "0.12.5", @@ -8332,6 +8047,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/varint-decoder/-/varint-decoder-1.0.0.tgz", "integrity": "sha512-JkOvdztASWGUAsXshCFHrB9f6AgR2Q8W08CEyJ+43b1qtFocmI8Sp1R/M0E/hDOY2FzVIqk63tOYLgDYWuJ7IQ==", + "peer": true, "dependencies": { "varint": "^5.0.0" }, @@ -8343,7 +8059,8 @@ "node_modules/varint-decoder/node_modules/varint": { "version": "5.0.2", "resolved": "https://registry.npmjs.org/varint/-/varint-5.0.2.tgz", - "integrity": "sha512-lKxKYG6H03yCZUpAGOPOsMcGxd1RHCu1iKvEHYDPmTyq2HueGhD73ssNBqqQWfvYs04G9iUFRvmAVLW20Jw6ow==" + "integrity": "sha512-lKxKYG6H03yCZUpAGOPOsMcGxd1RHCu1iKvEHYDPmTyq2HueGhD73ssNBqqQWfvYs04G9iUFRvmAVLW20Jw6ow==", + "peer": true }, "node_modules/vscode-oniguruma": { "version": "1.7.0", @@ -8393,6 +8110,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/wherearewe/-/wherearewe-2.0.1.tgz", "integrity": "sha512-XUguZbDxCA2wBn2LoFtcEhXL6AXo+hVjGonwhSTTTU9SzbWG8Xu3onNIpzf9j/mYUcJQ0f+m37SzG77G851uFw==", + "peer": true, "dependencies": { "is-electron": "^2.2.0" }, @@ -8452,9 +8170,9 @@ } }, "node_modules/wnfs": { - "version": "0.1.24", - "resolved": "https://registry.npmjs.org/wnfs/-/wnfs-0.1.24.tgz", - "integrity": "sha512-EHCztoKtUsREL2Iio0SfldGQAfskJLGG8RkLefRws/8jWJN1liRu4DBG+AdAZo91LB4iEHx4Bxpet1NYs/y0Jg==" + "version": "0.1.26", + "resolved": "https://registry.npmjs.org/wnfs/-/wnfs-0.1.26.tgz", + "integrity": "sha512-dn1+RCI1FWJ5f7yao7uO6EoApMF3TqB0QaKM1tFrywm+WRXyX4G3vFLQqDwx3ph6GzJ2Lf1ymDbCETkPAy4gCw==" }, "node_modules/word-wrap": { "version": "1.2.5", @@ -8516,6 +8234,7 @@ "version": "8.13.0", "resolved": "https://registry.npmjs.org/ws/-/ws-8.13.0.tgz", "integrity": "sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==", + "peer": true, "engines": { "node": ">=10.0.0" }, @@ -8536,6 +8255,7 @@ "version": "0.6.2", "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.6.2.tgz", "integrity": "sha512-T4rieHaC1EXcES0Kxxj4JWgaUQHDk+qwHcYOCFHfiwKz7tOVPLq7Hjq9dM1WCMhylqMEfP7hMcOIChvotiZegA==", + "peer": true, "dependencies": { "sax": ">=0.6.0", "xmlbuilder": "~11.0.0" @@ -8548,6 +8268,7 @@ "version": "11.0.1", "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==", + "peer": true, "engines": { "node": ">=4.0" } @@ -8555,7 +8276,8 @@ "node_modules/xsalsa20": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/xsalsa20/-/xsalsa20-1.2.0.tgz", - "integrity": "sha512-FIr/DEeoHfj7ftfylnoFt3rAIRoWXpx2AoDfrT2qD2wtp7Dp+COajvs/Icb7uHqRW9m60f5iXZwdsJJO3kvb7w==" + "integrity": "sha512-FIr/DEeoHfj7ftfylnoFt3rAIRoWXpx2AoDfrT2qD2wtp7Dp+COajvs/Icb7uHqRW9m60f5iXZwdsJJO3kvb7w==", + "peer": true }, "node_modules/xtend": { "version": "4.0.2", @@ -8566,14 +8288,6 @@ "node": ">=0.4" } }, - "node_modules/xxhashjs": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/xxhashjs/-/xxhashjs-0.2.2.tgz", - "integrity": "sha512-AkTuIuVTET12tpsVIQo+ZU6f/qDmKuRUcjaqR+OIvm+aCBsZ95i7UVY5WJ9TMsSaZ0DA2WxoZ4acu0sPH+OKAw==", - "dependencies": { - "cuint": "^0.2.2" - } - }, "node_modules/y18n": { "version": "5.0.8", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", diff --git a/package.json b/package.json index 7c945605..d424f7ea 100644 --- a/package.json +++ b/package.json @@ -82,64 +82,65 @@ "publish-latest": "npm publish --tag latest" }, "dependencies": { - "@chainsafe/libp2p-noise": "^13.0.0", - "@chainsafe/libp2p-yamux": "^5.0.0", "@ipld/dag-cbor": "^9.0.4", "@ipld/dag-pb": "^4.0.5", - "@libp2p/mplex": "^9.0.4", - "@libp2p/peer-id": "^3.0.2", - "@libp2p/websockets": "^7.0.4", - "@libp2p/webtransport": "^3.0.6", - "@multiformats/multiaddr": "^12.1.7", - "@ucans/core": "^0.12.0", - "blockstore-level": "^1.1.3", "debounce-promise": "^3.1.2", "emittery": "^1.0.1", - "events": "^3.3.0", - "fission-bloom-filters": "1.7.1", "interface-blockstore": "^5.2.5", - "interface-datastore": "^8.2.4", - "ipfs-bitswap": "^19.0.0", - "ipfs-unixfs": "^11.0.1", - "ipfs-unixfs-exporter": "^13.1.6", - "ipfs-unixfs-importer": "^15.1.7", + "ipfs-unixfs": "^11.1.0", + "ipfs-unixfs-exporter": "^13.2.1", + "ipfs-unixfs-importer": "^15.2.1", "iso-base": "^2.0.0", - "iso-did": "^1.3.1", + "iso-did": "^1.3.2", "iso-signatures": "^0.1.9", "it-all": "^3.0.3", - "libp2p": "^0.46.6", - "localforage": "^1.10.0", "multiformats": "^12.0.1", - "one-webcrypto": "^1.0.3", "uint8arrays": "^4.0.6", - "wnfs": "0.1.24" + "wnfs": "0.1.26" }, "devDependencies": { "@esbuild-plugins/node-globals-polyfill": "^0.2.3", - "@ipld/car": "^5.2.0", + "@ipld/car": "^5.2.2", "@types/debounce-promise": "^3.1.6", "@types/expect": "^24.3.0", "@types/mocha": "^10.0.1", - "@types/node": "^20.5.0", - "@typescript-eslint/eslint-plugin": "^6.4.0", - "@typescript-eslint/parser": "^6.4.0", + "@types/node": "^20.5.7", + "@typescript-eslint/eslint-plugin": "^6.5.0", + "@typescript-eslint/parser": "^6.5.0", "assert": "^2.0.0", "copyfiles": "^2.4.1", "dprint": "^0.40.2", "esbuild": "^0.19.2", "esbuild-plugin-wasm": "^1.1.0", - "eslint": "^8.47.0", + "eslint": "^8.48.0", "fast-check": "^3.12.0", "globby": "^13.2.2", "madge": "^6.1.0", "mocha": "^10.2.0", "rimraf": "^5.0.1", "ts-node": "^10.9.1", - "tslib": "^2.6.1", - "typedoc": "^0.24.8", - "typedoc-plugin-missing-exports": "^2.0.1", - "typedoc-plugin-rename-defaults": "^0.6.5", - "typescript": "^5.1.6", + "tslib": "^2.6.2", + "typedoc": "^0.25.0", + "typedoc-plugin-missing-exports": "^2.1.0", + "typedoc-plugin-rename-defaults": "^0.6.6", + "typescript": "^5.2.2", "util": "^0.12.4" + }, + "peerDependencies": { + "@chainsafe/libp2p-noise": "^13.0.0", + "@chainsafe/libp2p-yamux": "^5.0.0", + "@libp2p/mplex": "^9.0.5", + "@libp2p/peer-id": "^3.0.2", + "@libp2p/websockets": "^7.0.5", + "@libp2p/webtransport": "^3.0.7", + "@multiformats/multiaddr": "^12.1.7", + "@noble/ciphers": "^0.3.0", + "@noble/curves": "^1.2.0", + "@noble/hashes": "^1.3.2", + "@ucans/core": "^0.12.0", + "blockstore-level": "^1.1.3", + "ipfs-bitswap": "^19.0.0", + "libp2p": "^0.46.7", + "localforage": "^1.10.0" } } diff --git a/src/accessKey.ts b/src/accessKey.ts new file mode 100644 index 00000000..687ff4ec --- /dev/null +++ b/src/accessKey.ts @@ -0,0 +1,7 @@ +import * as Path from "./path/index.js" + +export type AccessKeyWithContext = { + did: string + key: Uint8Array + path: Path.Distinctive +} diff --git a/src/auth.ts b/src/auth.ts index 42e15770..15b8648d 100644 --- a/src/auth.ts +++ b/src/auth.ts @@ -7,11 +7,11 @@ import { AnnexParentType } from "./components/account/implementation.js" // REGISTER // ////////////// -export const register = ( +export const register = ( { account, agent, authority, identifier, cabinet }: { account: Account.Implementation agent: Agent.Implementation - authority: Authority.Implementation + authority: Authority.Implementation identifier: Identifier.Implementation cabinet: Cabinet } diff --git a/src/authority/query.ts b/src/authority/query.ts index 6c9ebd68..0a21ef3f 100644 --- a/src/authority/query.ts +++ b/src/authority/query.ts @@ -1,3 +1,4 @@ +import { isString } from "../common/type-checks.js" import * as Path from "../path/index.js" //////// @@ -21,6 +22,7 @@ export type FileSystemAbility = typeof ALLOWED_FILE_SYSTEM_ABILITIES[number] export type FileSystemQuery = { query: "fileSystem" ability: FileSystemAbility + did: string path: Path.Distinctive> } @@ -33,21 +35,27 @@ export const account: AccountQuery = { } export const fileSystem = { - rootAccess: [{ - query: "fileSystem", - ability: "*", - path: Path.directory("public"), - }, { - query: "fileSystem", - ability: "*", - path: Path.directory("private"), - }] as FileSystemQuery[], + rootAccess(did: string): FileSystemQuery[] { + return [{ + query: "fileSystem", + ability: "*", + did, + path: Path.directory("public"), + }, { + query: "fileSystem", + ability: "*", + did, + path: Path.directory("private"), + }] + }, limitedAccess( ability: typeof ALLOWED_FILE_SYSTEM_ABILITIES[number], + did: string, path: Path.Distinctive> ): FileSystemQuery { return { query: "fileSystem", + did, ability, path, } @@ -58,6 +66,36 @@ export const fileSystem = { // 🛠️ // //////// +export function isContained({ parent, child }: { parent: Query; child: Query }): boolean { + if (parent.query === "account") return child.query === "account" + + // File System + if (parent.query === "fileSystem") { + if (child.query !== "fileSystem") return false + + const ability = parent.ability === "*" + ? true + : (child.ability === "*" ? false : parent.ability === child.ability) + + const did = parent.did === child.did + + const unwrappedParentPath = Path.unwrap(parent.path) + const path = Path.unwrap(child.path).reduce( + (acc, part, idx) => { + if (!acc) return acc + if (idx + 1 > unwrappedParentPath.length) return true + return part === unwrappedParentPath[idx] + }, + true + ) + + return ability && did && path + } + + // ? + return false +} + export function needsWriteAccess(query: FileSystemQuery): boolean { return query.ability !== "read" } @@ -66,8 +104,8 @@ export function needsWriteAccess(query: FileSystemQuery): boolean { // ENCODING // ////////////// -export function fromJSON(query: string): Query { - const obj = JSON.parse(query) +export function fromJSON(query: string | Record): Query { + const obj = isString(query) ? JSON.parse(query) : query switch (obj.query) { case "account": @@ -101,25 +139,31 @@ function fileSystemQueryFromJSON(obj: Record): FileSystemQuery throw new Error(`Expected a path with a partition (private or public), got: ${obj.path}`) } + if (!isString(obj.did)) { + throw new Error("Expected a `did` property") + } + return { query: "fileSystem", ability: obj.ability as FileSystemAbility, + did: obj.did, path: partitionedPath, } } -export function toJSON(query: Query): string { +export function toJSON(query: Query): object { switch (query.query) { case "account": - return JSON.stringify({ + return { query: query.query, - }) + } case "fileSystem": - return JSON.stringify({ + return { query: query.query, ability: query.ability, + did: query.did, path: Path.toPosix(query.path), - }) + } } } diff --git a/src/channel.ts b/src/channel.ts index eff2a98c..e0a6195c 100644 --- a/src/channel.ts +++ b/src/channel.ts @@ -7,9 +7,9 @@ export type Channel = { send: (data: ChannelData) => void } -export type ChannelOptions = { - context: Context - onmessage: (event: MessageEvent) => void +export type ChannelOptions = { + onmessage: (event: MessageEvent, channel: Channel) => void + topic: string } export type ChannelData = string | ArrayBufferLike | Blob | ArrayBufferView diff --git a/src/channel/websocket.ts b/src/channel/websocket.ts index e1b3949b..c1f01358 100644 --- a/src/channel/websocket.ts +++ b/src/channel/websocket.ts @@ -5,22 +5,25 @@ import { Manners } from "../components.js" // 🛠️ // //////// -export const createWebsocketChannel = async ( +export const createWebsocketChannel = async ( manners: Manners.Implementation, socketEndpoint: string, - options: ChannelOptions + options: ChannelOptions ): Promise => { const { onmessage } = options const socket = new WebSocket(socketEndpoint) await waitForOpenConnection(socket) - socket.onmessage = onmessage manners.log("📣 Channel established", socket) - return { + const channel = { send: publish(socket), close: close(socket), } + + socket.onmessage = event => onmessage(event, channel) + + return channel } const waitForOpenConnection = async (socket: WebSocket): Promise => { @@ -31,7 +34,7 @@ const waitForOpenConnection = async (socket: WebSocket): Promise => { } export const close = (socket: WebSocket): () => void => { - return () => socket.close(1000) + return () => socket.close() } export const publish = (socket: WebSocket): (data: ChannelData) => void => { diff --git a/src/components.ts b/src/components.ts index baa05fa7..5bf7d2cf 100644 --- a/src/components.ts +++ b/src/components.ts @@ -14,11 +14,15 @@ import { FileSystem } from "./fs/class.js" // COMPONENTS // //////////////// -export type Components = { +export type Components< + Annex extends Account.AnnexParentType, + AuthorityProvideResponse, + AuthorityRequestResponse, +> = { account: Account.Implementation agent: Agent.Implementation - authority: Authority.Implementation - channel: Channel.Implementation + authority: Authority.Implementation + channel: Channel.Implementation depot: Depot.Implementation dns: DNS.Implementation identifier: Identifier.Implementation diff --git a/src/components/account/fission/implementations/common.ts b/src/components/account/fission/implementations/common.ts index 5f6bdc8e..d1532ec1 100644 --- a/src/components/account/fission/implementations/common.ts +++ b/src/components/account/fission/implementations/common.ts @@ -2,9 +2,10 @@ import * as Fission from "../../../../common/fission.js" import * as Ucan from "../../../../ucan/ts-ucan/index.js" import * as Identifier from "../../../identifier/implementation.js" +import { AccountQuery } from "../../../../authority/query.js" import { CID } from "../../../../common/index.js" import { Agent, DNS, Manners } from "../../../../components.js" -import { Inventory } from "../../../../ticket/inventory.js" +import { Inventory } from "../../../../inventory.js" import { Ticket } from "../../../../ticket/types.js" import { DataRoot, lookupUserDID } from "../index.js" @@ -54,7 +55,7 @@ export async function volume( ) => Promise<{ updated: true } | { updated: false; reason: string }> did: string }> { - const accountProof = findAccountProofUCAN(await identifier.did(), tickets) + const accountProof = findAccountProofTicket(await identifier.did(), tickets) const accountUsername = accountProof ? findUsernameFact(accountProof) : null if (username && username !== accountUsername) { @@ -103,7 +104,7 @@ export async function accountVolume( } // Find account-proof UCAN - const accountProof = findAccountProofUCAN(identifierDID, tickets) + const accountProof = findAccountProofTicket(identifierDID, tickets) const username = accountProof ? findUsernameFact(accountProof) : null if (!username) { @@ -123,7 +124,7 @@ export async function otherVolume( endpoints: Fission.Endpoints, dependencies: Dependencies, identifier: Identifier.Implementation, - tickets: Inventory, + inventory: Inventory, username: string ): Promise<{ dataRoot?: CID @@ -157,7 +158,7 @@ export async function updateDataRoot( endpoints: Fission.Endpoints, dependencies: Dependencies, identifier: Identifier.Implementation, - tickets: Inventory, + inventory: Inventory, dataRoot: CID, proofs: Ticket[] ): Promise<{ updated: true } | { updated: false; reason: string }> { @@ -166,7 +167,7 @@ export async function updateDataRoot( } // Find account-proof UCAN - const accountProof = findAccountProofUCAN(await identifier.did(), tickets) + const accountProof = findAccountProofTicket(await identifier.did(), inventory) const username = accountProof ? findUsernameFact(accountProof) : null if (!username) { @@ -184,42 +185,56 @@ export async function updateDataRoot( export async function did( dependencies: Dependencies, identifier: Identifier.Implementation, - tickets: Inventory + inventory: Inventory ): Promise { // Find account-proof UCAN - const accountProof = findAccountProofUCAN(await identifier.did(), tickets) + const accountProof = findAccountProofTicket(await identifier.did(), inventory) // DID is issuer of that username UCAN return accountProof - ? Ucan.decode(accountProof.token).payload.iss + ? accountProof.issuer : null } export async function fileSystemDID( dependencies: Dependencies, identifier: Identifier.Implementation, - tickets: Inventory + inventory: Inventory ) { // Find account-proof UCAN - const accountProof = findAccountProofUCAN(await identifier.did(), tickets) + const accountProof = findAccountProofTicket(await identifier.did(), inventory) // DID is issuer of that username UCAN return accountProof - ? Ucan.decode(accountProof.token).payload.aud + ? accountProof.audience : null } export async function hasSufficientAuthority( dependencies: Dependencies, identifier: Identifier.Implementation, - tickets: Inventory + inventory: Inventory ): Promise< { suffices: true } | { suffices: false; reason: string } > { - const accountProof = findAccountProofUCAN(await identifier.did(), tickets) + const accountProof = findAccountProofTicket(await identifier.did(), inventory) return accountProof ? { suffices: true } : { suffices: false, reason: "Missing the needed account capabilities" } } +export async function provideAuthority( + accountQuery: AccountQuery, + identifier: Identifier.Implementation, + inventory: Inventory +): Promise { + const maybeTicket = findAccountTicket( + await identifier.did(), + inventory + ) + + if (!maybeTicket) return [] + return [maybeTicket] +} + //////// // 🛠️ // //////// @@ -228,18 +243,18 @@ export async function hasSufficientAuthority( * Find the original UCAN the user got back from the Fission server * after registration. This UCAN will have the username fact. */ -export function findAccountProofUCAN( +export function findAccountProofTicket( audience: string, - tickets: Inventory + inventory: Inventory ): Ticket | null { const matcher = (ticket: Ticket) => !!findUsernameFact(ticket) // Grab the UCANs addressed to this audience (ideally current identifier), // then look for the username fact ucan in the delegation chains of those UCANs. - return tickets.lookupByAudience(audience).reduce( + return inventory.lookupTicketByAudience(audience).reduce( (acc: Ticket | null, ticket) => { if (acc) return acc - return tickets.descendUntilMatching(ticket, matcher, Ucan.ticketProofResolver) + return inventory.descendUntilMatchingTicket(ticket, matcher, Ucan.ticketProofResolver) }, null ) @@ -254,20 +269,20 @@ export function findAccountProofUCAN( * In other words, if the device that originally registered the account * linked to another device, it would delegate the account-proof UCAN * to the other device. If then asked for the account UCAN on that other - * device it would be the delegated UCAN. + * device it would be the delegation UCAN. */ -export function findAccountUCAN( +export function findAccountTicket( audience: string, tickets: Inventory -) { +): Ticket | null { const matcher = (ticket: Ticket) => !!findUsernameFact(ticket) // Grab the UCANs addressed to this audience (ideally current identifier), // then look for the username fact ucan in the delegation chains of those UCANs. - return tickets.lookupByAudience(audience).reduce( + return tickets.lookupTicketByAudience(audience).reduce( (acc: Ticket | null, ticket) => { if (acc) return acc - const hasProof = !!tickets.descendUntilMatching(ticket, matcher, Ucan.ticketProofResolver) + const hasProof = !!tickets.descendUntilMatchingTicket(ticket, matcher, Ucan.ticketProofResolver) if (hasProof) return ticket return null }, diff --git a/src/components/account/fission/implementations/delegated.ts b/src/components/account/fission/implementations/delegated.ts index a0a48e5c..bb680577 100644 --- a/src/components/account/fission/implementations/delegated.ts +++ b/src/components/account/fission/implementations/delegated.ts @@ -1,7 +1,6 @@ import * as Fission from "../../../../common/fission.js" import * as Common from "./common.js" -import { AccountQuery } from "../../../../authority/query.js" import { Ticket } from "../../../../ticket/types.js" import { Implementation } from "../../implementation.js" import { Annex, Dependencies } from "./common.js" @@ -38,14 +37,6 @@ export async function register( } } -//////////////////////////// -// IDENTIFIER & AUTHORITY // -//////////////////////////// - -export async function provideAuthority(accountQuery: AccountQuery): Promise { - return [] // TODO -} - //////// // 🛳 // //////// @@ -66,6 +57,6 @@ export function implementation( did: (...args) => Common.did(dependencies, ...args), hasSufficientAuthority: (...args) => Common.hasSufficientAuthority(dependencies, ...args), - provideAuthority, + provideAuthority: Common.provideAuthority, } } diff --git a/src/components/account/fission/implementations/standard.ts b/src/components/account/fission/implementations/standard.ts index 623ba47b..f7e8b3ac 100644 --- a/src/components/account/fission/implementations/standard.ts +++ b/src/components/account/fission/implementations/standard.ts @@ -233,14 +233,6 @@ async function registerVerifiedAccount( } } -//////////////////////////// -// IDENTIFIER & AUTHORITY // -//////////////////////////// - -export async function provideAuthority(accountQuery: AccountQuery): Promise { - return [] // TODO -} - //////// // 🛳 // //////// @@ -262,6 +254,6 @@ export function implementation( did: (...args) => Common.did(dependencies, ...args), hasSufficientAuthority: (...args) => Common.hasSufficientAuthority(dependencies, ...args), - provideAuthority, + provideAuthority: Common.provideAuthority, } } diff --git a/src/components/account/implementation.ts b/src/components/account/implementation.ts index 9cd1681e..ba3d1ccc 100644 --- a/src/components/account/implementation.ts +++ b/src/components/account/implementation.ts @@ -1,5 +1,5 @@ import { AccountQuery } from "../../authority/query.js" -import { Inventory } from "../../ticket/inventory.js" +import { Inventory } from "../../inventory.js" import { Ticket } from "../../ticket/types.js" import * as Identifier from "../identifier/implementation.js" @@ -13,7 +13,7 @@ export type Implementation = { /** * Additional methods you want to be part of `program.account` */ - annex: (identifier: Identifier.Implementation, tickets: Inventory) => Annex + annex: (identifier: Identifier.Implementation, inventory: Inventory) => Annex // CREATION @@ -36,12 +36,15 @@ export type Implementation = { /** * The DID associated with this account. */ - did(identifier: Identifier.Implementation, tickets: Inventory): Promise + did(identifier: Identifier.Implementation, inventory: Inventory): Promise /** * Check if we have everything we need (eg. capabilities) regarding the account. */ - hasSufficientAuthority(identifier: Identifier.Implementation, tickets: Inventory): Promise< + hasSufficientAuthority( + identifier: Identifier.Implementation, + inventory: Inventory + ): Promise< { suffices: true } | { suffices: false; reason: string } > @@ -49,5 +52,9 @@ export type Implementation = { * Provides tickets to those who request authority. * Authority can be granted based on the received queries. */ - provideAuthority(query: AccountQuery): Promise + provideAuthority( + query: AccountQuery, + identifier: Identifier.Implementation, + inventory: Inventory + ): Promise } diff --git a/src/components/account/local.ts b/src/components/account/local.ts index 7a71a0ad..c768bc1f 100644 --- a/src/components/account/local.ts +++ b/src/components/account/local.ts @@ -1,7 +1,7 @@ import * as Identifier from "../identifier/implementation.js" import { AccountQuery } from "../../authority/query.js" -import { Inventory } from "../../ticket/inventory.js" +import { Inventory } from "../../inventory.js" import { Ticket } from "../../ticket/types.js" import { Implementation } from "./implementation.js" diff --git a/src/components/agent/implementation.ts b/src/components/agent/implementation.ts index 9d9b7de5..aa94a16f 100644 --- a/src/components/agent/implementation.ts +++ b/src/components/agent/implementation.ts @@ -1,4 +1,4 @@ -import type { Alg as SignatureAlgorithm, KeyType } from "iso-did/core" +import type { Alg as SignatureAlgorithm, KeyType } from "iso-did/key" export type Implementation = { /** @@ -33,7 +33,7 @@ export type Implementation = { sign: (data: Uint8Array) => Promise /** - * This goes hand in hand with the DID `keyTypes` record from the crypto component. + * The algorithm of the signing key. */ keyAlgorithm: () => Promise diff --git a/src/components/authority/browser-url.ts b/src/components/authority/browser-url.ts new file mode 100644 index 00000000..ba0a965f --- /dev/null +++ b/src/components/authority/browser-url.ts @@ -0,0 +1,25 @@ +import * as Identifier from "../identifier/implementation.js" +import * as Provider from "./browser-url/provider.js" +import * as Requestor from "./browser-url/requestor.js" +import * as DefaultClerk from "./clerk/default.js" + +import { ProvideResponse, RequestResponse } from "./browser-url/common.js" +import { Implementation } from "./implementation.js" + +//////// +// 🛳️ // +//////// + +export { ProvideResponse, RequestResponse } from "./browser-url/common.js" +export { ProvideParams } from "./browser-url/provider.js" +export { RequestParams } from "./browser-url/requestor.js" + +export function implementation( + identifier: Identifier.Implementation +): Implementation { + return { + provide: Provider.provide, + request: Requestor.request, + clerk: DefaultClerk.implementation(identifier), + } +} diff --git a/src/components/authority/browser-url/common.ts b/src/components/authority/browser-url/common.ts new file mode 100644 index 00000000..c19a7553 --- /dev/null +++ b/src/components/authority/browser-url/common.ts @@ -0,0 +1,180 @@ +import { xchacha20poly1305 } from "@noble/ciphers/chacha" +import { x25519 } from "@noble/curves/ed25519" +import { hkdf } from "@noble/hashes/hkdf" +import { sha256 } from "@noble/hashes/sha256" +import { varint } from "iso-base/varint" +import { base58btc } from "multiformats/bases/base58" +import * as Uint8Arrays from "uint8arrays" + +import { isBlob, isObject, isString } from "../../../common/type-checks.js" + +//////// +// 🏔️️ // +//////// + +export const CIPHER_TEXT_ENCODING = "base64url" +export const DOMAIN_SEPARATION_TAG = Uint8Arrays.fromString( + "oddjs-qr-code", + "utf8" +) + +export const INITIAL_NONCE = new Uint8Array(0) + +//////// +// 🧩️ // +//////// + +export type Cipher = ReturnType["cipher"] + +export type Msg = { + did: string + payload: string + step: string +} & Record + +export type ProvideResponse = { + url: string +} + +export type RequestResponse = {} + +export type Step = "handshake" | "query" | "fin" +export type StepResult = { nextNonce: Uint8Array; nextStep: Step } + +//////// +// 🛠️ // +//////// + +export async function decodeChannelData( + data: unknown +): Promise { + let json + + data = isBlob(data) ? await data.text() : data + + if (!isString(data)) { + console.warn(`Received a message, but got a non-string message.`) + return null + } + + try { + json = JSON.parse(data) + } catch (err) { + console.warn(`Received a message, but couldn't decode it as JSON:`, err) + return null + } + + if (!isObject(json)) { + console.warn(`Received a message, but got some JSON that is not an object.`) + return null + } + + if (!isString(json.did)) { + console.warn(`Received a message, but got some JSON that does not have the \`did\` property.`) + return null + } + + if (!isString(json.step)) { + console.warn(`Received a message, but got some JSON that does not have the \`step\` property.`) + return null + } + + if (!isString(json.payload)) { + console.warn(`Received a message, but got some JSON that does not have the \`payload\` property.`) + return null + } + + return { + ...json, + did: json.did, + payload: json.payload, + step: json.step, + } +} + +export function decryptPayload( + cipher: Cipher, + encryptedPayload: string +): Uint8Array { + return cipher.decrypt( + Uint8Arrays.fromString( + encryptedPayload, + CIPHER_TEXT_ENCODING + ) + ) +} + +export function decryptJSONPayload( + cipher: Cipher, + encryptedPayload: string +) { + return JSON.parse( + Uint8Arrays.toString( + decryptPayload(cipher, encryptedPayload), + "utf8" + ) + ) +} + +export function encryptPayload( + cipher: Cipher, + payload: Uint8Array +): string { + return Uint8Arrays.toString( + cipher.encrypt( + payload + ), + CIPHER_TEXT_ENCODING + ) +} + +export function encryptJSONPayload( + cipher: Cipher, + payload: unknown +) { + return encryptPayload( + cipher, + Uint8Arrays.fromString( + JSON.stringify(payload), + "utf8" + ) + ) +} + +export function makeCipher( + { nonce, ourPrivateKey, producerPublicKey, remotePublicKey }: { + nonce: Uint8Array + ourPrivateKey: Uint8Array + producerPublicKey: Uint8Array + remotePublicKey: Uint8Array + } +) { + const sharedSecret = x25519.getSharedSecret(ourPrivateKey, remotePublicKey) + const hashedNonce = sha256(nonce) + + const okm = hkdf( + sha256, + sharedSecret, + producerPublicKey, + Uint8Arrays.concat([ + DOMAIN_SEPARATION_TAG, + Uint8Arrays.fromString(":", "utf8"), + hashedNonce, + ]), + 32 + 24 + hashedNonce.length // length = ChaCha key + IV + next-nonce + ) + + const xChaChaKey = okm.slice(0, 32) + const iv = okm.slice(32, 32 + 24) + + return { + cipher: xchacha20poly1305(xChaChaKey, iv), + nextNonce: okm.slice(32 + 24), + } +} + +export function publicKeyFromDID(did: string) { + const encodedPublicKey = base58btc.decode(did.replace(/^did\:key\:/, "")) + const [_code, size] = varint.decode(encodedPublicKey) + return encodedPublicKey.slice(size) +} diff --git a/src/components/authority/browser-url/provider.ts b/src/components/authority/browser-url/provider.ts new file mode 100644 index 00000000..79511de0 --- /dev/null +++ b/src/components/authority/browser-url/provider.ts @@ -0,0 +1,348 @@ +import * as Uint8Arrays from "uint8arrays" + +import { x25519 } from "@noble/curves/ed25519" +import { randomBytes } from "iso-base/crypto" +import { tag } from "iso-base/varint" +import { base58btc } from "multiformats/bases/base58" + +import * as Query from "../../../authority/query.js" +import * as Events from "../../../events/authority.js" +import * as Path from "../../../path/index.js" +import * as Tickets from "../../../ticket/index.js" +import * as Ucan from "../../../ucan/ts-ucan/index.js" +import * as Account from "../../account/implementation.js" +import * as Channel from "../../channel/implementation.js" +import * as Identifier from "../../identifier/implementation.js" + +import { AccessKeyWithContext } from "../../../accessKey.js" +import { Channel as ChannelType } from "../../../channel.js" +import { isObject, isString } from "../../../common/type-checks.js" +import { EventEmitter } from "../../../events/emitter.js" +import { Inventory } from "../../../inventory.js" +import { Ticket } from "../../../ticket/types.js" +import { + CIPHER_TEXT_ENCODING, + Cipher, + Msg, + ProvideResponse, + StepResult, + decodeChannelData, + decryptJSONPayload, + decryptPayload, + encryptJSONPayload, + makeCipher, +} from "./common.js" +import { Session } from "./session.js" + +export type ProvideParams = { + dependencies: { + account: Account.Implementation + channel: Channel.Implementation + identifier: Identifier.Implementation + } + eventEmitter: EventEmitter + inventory: Inventory + queries: Query.Query[] +} + +export async function provide( + params: ProvideParams +): Promise { + const challenge = randomBytes(16) + + const privateKey = x25519.utils.randomPrivateKey() + const publicKey = x25519.getPublicKey(privateKey) + + const id = base58btc.encode(tag(0xec, publicKey)) + const did = `did:key:${id}` + + const sessionsCache = {} + + params.dependencies.channel.establish({ + topic: did, + onmessage: (event: MessageEvent, channel: ChannelType) => + messageHandler({ + ...params, + challenge, + channel, + event, + ourDID: did, + ourPrivateKey: privateKey, + ourPublicKey: publicKey, + sessionsCache, + }), + }) + + // URL + const url = new URL(location.href) + url.searchParams.set("authority[challenge]", Uint8Arrays.toString(challenge, CIPHER_TEXT_ENCODING)) + url.searchParams.set("authority[publicKey]", Uint8Arrays.toString(publicKey, CIPHER_TEXT_ENCODING)) + + return { + url: url.toString(), + } +} + +////////////// +// MESSAGES // +////////////// + +type MessageHandlerParams = ProvideParams & { + challenge: Uint8Array + channel: ChannelType + event: MessageEvent + ourDID: string + ourPrivateKey: Uint8Array + ourPublicKey: Uint8Array + sessionsCache: Record> +} + +async function messageHandler( + params: MessageHandlerParams +) { + const msg = await decodeChannelData(params.event.data) + if (!msg) return + + const sessionsCache = params.sessionsCache + const sessionFromCache = sessionsCache[msg.did] + const session = sessionFromCache ? sessionFromCache : new ProviderSession({ + ...params, + remoteDID: msg.did, + }) + + sessionsCache[msg.did] = session + await session.proceed(msg) + + if (session.ended()) { + delete sessionsCache[msg.did] + } +} + +///////////// +// SESSION // +///////////// + +class ProviderSession extends Session { + challenge: Uint8Array + dependencies: MessageHandlerParams["dependencies"] + inventory: Inventory + + constructor( + params: MessageHandlerParams & { + remoteDID: string + } + ) { + super(params) + + this.challenge = params.challenge + this.dependencies = params.dependencies + this.inventory = params.inventory + } + + //////////////////////// + // STEP 1 - HANDSHAKE // + //////////////////////// + + async handshake(msg: Msg): Promise { + let decryption = makeCipher({ + nonce: this.nonce, + producerPublicKey: this.ourPublicKey, + ourPrivateKey: this.ourPrivateKey, + remotePublicKey: this.remotePublicKey, + }) + + const payload = decryptPayload(decryption.cipher, msg.payload) + + const hasCorrectChallenge = Uint8Arrays.equals( + payload, + this.challenge + ) + + if (!hasCorrectChallenge) { + return this.earlyExit(`Challenge failed during handshake with ${msg.did}`) + } + + let { cipher, nextNonce } = makeCipher({ + nonce: decryption.nextNonce, + producerPublicKey: this.ourPublicKey, + ourPrivateKey: this.ourPrivateKey, + remotePublicKey: this.remotePublicKey, + }) + + this.sendMessage( + "handshake", + encryptJSONPayload(cipher, { approved: true }) + ) + + return { nextNonce, nextStep: "query" } + } + + //////////////////// + // STEP 2 - QUERY // + //////////////////// + + async query(msg: Msg): Promise { + let decryption = makeCipher({ + nonce: this.nonce, + producerPublicKey: this.ourPublicKey, + ourPrivateKey: this.ourPrivateKey, + remotePublicKey: this.remotePublicKey, + }) + + const payload = decryptJSONPayload(decryption.cipher, msg.payload) + + if ( + !isObject(payload) + || !Array.isArray(payload.queries) + || !payload.queries.every((p: unknown) => isString(p) || isObject(p)) + || !isString(payload.identifier) + ) { + return this.earlyExit(`Ignoring queries from ${msg.did}, improperly encoded queries.`) + } + + const remoteIdentifierDID = payload.identifier + + const queries = payload.queries.map(Query.fromJSON) + const allContained = queries.every(child => { + return queries.some(parent => Query.isContained({ parent, child })) + }) + + if (!allContained) { + return this.earlyExit(`Ignoring queries from ${msg.did}, asking for more than was provided.`) + } + + return new Promise((resolve, reject) => { + let { cipher, nextNonce } = makeCipher({ + nonce: decryption.nextNonce, + producerPublicKey: this.ourPublicKey, + ourPrivateKey: this.ourPrivateKey, + remotePublicKey: this.remotePublicKey, + }) + + this.eventEmitter.emit("provide:query", { + approve: (queries) => { + this + .approveQueries(queries, remoteIdentifierDID, cipher) + .then(() => resolve(this.end), reject) + }, + dismiss: () => { + this + .dismissQueries(cipher) + .then(() => resolve(this.end), reject) + }, + queries, + }) + }) + } + + async approveQueries( + queries: Query.Query[], + remoteIdentifierDID: string, + cipher: Cipher + ): Promise { + if (queries.length === 0) throw new Error("Cannot approve an empty list of queries.") + + const identifierDID = await this.dependencies.identifier.did() + const identifierKeyPair = { + did: () => identifierDID, + jwtAlg: await this.dependencies.identifier.ucanAlgorithm(), + sign: this.dependencies.identifier.sign, + } + + const fsQueries = queries.reduce( + (acc, q) => q.query === "fileSystem" ? [...acc, q] : acc, + [] as Query.FileSystemQuery[] + ) + + const accountTicketPromises = queries + .reduce( + (acc, q) => q.query === "account" ? [...acc, q] : acc, + [] as Query.AccountQuery[] + ) + .map(async q => { + const tickets = await this.dependencies.account.provideAuthority( + q, + this.dependencies.identifier, + this.inventory + ) + + const promises = tickets.map(async t => { + const ucan = await Ucan.build({ + audience: remoteIdentifierDID, + issuer: identifierKeyPair, + proofs: [(await Tickets.cid(t)).toString()], + }) + + const ticket = Ucan.toTicket(ucan) + + return this.inventory.bundleTickets( + ticket, + Ucan.ticketProofResolver + ) + }) + + const nested = await Promise.all(promises) + return nested.flat() + }) + + const accountTicketsBundles = await Promise.all(accountTicketPromises) + const accountTickets = Tickets.collectUnique(accountTicketsBundles.flat()) + + const fileSystemTicketPromises = fsQueries + .map(q => this.inventory.lookupFileSystemTicket(q.path, q.did)) + .reduce((acc, a) => a ? [...acc, a] : acc, [] as Ticket[]) + .map(async t => { + const ucan = await Ucan.build({ + audience: remoteIdentifierDID, + issuer: identifierKeyPair, + proofs: [(await Tickets.cid(t)).toString()], + }) + + const ticket = Ucan.toTicket(ucan) + + return this.inventory.bundleTickets( + ticket, + Ucan.ticketProofResolver + ) + }) + + const fileSystemTicketBundles = await Promise.all(fileSystemTicketPromises) + const fileSystemTickets = Tickets.collectUnique(fileSystemTicketBundles.flat()) + + const accessKeys = fsQueries + .filter(q => Path.isPartition("private", q.path)) + .map(q => this.inventory.findAccessKey(q.path, q.did)) + .reduce( + (acc, a) => a ? [...acc, a] : acc, + [] as AccessKeyWithContext[] + ) + + this.sendMessage( + "query", + encryptJSONPayload(cipher, { + approved: queries.map(Query.toJSON), + accountTickets, + fileSystemTickets, + accessKeys: accessKeys.map(a => { + return { + did: a.did, + key: Uint8Arrays.toString(a.key, CIPHER_TEXT_ENCODING), + path: Path.toPosix(a.path), + } + }), + }) + ) + + this.eventEmitter.emit("provide:authorised", { queries }) + this.eventEmitter.emit("provide:authorized", { queries }) + } + + async dismissQueries(cipher: Cipher): Promise { + this.sendMessage( + "query", + encryptJSONPayload(cipher, { dismissed: true }) + ) + + this.eventEmitter.emit("provide:dismissed") + } +} diff --git a/src/components/authority/browser-url/requestor.ts b/src/components/authority/browser-url/requestor.ts new file mode 100644 index 00000000..eafdde75 --- /dev/null +++ b/src/components/authority/browser-url/requestor.ts @@ -0,0 +1,284 @@ +import * as Uint8Arrays from "uint8arrays" + +import { x25519 } from "@noble/curves/ed25519" +import { tag } from "iso-base/varint" +import { base58btc } from "multiformats/bases/base58" + +import * as Query from "../../../authority/query.js" +import * as Events from "../../../events/authority.js" +import * as Path from "../../../path/index.js" +import * as Channel from "../../channel/implementation.js" +import * as Identifier from "../../identifier/implementation.js" + +import { Channel as ChannelType } from "../../../channel.js" +import { isObject, isString } from "../../../common/type-checks.js" +import { EventEmitter } from "../../../events/emitter.js" +import { Ticket } from "../../../index.js" +import { isTicket } from "../../../ticket/index.js" +import { AuthorityArtefacts, RequestOptions } from "../implementation.js" +import { + CIPHER_TEXT_ENCODING, + INITIAL_NONCE, + Msg, + RequestResponse, + StepResult, + decodeChannelData, + decryptJSONPayload, + encryptJSONPayload, + encryptPayload, + makeCipher, +} from "./common.js" +import { Session } from "./session.js" + +export type RequestParams = { + dependencies: { + channel: Channel.Implementation + identifier: Identifier.Implementation + } + eventEmitter: EventEmitter + options: RequestOptions + queries: Query.Query[] +} + +export async function request( + params: RequestParams +): Promise | null> { + const url = new URL(location.href) + const challenge = url.searchParams.get("authority[challenge]") + const otherPubKeyString = url.searchParams.get("authority[publicKey]") + + // Nothing to do + if (!challenge || !otherPubKeyString) return null + + // Crypto + const privateKey = x25519.utils.randomPrivateKey() + const publicKey = x25519.getPublicKey(privateKey) + + const ourDID = `did:key:${base58btc.encode(tag(0xec, publicKey))}` + const otherPubKey = Uint8Arrays.fromString(otherPubKeyString, CIPHER_TEXT_ENCODING) + + const handshakeCipher = makeCipher({ + nonce: INITIAL_NONCE, + producerPublicKey: otherPubKey, + ourPrivateKey: privateKey, + remotePublicKey: otherPubKey, + }) + + // Timeout after 60 seconds + return new Promise((resolve, reject) => { + let timeoutId: number = 0 + let channel: ChannelType + + function setTimer() { + clearTimeout(timeoutId) + timeoutId = setTimeout(() => { + channel.close() + reject( + "Authority exchange timed out. The URL parameters could be out of date, or the provider has started a new session. Each time `.provide()` is called a new session is started, make sure you're using the correct URL or QR code." + ) + }, 60000) as unknown as number + return timeoutId + } + + // Setup channel + const topicID = base58btc.encode(tag(0xec, otherPubKey)) + const topicDID = `did:key:${topicID}` + + const sessionsCache = {} + + params.dependencies.channel.establish({ + topic: topicDID, + onmessage: (event: MessageEvent, channel: ChannelType) => + messageHandler({ + ...params, + channel, + event, + nonce: handshakeCipher.nextNonce, + ourDID, + ourPrivateKey: privateKey, + ourPublicKey: publicKey, + resolve, + sessionsCache, + resetTimeout: setTimer, + }), + }).then(c => { + channel = c + + // Send handshake message + channel.send( + JSON.stringify({ + step: "handshake", + did: ourDID, + payload: encryptPayload( + handshakeCipher.cipher, + Uint8Arrays.fromString(challenge, CIPHER_TEXT_ENCODING) + ), + }) + ) + + setTimer() + }) + }) +} + +////////////// +// MESSAGES // +////////////// + +type MessageHandlerParams = RequestParams & { + channel: ChannelType + event: MessageEvent + nonce: Uint8Array + ourDID: string + ourPrivateKey: Uint8Array + ourPublicKey: Uint8Array + resolve: (value: AuthorityArtefacts | null) => void + sessionsCache: Record + resetTimeout: () => number +} + +async function messageHandler(params: MessageHandlerParams) { + const msg = await decodeChannelData(params.event.data) + if (!msg) return + + const timeoutId = params.resetTimeout() + + const sessionsCache = params.sessionsCache + const sessionFromCache = sessionsCache[msg.did] + const session = sessionFromCache ? sessionFromCache : new RequestorSession({ + ...params, + remoteDID: msg.did, + }) + + sessionsCache[msg.did] = session + await session.proceed(msg) + + if (session.ended()) { + delete sessionsCache[msg.did] + params.channel.close() + clearTimeout(timeoutId) + params.resolve(null) + } +} + +///////////// +// SESSION // +///////////// + +class RequestorSession extends Session { + dependencies: MessageHandlerParams["dependencies"] + resolve: MessageHandlerParams["resolve"] + + constructor( + params: MessageHandlerParams & { + remoteDID: string + } + ) { + super(params) + + this.dependencies = params.dependencies + this.resolve = params.resolve + } + + //////////////////////// + // STEP 1 - HANDSHAKE // + //////////////////////// + + async handshake(msg: Msg): Promise { + let decryption = makeCipher({ + nonce: this.nonce, + producerPublicKey: this.remotePublicKey, + ourPrivateKey: this.ourPrivateKey, + remotePublicKey: this.remotePublicKey, + }) + + const payload = decryptJSONPayload(decryption.cipher, msg.payload) + + if (payload.approved !== true) { + return this.earlyExit(`Cancelling authority request, producer did not accept.`) + } + + let { cipher, nextNonce } = makeCipher({ + nonce: decryption.nextNonce, + producerPublicKey: this.remotePublicKey, + ourPrivateKey: this.ourPrivateKey, + remotePublicKey: this.remotePublicKey, + }) + + this.sendMessage( + "query", + encryptJSONPayload(cipher, { + identifier: await this.dependencies.identifier.did(), + queries: this.queries.map(Query.toJSON), + }) + ) + + return { nextNonce, nextStep: "query" } + } + + //////////////////// + // STEP 2 - QUERY // + //////////////////// + + async query(msg: Msg): Promise { + let decryption = makeCipher({ + nonce: this.nonce, + producerPublicKey: this.remotePublicKey, + ourPrivateKey: this.ourPrivateKey, + remotePublicKey: this.remotePublicKey, + }) + + const payload = decryptJSONPayload(decryption.cipher, msg.payload) + + if (payload.dismissed === true) { + this.eventEmitter.emit("request:dismissed") + return this.end + } + + if ( + !isObject(payload) + || !Array.isArray(payload.accessKeys) + || !Array.isArray(payload.accountTickets) + || !Array.isArray(payload.approved) + || !Array.isArray(payload.fileSystemTickets) + || !payload.accessKeys.every((p: unknown) => + isObject(p) && isString(p.did) && isString(p.key) && isString(p.path) + ) + || !payload.accountTickets.every((p: unknown) => isObject(p)) + || !payload.approved.every((p: unknown) => isString(p) || isObject(p)) + || !payload.fileSystemTickets.every((p: unknown) => isObject(p)) + ) { + return this.earlyExit(`Ignoring queries from ${msg.did}, improperly encoded query approvals.`, payload) + } + + const accountTickets = payload.accountTickets.reduce( + (acc, t) => isTicket(t) ? [...acc, t] : acc, + [] as Ticket[] + ) + + const fileSystemTickets = payload.fileSystemTickets.reduce( + (acc, t) => isTicket(t) ? [...acc, t] : acc, + [] as Ticket[] + ) + + const accessKeys = payload.accessKeys.map(a => { + return { + did: a.did, + key: Uint8Arrays.fromString(a.key, CIPHER_TEXT_ENCODING), + path: Path.fromPosix(a.path), + } + }) + + const queries = payload.approved.map(q => Query.fromJSON(q)) + + this.resolve({ + accessKeys, + accountTickets, + fileSystemTickets, + authorisedQueries: queries, + requestResponse: {}, + }) + + return this.end + } +} diff --git a/src/components/authority/browser-url/session.ts b/src/components/authority/browser-url/session.ts new file mode 100644 index 00000000..00ec56ef --- /dev/null +++ b/src/components/authority/browser-url/session.ts @@ -0,0 +1,103 @@ +import * as Events from "../../../events/authority.js" + +import { Query } from "../../../authority/query.js" +import { Channel as ChannelType } from "../../../channel.js" +import { EventEmitter } from "../../../events/emitter.js" +import { INITIAL_NONCE, Msg, Step, StepResult, publicKeyFromDID } from "./common.js" + +export abstract class Session { + channel: ChannelType + eventEmitter: EventEmitter + ourDID: string + ourPrivateKey: Uint8Array + ourPublicKey: Uint8Array + queries: Query[] + remoteDID: string + remotePublicKey: Uint8Array + + nonce: Uint8Array + step: Step + + constructor(params: { + channel: ChannelType + eventEmitter: EventEmitter + nonce?: Uint8Array + ourDID: string + ourPrivateKey: Uint8Array + ourPublicKey: Uint8Array + queries: Query[] + remoteDID: string + }) { + this.channel = params.channel + this.eventEmitter = params.eventEmitter + this.ourDID = params.ourDID + this.ourPrivateKey = params.ourPrivateKey + this.ourPublicKey = params.ourPublicKey + this.queries = params.queries + this.remoteDID = params.remoteDID + this.remotePublicKey = publicKeyFromDID(params.remoteDID) + + this.nonce = params.nonce || INITIAL_NONCE + this.step = "handshake" + } + + end: StepResult = { + nextNonce: INITIAL_NONCE, + nextStep: "fin", + } + + ended() { + return this.step === "fin" + } + + // Steps + + async proceed(msg: Msg): Promise { + const result = await this.#proceed(msg) + this.nonce = result.nextNonce + this.step = result.nextStep + } + + async #proceed(msg: Msg): Promise { + if (msg.did === this.ourDID) { + return this.earlyExit() + } + + if (this.step !== msg.step) { + return this.earlyExit( + `Ignoring client ${msg.did}, steps don't match. Received '${msg.step}', but the active step is '${this.step}'.` + ) + } + + if (this.remoteDID && msg.did !== this.remoteDID) { + return this.earlyExit( + `Ignoring client ${msg.did}, does not match DID in current state.` + ) + } + + switch (this.step) { + case "handshake": + return this.handshake(msg) + case "query": + return this.query(msg) + default: + throw new Error(`Invalid step: ${this.step}`) + } + } + + abstract handshake(msg: Msg): Promise + abstract query(msg: Msg): Promise + + // 🛠️ + + sendMessage(step: Step, payload: string): void { + this.channel.send(JSON.stringify({ step, did: this.ourDID, payload })) + } + + // ⚠️ + + earlyExit(...args: any): StepResult { + if (args.length) console.warn(...args) + return this.end + } +} diff --git a/src/components/authority/ts-ucan.ts b/src/components/authority/clerk/default.ts similarity index 76% rename from src/components/authority/ts-ucan.ts rename to src/components/authority/clerk/default.ts index c23c6e44..6897c008 100644 --- a/src/components/authority/ts-ucan.ts +++ b/src/components/authority/clerk/default.ts @@ -1,11 +1,11 @@ -import * as AgentDID from "../../agent/did.js" -import * as Path from "../../path/index.js" -import * as Ucan from "../../ucan/ts-ucan/index.js" -import * as Agent from "../agent/implementation.js" -import * as Identifier from "../identifier/implementation.js" +import * as AgentDID from "../../../agent/did.js" +import * as Path from "../../../path/index.js" +import * as Ucan from "../../../ucan/ts-ucan/index.js" +import * as Agent from "../../agent/implementation.js" +import * as Identifier from "../../identifier/implementation.js" -import { Ticket } from "../../ticket/types.js" -import { Implementation } from "./implementation.js" +import { Ticket } from "../../../ticket/types.js" +import { Clerk } from "../implementation.js" /////////// // CLERK // @@ -83,17 +83,15 @@ export function matchFileSystemTicket( export function implementation( identifier: Identifier.Implementation -): Implementation { +): Clerk { return { - clerk: { - tickets: { - fileSystem: { - create: (...args) => createFileSystemTicket(identifier, ...args), - matcher: matchFileSystemTicket, - }, - misc: { - identifierToAgentDelegation, - }, + tickets: { + fileSystem: { + create: (...args) => createFileSystemTicket(identifier, ...args), + matcher: matchFileSystemTicket, + }, + misc: { + identifierToAgentDelegation, }, }, } diff --git a/src/components/authority/implementation.ts b/src/components/authority/implementation.ts index 3085ee62..0dc66049 100644 --- a/src/components/authority/implementation.ts +++ b/src/components/authority/implementation.ts @@ -1,30 +1,17 @@ -import * as Events from "../../events/authority.js" import * as Path from "../../path/index.js" - +import * as Account from "../account/implementation.js" import * as Agent from "../agent/implementation.js" import * as Identifier from "../identifier/implementation.js" +import { AccessKeyWithContext } from "../../accessKey.js" import { Query } from "../../authority/query.js" -import { EventEmitter } from "../../events/emitter.js" import { Ticket } from "../../ticket/types.js" +import { ProvideParams } from "./browser-url/provider.js" +import { RequestParams } from "./browser-url/requestor.js" -export type RequestOptions = { - extraParams?: Record - query?: Query - returnUrl?: string -} - -export type Provider = { - type: "provider" - - provide(tickets: Ticket[], eventEmitter: EventEmitter): Promise -} - -export type Requestor = { - type: "requestor" - - request: (options: RequestOptions, eventEmitter: EventEmitter) => Promise -} +/////////// +// CLERK // +/////////// /** * Responsible for managing tickets or parts thereof. @@ -63,9 +50,29 @@ export type Clerk = { } } -/** - * Implementation. - */ -export type Implementation = { +/////////////// +// REQUESTOR // +/////////////// + +export type AuthorityArtefacts = { + accessKeys: AccessKeyWithContext[] + accountTickets: Ticket[] + authorisedQueries: Query[] + fileSystemTickets: Ticket[] + requestResponse: RequestResponse +} + +export type RequestOptions = { + extraParams?: Record + returnUrl?: string +} + +//////////////////// +// IMPLEMENTATION // +//////////////////// + +export type Implementation = { clerk: Clerk + provide(params: ProvideParams): Promise + request(params: RequestParams): Promise | null> } diff --git a/src/components/channel/fission.ts b/src/components/channel/fission.ts index fe157666..d668ab2c 100644 --- a/src/components/channel/fission.ts +++ b/src/components/channel/fission.ts @@ -5,12 +5,6 @@ import * as Fission from "../../common/fission.js" import { Manners } from "../../components.js" import { Implementation } from "./implementation.js" -//////// -// 🧩 // -//////// - -export type Context = { did: string } - //////// // 🛠️ // //////// @@ -18,7 +12,7 @@ export type Context = { did: string } export function establish( manners: Manners.Implementation, endpoints: Endpoints, - options: ChannelOptions + options: ChannelOptions ): Promise { const host = `${endpoints.server}${endpoints.apiPath}` .replace(/^https:\/\//, "wss://") @@ -26,7 +20,7 @@ export function establish( return createWebsocketChannel( manners, - `${host}/account/link/${options.context.did}`, + `${host}/relay/${options.topic}`, options ) } @@ -38,7 +32,7 @@ export function establish( export function implementation( manners: Manners.Implementation, optionalEndpoints?: Endpoints -): Implementation { +): Implementation { const endpoints = optionalEndpoints || Fission.PRODUCTION return { diff --git a/src/components/channel/implementation.ts b/src/components/channel/implementation.ts index 763daa61..e109a471 100644 --- a/src/components/channel/implementation.ts +++ b/src/components/channel/implementation.ts @@ -1,8 +1,8 @@ import { Channel, ChannelOptions } from "../../channel.js" -export type Implementation = { +export type Implementation = { /** * Creates a `Channel` which can be used to transfer data over. */ - establish: (options: ChannelOptions) => Promise + establish: (options: ChannelOptions) => Promise } diff --git a/src/components/channel/local.ts b/src/components/channel/local.ts index 3ec045a5..84f56637 100644 --- a/src/components/channel/local.ts +++ b/src/components/channel/local.ts @@ -1,18 +1,12 @@ import { Channel, ChannelOptions } from "../../channel.js" import { Implementation } from "./implementation.js" -//////// -// 🧩 // -//////// - -export type Context = {} - //////// // 🛠️ // //////// export function establish( - options: ChannelOptions + options: ChannelOptions ): Promise { throw new Error("No local channel available just yet.") // NOTE: Do WebRTC implementation? } @@ -21,7 +15,7 @@ export function establish( // 🛳️ // //////// -export function implementation(): Implementation { +export function implementation(): Implementation { return { establish, } diff --git a/src/components/depot/ipfs-bitswap-websockets.ts b/src/components/depot/ipfs-bitswap-websockets.ts index a2915df2..da4a148c 100644 --- a/src/components/depot/ipfs-bitswap-websockets.ts +++ b/src/components/depot/ipfs-bitswap-websockets.ts @@ -147,7 +147,7 @@ export async function implementation( if (await blockstore.has(cid)) return blockstore.get(cid) // TODO: Can we use CAR files to get a bunch of blocks at once? - return fetch(`${gatewayUrl.replace(/\/+$/, "")}/api/v0/block/get?arg=${cid.toString()}`) + return fetch(`${gatewayUrl.replace(/\/+$/, "")}/ipfs/${cid.toString()}?format=raw`) .then(r => { if (r.ok) return r.arrayBuffer() throw new Error("Failed to fetch block from gateway") diff --git a/src/compositions/fission.ts b/src/compositions/fission.ts index d2678821..c7b936bf 100644 --- a/src/compositions/fission.ts +++ b/src/compositions/fission.ts @@ -22,7 +22,7 @@ import * as Config from "../configuration.js" import * as Account from "../components/account/fission.js" import * as Agent from "../components/agent/web-crypto-api.js" -import * as Authority from "../components/authority/ts-ucan.js" +import * as Authority from "../components/authority/browser-url.js" import * as Channel from "../components/channel/fission.js" import * as Depot from "../components/depot/fission.js" import * as DNS from "../components/dns/dns-over-https/fission.js" @@ -35,7 +35,7 @@ export * from "../common/fission.js" export { Annexes } from "../components/account/fission.js" export type DefaultAnnex = Account.Annexes.Standard -export { Context as ChannelContext } from "../components/channel/fission.js" +export { ProvideParams, ProvideResponse, RequestParams, RequestResponse } from "../components/authority/browser-url.js" /** * Account type. @@ -85,27 +85,51 @@ export async function components( accountImplementation: "delegated" environment?: string | Fission.Endpoints } -): Promise> +): Promise< + Components< + Account.Annexes.Delegated, + Authority.ProvideResponse, + Authority.RequestResponse + > +> export async function components( config: Configuration, settings?: { accountImplementation: "standard" environment?: string | Fission.Endpoints } -): Promise> +): Promise< + Components< + Account.Annexes.Standard, + Authority.ProvideResponse, + Authority.RequestResponse + > +> export async function components( config: Configuration, settings?: { environment?: string | Fission.Endpoints } -): Promise> +): Promise< + Components< + DefaultAnnex, + Authority.ProvideResponse, + Authority.RequestResponse + > +> export async function components( config: Configuration, settings?: { accountType?: AccountImplementations environment?: string | Fission.Endpoints } -): Promise> { +): Promise< + Components< + Account.Annexes.Delegated | Account.Annexes.Standard, + Authority.ProvideResponse, + Authority.RequestResponse + > +> { const namespace = Config.namespace(config) // Determine environment diff --git a/src/compositions/local.ts b/src/compositions/local.ts index 18fb8885..25bf2f52 100644 --- a/src/compositions/local.ts +++ b/src/compositions/local.ts @@ -21,7 +21,7 @@ import * as Config from "../configuration.js" import * as Account from "../components/account/local.js" import * as Agent from "../components/agent/web-crypto-api.js" -import * as Authority from "../components/authority/ts-ucan.js" +import * as Authority from "../components/authority/browser-url.js" import * as Channel from "../components/channel/local.js" import * as Depot from "../components/depot/local.js" import * as DNS from "../components/dns/dns-over-https/cloudflare-google.js" @@ -30,7 +30,6 @@ import * as Manners from "../components/manners/default.js" import * as Storage from "../components/storage/indexed-db.js" export { Annex } from "../components/account/local.js" -export { Context as ChannelContext } from "../components/channel/local.js" /** * The default Fission stack using web crypto auth and IPFS. @@ -41,7 +40,13 @@ export async function components( settings: Configuration & { environment?: string } -): Promise> { +): Promise< + Components< + Account.Annex, + Authority.ProvideResponse, + Authority.RequestResponse + > +> { const config = Config.extract(settings) const namespace = Config.namespace(config) diff --git a/src/events/authority.ts b/src/events/authority.ts index ababf8d7..a3c9e79b 100644 --- a/src/events/authority.ts +++ b/src/events/authority.ts @@ -1,10 +1,16 @@ -export type AuthorityRequestor = { - "challenge": undefined // TODO -} +import { Query } from "../authority/query.js" + +export type Authority = { + "provide:authorised": { queries: Query[] } + "provide:authorized": { queries: Query[] } + "provide:dismissed": undefined + "provide:query": { + approve: (queries: Query[]) => void + dismiss: () => void + queries: Query[] + } -export type AuthorityProvider = { - "approved": undefined - "challenge": undefined // TODO - "dismissed": undefined - "query": Record // TODO + "request:authorised": { queries: Query[] } + "request:authorized": { queries: Query[] } + "request:dismissed": undefined } diff --git a/src/fileSystem.ts b/src/fileSystem.ts index fba66672..e1dec757 100644 --- a/src/fileSystem.ts +++ b/src/fileSystem.ts @@ -9,7 +9,7 @@ import { Maybe } from "./common/index.js" import { Authority, Storage } from "./components.js" import { FileSystem } from "./fs/class.js" import { Dependencies } from "./fs/types.js" -import { Inventory } from "./ticket/inventory.js" +import { Inventory } from "./inventory.js" import { Ticket } from "./ticket/types.js" //////// @@ -19,7 +19,7 @@ import { Ticket } from "./ticket/types.js" /** * Load a file system. */ -export async function loadFileSystem(args: { +export async function loadFileSystem(args: { cabinet: Cabinet dataRoot?: CID dataRootUpdater?: ( @@ -27,7 +27,7 @@ export async function loadFileSystem(args: { proofs: Ticket[] ) => Promise<{ updated: true } | { updated: false; reason: string }> dependencies: Dependencies & { - authority: Authority.Implementation + authority: Authority.Implementation storage: Storage.Implementation } did: string @@ -69,7 +69,7 @@ export async function loadFileSystem(args: { } // If a file system exists, load it and return it - const tickets = new Inventory(authority, cabinet) + const inventory = new Inventory(authority.clerk, cabinet) const updateDataRoot = dataRootUpdater if (cid) { @@ -77,7 +77,7 @@ export async function loadFileSystem(args: { fs = await FileSystem.fromCID( cid, - { cidLog, dependencies, did, tickets, updateDataRoot } + { cidLog, dependencies, did, inventory, updateDataRoot } ) // Mount private nodes @@ -102,7 +102,7 @@ export async function loadFileSystem(args: { cidLog, dependencies, did, - tickets, + inventory, updateDataRoot, }) diff --git a/src/fs/class.node.test.ts b/src/fs/class.node.test.ts index 7d47740a..284d744e 100644 --- a/src/fs/class.node.test.ts +++ b/src/fs/class.node.test.ts @@ -8,12 +8,16 @@ import * as Unix from "./unix.js" import { account, agent, authority, depot, identifier, manners, storage } from "../../tests/helpers/components.js" import { CID } from "../common/cid.js" -import { Inventory } from "../ticket/inventory.js" +import { Inventory } from "../inventory.js" import { Ticket } from "../ticket/types.js" import { FileSystem } from "./class.js" describe("File System Class", async () => { let fs: FileSystem + let mounts: { + path: Path.Distinctive + capsuleKey: Uint8Array + }[] const fsOpts = { dependencies: { account, agent, depot, identifier, manners }, @@ -28,7 +32,7 @@ describe("File System Class", async () => { const cidLog = await CIDLog.create({ did, storage }) const cabinet = await Cabinet.create({ storage }) - const tickets = new Inventory(authority, cabinet) + const inventory = new Inventory(authority.clerk, cabinet) const updateDataRoot = async ( dataRoot: CID, @@ -37,9 +41,9 @@ describe("File System Class", async () => { return { updated: true } } - fs = await FileSystem.empty({ ...fsOpts, cidLog, did, tickets, updateDataRoot }) + fs = await FileSystem.empty({ ...fsOpts, cidLog, did, inventory, updateDataRoot }) - const mounts = await fs.mountPrivateNodes([ + mounts = await fs.mountPrivateNodes([ { path: Path.root() }, ]) @@ -73,11 +77,13 @@ describe("File System Class", async () => { const cidLog = await CIDLog.create({ did, storage }) const cabinet = await Cabinet.create({ storage }) - const tickets = new Inventory(authority, cabinet) + const inventory = new Inventory(authority.clerk, cabinet) - const loadedFs = await FileSystem.fromCID(dataRoot, { ...fsOpts, cidLog, did, tickets }) + const loadedFs = await FileSystem.fromCID(dataRoot, { ...fsOpts, cidLog, did, inventory }) await loadedFs.mountPrivateNodes([ - { path: Path.removePartition(privatePath), capsuleKey }, + // TODO: Needs to be fixed in rs-wnfs + // { path: Path.removePartition(privatePath), capsuleKey }, + { path: Path.root(), capsuleKey: mounts[0].capsuleKey }, ]) assert.equal(await loadedFs.read(publicPath, "utf8"), "public") @@ -99,9 +105,9 @@ describe("File System Class", async () => { const cidLog = await CIDLog.create({ did, storage }) const cabinet = await Cabinet.create({ storage }) - const tickets = new Inventory(authority, cabinet) + const inventory = new Inventory(authority.clerk, cabinet) - const loadedFs = await FileSystem.fromCID(dataRoot, { ...fsOpts, cidLog, did, tickets }) + const loadedFs = await FileSystem.fromCID(dataRoot, { ...fsOpts, cidLog, did, inventory }) if (capsuleKey) { await loadedFs.mountPrivateNodes([ @@ -123,10 +129,10 @@ describe("File System Class", async () => { const cidLog = await CIDLog.create({ did, storage }) const cabinet = await Cabinet.create({ storage }) - const tickets = new Inventory(authority, cabinet) + const inventory = new Inventory(authority.clerk, cabinet) const { dataRoot } = await fs.write(privatePath, "utf8", "private") - const loadedFs = await FileSystem.fromCID(dataRoot, { ...fsOpts, cidLog, did, tickets }) + const loadedFs = await FileSystem.fromCID(dataRoot, { ...fsOpts, cidLog, did, inventory }) if (oldCapsuleKey) { await loadedFs.mountPrivateNodes([ @@ -137,6 +143,10 @@ describe("File System Class", async () => { } assert.equal(await loadedFs.read(privatePath, "utf8"), "private") + + await loadedFs.write(privatePath, "utf8", "new content") + + assert.equal(await loadedFs.read(privatePath, "utf8"), "new content") }) // READING & WRITING diff --git a/src/fs/class.ts b/src/fs/class.ts index 9e7337f6..544f595d 100644 --- a/src/fs/class.ts +++ b/src/fs/class.ts @@ -12,8 +12,8 @@ import * as Store from "./store.js" import { EventEmitter, createEmitter } from "../events/emitter.js" import { EventListener } from "../events/listen.js" +import { Inventory } from "../inventory.js" import { Partition, Partitioned, PartitionedNonEmpty, Private, Public } from "../path/index.js" -import { Inventory } from "../ticket/inventory.js" import { Ticket } from "../ticket/types.js" import { searchLatest } from "./common.js" import { findPrivateNode, partition as determinePartition } from "./mounts.js" @@ -40,8 +40,8 @@ export type FileSystemOptions = { cidLog: CIDLog dependencies: Dependencies did: string + inventory: Inventory settleTimeBeforePublish?: number - tickets: Inventory updateDataRoot?: (dataRoot: CID, proofs: Ticket[]) => Promise<{ updated: true } | { updated: false; reason: string }> } @@ -51,9 +51,9 @@ export class FileSystem { #cidLog: CIDLog #dependencies: Dependencies #eventEmitter: EventEmitter - #settleTimeBeforePublish: number + #inventory: Inventory #rootTree: RootTree.RootTree - #tickets: Inventory + #settleTimeBeforePublish: number #updateDataRoot?: (dataRoot: CID, proofs: Ticket[]) => Promise<{ updated: true } | { updated: false; reason: string }> #privateNodes: MountedPrivateNodes = {} @@ -67,9 +67,9 @@ export class FileSystem { cidLog: CIDLog, dependencies: Dependencies, did: string, - settleTimeBeforePublish: number, + inventory: Inventory, rootTree: RootTree.RootTree, - tickets: Inventory, + settleTimeBeforePublish: number, updateDataRoot?: ( dataRoot: CID, proofs: Ticket[] @@ -78,9 +78,9 @@ export class FileSystem { this.#blockStore = blockStore this.#cidLog = cidLog this.#dependencies = dependencies + this.#inventory = inventory this.#settleTimeBeforePublish = settleTimeBeforePublish this.#rootTree = rootTree - this.#tickets = tickets this.#updateDataRoot = updateDataRoot this.#eventEmitter = createEmitter() @@ -97,7 +97,7 @@ export class FileSystem { * @internal */ static async empty(opts: FileSystemOptions): Promise { - const { cidLog, dependencies, did, settleTimeBeforePublish, tickets, updateDataRoot } = opts + const { cidLog, dependencies, did, inventory, settleTimeBeforePublish, updateDataRoot } = opts const blockStore = Store.fromDepot(dependencies.depot) const rootTree = await RootTree.empty() @@ -107,9 +107,9 @@ export class FileSystem { cidLog, dependencies, did, - settleTimeBeforePublish || 2500, + inventory, rootTree, - tickets, + settleTimeBeforePublish || 2500, updateDataRoot ) } @@ -119,7 +119,7 @@ export class FileSystem { * @internal */ static async fromCID(cid: CID, opts: FileSystemOptions): Promise { - const { cidLog, dependencies, did, settleTimeBeforePublish, tickets, updateDataRoot } = opts + const { cidLog, dependencies, did, inventory, settleTimeBeforePublish, updateDataRoot } = opts const blockStore = Store.fromDepot(dependencies.depot) const rootTree = await RootTree.fromCID({ blockStore, cid, depot: dependencies.depot }) @@ -129,9 +129,9 @@ export class FileSystem { cidLog, dependencies, did, - settleTimeBeforePublish || 2500, + inventory, rootTree, - tickets, + settleTimeBeforePublish || 2500, updateDataRoot ) } @@ -674,10 +674,10 @@ export class FileSystem { this.#blockStore, this.#dependencies, this.did, + this.#inventory, { ...this.#privateNodes }, this.#rng, - { ...this.#rootTree }, - this.#tickets + { ...this.#rootTree } ) } diff --git a/src/fs/transaction.ts b/src/fs/transaction.ts index b7b539cb..1c1d7bbb 100644 --- a/src/fs/transaction.ts +++ b/src/fs/transaction.ts @@ -6,8 +6,8 @@ import * as Queries from "./queries.js" import * as Unix from "./unix.js" import { CID } from "../common/cid.js" +import { Inventory } from "../inventory.js" import { Partition, Partitioned, PartitionedNonEmpty, Private, Public } from "../path/index.js" -import { Inventory } from "../ticket/inventory.js" import { Ticket } from "../ticket/types.js" import { addOrIncreaseNameNumber, pathSegmentsWithoutPartition, searchLatest } from "./common.js" import { dataFromBytes, dataToBytes } from "./data.js" @@ -31,10 +31,10 @@ export class TransactionContext { #blockStore: BlockStore #dependencies: Dependencies #did: string + #inventory: Inventory #privateNodes: MountedPrivateNodes #rng: Rng #rootTree: RootTree - #tickets: Inventory #changes: Set<{ type: MutationType @@ -46,10 +46,10 @@ export class TransactionContext { blockStore: BlockStore, dependencies: Dependencies, did: string, + inventory: Inventory, privateNodes: MountedPrivateNodes, rng: Rng, - rootTree: RootTree, - tickets: Inventory + rootTree: RootTree ) { this.#blockStore = blockStore this.#dependencies = dependencies @@ -57,7 +57,7 @@ export class TransactionContext { this.#privateNodes = privateNodes this.#rng = rng this.#rootTree = rootTree - this.#tickets = tickets + this.#inventory = inventory this.#changes = new Set() } @@ -75,7 +75,7 @@ export class TransactionContext { const proofs = await changes.reduce( async (accPromise: Promise, change): Promise => { const acc = await accPromise - const proof = context.#tickets.lookupFileSystemTicket( + const proof = context.#inventory.lookupFileSystemTicket( change.path, context.#did ) @@ -108,7 +108,7 @@ export class TransactionContext { ) if (maybeNode) { - const [_, newForest] = await maybeNode.node.store(oldForest, context.#blockStore, context.#rng) + const [_newAccessKey, newForest] = await maybeNode.node.store(oldForest, context.#blockStore, context.#rng) return newForest } else { return oldForest @@ -615,7 +615,7 @@ export class TransactionContext { // Mark node as changed this.#changes.add({ type: mutType, - path: Path.withPartition("private", path), + path: path, }) // Replace forest @@ -623,9 +623,10 @@ export class TransactionContext { // Replace private node const nodePosix = Path.toPosix(priv.path, { absolute: true }) + const node = result.rootDir.asNode() this.#privateNodes[nodePosix] = { - node: result.rootDir.asNode(), + node, path: priv.path, } } diff --git a/src/identifier/did.ts b/src/identifier/did.ts new file mode 100644 index 00000000..e968190a --- /dev/null +++ b/src/identifier/did.ts @@ -0,0 +1,30 @@ +import { DIDKey } from "iso-did/key" +import { spki } from "iso-signatures/spki" + +import { exportPublicKey } from "../common/crypto.js" +import * as Agent from "../components/agent/implementation.js" + +/** + * Create a DID based on the exchange key-pair of the agent. + */ +export async function exchange(agent: Agent.Implementation): Promise { + const pubKey = await agent.exchangeKey().then(exportPublicKey).then(spki.decode) + const ksAlg = await agent.keyAlgorithm() + + return DIDKey.fromPublicKey(ksAlg, pubKey).toString() +} + +/** + * Alias `exchange` to `sharing` + */ +export { exchange as sharing } + +/** + * Create a DID based on the signing key-pair. + */ +export async function signing(agent: Agent.Implementation): Promise { + const pubKey = await agent.signingKey().then(exportPublicKey).then(spki.decode) + const ksAlg = await agent.keyAlgorithm() + + return DIDKey.fromPublicKey(ksAlg, pubKey).toString() +} diff --git a/src/index.ts b/src/index.ts index 64ccc193..4e6c357a 100644 --- a/src/index.ts +++ b/src/index.ts @@ -16,6 +16,7 @@ */ import * as Auth from "./auth.js" +import * as AuthorityEvents from "./events/authority.js" import * as Events from "./events/program.js" import * as Path from "./path/index.js" import * as Cabinet from "./repositories/cabinet.js" @@ -27,11 +28,12 @@ import { Components } from "./components.js" import { AnnexParentType } from "./components/account/implementation.js" import { RequestOptions } from "./components/authority/implementation.js" import { Configuration, namespace } from "./configuration.js" +import { createEmitter } from "./events/emitter.js" import { ListenTo, listenTo } from "./events/listen.js" import { loadFileSystem } from "./fileSystem.js" import { FileSystem } from "./fs/class.js" import { addSampleData } from "./fs/data/sample.js" -import { Inventory } from "./ticket/inventory.js" +import { Inventory } from "./inventory.js" import { Ticket } from "./ticket/types.js" //////////////// @@ -56,7 +58,7 @@ export { RequestOptions } from "./components/authority/implementation.js" export { CodecIdentifier } from "./dag/codecs.js" export { FileSystem } from "./fs/class.js" export { TransactionContext } from "./fs/transaction.js" -export { Inventory } from "./ticket/inventory.js" +export { Inventory } from "./inventory.js" export { Ticket } from "./ticket/types.js" /////////////////////// @@ -76,7 +78,11 @@ export { Ticket } from "./ticket/types.js" * * @group 🚀 */ -export type Program = +export type Program< + Annex extends Account.AnnexParentType, + AuthorityProvideResponse, + AuthorityRequestResponse, +> = & { /** * {@inheritDoc AccountCategory} @@ -86,12 +92,19 @@ export type Program = /** * {@inheritDoc AuthorityCategory} */ - authority: AuthorityCategory + authority: AuthorityCategory< + AuthorityProvideResponse, + AuthorityRequestResponse + > /** * Components used to build this program. */ - components: Components + components: Components< + Annex, + AuthorityProvideResponse, + AuthorityRequestResponse + > /** * Configuration used to build this program. @@ -131,11 +144,9 @@ export type AccountCategory = ReturnType = { /** * Does my program have the authority to work with these part of the file system? * And does the configured account system have the required authority? @@ -144,9 +155,9 @@ export type AuthorityCategory = { { has: true } | { has: false; reason: string } > - provide: () => Promise - request: (options: RequestOptions) => Promise -} + provide: (queries: Query | (Query | Query[])[]) => Promise + request: (queries: Query | (Query | Query[])[], options: RequestOptions) => Promise +} & ListenTo /** * File system. @@ -221,11 +232,25 @@ export type IdentityCategory = { * * @group 🚀 */ -export async function program( +export async function program< + Annex extends AnnexParentType, + AuthorityProvideResponse, + AuthorityRequestResponse, +>( config: Configuration, - components: Components -): Promise> { - const { account, agent, authority, identifier } = components + components: Components< + Annex, + AuthorityProvideResponse, + AuthorityRequestResponse + > +): Promise< + Program< + Annex, + AuthorityProvideResponse, + AuthorityRequestResponse + > +> { + const { account, agent, authority, channel, identifier } = components // Is supported? await Promise.all( @@ -237,7 +262,7 @@ export async function program( // Create repositories const cabinet = await Cabinet.create({ storage: components.storage }) - const tickets = new Inventory(components.authority, cabinet) + const inventory = new Inventory(components.authority.clerk, cabinet) cabinet.events.on("collection:changed", async ({ collection }) => { // TODO: emit authority:inventory-changed event @@ -245,7 +270,11 @@ export async function program( }) // Authority - const authorityCategory = { + const authorityEmitter = createEmitter() + const authorityCategory: AuthorityCategory< + AuthorityProvideResponse, + AuthorityRequestResponse + > = { async has( query: Query | (Query | Query[])[] ): Promise<{ has: true } | { has: false; reason: string }> { @@ -254,7 +283,7 @@ export async function program( // Account access if (queries.some(q => q.query === "account")) { - const accountAccess = await account.hasSufficientAuthority(identifier, tickets) + const accountAccess = await account.hasSufficientAuthority(identifier, inventory) if (!accountAccess.suffices) { return { has: false, @@ -291,13 +320,55 @@ export async function program( return { has: true } }, - // TODO: - async provide() {}, - async request() {}, + async provide(query: Query | (Query | Query[])[]): Promise { + const queries = (Array.isArray(query) ? query : [query]).flat() + + return authority.provide({ + dependencies: { + account, + channel, + identifier, + }, + eventEmitter: authorityEmitter, + inventory, + queries, + }) + }, + + async request( + query: Query | (Query | Query[])[], + options: RequestOptions + ): Promise { + const queries = (Array.isArray(query) ? query : [query]).flat() + const response = await authority.request({ + dependencies: { + channel, + identifier, + }, + eventEmitter: authorityEmitter, + options, + queries, + }) + + if (response) { + await cabinet.addTickets("account", response.accountTickets) + await cabinet.addTickets("file_system", response.fileSystemTickets) + await cabinet.addAccessKeys(response.accessKeys) + + await authorityEmitter.emit("request:authorised", { queries: response.authorisedQueries }) + await authorityEmitter.emit("request:authorized", { queries: response.authorisedQueries }) + + return response.requestResponse + } + + return null + }, + + ...listenTo(authorityEmitter), } // Other categories - const fileSystemCategory: Program["fileSystem"] = { + const fileSystemCategory: FileSystemCategory = { addSampleData: (fs: FileSystem) => addSampleData(fs), load: async (params: { dataRoot?: CID @@ -315,9 +386,9 @@ export async function program( }, } - const identityCategory: Program["identity"] = { + const identityCategory: IdentityCategory = { async account(): Promise { - return account.did(identifier, tickets) + return account.did(identifier, inventory) }, async agent() { return agent.did() @@ -344,7 +415,7 @@ export async function program( register: Auth.register({ account, agent, authority, identifier, cabinet }), canRegister: account.canRegister, - ...components.account.annex(identifier, tickets), + ...components.account.annex(identifier, inventory), }, } diff --git a/src/inventory.ts b/src/inventory.ts new file mode 100644 index 00000000..3cb41e8e --- /dev/null +++ b/src/inventory.ts @@ -0,0 +1,129 @@ +import * as Path from "./path/index.js" + +import { AccessKeyWithContext } from "./accessKey.js" +import { CID } from "./common/cid.js" +import { Clerk } from "./components/authority/implementation.js" +import { Cabinet } from "./repositories/cabinet.js" +import { Ticket } from "./ticket/types.js" + +export class Inventory { + #authorityClerk: Clerk + #cabinet: Cabinet + + /** @internal */ + constructor( + authorityClerk: Clerk, + cabinet: Cabinet + ) { + this.#authorityClerk = authorityClerk + this.#cabinet = cabinet + } + + ///////////// + // LOOKUPS // + ///////////// + + /** + * Collect the given ticket and all its proofs. + */ + bundleTickets( + ticket: Ticket, + proofResolver: (ticket: Ticket) => CID[] + ): Ticket[] { + return [ + ticket, + ...proofResolver(ticket).map(cid => { + const t = this.lookupTicketByCID(cid) + if (!t) throw new Error(`Missing a proof in the local repository: ${cid}`) + return t + }), + ] + } + + descendUntilMatchingTicket( + ticket: Ticket, + matcher: (ticket: Ticket) => boolean, + proofResolver: (ticket: Ticket) => CID[] + ): Ticket | null { + if (matcher(ticket)) return ticket + return proofResolver(ticket).reduce( + (acc: Ticket | null, ticketCID) => { + if (acc) return acc + const prf = this.lookupTicketByCID(ticketCID.toString()) + return prf && matcher(prf) ? prf : null + }, + null + ) + } + + findAccessKey( + path: Path.Distinctive, + did: string + ): AccessKeyWithContext | null { + const unwrappedPath = Path.unwrap(path) + const pathKind = Path.kind(path) + + return unwrappedPath.reduce( + (acc: null | AccessKeyWithContext, _p, idx) => { + if (acc) return acc + const partialPath = Path.fromKind(pathKind, ...unwrappedPath.slice(0, idx + 1)) + const key = this.lookupAccessKey(partialPath, did) + return key ? { did, key: key, path: partialPath } : null + }, + null + ) + } + + lookupAccessKey(path: Path.Distinctive, did: string): Uint8Array | null { + const item = this.#cabinet.collection[`${did}/${Path.toPosix(path)}`] + return item?.type === "access-key" ? item.key : null + } + + lookupTicketByAudience(audience: string): Ticket[] { + return (this.#cabinet.ticketsIndexedByAudience[audience]?.map(t => t.ticket) || []) + } + + lookupTicketByCID(cid: string | CID): Ticket | null { + return this.#cabinet.ticketsIndexedByCID[cid.toString()]?.ticket || null + } + + lookupFileSystemTicket( + path: Path.DistinctivePath, + did: string + ): Ticket | null { + const fsTickets = this.#cabinet.tickets + .filter(t => t.category === "file_system") + .map(t => t.ticket) + + return this.#lookupFileSystemTicket( + fsTickets, + path => this.#authorityClerk.tickets.fileSystem.matcher(path, did), + path + ) + } + + #lookupFileSystemTicket( + fsTickets: Ticket[], + matcher: (pathSoFar: Path.Distinctive) => (ticket: Ticket) => boolean, + path: Path.DistinctivePath + ): Ticket | null { + const pathParts = Path.unwrap(path) + + const results = ["", ...pathParts].reduce( + (acc: Ticket[], _part, idx): Ticket[] => { + const pathSoFar = Path.fromKind(Path.kind(path), ...(pathParts.slice(0, idx))) + + return [ + ...acc, + ...fsTickets.filter( + matcher(pathSoFar) + ), + ] + }, + [] + ) + + // TODO: Need to sort by ability level, ie. prefer super user over anything else + return results[0] || null + } +} diff --git a/src/repositories/cabinet.ts b/src/repositories/cabinet.ts index 69569b26..ea94208d 100644 --- a/src/repositories/cabinet.ts +++ b/src/repositories/cabinet.ts @@ -3,22 +3,22 @@ import * as Uint8Arrays from "uint8arrays" import * as Storage from "../components/storage/implementation.js" import * as Path from "../path/index.js" +import { AccessKeyWithContext } from "../accessKey.js" import { CID, decodeCID, encodeCID } from "../common/cid.js" import { isObject, isString } from "../common/type-checks.js" import Repository, { RepositoryOptions } from "../repository.js" import { cid as ticketCID } from "../ticket/index.js" -import { Category, Ticket, isCategory } from "../ticket/types.js" +import { Category, Ticket, TicketWithContext, isCategory } from "../ticket/types.js" //////// // 🧩 // //////// export type CabinetItem = - | { type: "access-key"; did: string; key: Uint8Array; path: Path.Distinctive } + | { type: "access-key" } & AccessKeyWithContext | { type: "ticket" } & TicketWithContext export type CabinetCollection = Record -export type TicketWithContext = { category: Category; cid: CID; ticket: Ticket } //////// // 🛠️ // @@ -163,7 +163,7 @@ export class Repo extends Repository { } async addTickets(category: Category, tickets: Ticket[]): Promise { - const items: Array<{ type: "ticket" } & TicketWithContext> = await Promise.all( + const ticketsWithContext: Array<{ type: "ticket" } & TicketWithContext> = await Promise.all( tickets.map(async t => ({ type: "ticket", category, @@ -172,14 +172,19 @@ export class Repo extends Repository { })) ) - return this.add(items) + return this.add( + // Only add tickets we don't have yet + ticketsWithContext.filter(t => { + return !this.ticketsIndexedByCID[t.cid.toString()] + }) + ) } - addAccessKey(item: { did: string; key: Uint8Array; path: Path.Distinctive }) { + addAccessKey(item: AccessKeyWithContext) { return this.addAccessKeys([item]) } - addAccessKeys(items: { did: string; key: Uint8Array; path: Path.Distinctive }[]) { + addAccessKeys(items: AccessKeyWithContext[]) { // Delete old access keys matching the same DID and path, // in case we want to make a new file system. items.forEach(item => { diff --git a/src/ticket/index.ts b/src/ticket/index.ts index d9007b96..00e6b0f9 100644 --- a/src/ticket/index.ts +++ b/src/ticket/index.ts @@ -3,6 +3,7 @@ import { sha256 } from "multiformats/hashes/sha2" import * as Uint8Arrays from "uint8arrays" import { CID } from "../common/cid.js" +import { isObject, isString } from "../common/type-checks.js" import { Ticket } from "./types.js" //////// @@ -16,3 +17,23 @@ export async function cid(ticket: Ticket): Promise { return CID.createV1(Raw.code, multihash) } + +export function collectUnique(tickets: Ticket[]): Ticket[] { + return tickets.reduce((acc, ticket) => { + if (acc.tokens.includes(ticket.token)) { + return acc + } + + return { + tickets: [...acc.tickets, ticket], + tokens: [...acc.tokens, ticket.token], + } + }, { + tickets: [] as Ticket[], + tokens: [] as string[], + }).tickets +} + +export function isTicket(ticket: unknown): ticket is Ticket { + return isObject(ticket) && isString(ticket.issuer) && isString(ticket.audience) && isString(ticket.token) +} diff --git a/src/ticket/inventory.ts b/src/ticket/inventory.ts deleted file mode 100644 index 61be17c1..00000000 --- a/src/ticket/inventory.ts +++ /dev/null @@ -1,124 +0,0 @@ -import * as Path from "../path/index.js" - -import { CID } from "../common/cid.js" -import { Authority } from "../components.js" -import { Cabinet } from "../repositories/cabinet.js" -import { Ticket } from "./types.js" - -export class Inventory { - #authority: Authority.Implementation - #cabinet: Cabinet - - /** @internal */ - constructor( - authority: Authority.Implementation, - cabinet: Cabinet - ) { - this.#authority = authority - this.#cabinet = cabinet - } - - ///////////// - // LOOKUPS // - ///////////// - - descendUntilMatching( - ticket: Ticket, - matcher: (ticket: Ticket) => boolean, - descend: (ticket: Ticket) => CID[] - ): Ticket | null { - if (matcher(ticket)) return ticket - return descend(ticket).reduce( - (acc: Ticket | null, ticketCID) => { - if (acc) return acc - const prf = this.lookupByCID(ticketCID.toString()) - return prf && matcher(prf) ? prf : null - }, - null - ) - } - - // findMatching( - // matcher: (ticket: Ticket) => boolean, - // descend: (ticket: Ticket) => CID[] - // ): Ticket | null { - // return this.#cabinet.tickets.reduce( - // (acc: Ticket | null, t) => { - // if (acc) return acc - // if (matcher(t.ticket)) return t.ticket - // return this.descendUntilMatching(t.ticket, matcher, descend) - // }, - // null - // ) - // } - - lookupByAudience(audience: string): Ticket[] { - return (this.#cabinet.ticketsIndexedByAudience[audience]?.map(t => t.ticket) || []) - } - - lookupByCID(cid: string): Ticket | null { - return this.#cabinet.ticketsIndexedByCID[cid]?.ticket || null - } - - lookupFileSystemTicket( - path: Path.DistinctivePath, - did: string - ): Ticket | null { - const fsTickets = this.#cabinet.tickets - .filter(t => t.category === "file_system") - .map(t => t.ticket) - - return this.#lookupFileSystemUcan( - fsTickets, - path => this.#authority.clerk.tickets.fileSystem.matcher(path, did), - path - ) - } - - #lookupFileSystemUcan( - fsTickets: Ticket[], - matcher: (pathSoFar: Path.Distinctive) => (ticket: Ticket) => boolean, - path: Path.DistinctivePath - ): Ticket | null { - const pathParts = Path.unwrap(path) - - const results = ["", ...pathParts].reduce( - (acc: Ticket[], _part, idx): Ticket[] => { - const pathSoFar = Path.fromKind(Path.kind(path), ...(pathParts.slice(0, idx))) - - return [ - ...acc, - ...fsTickets.filter( - matcher(pathSoFar) - ), - ] - }, - [] - ) - - // TODO: Need to sort by ability level, ie. prefer super user over anything else - return results[0] || null - } - - rootIssuer( - ticket: Ticket, - proofsResolver: (ticket: Ticket) => CID[] - ): string { - const proofs = proofsResolver(ticket) - - if (proofs.length) { - // Always prefer the first proof. - // TBH, not sure what's best here. - const prf = proofs[0] - const t = this.#cabinet.ticketsIndexedByCID[prf.toString()] - if (!t) throw new Error("Missing a ticket in the inventory") - - return this.rootIssuer( - t.ticket, - proofsResolver - ) - } else { - return ticket.issuer - } - } -} diff --git a/src/ticket/types.ts b/src/ticket/types.ts index 907748d6..6f30169c 100644 --- a/src/ticket/types.ts +++ b/src/ticket/types.ts @@ -1,3 +1,5 @@ +import { CID } from "../common/cid.js" + const CATEGORIES = ["account", "file_system", "misc"] as const /** @@ -19,3 +21,8 @@ export type Category = typeof CATEGORIES[number] export function isCategory(string: string): string is Category { return CATEGORIES.includes(string as Category) } + +/** + * Ticket with context. + */ +export type TicketWithContext = { category: Category; cid: CID; ticket: Ticket } diff --git a/tests/helpers/components.ts b/tests/helpers/components.ts index 95967d9a..5a62dd0b 100644 --- a/tests/helpers/components.ts +++ b/tests/helpers/components.ts @@ -4,7 +4,7 @@ import { sha256 } from "multiformats/hashes/sha2" import * as LocalAccount from "../../src/components/account/local.js" import * as WebCryptoAgent from "../../src/components/agent/web-crypto-api.js" -import * as TsUcanAuthority from "../../src/components/authority/ts-ucan.js" +import * as BrowserUrlAuthority from "../../src/components/authority/browser-url.js" import * as DOH from "../../src/components/dns/dns-over-https/cloudflare-google.js" import * as WebCryptoIdentifier from "../../src/components/identifier/web-crypto-api.js" import * as ProperManners from "../../src/components/manners/default.js" @@ -96,10 +96,8 @@ const manners: Manners.Implementation = { // CHANNEL // ///////////// -export type ChannelContext = [] - -const channel: Channel.Implementation = { - establish: (options: ChannelOptions) => { +const channel: Channel.Implementation = { + establish: (options: ChannelOptions) => { throw new Error("Channels are not implemented for tests") }, } @@ -136,13 +134,20 @@ const identifier: Identifier.Implementation = await WebCryptoIdentifier.implemen // IDENTIFIER // //////////////// -const authority: Authority.Implementation = TsUcanAuthority.implementation(identifier) +const authority: Authority.Implementation< + BrowserUrlAuthority.ProvideResponse, + BrowserUrlAuthority.RequestResponse +> = BrowserUrlAuthority.implementation(identifier) //////// // 🛳 // //////// -const components: Components = { +const components: Components< + LocalAccount.Annex, + BrowserUrlAuthority.ProvideResponse, + BrowserUrlAuthority.RequestResponse +> = { depot, manners, storage, diff --git a/tsconfig.json b/tsconfig.json index cbf3dc2a..8f786a16 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -2,7 +2,7 @@ "compilerOptions": { "moduleResolution": "node16", "target": "es2022", - "module": "es2022", + "module": "node16", "lib": [ "dom", "es2022",