diff --git a/apps/site/app/api/post/route.ts b/apps/site/app/api/post/route.ts index 49bd4da5..b49099fe 100644 --- a/apps/site/app/api/post/route.ts +++ b/apps/site/app/api/post/route.ts @@ -1,60 +1,32 @@ -import { novaPubClient } from '@/config/publicClient' -import { Defender } from '@openzeppelin/defender-sdk' -import { ethers } from 'ethers' +import { + syndicateClientPost, + generatePostTxnInput, + projectIdPost, +} from '@/config/syndicateClient' import type { NextRequest } from 'next/server' -import { addresses, postGatewayABI } from 'scrypt' -import type { Hex } from 'viem' - -export const maxDuration = 30 // This function can run for a maximum of 30 seconds +import { waitForHash } from '@syndicateio/syndicate-node/utils' export async function POST(req: NextRequest) { const post = await req.json() - const credentials = { - relayerApiKey: process.env.NONCE_API_UNO, - relayerApiSecret: process.env.NONCE_SECRET_UNO, - } - - try { - const defenderClient = new Defender(credentials) - const provider = defenderClient.relaySigner.getProvider() - const signer = defenderClient.relaySigner.getSigner(provider, { - speed: 'fast', - }) - - const postGateway = new ethers.Contract( - addresses.postGateway.nova, - postGatewayABI, - signer as unknown as ethers.Signer, + const postTx = + // biome-ignore lint: + await syndicateClientPost!.transact.sendTransaction( + generatePostTxnInput(post), ) - const tx = await postGateway.post(post) + const successfulTxHash = await waitForHash(syndicateClientPost, { + projectId: projectIdPost, + transactionId: postTx.transactionId, + }) - await novaPubClient.waitForTransactionReceipt({ - hash: tx.hash as Hex, - }) + console.log({ successfulTxHash }) - return new Response(JSON.stringify({ success: true, hash: tx.hash }), { + return new Response( + JSON.stringify({ success: true, hash: successfulTxHash }), + { status: 200, headers: { 'Content-Type': 'application/json' }, - }) - } catch (error) { - let errorMessage = 'Unknown error' - let statusCode = 500 - - if (error instanceof Error) { - errorMessage = error.message - statusCode = - // biome-ignore lint: `status` is not part of the standard Error interface - typeof (error as any).status === 'number' ? (error as any).status : 500 - } - - return new Response( - JSON.stringify({ success: false, hash: null, error: errorMessage }), - { - status: statusCode, - headers: { 'Content-Type': 'application/json' }, - }, - ) - } + }, + ) } diff --git a/apps/site/app/api/postBatch/route.ts b/apps/site/app/api/postBatch/route.ts index 047c7412..c621492e 100644 --- a/apps/site/app/api/postBatch/route.ts +++ b/apps/site/app/api/postBatch/route.ts @@ -1,60 +1,32 @@ -import { novaPubClient } from '@/config/publicClient' -import { Defender } from '@openzeppelin/defender-sdk' -import { ethers } from 'ethers' import type { NextRequest } from 'next/server' -import { addresses, postGatewayABI } from 'scrypt' -import type { Hex } from 'viem' - -export const maxDuration = 30 // This function can run for a maximum of 30 seconds +import { + syndicateClientPost, + generatePostBatchTxnInput, + projectIdPost, +} from '@/config/syndicateClient' +import { waitForHash } from '@syndicateio/syndicate-node/utils' export async function POST(req: NextRequest) { const postsArray = await req.json() - console.log({ postsArray }) - - const credentials = { - relayerApiKey: process.env.NONCE_API_UNO, - relayerApiSecret: process.env.NONCE_SECRET_UNO, - } - try { - const defenderClient = new Defender(credentials) - const provider = defenderClient.relaySigner.getProvider() - const signer = defenderClient.relaySigner.getSigner(provider, { - speed: 'fast', - }) - - const postGateway = new ethers.Contract( - addresses.postGateway.nova, - postGatewayABI, - signer as unknown as ethers.Signer, + const postTx = + // biome-ignore lint: + await syndicateClientPost!.transact.sendTransaction( + generatePostBatchTxnInput(postsArray), ) - const tx = await postGateway.postBatch(postsArray) - await novaPubClient.waitForTransactionReceipt({ - hash: tx.hash as Hex, - }) + const successfulTxHash = await waitForHash(syndicateClientPost, { + projectId: projectIdPost, + transactionId: postTx.transactionId, + }) + + console.log({ successfulTxHash }) - return new Response(JSON.stringify({ success: true, hash: tx.hash }), { + return new Response( + JSON.stringify({ success: true, hash: successfulTxHash }), + { status: 200, headers: { 'Content-Type': 'application/json' }, - }) - } catch (error) { - let errorMessage = 'Unknown error' - let statusCode = 500 - - if (error instanceof Error) { - errorMessage = error.message - statusCode = - // biome-ignore lint: `status` is not part of the standard Error interface - typeof (error as any).status === 'number' ? (error as any).status : 500 - } - - return new Response( - JSON.stringify({ success: false, hash: null, error: errorMessage }), - { - status: statusCode, - headers: { 'Content-Type': 'application/json' }, - }, - ) - } + }, + ) } diff --git a/apps/site/app/api/registerFor/route.ts b/apps/site/app/api/registerFor/route.ts index ebf2d7db..ae162873 100644 --- a/apps/site/app/api/registerFor/route.ts +++ b/apps/site/app/api/registerFor/route.ts @@ -1,89 +1,52 @@ -import { optimismPubClient } from '@/config/publicClient' -import { Defender } from '@openzeppelin/defender-sdk' -import { ethers } from 'ethers' import type { NextRequest } from 'next/server' -import { addresses, idRegistryABI } from 'scrypt' -import { type Hex, decodeAbiParameters } from 'viem' - -export const maxDuration = 30 // This function can run for a maximum of 30 seconds +import { decodeAbiParameters } from 'viem' +import { + syndicateClientIdRegistry, + generateIdRegistryInput, + projectIdRegistry, +} from '@/config/syndicateClient' +import { waitForHash } from '@syndicateio/syndicate-node/utils' +import { optimismPubClient } from '@/config/publicClient' +import type { Hex } from 'viem' export async function POST(req: NextRequest) { const user = await req.json() - console.log({ user }) - const { username, ...userWithoutUsername } = user const { to, recovery, deadline, sig } = userWithoutUsername - console.log({ userWithoutUsername }) - const credentials = { - relayerApiKey: process.env.IDREGISTRY_API_UNO, - relayerApiSecret: process.env.IDREGISTRY_SECRET_UNO, - } - - try { - const defenderClient = new Defender(credentials) - const provider = defenderClient.relaySigner.getProvider() - const signer = defenderClient.relaySigner.getSigner(provider, { - speed: 'fast', - }) - - const idRegistry = new ethers.Contract( - addresses.idRegistry.optimism, - idRegistryABI, - signer as unknown as ethers.Signer, - ) - - const registerTxn = await idRegistry.registerFor( - to, - recovery, - deadline, - sig, + const registerTx = + // biome-ignore lint: + await syndicateClientIdRegistry!.transact.sendTransaction( + generateIdRegistryInput({ to, recovery, deadline, sig }), ) - const txnReceipt = await optimismPubClient.waitForTransactionReceipt({ - hash: registerTxn.hash as Hex, - }) - - const [rid, recoveryAddress] = decodeAbiParameters( - [ - { name: 'rid', type: 'uint256' }, - { name: 'recoveryAddress', type: 'address' }, - ], - txnReceipt.logs[0].data, - ) - - console.log('rid: ', rid) - console.log('transaction receipt: ', registerTxn) - - return new Response( - JSON.stringify({ - success: true, - hash: registerTxn.hash, - rid: rid.toString(), - }), - { - status: 200, - headers: { 'Content-Type': 'application/json' }, - }, - ) - } catch (error) { - console.error(error) - let errorMessage = 'Unknown error' - let statusCode = 500 - - if (error instanceof Error) { - errorMessage = error.message - statusCode = - // biome-ignore lint: `status` is not part of the standard Error interface - typeof (error as any).status === 'number' ? (error as any).status : 500 - } - - return new Response( - JSON.stringify({ success: false, error: errorMessage }), - { - status: statusCode, - headers: { 'Content-Type': 'application/json' }, - }, - ) - } + const successfulTxHash = await waitForHash(syndicateClientIdRegistry, { + projectId: projectIdRegistry, + transactionId: registerTx.transactionId, + }) + + const txnReceipt = await optimismPubClient.waitForTransactionReceipt({ + hash: successfulTxHash as Hex, + }) + + const [rid] = decodeAbiParameters( + [ + { name: 'rid', type: 'uint256' }, + { name: 'recoveryAddress', type: 'address' }, + ], + + txnReceipt.logs[0].data, + ) + + return new Response( + JSON.stringify({ + success: true, + hash: successfulTxHash, + rid: rid.toString(), + }), + { + status: 200, + headers: { 'Content-Type': 'application/json' }, + }, + ) } diff --git a/apps/site/biome.json b/apps/site/biome.json index 9a95a48f..ff55bcbf 100644 --- a/apps/site/biome.json +++ b/apps/site/biome.json @@ -15,7 +15,8 @@ "rules": { "recommended": true, "style": { - "noUselessElse": "off" + "noUselessElse": "off", + "noNonNullAssertion": "off" }, "suspicious": { "noRedeclare": "off", diff --git a/apps/site/config/syndicateClient.ts b/apps/site/config/syndicateClient.ts new file mode 100644 index 00000000..7b722f26 --- /dev/null +++ b/apps/site/config/syndicateClient.ts @@ -0,0 +1,73 @@ +import { SyndicateClient } from '@syndicateio/syndicate-node' +import { addresses } from 'scrypt' + +type PostMessage = { + rid: bigint + timestamp: bigint + msgType: number + msgBody: string +} + +type Post = { + signer: string + message: PostMessage + hashType: number + hash: string + sigType: number + sig: string +} + +type Register = { + to: string + recovery: string + deadline: number + sig: string +} + +type PostBatchFunction = { + posts: Post[] +} + +export const projectIdPost = + process.env.SYNDICATE_PROJECT_ID_POSTGATEWAY ?? 'Error' +export const projectIdRegistry = + process.env.SYNDICATE_PROJECT_ID_IDREGISTRY ?? 'Error' + +export const generatePostBatchTxnInput = (postsArray: PostBatchFunction) => ({ + projectId: projectIdPost, + contractAddress: addresses.postGateway.nova, + chainId: 42170, + functionSignature: + 'postBatch((address signer, (uint256 rid, uint256 timestamp, uint8 msgType, bytes msgBody) message, uint16 hashType, bytes32 hash, uint16 sigType, bytes sig)[] posts)', + args: { + posts: postsArray, + }, +}) + +export const generatePostTxnInput = (post: Post) => ({ + projectId: projectIdPost, + contractAddress: addresses.postGateway.nova, + chainId: 42170, + functionSignature: + 'post((address signer, (uint256 rid, uint256 timestamp, uint8 msgType, bytes msgBody) message, uint16 hashType, bytes32 hash, uint16 sigType, bytes sig) post)', + args: { + post: post, + }, +}) + +export const generateIdRegistryInput = (register: Register) => ({ + projectId: projectIdRegistry, + contractAddress: addresses.idRegistry.optimism, + chainId: 10, + functionSignature: + 'registerFor(address to, address recovery, uint256 deadline, bytes sig)', + args: { + to: register.to, + recovery: register.recovery, + deadline: register.deadline, + sig: register.sig, + }, +}) + +export const syndicateClientPost = new SyndicateClient({ token: process.env.SYNDICATE_POST_API_KEY as string }) +export const syndicateClientIdRegistry = new SyndicateClient({ token: process.env.SYNDICATE_ID_API_KEY as string }) \ No newline at end of file diff --git a/apps/site/lib/api.ts b/apps/site/lib/api.ts index cffc7886..1d6eb48f 100644 --- a/apps/site/lib/api.ts +++ b/apps/site/lib/api.ts @@ -1,5 +1,4 @@ 'use client' - import { getAccessToken } from '@privy-io/react-auth' type Message = { @@ -25,6 +24,102 @@ type User = { sig: string } +export interface TransactionAttempt { + block: number + blockCreatedAt: string + chainId: number + createdAt: string + hash: string + nonce: number + reverted: boolean + signedTxn: string + status: string + transactionId: string + updatedAt: string + walletAddress: string +} + +export interface SyndicateApiResponse { + chainId: number + contractAddress: string + createdAt: string + data: string + decodedData: object + functionSignature: string + invalid: boolean + projectId: string + transactionAttempts: TransactionAttempt[] + transactionId: string + updatedAt: string + value: string +} + +export interface WaitUntilTxOptions { + projectID: string + txID: string + authToken: string + maxAttempts?: number + every?: number +} + +export const authToken = process.env.SYNDICATE_API_KEY + +export const getTransactionRequest = async ({ + projectID, + txID, + authToken, +}: Pick & { authToken: string }) => { + const response = await fetch( + `https://api.syndicate.io/wallet/project/${projectID}/request/${txID}`, + { + method: 'GET', + headers: { Authorization: `Bearer ${authToken}` }, + }, + ) + if (!response.ok) { + throw new Error(`Failed to get transaction request: ${response.statusText}`) + } + return response.json() +} + +export async function waitUntilTx({ + projectID, + txID, + authToken, + maxAttempts = 20, + every = 1000, +}: WaitUntilTxOptions) { + let currAttempts = 0 + let transactionHash = null + + while (!transactionHash && currAttempts < maxAttempts) { + const txAttempts = ( + await getTransactionRequest({ projectID, txID, authToken }) + )?.transactionAttempts + + console.log({ txAttempts }) + + if (txAttempts && txAttempts.length > 0) { + const lastAttempt = txAttempts[txAttempts.length - 1] + if (lastAttempt.status === 'PENDING' && !lastAttempt.reverted) { + transactionHash = lastAttempt.hash + break + } + } + + currAttempts++ + if (!transactionHash && currAttempts < maxAttempts) { + await new Promise((resolve) => setTimeout(resolve, every)) + } + } + + if (!transactionHash) { + throw new Error('Transaction not found within maximum attempts') + } + + return transactionHash +} + /* API ROUTES */ // This is in to help with serialization of bigints during json stringify diff --git a/apps/site/package.json b/apps/site/package.json index 9a205ea1..79d2cd8f 100644 --- a/apps/site/package.json +++ b/apps/site/package.json @@ -29,6 +29,7 @@ "@radix-ui/react-popover": "^1.0.7", "@radix-ui/react-separator": "^1.0.3", "@radix-ui/react-slot": "^1.0.2", + "@syndicateio/syndicate-node": "^1.0.1", "@vercel/analytics": "^1.0.2", "@vercel/kv": "^1.0.0", "base64url": "^3.0.1", diff --git a/packages/scrypt/constants/addresses.ts b/packages/scrypt/constants/addresses.ts index e3a189e4..32b8828b 100644 --- a/packages/scrypt/constants/addresses.ts +++ b/packages/scrypt/constants/addresses.ts @@ -18,4 +18,4 @@ export const addresses: AddressBook = { riverRecovery: { optimism: '0xFB0F92f8abdFA25415ADbb6EC0cd9EC33953F29a', }, -} +} \ No newline at end of file diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 10fe00a0..d0fd0af1 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -130,6 +130,9 @@ importers: '@radix-ui/react-slot': specifier: ^1.0.2 version: 1.0.2(@types/react@18.2.21)(react@18.2.0) + '@syndicateio/syndicate-node': + specifier: ^1.0.1 + version: 1.0.1 '@vercel/analytics': specifier: ^1.0.2 version: 1.0.2 @@ -4901,6 +4904,18 @@ packages: tslib: 2.6.2 dev: false + /@syndicateio/syndicate-node@1.0.1: + resolution: {integrity: sha512-WaXyHPabxLL73qnkrzdOzeaqC+6hccnnnkRCQsreIYPteHSOk7AjGrHTgRBcPHGPtdv35rQEG/4vv5WkxHtCoA==} + dependencies: + form-data: 4.0.0 + js-base64: 3.7.2 + node-fetch: 2.7.0(encoding@0.1.13) + qs: 6.11.2 + url-join: 4.0.1 + transitivePeerDependencies: + - encoding + dev: false + /@szmarczak/http-timer@4.0.6: resolution: {integrity: sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w==} engines: {node: '>=10'} @@ -6522,14 +6537,6 @@ packages: responselike: 2.0.1 dev: false - /call-bind@1.0.5: - resolution: {integrity: sha512-C3nQxfFZxFRVoJoGKKI8y3MOEo129NQ+FgQ08iye+Mk4zNZZGdjfs06bVTr+DBSlA66Q2VEcMki/cUCP4SercQ==} - dependencies: - function-bind: 1.1.2 - get-intrinsic: 1.2.2 - set-function-length: 1.1.1 - dev: true - /call-bind@1.0.7: resolution: {integrity: sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==} engines: {node: '>= 0.4'} @@ -6539,7 +6546,6 @@ packages: function-bind: 1.1.2 get-intrinsic: 1.2.4 set-function-length: 1.2.1 - dev: false /callsites@3.1.0: resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} @@ -7312,15 +7318,6 @@ packages: engines: {node: '>=10'} dev: false - /define-data-property@1.1.1: - resolution: {integrity: sha512-E7uGkTzkk1d0ByLeSc6ZsFS79Axg+m1P/VsgYsxHgiuc3tFSj+MjMIwe90FC4lOAZzNBdY7kkO2P2wKdsQ1vgQ==} - engines: {node: '>= 0.4'} - dependencies: - get-intrinsic: 1.2.4 - gopd: 1.0.1 - has-property-descriptors: 1.0.1 - dev: true - /define-data-property@1.1.4: resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==} engines: {node: '>= 0.4'} @@ -7328,7 +7325,6 @@ packages: es-define-property: 1.0.0 es-errors: 1.3.0 gopd: 1.0.1 - dev: false /defu@6.1.3: resolution: {integrity: sha512-Vy2wmG3NTkmHNg/kzpuvHhkqeIx3ODWqasgCRbKtbXEN0G+HpEEv9BtJLp7ZG1CZloFaC41Ah3ZFbq7aqCqMeQ==} @@ -7607,7 +7603,6 @@ packages: engines: {node: '>= 0.4'} dependencies: get-intrinsic: 1.2.4 - dev: false /es-errors@1.3.0: resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} @@ -8587,15 +8582,6 @@ packages: resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} engines: {node: 6.* || 8.* || >= 10.*} - /get-intrinsic@1.2.2: - resolution: {integrity: sha512-0gSo4ml/0j98Y3lngkFEot/zhiCeWsbYIlZ+uZOVgzLyLaUw7wxUL+nCTP0XJvJg1AXulJRI3UJi8GsbDuxdGA==} - dependencies: - function-bind: 1.1.2 - has-proto: 1.0.1 - has-symbols: 1.0.3 - hasown: 2.0.1 - dev: true - /get-intrinsic@1.2.4: resolution: {integrity: sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==} engines: {node: '>= 0.4'} @@ -8898,17 +8884,10 @@ packages: engines: {node: '>=8'} dev: true - /has-property-descriptors@1.0.1: - resolution: {integrity: sha512-VsX8eaIewvas0xnvinAe9bw4WfIeODpGYikiWYLH+dma0Jw6KHYqWiWfhQlgOVK8D6PvjubK5Uc4P0iIhIcNVg==} - dependencies: - get-intrinsic: 1.2.4 - dev: true - /has-property-descriptors@1.0.2: resolution: {integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==} dependencies: es-define-property: 1.0.0 - dev: false /has-proto@1.0.1: resolution: {integrity: sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==} @@ -8946,12 +8925,6 @@ packages: minimalistic-assert: 1.0.1 dev: false - /hasown@2.0.0: - resolution: {integrity: sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==} - engines: {node: '>= 0.4'} - dependencies: - function-bind: 1.1.2 - /hasown@2.0.1: resolution: {integrity: sha512-1/th4MHjnwncwXsIW6QMzlvYL9kG5e/CpVvLRZe4XPa8TOUNbCELqmvhDmnkNsAjwaG4+I8gJJL0JBvTTLO9qA==} engines: {node: '>= 0.4'} @@ -9453,7 +9426,7 @@ packages: /is-core-module@2.13.1: resolution: {integrity: sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==} dependencies: - hasown: 2.0.0 + hasown: 2.0.1 /is-decimal@2.0.1: resolution: {integrity: sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A==} @@ -9691,6 +9664,10 @@ packages: engines: {node: '>=10'} dev: false + /js-base64@3.7.2: + resolution: {integrity: sha512-NnRs6dsyqUXejqk/yv2aiXlAvOs56sLkX6nUdeaNezI5LFFLlsZjOThmwnrcwh5ZZRwZlCMnVAY3CvhIhoVEKQ==} + dev: false + /js-cookie@2.2.1: resolution: {integrity: sha512-HvdH2LzI/EAZcUwA8+0nKNtWHqS+ZmijLA30RwZA0bo7ToCckjK5MkGhjED9KoRcXO6BaGI3I9UIzSA1FKFPOQ==} dev: false @@ -9773,7 +9750,7 @@ packages: resolution: {integrity: sha512-zfA+5SuwYN2VWqN1/5HZaDzQKLJHaBVMZIIM+wuYjdptkaQsqzDdqjqf+lZZJUuJq1aanHiY8LhH8LmH+qBYJA==} engines: {node: '>= 0.4'} dependencies: - call-bind: 1.0.5 + call-bind: 1.0.7 isarray: 2.0.5 jsonify: 0.0.1 object-keys: 1.1.1 @@ -12230,6 +12207,13 @@ packages: side-channel: 1.0.4 dev: false + /qs@6.11.2: + resolution: {integrity: sha512-tDNIz22aBzCDxLtVH++VnTfzxlfeK5CbqohpSqpJgj1Wg/cQbStNAz3NuqCs5vV+pjBsK4x4pN9HlVh7rcYRiA==} + engines: {node: '>=0.6'} + dependencies: + side-channel: 1.0.4 + dev: false + /qs@6.5.3: resolution: {integrity: sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==} engines: {node: '>=0.6'} @@ -13015,16 +12999,6 @@ packages: /set-blocking@2.0.0: resolution: {integrity: sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==} - /set-function-length@1.1.1: - resolution: {integrity: sha512-VoaqjbBJKiWtg4yRcKBQ7g7wnGnLV3M8oLvVWwOk2PdYY6PEFegR1vezXR0tw6fZGF9csVakIRjrJiy2veSBFQ==} - engines: {node: '>= 0.4'} - dependencies: - define-data-property: 1.1.1 - get-intrinsic: 1.2.4 - gopd: 1.0.1 - has-property-descriptors: 1.0.1 - dev: true - /set-function-length@1.2.1: resolution: {integrity: sha512-j4t6ccc+VsKwYHso+kElc5neZpjtq9EnRICFZtWyBsLojhmeF/ZBd/elqm22WJh/BziDe/SBiOeAt0m2mfLD0g==} engines: {node: '>= 0.4'} @@ -13035,7 +13009,6 @@ packages: get-intrinsic: 1.2.4 gopd: 1.0.1 has-property-descriptors: 1.0.2 - dev: false /set-harmonic-interval@1.0.1: resolution: {integrity: sha512-AhICkFV84tBP1aWqPwLZqFvAwqEoVA9kxNMniGEUvzOlm4vLmOFLiTT3UZ6bziJTy4bOVpzWGTfSCbmaayGx8g==} @@ -14282,6 +14255,10 @@ packages: punycode: 2.3.1 dev: false + /url-join@4.0.1: + resolution: {integrity: sha512-jk1+QP6ZJqyOiuEI9AEWQfju/nB2Pw466kbA0LEZljHwKeMgd9WrAEgEGxjPDD2+TNbbb37rTyhEfrCXfuKXnA==} + dev: false + /url-set-query@1.0.0: resolution: {integrity: sha512-3AChu4NiXquPfeckE5R5cGdiHCMWJx1dwCWOmWIL4KHAziJNOFIYJlpGFeKDvwLPHovZRCxK3cYlwzqI9Vp+Gg==} dev: false