diff --git a/defender/package.json b/defender/package.json index 2d8a57f4..b682499d 100644 --- a/defender/package.json +++ b/defender/package.json @@ -10,9 +10,11 @@ "deploy:test": "pnpm build && pnpm setup:test", "deploy:prod": "pnpm build && pnpm setup:prod", "setup:test": "npx tsx src/setup.ts TEST", - "setup:prod": "npx tsx src/setup.ts PROD" + "setup:prod": "npx tsx src/setup.ts PROD", + "scripts:fix-allowlist-duplicates": "npx tsx src/scripts/fix-allowlist-duplicates.ts" }, "dependencies": { + "@graphql-mesh/cache-localforage": "^0.95.7", "@hypercerts-org/contracts": "0.8.11", "@openzeppelin/defender-autotask-client": "1.50.0", "@openzeppelin/defender-autotask-utils": "1.50.0", @@ -20,9 +22,11 @@ "@openzeppelin/defender-sentinel-client": "1.49.0", "@openzeppelin/merkle-tree": "^1.0.2", "@supabase/supabase-js": "^2.4.1", + "@types/lodash": "^4.14.199", "axios": "^1.2.6", "dotenv": "^16.0.3", "ethers": "5.7.2", + "lodash": "^4.17.21", "node-fetch": "^3.3.0" }, "devDependencies": { diff --git a/defender/src/scripts/fix-allowlist-duplicates.ts b/defender/src/scripts/fix-allowlist-duplicates.ts new file mode 100644 index 00000000..1f0fd89e --- /dev/null +++ b/defender/src/scripts/fix-allowlist-duplicates.ts @@ -0,0 +1,122 @@ +// const supabaseLib = require("@supabase/supabase-js"); +// const dotenv = require("dotenv"); +// const _ = require("lodash"); +// import * as fetch from "node-fetch"; +// const hypercertsSDK = require("@hypercerts-org/hypercerts-sdk"); + +import { createClient } from "@supabase/supabase-js"; +import dotenv from "dotenv"; +import _ from "lodash"; +import fetch from "node-fetch"; + +const pageSize = 1000; + +dotenv.config(); +const supabase = createClient( + process.env.NEXT_PUBLIC_SUPABASE_HYPERCERTS_URL as string, + process.env.NEXT_PUBLIC_SUPABASE_HYPERCERTS_SERVICE_ROLE_KEY as string, +); + +const fetchAllowlistPage = async (lastId: number) => { + console.log("fetching page with id >", lastId); + return supabase + .from("allowlistCache-chainId") + .select("*") + .order("id", { ascending: true }) + .gt("id", lastId) + .eq("chainId", 10) + .limit(pageSize); +}; + +const deleteEntries = async (ids: number[]) => { + console.log("deleting entries", ids); + return supabase.from("allowlistCache-chainId").delete().in("id", ids); +}; + +const query = ` +query ClaimTokensByClaim($claimId: String!, $orderDirection: OrderDirection, $first: Int, $skip: Int) { + claimTokens(where: { claim: $claimId }, skip: $skip, first: $first, orderDirection: $orderDirection) { + id + owner + tokenID + units + } +} +`; + +const fetchClaimTokenForClaimId = async (claimId: string) => { + return fetch( + "https://api.thegraph.com/subgraphs/name/hypercerts-admin/hypercerts-optimism-mainnet", + { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ + variables: { + claimId, + first: 1000, + }, + query, + }), + }, + ) + .then((res) => res.json()) + .then((res) => res.data?.claimTokens); +}; + +const main = async () => { + const totalNumberOfResults = await supabase + .from("allowlistCache-chainId") + .select("id", { count: "exact" }); + + console.log("totalNumberOfResults", totalNumberOfResults.count); + + let lastId = 1; + + // Iterate over all pages + while (true) { + const { data } = await fetchAllowlistPage(lastId); + if (data.length === 0) { + break; + } + lastId = data[data.length - 1].id; + + const allowlistEntriesByClaimId = _.groupBy(data, "claimId"); + // console.log("fetched page", i); + + for (const claimId in allowlistEntriesByClaimId) { + // console.log("checking duplicates for", claimId); + const entries = allowlistEntriesByClaimId[claimId]; + // console.log(entries.length, "entries found"); + + const tokensForClaim = await fetchClaimTokenForClaimId(claimId); + // console.log("tokensForClaim", tokensForClaim); + + const addressesForClaimTokens = tokensForClaim.map( + (token: any) => token.owner, + ); + const addressesForEntry = entries.map((x) => x.address); + // console.log("Addresses for claim tokens", addressesForClaimTokens); + // console.log("Addresses for entries", addressesForEntry); + + const duplicates = _.intersectionBy( + addressesForClaimTokens, + addressesForEntry, + ); + + if (duplicates.length > 0) { + const supabaseEntries = entries.filter((entry) => + duplicates.includes(entry.address), + ); + // console.log("duplicates found for claimId", claimId, duplicates.length); + // console.log("duplicates", duplicates); + // console.log("duplicate supabaseEntries", supabaseEntries); + const idsToDelete = supabaseEntries.map((x) => x.id); + await deleteEntries(idsToDelete); + } + } + } +}; + +main(); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 273da490..0c3ab578 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -198,6 +198,9 @@ importers: defender: dependencies: + '@graphql-mesh/cache-localforage': + specifier: ^0.95.7 + version: 0.95.8(@graphql-mesh/types@0.95.8)(@graphql-mesh/utils@0.95.8)(graphql@16.8.1)(tslib@2.6.2) '@hypercerts-org/contracts': specifier: 0.8.11 version: 0.8.11 @@ -219,6 +222,9 @@ importers: '@supabase/supabase-js': specifier: ^2.4.1 version: 2.38.3 + '@types/lodash': + specifier: ^4.14.199 + version: 4.14.200 axios: specifier: ^1.2.6 version: 1.5.1(debug@4.3.4) @@ -228,6 +234,9 @@ importers: ethers: specifier: 5.7.2 version: 5.7.2 + lodash: + specifier: ^4.17.21 + version: 4.17.21 node-fetch: specifier: ^3.3.0 version: 3.3.2 @@ -6063,6 +6072,18 @@ packages: tslib: 2.6.2 dev: false + /@graphql-inspector/core@5.0.1(graphql@16.8.1): + resolution: {integrity: sha512-1CWfFYucnRdULGiN1NDSinlNlpucBT+0x4i4AIthKe5n5jD9RIVyJtkA8zBbujUFrP++YE3l+TQifwbN1yTQsw==} + engines: {node: '>=16.0.0'} + peerDependencies: + graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 + dependencies: + dependency-graph: 0.11.0 + graphql: 16.8.1 + object-inspect: 1.12.3 + tslib: 2.6.0 + dev: false + /@graphql-mesh/cache-localforage@0.93.1(@graphql-mesh/types@0.93.2)(@graphql-mesh/utils@0.93.2)(graphql@16.8.1)(tslib@2.6.2): resolution: {integrity: sha512-cY/LJ+XC8kiyPoLxqPAMlOAvaeB81CZafdadLNyNDFuu66qDiZqWTYPw/lnhp2nyeukC8o/P69oP7d2OqVaCZA==} peerDependencies: @@ -6078,6 +6099,22 @@ packages: tslib: 2.6.2 dev: false + /@graphql-mesh/cache-localforage@0.95.8(@graphql-mesh/types@0.95.8)(@graphql-mesh/utils@0.95.8)(graphql@16.8.1)(tslib@2.6.2): + resolution: {integrity: sha512-PgCTHh1dLwjmusWEWAMQkglL7gR8VyyT9pzTcYBVFhGYNXysepCrl85QtaqtEMnR/YijgpCWaKGIYK+bosQZsg==} + engines: {node: '>=16.0.0'} + peerDependencies: + '@graphql-mesh/types': ^0.95.8 + '@graphql-mesh/utils': ^0.95.8 + graphql: '*' + tslib: ^2.4.0 + dependencies: + '@graphql-mesh/types': 0.95.8(@graphql-mesh/store@0.95.8)(@graphql-tools/utils@10.0.11)(graphql@16.8.1)(tslib@2.6.2) + '@graphql-mesh/utils': 0.95.8(@graphql-mesh/cross-helpers@0.4.1)(@graphql-mesh/types@0.95.8)(@graphql-tools/utils@10.0.11)(graphql@16.8.1)(tslib@2.6.2) + graphql: 16.8.1 + localforage: 1.10.0 + tslib: 2.6.2 + dev: false + /@graphql-mesh/cli@0.82.35(@babel/core@7.23.5)(@types/node@18.18.7)(graphql-tag@2.12.6)(graphql@16.8.1)(react-native@0.72.6): resolution: {integrity: sha512-5IuXpk+Zpg05u6qNPX19VzC5/HCiLdDRF6EPZ3ze57FIRgGA3YsB1CUGga6Ky3inalURYwx0kWqmdjbdKZYx1w==} hasBin: true @@ -6184,6 +6221,18 @@ packages: - react-native-windows dev: false + /@graphql-mesh/cross-helpers@0.4.1(@graphql-tools/utils@10.0.11)(graphql@16.8.1): + resolution: {integrity: sha512-NkLzFuY72tmmKO7gKWoDzoYcRVf3lLoCdlw30fSNKFKEWDAV3Tyh4v0fPvU3SEmoTJio7v0TIYZqtVt3dBBDFw==} + engines: {node: '>=16.0.0'} + peerDependencies: + '@graphql-tools/utils': ^9.2.1 || ^10.0.0 + graphql: '*' + dependencies: + '@graphql-tools/utils': 10.0.11(graphql@16.8.1) + graphql: 16.8.1 + path-browserify: 1.0.1 + dev: false + /@graphql-mesh/graphql@0.93.1(@graphql-mesh/cross-helpers@0.3.4)(@graphql-mesh/store@0.93.1)(@graphql-mesh/types@0.93.2)(@graphql-mesh/utils@0.93.2)(@graphql-tools/utils@9.2.1)(@types/node@18.18.7)(graphql@16.8.1)(tslib@2.6.2): resolution: {integrity: sha512-1G2/1jkl1VPWhsZsUBwFQI5d9OxxEc+CMxy5ef0qI2WEXqIocOxMhEY53cc+tCSbuXR99rxos+KD/8Z6ZasaOQ==} peerDependencies: @@ -6321,6 +6370,26 @@ packages: tslib: 2.6.2 dev: false + /@graphql-mesh/store@0.95.8(@graphql-mesh/cross-helpers@0.4.1)(@graphql-mesh/types@0.95.8)(@graphql-mesh/utils@0.95.8)(@graphql-tools/utils@10.0.11)(graphql@16.8.1)(tslib@2.6.2): + resolution: {integrity: sha512-29lpMcvqS1DM9alUOCyj6he2V7ZzG/DZxkerRefT8Mo5FexwJZI3LeI0YHNSY9Cq0x8KzRoH1TWcTTN/1PDRRw==} + engines: {node: '>=16.0.0'} + peerDependencies: + '@graphql-mesh/cross-helpers': ^0.4.1 + '@graphql-mesh/types': ^0.95.8 + '@graphql-mesh/utils': ^0.95.8 + '@graphql-tools/utils': ^9.2.1 || ^10.0.0 + graphql: '*' + tslib: ^2.4.0 + dependencies: + '@graphql-inspector/core': 5.0.1(graphql@16.8.1) + '@graphql-mesh/cross-helpers': 0.4.1(@graphql-tools/utils@10.0.11)(graphql@16.8.1) + '@graphql-mesh/types': 0.95.8(@graphql-mesh/store@0.95.8)(@graphql-tools/utils@10.0.11)(graphql@16.8.1)(tslib@2.6.2) + '@graphql-mesh/utils': 0.95.8(@graphql-mesh/cross-helpers@0.4.1)(@graphql-mesh/types@0.95.8)(@graphql-tools/utils@10.0.11)(graphql@16.8.1)(tslib@2.6.2) + '@graphql-tools/utils': 10.0.11(graphql@16.8.1) + graphql: 16.8.1 + tslib: 2.6.2 + dev: false + /@graphql-mesh/string-interpolation@0.4.4(graphql@16.8.1)(tslib@2.6.2): resolution: {integrity: sha512-IotswBYZRaPswOebcr2wuOFuzD3dHIJxVEkPiiQubqjUIR8HhQI22XHJv0WNiQZ65z8NR9+GYWwEDIc2JRCNfQ==} peerDependencies: @@ -6334,6 +6403,20 @@ packages: tslib: 2.6.2 dev: false + /@graphql-mesh/string-interpolation@0.5.3(graphql@16.8.1)(tslib@2.6.2): + resolution: {integrity: sha512-/R4kj3M1uqUie/7RZ58zgRrT8RBrDsCCR6ii00s62DbLsl+jZYOZFyTqHGsFbP7L7aHnl0fo1dwhEJIs+rjCLg==} + engines: {node: '>=16.0.0'} + peerDependencies: + graphql: '*' + tslib: ^2.4.0 + dependencies: + dayjs: 1.11.10 + graphql: 16.8.1 + json-pointer: 0.6.2 + lodash.get: 4.4.2 + tslib: 2.6.2 + dev: false + /@graphql-mesh/transform-type-merging@0.93.1(@graphql-mesh/types@0.93.2)(@graphql-mesh/utils@0.93.2)(graphql@16.8.1)(tslib@2.6.2): resolution: {integrity: sha512-CUrqCMaEqO1LDusv59UPqmQju3f+LpEGxFu7CydMiIvbfKDDDrf8+dF3OVU7d/ZOMRxB6hR80JsQF0SVeXPCOQ==} peerDependencies: @@ -6367,6 +6450,24 @@ packages: tslib: 2.6.2 dev: false + /@graphql-mesh/types@0.95.8(@graphql-mesh/store@0.95.8)(@graphql-tools/utils@10.0.11)(graphql@16.8.1)(tslib@2.6.2): + resolution: {integrity: sha512-H2xh5KGc3+Ly3VdAPnRdKTibZpW9zEFgUzsozL9MQhCs6WLX+/kOADb0uIDqYFKX5c/2axmcy87BFNOausXYig==} + engines: {node: '>=16.0.0'} + peerDependencies: + '@graphql-mesh/store': ^0.95.8 + '@graphql-tools/utils': ^9.2.1 || ^10.0.0 + graphql: '*' + tslib: ^2.4.0 + dependencies: + '@graphql-mesh/store': 0.95.8(@graphql-mesh/cross-helpers@0.4.1)(@graphql-mesh/types@0.95.8)(@graphql-mesh/utils@0.95.8)(@graphql-tools/utils@10.0.11)(graphql@16.8.1)(tslib@2.6.2) + '@graphql-tools/batch-delegate': 9.0.0(graphql@16.8.1) + '@graphql-tools/delegate': 10.0.3(graphql@16.8.1) + '@graphql-tools/utils': 10.0.11(graphql@16.8.1) + '@graphql-typed-document-node/core': 3.2.0(graphql@16.8.1) + graphql: 16.8.1 + tslib: 2.6.2 + dev: false + /@graphql-mesh/utils@0.93.2(@graphql-mesh/cross-helpers@0.3.4)(@graphql-mesh/types@0.93.2)(@graphql-tools/utils@9.2.1)(graphql@16.8.1)(tslib@2.6.2): resolution: {integrity: sha512-U+VytfSoqPofH/pmYZHFY10SkIFtHKrvE7Isxv1d0DiweVjdH3Qtojw13DWFpu/EKtgJY5bqoVnlcsZJYlKQoA==} peerDependencies: @@ -6390,6 +6491,31 @@ packages: tslib: 2.6.2 dev: false + /@graphql-mesh/utils@0.95.8(@graphql-mesh/cross-helpers@0.4.1)(@graphql-mesh/types@0.95.8)(@graphql-tools/utils@10.0.11)(graphql@16.8.1)(tslib@2.6.2): + resolution: {integrity: sha512-gH2/kXvxMHVWMX8DppIIZpFfSUaoKDJ6eQHFoAAsdabGE+vLtVk0OEYqMGVGtD/8ZDFa/P6CmwXc6hBzoLY6Kg==} + engines: {node: '>=16.0.0'} + peerDependencies: + '@graphql-mesh/cross-helpers': ^0.4.1 + '@graphql-mesh/types': ^0.95.8 + '@graphql-tools/utils': ^9.2.1 || ^10.0.0 + graphql: '*' + tslib: ^2.4.0 + dependencies: + '@graphql-mesh/cross-helpers': 0.4.1(@graphql-tools/utils@10.0.11)(graphql@16.8.1) + '@graphql-mesh/string-interpolation': 0.5.3(graphql@16.8.1)(tslib@2.6.2) + '@graphql-mesh/types': 0.95.8(@graphql-mesh/store@0.95.8)(@graphql-tools/utils@10.0.11)(graphql@16.8.1)(tslib@2.6.2) + '@graphql-tools/delegate': 10.0.3(graphql@16.8.1) + '@graphql-tools/utils': 10.0.11(graphql@16.8.1) + '@whatwg-node/fetch': 0.9.14 + dset: 3.1.3 + graphql: 16.8.1 + js-yaml: 4.1.0 + lodash.get: 4.4.2 + lodash.topath: 4.5.2 + tiny-lru: 11.2.5 + tslib: 2.6.2 + dev: false + /@graphql-tools/apollo-engine-loader@8.0.0(graphql@16.8.1): resolution: {integrity: sha512-axQTbN5+Yxs1rJ6cWQBOfw3AEeC+fvIuZSfJLPLLvFJLj4pUm9fhxey/g6oQZAAQJqKPfw+tLDUQvnfvRK8Kmg==} engines: {node: '>=16.0.0'} @@ -6418,6 +6544,20 @@ packages: value-or-promise: 1.0.12 dev: false + /@graphql-tools/batch-delegate@9.0.0(graphql@16.8.1): + resolution: {integrity: sha512-23NmxcHQeKcfhMQyrRPTZfW4/+bSpAyR/qAhRjx+/hikDIa1Uv2XVgV9jIitSgM0OEk/KGPB4VQv+LCOWvAYiw==} + engines: {node: '>=16.0.0'} + peerDependencies: + graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 + dependencies: + '@graphql-tools/delegate': 10.0.3(graphql@16.8.1) + '@graphql-tools/utils': 10.0.11(graphql@16.8.1) + dataloader: 2.2.2 + graphql: 16.8.1 + tslib: 2.6.2 + value-or-promise: 1.0.12 + dev: false + /@graphql-tools/batch-execute@8.5.22(graphql@16.8.1): resolution: {integrity: sha512-hcV1JaY6NJQFQEwCKrYhpfLK8frSXDbtNMoTur98u10Cmecy1zrqNKSqhEyGetpgHxaJRqszGzKeI3RuroDN6A==} peerDependencies: @@ -6441,7 +6581,6 @@ packages: graphql: 16.8.1 tslib: 2.6.2 value-or-promise: 1.0.12 - dev: true /@graphql-tools/code-file-loader@7.3.23(@babel/core@7.23.5)(graphql@16.8.1): resolution: {integrity: sha512-8Wt1rTtyTEs0p47uzsPJ1vAtfAx0jmxPifiNdmo9EOCuUPyQGEbMaik/YkqZ7QUFIEYEQu+Vgfo8tElwOPtx5Q==} @@ -6488,7 +6627,6 @@ packages: dataloader: 2.2.2 graphql: 16.8.1 tslib: 2.6.2 - dev: true /@graphql-tools/delegate@9.0.35(graphql@16.8.1): resolution: {integrity: sha512-jwPu8NJbzRRMqi4Vp/5QX1vIUeUPpWmlQpOkXQD2r1X45YsVceyUUBnktCrlJlDB4jPRVy7JQGwmYo3KFiOBMA==} @@ -6659,7 +6797,6 @@ packages: graphql: 16.8.1 tslib: 2.6.2 value-or-promise: 1.0.12 - dev: true /@graphql-tools/git-loader@8.0.3(graphql@16.8.1): resolution: {integrity: sha512-Iz9KbRUAkuOe8JGTS0qssyJ+D5Snle17W+z9anwWrLFrkBhHrRFUy5AdjZqgJuhls0x30QkZBnnCtnHDBdQ4nA==} @@ -6840,7 +6977,6 @@ packages: '@graphql-tools/utils': 10.0.11(graphql@16.8.1) graphql: 16.8.1 tslib: 2.6.2 - dev: true /@graphql-tools/optimize@1.4.0(graphql@16.8.1): resolution: {integrity: sha512-dJs/2XvZp+wgHH8T5J2TqptT9/6uVzIYvA6uFACha+ufvdMBedkfR4b4GbT8jAKLRARiqRTxy3dctnwkTM2tdw==} @@ -6934,7 +7070,6 @@ packages: graphql: 16.8.1 tslib: 2.6.2 value-or-promise: 1.0.12 - dev: true /@graphql-tools/schema@10.0.2(graphql@16.8.1): resolution: {integrity: sha512-TbPsIZnWyDCLhgPGnDjt4hosiNU2mF/rNtSk5BVaXWnZqvKJ6gzJV4fcHcvhRIwtscDMW2/YTnK6dLVnk8pc4w==} @@ -7053,7 +7188,6 @@ packages: dset: 3.1.3 graphql: 16.8.1 tslib: 2.6.2 - dev: true /@graphql-tools/utils@10.0.7(graphql@16.8.1): resolution: {integrity: sha512-KOdeMj6Hd/MENDaqPbws3YJl3wVy0DeYnL7PyUms5Skyf7uzI9INynDwPMhLXfSb0/ph6BXTwMd5zBtWbF8tBQ==} @@ -7065,7 +7199,6 @@ packages: dset: 3.1.3 graphql: 16.8.1 tslib: 2.6.2 - dev: true /@graphql-tools/utils@8.13.1(graphql@16.8.1): resolution: {integrity: sha512-qIh9yYpdUFmctVqovwMdheVNJqFh+DQNWIhX87FJStfXYnmweBUDATok9fWPleKeFwxnW8IapKmY8m8toJEkAw==} @@ -15862,7 +15995,6 @@ packages: engines: {node: '>=16.0.0'} dependencies: tslib: 2.6.2 - dev: true /cross-spawn@7.0.3: resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==} @@ -26201,6 +26333,10 @@ packages: resolution: {integrity: sha512-e5mCJlSH7poANfC8z8S9s9S2IN5/4Zb3aZ33f5s8YqoazCFzNLloLU8r5VCG+G7WoqLvAAZoVMcy3tp/3X0Plw==} dev: false + /object-inspect@1.12.3: + resolution: {integrity: sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==} + dev: false + /object-inspect@1.13.1: resolution: {integrity: sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==} @@ -30888,6 +31024,11 @@ packages: resolution: {integrity: sha512-AD5ih2NlSssTCwsMznbvwMZpJ1cbhkGd2uueNxzv2jDlEeZdU04JQfRnggJQ8DrcVBGjAsCKwFBbDlVNtEMlzw==} dev: false + /tiny-lru@11.2.5: + resolution: {integrity: sha512-JpqM0K33lG6iQGKiigcwuURAKZlq6rHXfrgeL4/I8/REoyJTGU+tEMszvT/oTRVHG2OiylhGDjqPp1jWMlr3bw==} + engines: {node: '>=12'} + dev: false + /tiny-lru@8.0.2: resolution: {integrity: sha512-ApGvZ6vVvTNdsmt676grvCkUCGwzG9IqXma5Z07xJgiC5L7akUMof5U8G2JTI9Rz/ovtVhJBlY6mNhEvtjzOIg==} engines: {node: '>=6'} @@ -31217,6 +31358,10 @@ packages: /tslib@2.5.3: resolution: {integrity: sha512-mSxlJJwl3BMEQCUNnxXBU9jP4JBktcEGhURcPR6VQVlnP0FdDEsIaz0C35dXNGLyRfrATNofF0F5p2KPxQgB+w==} + /tslib@2.6.0: + resolution: {integrity: sha512-7At1WUettjcSRHXCyYtTselblcHl9PJFFVKiCAy/bY97+BPZXSQ2wbq0P9s8tK2G7dFQfNnlJnPAiArVBVBsfA==} + dev: false + /tslib@2.6.2: resolution: {integrity: sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==} diff --git a/scripts/cleanup-allowlist.ts b/scripts/cleanup-allowlist.ts new file mode 100644 index 00000000..e69de29b