diff --git a/package.json b/package.json index e96e348..6f5b9d5 100644 --- a/package.json +++ b/package.json @@ -23,8 +23,10 @@ "@nestjs/common": "^10.0.0", "@nestjs/config": "^3.1.1", "@nestjs/core": "^10.0.0", + "@nestjs/mongoose": "^10.0.2", "@nestjs/platform-express": "^10.0.0", "ethers": "^6.10.0", + "mongoose": "^8.1.1", "reflect-metadata": "^0.1.13", "rxjs": "^7.8.1", "viem": "^2.7.3" diff --git a/src/app.module.ts b/src/app.module.ts index 36e4699..b5da0cc 100644 --- a/src/app.module.ts +++ b/src/app.module.ts @@ -1,6 +1,10 @@ import { Module } from '@nestjs/common'; import { GatewayModule } from './gateway/gateway.module'; import { ConfigModule } from '@nestjs/config'; +import { ConfigService } from '@nestjs/config'; +import { MongooseModule } from '@nestjs/mongoose'; +import { AppProperties } from './configuration/app-properties'; +import { AppPropertiesModule } from './configuration/app-properties.module'; @Module({ imports: [ @@ -8,8 +12,14 @@ import { ConfigModule } from '@nestjs/config'; isGlobal: true, envFilePath: ['.env'], }), - GatewayModule], - controllers: [], - providers: [], + MongooseModule.forRootAsync({ + imports: [AppPropertiesModule], + useFactory: async (configService: AppProperties) => ({ + uri: configService.mongoConnectionString + }), + inject: [AppProperties] + }), + GatewayModule + ], }) export class AppModule {} diff --git a/src/configuration/app-properties.module.ts b/src/configuration/app-properties.module.ts new file mode 100644 index 0000000..12ff7e0 --- /dev/null +++ b/src/configuration/app-properties.module.ts @@ -0,0 +1,8 @@ +import { Module } from '@nestjs/common'; +import { AppProperties } from './app-properties'; + +@Module({ + exports: [AppProperties], + providers: [AppProperties], +}) +export class AppPropertiesModule {} diff --git a/src/configuration/app-properties.ts b/src/configuration/app-properties.ts new file mode 100644 index 0000000..d16df9d --- /dev/null +++ b/src/configuration/app-properties.ts @@ -0,0 +1,14 @@ +import { Injectable } from "@nestjs/common"; +import { ConfigService } from "@nestjs/config"; + +@Injectable() +export class AppProperties { + + mongoConnectionString: string + signerWallet: string + + constructor(private readonly configService: ConfigService) { + this.mongoConnectionString = this.configService.getOrThrow("MONGO_CONNECTION_STRING"); + this.signerWallet = this.configService.getOrThrow("SIGNER_WALLET") + } +} \ No newline at end of file diff --git a/src/gateway/db/resolved-ens.schema.ts b/src/gateway/db/resolved-ens.schema.ts new file mode 100644 index 0000000..8f06f3f --- /dev/null +++ b/src/gateway/db/resolved-ens.schema.ts @@ -0,0 +1,40 @@ +import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose'; +import * as mongoose from 'mongoose'; + +@Schema({ timestamps: true, collection: "subnames", autoCreate: false, }) +class Subname { + @Prop({ unique: true, required: true, type: String }) + fullName: string; + + @Prop({ required: true, type: String }) + label: string; + + @Prop({ required: true, type: String }) + domain: string; + + @Prop({ required: false, type: String }) + ttl: number; + + @Prop({ + required: true, + type: Map, + default: [], + _id: false, + }) + addresses: Map; + + @Prop({ + required: false, + type: Map, + default: [], + _id: false, + }) + textRecords: Map; + + @Prop({ required: false, type: String }) + contentHash: string; +} + +export const SUBANME_DOMAIN = 'Subname'; +export const SubnameSchema = SchemaFactory.createForClass(Subname); +export type SubnameDocument = mongoose.HydratedDocument; \ No newline at end of file diff --git a/src/gateway/db/resovled-ens.repository.ts b/src/gateway/db/resovled-ens.repository.ts new file mode 100644 index 0000000..9fc63d7 --- /dev/null +++ b/src/gateway/db/resovled-ens.repository.ts @@ -0,0 +1,14 @@ +import { InjectModel } from "@nestjs/mongoose"; +import { SUBANME_DOMAIN, SubnameDocument } from "./resolved-ens.schema"; +import { Model } from "mongoose"; +import { Injectable } from "@nestjs/common"; + +@Injectable() +export class ResolvedEnsRepository { + @InjectModel(SUBANME_DOMAIN) + dao: Model + + public async findOne(query: Record): Promise { + return this.dao.findOne(query); + } +} \ No newline at end of file diff --git a/src/gateway/gateway.handler.ts b/src/gateway/gateway.handler.ts deleted file mode 100644 index cc5d1af..0000000 --- a/src/gateway/gateway.handler.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { Injectable } from "@nestjs/common"; - -interface GatewayHandler { - handle(ensName: string, args: any[]) -} - -type ResolverSignature = "addr" | "text" | "contentHash" - -export class AddrHandler implements GatewayHandler { - - public async handle(ensName: string, args: string[]): Promise { - return ""; - } -} - -export class TextHandler implements GatewayHandler { - public async handle(ensName: string, args: string[]): Promise { - return ""; - } -} - -export class ContentHashHandler implements GatewayHandler { - public async handle(ensName: string, args: string[]): Promise { - return ""; - } -} - -const handlers: Record = { - addr: new AddrHandler(), - contentHash: new ContentHashHandler(), - text: new TextHandler() -} - -@Injectable() -export class DatabaseGatewayHandlers { - public handleFunction(resolverSignature: ResolverSignature, args: any[]) { - - } -} - diff --git a/src/gateway/gateway.module.ts b/src/gateway/gateway.module.ts index 32ebb51..f42263a 100644 --- a/src/gateway/gateway.module.ts +++ b/src/gateway/gateway.module.ts @@ -1,9 +1,27 @@ -import { Module } from "@nestjs/common"; -import { GatewayController } from "./gateway.controller"; -import { GatewayService } from "./gateway.service"; +import { Module } from '@nestjs/common'; +import { GatewayController } from './gateway.controller'; +import { GatewayService } from './gateway.service'; +import { MongooseModule } from '@nestjs/mongoose'; +import { SUBANME_DOMAIN, SubnameSchema } from './db/resolved-ens.schema'; +import { GatewayDatabaseResolver } from './resolver/database.resolver'; +import { AppPropertiesModule } from 'src/configuration/app-properties.module'; +import { ResolvedEnsRepository } from './db/resovled-ens.repository'; @Module({ - controllers: [GatewayController], - providers: [GatewayService] + imports: [ + MongooseModule.forFeature([ + { + schema: SubnameSchema, + name: SUBANME_DOMAIN, + }, + ]), + AppPropertiesModule, + ], + controllers: [GatewayController], + providers: [ + GatewayService, + GatewayDatabaseResolver, + ResolvedEnsRepository + ], }) -export class GatewayModule {} \ No newline at end of file +export class GatewayModule {} diff --git a/src/gateway/gateway.service.ts b/src/gateway/gateway.service.ts index d2559f8..d160b63 100644 --- a/src/gateway/gateway.service.ts +++ b/src/gateway/gateway.service.ts @@ -1,4 +1,4 @@ -import { Injectable } from '@nestjs/common'; +import { BadRequestException, Injectable } from '@nestjs/common'; import { Address, Hash, @@ -9,21 +9,34 @@ import { encodeFunctionResult, encodePacked, keccak256, + namehash, parseAbiParameters, } from 'viem'; import { decodeDnsName } from './gateway.utils'; -import RESOLVER_ABI from './resolver.json'; +import RESOLVER_ABI from './resolver_abi.json'; import { privateKeyToAccount } from 'viem/accounts'; -import { ConfigService } from '@nestjs/config'; import { ethers } from 'ethers'; +import { GatewayResolver } from './resolver/gatway.resolver'; +import { AppProperties } from 'src/configuration/app-properties'; +import { GatewayDatabaseResolver } from './resolver/database.resolver'; + +const addr = 'addr'; +const text = 'text'; +const contentHash = 'contentHash'; +const supportedFunctions = [addr, text, contentHash]; +const defaultCoinType = '60'; @Injectable() export class GatewayService { - viemSigner: PrivateKeyAccount; - ethersSigner: ethers.SigningKey; - - constructor(private readonly config: ConfigService) { - const privateKey = this.config.getOrThrow('SIGNER_WALLET') as string; + private viemSigner: PrivateKeyAccount; + private ethersSigner: ethers.SigningKey; + + constructor( + private readonly appProperties: AppProperties, + // doesn't work with GatewayResolver interface, investigate why + private readonly resolver: GatewayDatabaseResolver, + ) { + const privateKey = this.appProperties.signerWallet; const _pk = privateKey.startsWith('0x') ? privateKey : `0x${privateKey}`; this.viemSigner = privateKeyToAccount(_pk as Hash); @@ -40,7 +53,6 @@ export class GatewayService { // 8 - 'resolve' function signature const data = callData.substring(10); - console.log(`Signer address ${this.viemSigner.address}`); const parsedCallData = decodeAbiParameters( parseAbiParameters('bytes name, bytes callData'), `0x${data}`, @@ -62,15 +74,16 @@ export class GatewayService { `Request for resolving name ${decodedName} with function ${decodedFunction.functionName}, with params ${decodedFunction.args}`, ); - const { resultAddress, ttl } = this.resolveResult( + const { value, ttl } = await this.resolveResult( decodedName, decodedFunction.functionName, + decodedFunction.args, ); const result = encodeFunctionResult({ abi: RESOLVER_ABI, functionName: decodedFunction.functionName, - result: [resultAddress], + result: [value], }); const digest = keccak256( @@ -94,8 +107,12 @@ export class GatewayService { // message: digest, // }); - const sig = this.ethersSigner.sign(digest) - const ethersSig = ethers.concat([sig.r, sig.s, new Uint8Array([sig.v])]) as any; + const sig = this.ethersSigner.sign(digest); + const ethersSig = ethers.concat([ + sig.r, + sig.s, + new Uint8Array([sig.v]), + ]) as any; const finalResult = encodeAbiParameters( parseAbiParameters('bytes response, uint64 ttl, bytes signature'), @@ -107,10 +124,33 @@ export class GatewayService { }; } - private resolveResult = (ensName: string, functionName: string) => { - return { - resultAddress: '0x3E1e131E7e613D260F809E6BBE6Cbf7765EDC77f', - ttl: Date.now(), - }; + private resolveResult = async ( + ensName: string, + functionName: string, + args: readonly any[], + ) => { + const nameNode = namehash(ensName); + const funcNode = args[0]; + + if (nameNode !== funcNode) { + throw new BadRequestException('Namehash missmatch'); + } + + if (supportedFunctions.includes(functionName)) { + throw new BadRequestException('Unsupported opperation ' + functionName); + } + + switch (functionName) { + case addr: + const coinType = args.length > 1 ? args.length[1] : defaultCoinType; + return this.resolver.getAddress(ensName, coinType); + case text: + if (args.length < 2) { + throw new BadRequestException('Text key not found'); + } + return this.resolver.getText(ensName, args[1]); + default: + return this.resolver.getContentHash(ensName); + } }; } diff --git a/src/gateway/resolver/database.resolver.ts b/src/gateway/resolver/database.resolver.ts new file mode 100644 index 0000000..1cae610 --- /dev/null +++ b/src/gateway/resolver/database.resolver.ts @@ -0,0 +1,62 @@ +import { + Injectable, + NotFoundException, +} from '@nestjs/common'; +import { GatewayResolver, ResolverResult } from './gatway.resolver'; +import { ResolvedEnsRepository } from '../db/resovled-ens.repository'; + +// 60 for ethereum address +const DEFAULT_ADDRESS_COIN_TYPE = '60'; + +@Injectable() +export class GatewayDatabaseResolver implements GatewayResolver { + constructor(private readonly repository: ResolvedEnsRepository) {} + + public async getText(fullName: string, key: string): Promise {; + const subname = await this.getSubname(fullName); + + if (subname.textRecords && subname.textRecords[key]) { + return { + value: subname.textRecords[key], + ttl: subname.ttl || 0 + } + } + return { + ttl: 0, + value: "" + }; + } + + public async getAddress(fullName: string, coinType?: string): Promise { + const subname = await this.getSubname(fullName); + const _coin = coinType || DEFAULT_ADDRESS_COIN_TYPE; + if (subname.addresses && subname.addresses[_coin]) { + return { + value: subname.addresses[_coin], + ttl: subname.ttl || 0 + } + } + return { + ttl: 0, + value: "" + }; + } + + public async getContentHash(fullName: string): Promise { + const subname = await this.getSubname(fullName); + return { + value: subname.contentHash || "", + ttl: subname.ttl || 0 + } + } + + private getSubname = async (ensName: string) => { + const subname = await this.repository.findOne({ + fullName: ensName + }); + if (!subname && !subname.id) { + throw new NotFoundException(`Subname not found`); + } + return subname; + }; +} diff --git a/src/gateway/resolver/gatway.resolver.ts b/src/gateway/resolver/gatway.resolver.ts new file mode 100644 index 0000000..6affdf3 --- /dev/null +++ b/src/gateway/resolver/gatway.resolver.ts @@ -0,0 +1,11 @@ + +export interface ResolverResult { + value: string + ttl: number +} + +export interface GatewayResolver { + getText: (fullEnsName: string, key: string) => Promise; + getAddress: (fullEnsName: string, coinType: string) => Promise; + getContentHash: (fullEnsName: string) => Promise +} diff --git a/src/gateway/resolver.json b/src/gateway/resolver_abi.json similarity index 97% rename from src/gateway/resolver.json rename to src/gateway/resolver_abi.json index e72ec96..1d249bf 100644 --- a/src/gateway/resolver.json +++ b/src/gateway/resolver_abi.json @@ -1,30 +1,4 @@ [ - { - "inputs": [ - { - "internalType": "contract ENS", - "name": "_ens", - "type": "address" - }, - { - "internalType": "contract INameWrapper", - "name": "wrapperAddress", - "type": "address" - }, - { - "internalType": "address", - "name": "_trustedETHController", - "type": "address" - }, - { - "internalType": "address", - "name": "_trustedReverseRegistrar", - "type": "address" - } - ], - "stateMutability": "nonpayable", - "type": "constructor" - }, { "anonymous": false, "inputs": [ diff --git a/yarn.lock b/yarn.lock index 4096666..be11643 100644 --- a/yarn.lock +++ b/yarn.lock @@ -685,6 +685,13 @@ resolved "https://registry.yarnpkg.com/@lukeed/csprng/-/csprng-1.1.0.tgz#1e3e4bd05c1cc7a0b2ddbd8a03f39f6e4b5e6cfe" integrity sha512-Z7C/xXCiGWsg0KuKsHTKJxbWhpI3Vs5GwLfOean7MGyVFGqdRgBbAjOCh6u4bbjPc/8MJ2pZmK/0DLdCbivLDA== +"@mongodb-js/saslprep@^1.1.0": + version "1.1.4" + resolved "https://registry.yarnpkg.com/@mongodb-js/saslprep/-/saslprep-1.1.4.tgz#24ec1c4915a65f5c506bb88c081731450d91bb1c" + integrity sha512-8zJ8N1x51xo9hwPh6AWnKdLGEC5N3lDa6kms1YHmFBoRhTpJR6HG8wWk0td1MVCu9cD4YBrvjZEtd5Obw0Fbnw== + dependencies: + sparse-bitfield "^3.0.3" + "@nestjs/cli@^10.0.0": version "10.3.0" resolved "https://registry.yarnpkg.com/@nestjs/cli/-/cli-10.3.0.tgz#5f9ef49a60baf4b39cb87e4b74240f7c9339e923" @@ -744,6 +751,11 @@ path-to-regexp "3.2.0" tslib "2.6.2" +"@nestjs/mongoose@^10.0.2": + version "10.0.2" + resolved "https://registry.yarnpkg.com/@nestjs/mongoose/-/mongoose-10.0.2.tgz#33018e22f0ba03a37ffb30d8b3c6b7cf904894d8" + integrity sha512-ITHh075DynjPIaKeJh6WkarS21WXYslu4nrLkNPbWaCP6JfxVAOftaA2X5tPSiiE/gNJWgs+QFWsfCFZUUenow== + "@nestjs/platform-express@^10.0.0": version "10.3.1" resolved "https://registry.yarnpkg.com/@nestjs/platform-express/-/platform-express-10.3.1.tgz#f72f337ddd96895e56284b13971bdbd3479e24b3" @@ -1109,6 +1121,18 @@ dependencies: "@types/superagent" "*" +"@types/webidl-conversions@*": + version "7.0.3" + resolved "https://registry.yarnpkg.com/@types/webidl-conversions/-/webidl-conversions-7.0.3.tgz#1306dbfa53768bcbcfc95a1c8cde367975581859" + integrity sha512-CiJJvcRtIgzadHCYXw7dqEnMNRjhGZlYK05Mj9OyktqV8uVT8fD2BFOB7S1uwBE3Kj2Z+4UyPmFw/Ixgw/LAlA== + +"@types/whatwg-url@^11.0.2": + version "11.0.4" + resolved "https://registry.yarnpkg.com/@types/whatwg-url/-/whatwg-url-11.0.4.tgz#ffed0dc8d89d91f62e3f368fcbda222a487c4f63" + integrity sha512-lXCmTWSHJvf0TRSO58nm978b8HJ/EdsSsEKLd3ODHFjo+3VGAyyTp4v50nWvwtzBxSMQrVOK7tcuN0zGPLICMw== + dependencies: + "@types/webidl-conversions" "*" + "@types/yargs-parser@*": version "21.0.3" resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-21.0.3.tgz#815e30b786d2e8f0dcd85fd5bcf5e1a04d008f15" @@ -1680,6 +1704,11 @@ bser@2.1.1: dependencies: node-int64 "^0.4.0" +bson@^6.2.0: + version "6.3.0" + resolved "https://registry.yarnpkg.com/bson/-/bson-6.3.0.tgz#d47acba525ba7d7eb0e816c10538bce26a337fe0" + integrity sha512-balJfqwwTBddxfnidJZagCBPP/f48zj9Sdp3OJswREOgsJzHiQSaOIAtApSgDQFYgHqAvFkp53AFSqjMDZoTFw== + buffer-from@^1.0.0: version "1.1.2" resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5" @@ -2017,7 +2046,7 @@ debug@2.6.9: dependencies: ms "2.0.0" -debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.4: +debug@4.x, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.4: version "4.3.4" resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== @@ -3515,6 +3544,11 @@ jsonfile@^6.0.1: optionalDependencies: graceful-fs "^4.1.6" +kareem@2.5.1: + version "2.5.1" + resolved "https://registry.yarnpkg.com/kareem/-/kareem-2.5.1.tgz#7b8203e11819a8e77a34b3517d3ead206764d15d" + integrity sha512-7jFxRVm+jD+rkq3kY0iZDJfsO2/t4BBPeEb2qKn2lR/9KhuksYk5hxzfRYWMPV8P/x2d0kHD306YyWLzjjH+uA== + keyv@^4.5.3: version "4.5.4" resolved "https://registry.yarnpkg.com/keyv/-/keyv-4.5.4.tgz#a879a99e29452f942439f2a405e3af8b31d4de93" @@ -3644,6 +3678,11 @@ memfs@^3.4.1: dependencies: fs-monkey "^1.0.4" +memory-pager@^1.0.2: + version "1.5.0" + resolved "https://registry.yarnpkg.com/memory-pager/-/memory-pager-1.5.0.tgz#d8751655d22d384682741c972f2c3d6dfa3e66b5" + integrity sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg== + merge-descriptors@1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" @@ -3742,6 +3781,48 @@ mkdirp@^0.5.4: dependencies: minimist "^1.2.6" +mongodb-connection-string-url@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/mongodb-connection-string-url/-/mongodb-connection-string-url-3.0.0.tgz#b4f87f92fd8593f3b9365f592515a06d304a1e9c" + integrity sha512-t1Vf+m1I5hC2M5RJx/7AtxgABy1cZmIPQRMXw+gEIPn/cZNF3Oiy+l0UIypUwVB5trcWHq3crg2g3uAR9aAwsQ== + dependencies: + "@types/whatwg-url" "^11.0.2" + whatwg-url "^13.0.0" + +mongodb@6.3.0: + version "6.3.0" + resolved "https://registry.yarnpkg.com/mongodb/-/mongodb-6.3.0.tgz#ec9993b19f7ed2ea715b903fcac6171c9d1d38ca" + integrity sha512-tt0KuGjGtLUhLoU263+xvQmPHEGTw5LbcNC73EoFRYgSHwZt5tsoJC110hDyO1kjQzpgNrpdcSza9PknWN4LrA== + dependencies: + "@mongodb-js/saslprep" "^1.1.0" + bson "^6.2.0" + mongodb-connection-string-url "^3.0.0" + +mongoose@^8.1.1: + version "8.1.1" + resolved "https://registry.yarnpkg.com/mongoose/-/mongoose-8.1.1.tgz#2ea2dcdcf4943196f585b3915f63001e79214e1b" + integrity sha512-DbLb0NsiEXmaqLOpEz+AtAsgwhRw6f25gwa1dF5R7jj6lS1D8X6uTdhBSC8GDVtOwe5Tfw2EL7nTn6hiJT3Bgg== + dependencies: + bson "^6.2.0" + kareem "2.5.1" + mongodb "6.3.0" + mpath "0.9.0" + mquery "5.0.0" + ms "2.1.3" + sift "16.0.1" + +mpath@0.9.0: + version "0.9.0" + resolved "https://registry.yarnpkg.com/mpath/-/mpath-0.9.0.tgz#0c122fe107846e31fc58c75b09c35514b3871904" + integrity sha512-ikJRQTk8hw5DEoFVxHG1Gn9T/xcjtdnOKIU1JTmGjZZlg9LST2mBLmcX3/ICIbgJydT2GOc15RnNy5mHmzfSew== + +mquery@5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/mquery/-/mquery-5.0.0.tgz#a95be5dfc610b23862df34a47d3e5d60e110695d" + integrity sha512-iQMncpmEK8R8ncT8HJGsGc9Dsp8xcgYMVSbs5jgnm1lFHTZqMJTUWTDx1LBO8+mK3tPNZWFLBghQEIOULSTHZg== + dependencies: + debug "4.x" + ms@2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" @@ -4076,7 +4157,7 @@ proxy-addr@~2.0.7: forwarded "0.2.0" ipaddr.js "1.9.1" -punycode@^2.1.0: +punycode@^2.1.0, punycode@^2.3.0: version "2.3.1" resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.1.tgz#027422e2faec0b25e1549c3e1bd8309b9133b6e5" integrity sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg== @@ -4398,6 +4479,11 @@ side-channel@^1.0.4: get-intrinsic "^1.0.2" object-inspect "^1.9.0" +sift@16.0.1: + version "16.0.1" + resolved "https://registry.yarnpkg.com/sift/-/sift-16.0.1.tgz#e9c2ccc72191585008cf3e36fc447b2d2633a053" + integrity sha512-Wv6BjQ5zbhW7VFefWusVP33T/EM0vYikCaQ2qR8yULbsilAT8/wQaXvuQ3ptGLpoKx+lihJE3y2UTgKDyyNHZQ== + signal-exit@^3.0.2, signal-exit@^3.0.3, signal-exit@^3.0.7: version "3.0.7" resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" @@ -4444,6 +4530,13 @@ source-map@^0.6.0, source-map@^0.6.1: resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== +sparse-bitfield@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz#ff4ae6e68656056ba4b3e792ab3334d38273ca11" + integrity sha512-kvzhi7vqKTfkh0PZU+2D2PIllw2ymqJKujUcyPMd9Y75Nv4nPbGJZXNhxsgdQab2BmlDct1YnfQCguEvHr7VsQ== + dependencies: + memory-pager "^1.0.2" + sprintf-js@~1.0.2: version "1.0.3" resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" @@ -4677,6 +4770,13 @@ toidentifier@1.0.1: resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.1.tgz#3be34321a88a820ed1bd80dfaa33e479fbb8dd35" integrity sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA== +tr46@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/tr46/-/tr46-4.1.1.tgz#281a758dcc82aeb4fe38c7dfe4d11a395aac8469" + integrity sha512-2lv/66T7e5yNyhAAC4NaKe5nVavzuGJQVVtRYLyQ2OI8tsJ61PMLlelehb0wi2Hx6+hT/OJUWZcw8MjlSRnxvw== + dependencies: + punycode "^2.3.0" + tr46@~0.0.3: version "0.0.3" resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a" @@ -4916,6 +5016,11 @@ webidl-conversions@^3.0.0: resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871" integrity sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ== +webidl-conversions@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-7.0.0.tgz#256b4e1882be7debbf01d05f0aa2039778ea080a" + integrity sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g== + webpack-node-externals@3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/webpack-node-externals/-/webpack-node-externals-3.0.0.tgz#1a3407c158d547a9feb4229a9e3385b7b60c9917" @@ -4956,6 +5061,14 @@ webpack@5.89.0: watchpack "^2.4.0" webpack-sources "^3.2.3" +whatwg-url@^13.0.0: + version "13.0.0" + resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-13.0.0.tgz#b7b536aca48306394a34e44bda8e99f332410f8f" + integrity sha512-9WWbymnqj57+XEuqADHrCJ2eSXzn8WXIW/YSGaZtb2WKAInQ6CHfaUUcTyyver0p8BDg5StLQq8h1vtZuwmOig== + dependencies: + tr46 "^4.1.1" + webidl-conversions "^7.0.0" + whatwg-url@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-5.0.0.tgz#966454e8765462e37644d3626f6742ce8b70965d"