diff --git a/.eslintrc.json b/.eslintrc.json index fb35e9a..e62a3ad 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -110,7 +110,7 @@ }, "overrides": [ { - "files": ["scripts/*.ts"], + "files": ["scripts/*.ts", "utils/rate-limiter.ts"], "rules": { "no-console": "off" } diff --git a/.prettierignore b/.prettierignore index 92c93fb..33ced6f 100644 --- a/.prettierignore +++ b/.prettierignore @@ -1,2 +1,3 @@ public/* .next/* +lib/graphql/types/v2/* diff --git a/lib/additional-collectives.sql b/lib/additional-collectives.sql new file mode 100644 index 0000000..38f9b15 --- /dev/null +++ b/lib/additional-collectives.sql @@ -0,0 +1,94 @@ + -- Find collectives that left the specified hosts with money raised estimate + -- (projects and events amounts merged into their parent) + WITH target_host_ids AS ( + SELECT unnest(ARRAY[ + 9807, -- foundation + 11049, -- europe + 169078, -- oce-foundation-usd + 729588, -- oce-foundation-eur + 696998, -- opensource + 11004, -- open-source-collective-eur1 + 1012924, -- the-social-change-nest + 766450, -- the-social-change-nest-eu + 98478, -- giftcollective + 820725 -- raft + ]) AS id + ), + -- Collectives that had credits with target hosts (to identify former members) + collectives_with_target_host_history AS ( + SELECT DISTINCT COALESCE(c."ParentCollectiveId", c.id) AS parent_id + FROM "Transactions" t + INNER JOIN "Collectives" c ON c.id = t."CollectiveId" + WHERE t."HostCollectiveId" IN (SELECT id FROM target_host_ids) + AND t."type" = 'CREDIT' + AND t."RefundTransactionId" IS NULL + AND t."isRefund" IS NOT TRUE + AND t."deletedAt" IS NULL + AND c."deletedAt" IS NULL + ), + -- Parent collectives that are no longer hosted by target hosts + former_collectives AS ( + SELECT + c.id, + c.slug, + c.name, + c.type, + c."HostCollectiveId" AS current_host_id + FROM "Collectives" c + WHERE c."deletedAt" IS NULL + AND c.type NOT IN ('PROJECT', 'EVENT') + AND c.id IN (SELECT parent_id FROM collectives_with_target_host_history) + AND (c."HostCollectiveId" IS NULL OR c."HostCollectiveId" NOT IN (SELECT id FROM target_host_ids)) + -- Comment out the next line to INCLUDE collectives that moved to another host + AND c."HostCollectiveId" IS NULL + ), + -- All credits across ALL hosts, mapped to parent collective + all_credits_by_parent AS ( + SELECT + COALESCE(c."ParentCollectiveId", c.id) AS parent_id, + t."hostCurrency", + t."amountInHostCurrency" + FROM "Transactions" t + INNER JOIN "Collectives" c ON c.id = t."CollectiveId" + WHERE COALESCE(c."ParentCollectiveId", c.id) IN (SELECT id FROM former_collectives) + AND t."type" = 'CREDIT' + AND t."RefundTransactionId" IS NULL + AND t."isRefund" IS NOT TRUE + AND t."deletedAt" IS NULL + AND c."deletedAt" IS NULL + ), + -- Sum credits per parent across all hosts, pick currency with highest total + money_raised AS ( + SELECT DISTINCT ON (parent_id) + parent_id, + "hostCurrency" AS currency, + SUM("amountInHostCurrency") OVER (PARTITION BY parent_id, "hostCurrency") AS total + FROM all_credits_by_parent + ORDER BY parent_id, SUM("amountInHostCurrency") OVER (PARTITION BY parent_id, "hostCurrency") DESC + ), + latest_fx_rates AS ( + SELECT DISTINCT ON ("from") + "from", + rate + FROM "CurrencyExchangeRates" + WHERE "to" = 'USD' + ORDER BY "from", "createdAt" DESC + ) + SELECT + fc.id, + fc.slug, + fc.name, + fc.type, + fc.current_host_id, + current_host.slug AS current_host_slug, + mr.currency, + ROUND((mr.total / 100.0)::numeric, 2) AS amount_raised, + ROUND(((mr.total / 100.0) * COALESCE(fx.rate, 1))::numeric, 2) AS amount_raised_usd + FROM former_collectives fc + LEFT JOIN "Collectives" current_host ON current_host.id = fc.current_host_id + LEFT JOIN money_raised mr ON mr.parent_id = fc.id + LEFT JOIN latest_fx_rates fx ON fx."from" = mr.currency + WHERE true + -- Comment out the next line to INCLUDE collectives with less than 100 USD raised + AND ((mr.total / 100.0) * COALESCE(fx.rate, 1)) >= 100 + ORDER BY amount_raised_usd DESC NULLS LAST; diff --git a/lib/additional-collectives.ts b/lib/additional-collectives.ts new file mode 100644 index 0000000..72191d8 --- /dev/null +++ b/lib/additional-collectives.ts @@ -0,0 +1,624 @@ +/** + * List of collective slugs to include for their past activity, + * even though they are not currently hosted by one of the selected hosts. + */ +export const additionalCollectiveSlugs = [ + '1999collective', + '1k-casey', + '1kproject', + 'abqciqlovia', + 'abqfreefridge', + 'account-805de72b', + 'acpc', + 'act-fund', + 'adlt', + 'adviseccr', + 'afchildhoodjoyfund', + 'affect', + 'akibaparty', + 'alaskansocial', + 'amazmod-33', + 'amazon-workers-for-democracy', + 'amiberry', + 'androidide', + 'android-password-store', + 'angular-fullstack', + 'aosus', + 'apexchartsjs', + 'apmutualaid', + 'appalachian-land-study', + 'arataki-impact-fibre-isp', + 'archived-b5wteifahzy01', + 'archived-collective-984651', + 'archived-collective-info', + 'art_coop', + 'artistideal', + 'artistledgivingcircle', + 'asd-dads', + 'asianfoodcollective', + 'aspiration-project-disbursement', + 'athens', + 'athensmutualaidnetwork', + 'atx-mental-health-fund2', + 'autismandmeguernsey', + 'awp', + 'aylx', + 'baltimore-code-and-coffee', + 'baltimoremusicalimprov', + 'beacon-community-network', + 'beaker', + 'bedrock', + 'beehaw', + 'behind-enemy-lines', + 'benthos', + 'bettercivics', + 'betterdisplay', + 'betweenthewires', + 'bftp', + 'big-arts-organization', + 'bikebike-everywhere', + 'bismuth', + 'bkhroc', + 'black-families-love-and-unite', + 'blacklivesmatteratschool', + 'black-mothers-march', + 'black-trans-collective', + 'boostnoteio', + 'breath', + 'brent-solidarity-fund', + 'brew', + 'bronzeville-kenwood-ma', + 'bsz', + 'bull-city-mutual-aid', + 'bushwick-emergency-relief-fund', + 'buttercup', + 'cachet', + 'caesonia', + 'cannercms', + 'cann-hall-mutual-aid', + 'canonbury-mutual-aid-2020', + 'cant-buy-my-silence-us', + 'carbon-app', + 'cares-fox-cities', + 'carleton-college', + 'carlislechp', + 'carols-kindness', + 'ccc33chicago', + 'cfsc', + 'change-waco', + 'charmcityjs', + 'chatwoot', + 'cheeselab', + 'chehalisrivermutualaidnetwork', + 'chicagolandwarehousefund', + 'chicago-ma-build-squad', + 'chicago-tenants-movement', + 'chordata', + 'chrome-vue', + 'chsf', + 'circle-city-mutual-aid', + 'civic-tech-dc', + 'claudia-jones-school', + 'cleveland-books-to-prisoners', + 'climate-collective-oxford', + 'climate-hub-wandsworth', + 'climatewborders', + 'cloudbox', + 'clubber-ml', + 'cmag', + 'cmeg-deai-fund', + 'code-and-coffee', + 'codeblue', + 'codebuddies', + 'code-for-dayton', + 'codefordenver', + 'code-for-hawaii-back', + 'code-for-pittsburgh', + 'code-with-aloha', + 'code-with-the-carolinas', + 'collectivediaspora', + 'columbiana-county-pride', + 'commonplace', + 'communityco-housing', + 'community-fruit', + 'communityrule', + 'comrade-co-op', + 'convoy4ukraine', + 'coop4lib', + 'cooperativejournal', + 'cotowali', + 'council-data-project', + 'covid-print-oxford', + 'cpstrong', + 'crop-la', + 'csh-food-co-op', + 'cupcake', + 'cursorless', + 'cypurr-collective', + 'data-empowerment-fund', + 'dbt-athena', + 'dc-mutual-aid-apothecary', + 'dc-tool-library', + 'decoupled-days', + 'denvercommunityfridges', + 'denverscript', + 'dep', + 'dev-founders', + 'disco-one-project-grant', + 'distribute-aid-usa', + 'distributed', + 'dividon', + 'dj-stripe', + 'do-collective-art-projects', + 'donoharmatvcu', + 'donut', + 'drive-by-howdy', + 'drupalcamp-bristol', + 'drupal-diversity-and-inclusion-speaker-initiative', + 'drupalnj', + 'drupalstl', + 'drupalutah', + 'dsmsurj', + 'dual-power-gathering', + 'duopo', + 'durham-community-apothecary', + 'eastlaketenants', + 'econ', + 'edgewater-mutual-aid', + 'eitherorg', + 'elgin-mutual-aid-collective', + 'elmsln', + 'emdr-london-group', + 'emplea_do', + 'encampment-medical-team', + 'endurance-scholarship', + 'entropic', + 'erutan-art', + 'esa-ne', + 'evanston-fight-for-black-lives', + 'ewan-brown-anarchist-bookfair', + 'expo-cli', + 'expressots', + 'eyedropper', + 'f4mp', + 'fair-collective', + 'farstar', + 'favor', + 'feathers', + 'federatedpress', + 'fela', + 'femme-defensa', + 'ffplayout', + 'file-icons', + 'fines-and-fees-freedom-fund', + 'fisk-vanderbilt-masters-to-phd-bridge-program', + 'fito-network', + 'fits', + 'flatpak', + 'florence-social', + 'flourish-films', + 'flowlab', + 'fnb_raleigh', + 'focused-collaboration', + 'forma-institut', + 'fountainjs', + 'fpvout', + 'freebsd-vm-bhyve', + 'freefoodcollective', + 'fridays-for-future-dc', + 'fridays-for-future-nyc', + 'fridaysforfuture-us', + 'fridaysforfuture-usd-it-admin', + 'friends-of-green-burial-pa', + 'friends-of-the-howard-human-and-civil-rights-law-review', + 'fxma', + 'gatsby', + 'gatsby-plugin-typegen', + 'getbootstrapcdn', + 'geysermcold', + 'gitlens', + 'glimpse', + 'godscloset', + 'google-open-source-cms-fund', + 'goose-green-solidarity-fund', + 'gqless', + 'graphqlentityframework', + 'graphqlnyc', + 'guardian-rebellion', + 'hack4impact', + 'handsoffuhuru', + 'hava-nababy', + 'heaux-history', + 'heklerke', + 'help-escaping-afghanistan', + 'henleycmag', + 'hermosamutualaid', + 'hernehillsolidarityfund', + 'hibiscusrose', + 'home-is-a-human-right', + 'hospitalrun', + 'hots-nyc', + 'housingmv', + 'hpsolidaritynetwork', + 'htop', + 'humanitarian-ai', + 'huneeds', + 'hyperapp', + 'ideation-youth-nation', + 'idyll', + 'ievobio', + 'ifcjs', + 'ihateregex', + 'impactfellowship', + 'impacttech', + 'inflection-grants', + 'invoiceplane', + 'inw-mutual-aid', + 'inxi', + 'ipfs-search', + 'iron-path-farms', + 'irving-park-mutual-aid', + 'ispcwa_old', + 'jesuisniilee-ma', + 'joinedincare', + 'jordans-safe-place', + 'jovo-framework', + 'jsbin', + 'julian-collective', + 'justice-reskill', + 'karafka', + 'kcmutualaidzone3', + 'keeling-mutual-aid', + 'kefc', + 'killedbygoogle', + 'kintsugiproject', + 'kolanutcollab', + 'kuumba-collective', + 'labdavanac', + 'lan4n', + 'landcorps', + 'laugh-it-out-hub', + 'launchcoop', + 'lefrak-corona-ma', + 'leveler', + 'leyton-ward-mutual-aid', + 'libra', + 'lindberg-park-neighborhood-association', + 'livinginquiries', + 'ljescuelita', + 'local-peace-economy', + 'logansquaremutualaid', + 'lolashare', + 'lollipop-cloud-team', + 'los-angeles-global-shapers', + 'lovewins', + 'loving', + 'lumen', + 'lumo', + 'lvlpma', + 'm4a-everywhere', + 'm4bl-dc-money-pot', + 'mahappsmetro', + 'mainlinezine', + 'mamas', + 'manifest-grants', + 'manybabies', + 'mapletestimony', + 'material-theme', + 'ma-vie-en-mode-avion', + 'mayfair-mutual-aid', + 'mealsofgratitude', + 'mealstohealoc', + 'memexgarden', + 'metagov-phase-3', + 'mhisa-fundraise', + 'michigan-drupal', + 'missingpiece', + 'ml4chemla', + 'mobile-ffmpeg', + 'molembike', + 'money-health-collective', + 'moneyjustice', + 'mozilla', + 'mp-collective', + 'mqttnet', + 'muntashir', + 'museum-workers-speak', + 'mutual-aid-alnwick', + 'native-roots-network', + 'nature-connection-network', + 'nebula', + 'newschoolmutualaidfund', + 'newtonsoftjson-for-unity', + 'ng-packagr', + 'nmhep', + 'noble', + 'nobo-house', + 'nodemailer', + 'node-redis', + 'nokomiseastmutualaid', + 'nomuslimban', + 'nopa-neighbors', + 'north-brooklyn-mutual-aid', + 'nssc', + 'nunhead-knocks', + 'nwma-coalition-chicago', + 'nycpp', + 'nytmma', + 'obvious-agency', + 'occ-ai', + 'oc-covid-relief-fund', + 'ocf-temporary-fund', + 'octotree', + 'offthestage', + 'onetwoheartu', + 'opencleveland', + 'open-eugene', + 'openipc-eu', + 'open-kentuckiana', + 'openknx-collective', + 'openmaine', + 'openmined', + 'opennashville', + 'openoakland', + 'openpatterson', + 'open-post-academics', + 'openprivacytech', + 'openproducerplatform', + 'opensanctions', + 'opensandiego', + 'openscapes', + 'opensourcediversity', + 'open-source-san-jose', + 'open-streaming-platform', + 'open-twin-cities', + 'openulmus', + 'orchidssg', + 'orogene', + 'ory', + 'ospo', + 'ourhouseinfoshop', + 'outkast-people-nation', + 'palestineaction', + 'palms-unhoused-mutual-aid', + 'pamf-hospital-meals', + 'pasquines', + 'patchbay', + 'patchwork', + 'paths-chicago', + 'pcp', + 'pdxnode', + 'peercoin', + 'peertubesocial', + 'peoples-utility', + 'pgchangemakers', + 'phenomic', + 'phillytru', + 'phoenix-hub', + 'phpstanorg', + 'piamancini-collective', + 'picocrypt', + 'pinpointsimulations', + 'pion-ion', + 'pistil', + 'pnwzone', + 'polar-bookshelf', + 'police-free-penn-mutual-aid', + 'polyphonics-choir', + 'portland-corona-virus-mutual-aid-fund', + 'possibilities-for-women', + 'possibilityproject', + 'power-for-all', + 'pressbooks', + 'print-my-blog', + 'priorswood', + 'privacyguides', + 'project-acp', + 'project-protocol', + 'project-safe-philly', + 'promenaidorg', + 'ps376psa', + 'psysciacc', + 'pug-php', + 'pwa', + 'python-software-foundation', + 'python-sortedcontainers', + 'qc-bytes', + 'qrcodeshow', + 'qrpicture', + 'quantum', + 'quarry-community-mutual-aid', + 'queering-the-path', + 'quodlibet', + 'r4ds', + 'ragtag', + 'railsgirlsatl', + 'rain-or-shine-diaper-fund', + 'raw', + 'rbkcarea2mutualaid', + 'react-hot-loader', + 'react-native-camera', + 'react-robins', + 'react-starter', + 'readup-collective', + 'redact', + 'redom', + 'redredemption', + 'refugee-resettlement-support', + 'regenerationcentre', + 're-opening-welcome-hall', + 'repro-justice-in-adoption', + 'residency-at-papillon-farm', + 'rethinking-economics-usa', + 'retrospring', + 'revery', + 'ridgewood-mutual-aid-project', + 'rise-and-shine', + 'rocketmod', + 'rockymountainmutualaid', + 'roidelapluie', + 'rometoolsbackup', + 'rootsunbound', + 'rootz', + 'roseto', + 'roslindale-community-fridge', + 'roslindale-food-collective', + 'rs-ipfs', + 'rumah', + 'runa-ctx', + 'rwf2', + 'sage', + 'satellizer', + 'sb-mutual-aid-care-club', + 'se16communityfund', + 'searx', + 'seattleliteracy', + 'secure-activism', + 'see-you-collective', + 'selborne-mutual-aid', + 'serpent-os', + 'sfba-mastodon', + 'sf-bay-area-mutual-aid', + 'sfcontemplarium', + 'sf-data-science', + 'sfglobalshapers', + 'short-story-club', + 'silhouette', + 'sinuous', + 'skatejs', + 'sketch-sh', + 'skgreactjs', + 'skylines', + 'smcsalumni', + 'socialhealthlabs', + 'sociallydistantart', + 'solarpunk', + 'solidaridad-inquilina', + 'solrmutualaid', + 'southeasttnmutualaidnetwork', + 'southphillyfridge', + 'sovereign-bodies-institute', + 'speak-brussels', + 'spring-garden-community-pantry', + 'ssftx', + 'ssma', + 'stanford-hospital-meals', + 'staticjscms', + 'statusfy', + 'stc', + 'stlmutualaid', + 'stoke-newington-c19-mutual-aid', + 'stop-the-sweeps-atx', + 'streamlink', + 'suedwestnetz', + 'sunflower', + 'sunrise-choir', + 'sun-seeker-mke', + 'superbloom-samsung-next-decentralization-grant', + 'supplyourheroes', + 'sustain-general-support-grant', + 'swop-chi', + 'symfony-diversity-speaker-mentoring', + 'tallahassee-food-not-bombs', + 'tania', + 'tavistocklocalshelp', + 'tavistock-scrubs-hub', + 'tb-deprecated', + 'tech-for-forest', + 'techtogether-atlanta', + 'techtogether-boston', + 'techtogethermiami', + 'techtogether-new-york', + 'techtogether-seattle', + 'temple2023', + 'ten-the-emergence-network', + 'tera-arise', + 'te-rourou-koha', + 'testing-library', + 'the-archive-project', + 'the-black-and-brown-collective', + 'the-camila-foundation', + 'the-eleventy-meetup', + 'the-future-is-us-collective', + 'the-get-to-college-project', + 'thegradient', + 'the-headband-project', + 'the-love-fridge', + 'themis', + 'themovingsupportproject', + 'the-persistence', + 'thereservoircollective', + 'thesgc', + 'the-training-collective-nyc', + 'the-unjournal', + 'thewceg', + 'the-week', + 'thexylom', + 'togglz', + 'tpf', + 'tpsda', + 'trails', + 'training-europe', + 'trellis', + 'trill', + 'trilogymp', + 'truecharts-bounties', + 'trust-fund', + 'ttww-infrastructure-fund', + 'turkey-and-syria-response-fund', + 'turn-down-for-what-nyc', + 'twisted-fields-research-collective', + 'txdug', + 'ukvma', + 'umd', + 'undoingourerasure', + 'unirx', + 'untitled-filmmaker-org', + 'uob-mutual-support', + 'upliftinkind', + 'upstatephp', + 'urbanistssocial', + 'usrse', + 'utahmutualaid', + 'uv', + 'vaccinehunter', + 'vacfind', + 'vertical-village-alliance', + 'vicious-mole', + 'volteuropa', + 'vuejsfrankfurt', + 'vue-native-core', + 'wallrunners', + 'walthamstow-chapel-end', + 'ward-2-mutual-aid', + 'ward3neighborsupport', + 'ward-5-mutual-aid', + 'warriorjs', + 'wa-state-3d-visor-mask-hub', + 'watchersdefensecollective', + 'wccat', + 'weberfridge', + 'we-care-for-us', + 'wenyan-lang', + 'westbrooklynwaterfrontmutualaid', + 'west-side-mutual-aid', + 'whakapono-believe', + 'whanau-ahirau', + 'windicss', + 'worcestercommunityfridges', + 'wordpress-gwinnett', + 'worldimprovementlab', + 'wpbmutualaid', + 'wp-discourse', + 'wv-democracy-fund', + 'wwwdxmarathoncom', + 'wwwmanhoodpagcouk', + 'xplr', + 'xrhackney', + 'xr-namur', + 'yfcrm', + 'yoga-para-la-gente', + 'york-community-energy', + 'youngstownactioncenter', + 'zipstream', +]; diff --git a/lib/apollo-client.ts b/lib/apollo-client.ts index 883361b..eeb4e08 100644 --- a/lib/apollo-client.ts +++ b/lib/apollo-client.ts @@ -6,7 +6,7 @@ import merge from 'deepmerge'; import isEqual from 'lodash/isEqual'; import { GetSessionParams } from 'next-auth/react'; -import { PublicEnv } from './env'; +import { PrivateEnv, PublicEnv } from './env'; export const APOLLO_STATE_PROP_NAME = '__APOLLO_STATE__'; @@ -33,7 +33,8 @@ function createApolloClient({ context, fetch }: { context?: GetSessionParams; fe ...headers, // authorization: session?.accessToken ? `Bearer ${session?.accessToken}` : '', // eslint-disable-next-line no-process-env - ...(process.env.OPENCOLLECTIVE_API_KEY && { 'Api-Key': process.env.OPENCOLLECTIVE_API_KEY }), + ...(PrivateEnv.OPENCOLLECTIVE_API_KEY && { 'Api-Key': PrivateEnv.OPENCOLLECTIVE_API_KEY }), + ...(PrivateEnv.OPENCOLLECTIVE_PERSONAL_TOKEN && { 'Personal-Token': PrivateEnv.OPENCOLLECTIVE_PERSONAL_TOKEN }), }, }; }); diff --git a/lib/env.ts b/lib/env.ts index c3d6ba8..e455174 100644 --- a/lib/env.ts +++ b/lib/env.ts @@ -38,4 +38,7 @@ export const PrivateEnv = { /* A random string used to encrypt JWTs */ NEXTAUTH_SECRET: process.env.NEXTAUTH_SECRET, + + OPENCOLLECTIVE_API_KEY: process.env.OPENCOLLECTIVE_API_KEY, + OPENCOLLECTIVE_PERSONAL_TOKEN: process.env.OPENCOLLECTIVE_PERSONAL_TOKEN, }; diff --git a/lib/graphql/queries.ts b/lib/graphql/queries.ts index a010034..08ba07a 100644 --- a/lib/graphql/queries.ts +++ b/lib/graphql/queries.ts @@ -115,3 +115,98 @@ export const totalCountQuery = gql` } } `; + +export const accountBySlugQuery = gql` + query AccountBySlug( + $slug: String! + $quarterFrom: DateTime + $quarterTo: DateTime + $yearFrom: DateTime + $yearTo: DateTime + $currency: Currency + ) { + account(slug: $slug, throwIfMissing: false) { + name + slug + imageUrl + tags + location { + country + } + ... on AccountWithHost { + host { + slug + name + } + } + + ALL: stats { + contributorsCount(includeChildren: true) + totalAmountSpent(net: true, includeChildren: true, currency: $currency) { + valueInCents + } + totalAmountReceivedTimeSeries(net: true, timeUnit: YEAR, includeChildren: true, currency: $currency) { + timeUnit + nodes { + date + amount { + valueInCents + } + } + } + } + + PAST_YEAR: stats { + contributorsCount(includeChildren: true, dateFrom: $yearFrom, dateTo: $yearTo) + totalAmountSpent(net: true, includeChildren: true, dateFrom: $yearFrom, dateTo: $yearTo, currency: $currency) { + valueInCents + } + totalAmountReceivedTimeSeries( + net: true + dateFrom: $yearFrom + dateTo: $yearTo + timeUnit: MONTH + includeChildren: true + currency: $currency + ) { + timeUnit + nodes { + date + amount { + valueInCents + } + } + } + } + + PAST_QUARTER: stats { + contributorsCount(includeChildren: true, dateFrom: $quarterFrom, dateTo: $quarterTo) + totalAmountSpent( + net: true + includeChildren: true + dateFrom: $quarterFrom + dateTo: $quarterTo + currency: $currency + ) { + valueInCents + } + totalAmountReceivedTimeSeries( + net: true + dateFrom: $quarterFrom + dateTo: $quarterTo + timeUnit: WEEK + includeChildren: true + currency: $currency + ) { + timeUnit + nodes { + date + amount { + valueInCents + } + } + } + } + } + } +`; diff --git a/lib/hosts.ts b/lib/hosts.ts index bb2f182..cc71351 100644 --- a/lib/hosts.ts +++ b/lib/hosts.ts @@ -17,6 +17,7 @@ const defaultExcludeCategoryTags = [ 'illinois', 'europe', 'chicago', + 'opencollectiveeu', ]; export const hosts: { @@ -46,21 +47,35 @@ export const hosts: { root: true, name: 'Open Collective', hostSlugs: [ - 'foundation', + // 'foundation', 'europe', + 'oce-foundation-usd', + 'oce-foundation-eur', 'opensource', - 'allforclimate', + 'open-source-collective-eur1', 'the-social-change-nest', - 'ocnz', + 'the-social-change-nest-eu', 'giftcollective', - 'numfocus', - 'platform6-coop', - 'wwcodeinc', - 'reculture', - 'fission', - 'ferrous-systems-gmbh', - 'nfsc', - 'xwikisas', + 'raft', + // 'allforclimate', + // 'ocnz', + // 'numfocus', + // 'platform6-coop', + // 'wwcodeinc', + // 'reculture', + // 'fission', + // 'ferrous-systems-gmbh', + // 'nfsc', + // 'xwikisas', + // 'metagov', + // 'foreningen-granslandet', + // 'huddlecraft', + // 'psl-foundation', + // 'pact_collective', + // 'brussels', + // 'vcs-academy', + // 'nativesintech', + // 'thirty-percy' ], currency: 'USD', startYear: 2016, @@ -86,6 +101,7 @@ export const hosts: { { name: 'Open Source Collective', slug: 'opensource', + hostSlugs: ['opensource', 'open-source-collective-eur1'], currency: 'USD', startYear: 2016, logoSrc: '/osc-logo.svg', @@ -108,6 +124,7 @@ export const hosts: { { name: 'Open Collective Europe', slug: 'europe', + hostSlugs: ['europe', 'oce-foundation-usd', 'oce-foundation-eur'], currency: 'EUR', startYear: 2019, logoSrc: '/oce-logo.svg', @@ -127,4 +144,71 @@ export const hosts: { includeCategoryTags: [], excludeCategoryTags: [...defaultExcludeCategoryTags], }, + { + name: 'Gift Collective', + slug: 'giftcollective', + currency: 'NZD', + startYear: 2020, + logoSrc: '/gift-collective-logo.png', + website: 'https://opencollective.com/giftcollective', + color: { hex: '#6B9E9E', closestPaletteColor: 'teal' }, + styles: { + text: 'text-[#6B9E9E]', + groupHoverText: 'group-hover:text-[#6B9E9E]', + button: 'bg-[#6B9E9E] text-white', + brandBox: 'lg:bg-[#6B9E9E] lg:bg-opacity-5 text-[#6B9E9E]', + box: 'bg-[#6B9E9E] bg-opacity-5 text-[#6B9E9E]', + border: 'border-[#6B9E9E]', + }, + groupTags: { + ...defaultGroupTags, + }, + includeCategoryTags: [], + excludeCategoryTags: [...defaultExcludeCategoryTags], + }, + { + name: 'Social Change Nest', + slug: 'the-social-change-nest', + hostSlugs: ['the-social-change-nest', 'the-social-change-nest-eu'], + currency: 'GBP', + startYear: 2019, + logoSrc: '/social-change-nest-logo.png', + website: 'https://opencollective.com/the-social-change-nest', + color: { hex: '#EC008C', closestPaletteColor: 'pink' }, + styles: { + text: 'text-[#EC008C]', + groupHoverText: 'group-hover:text-[#EC008C]', + button: 'bg-[#EC008C] text-white', + brandBox: 'lg:bg-[#EC008C] lg:bg-opacity-5 text-[#EC008C]', + box: 'bg-[#EC008C] bg-opacity-5 text-[#EC008C]', + border: 'border-[#EC008C]', + }, + groupTags: { + ...defaultGroupTags, + }, + includeCategoryTags: [], + excludeCategoryTags: [...defaultExcludeCategoryTags], + }, + { + name: 'Raft Foundation', + slug: 'raft', + currency: 'USD', + startYear: 2021, + logoSrc: '/raft-logo.png', + website: 'https://opencollective.com/raft', + color: { hex: '#C4B454', closestPaletteColor: 'yellow' }, + styles: { + text: 'text-[#C4B454]', + groupHoverText: 'group-hover:text-[#C4B454]', + button: 'bg-[#C4B454] text-white', + brandBox: 'lg:bg-[#C4B454] lg:bg-opacity-5 text-[#C4B454]', + box: 'bg-[#C4B454] bg-opacity-5 text-[#C4B454]', + border: 'border-[#C4B454]', + }, + groupTags: { + ...defaultGroupTags, + }, + includeCategoryTags: [], + excludeCategoryTags: [...defaultExcludeCategoryTags], + }, ]; diff --git a/package-lock.json b/package-lock.json index 7031e9f..a9c6b0b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16,6 +16,7 @@ "babel-plugin-formatjs": "^10.3.31", "babel-plugin-react-remove-properties": "^0.3.0", "babel-plugin-transform-react-remove-prop-types": "^0.4.24", + "bottleneck": "^2.19.5", "class-variance-authority": "^0.3.0", "dayjs": "^1.11.6", "deepmerge": "4.2.2", @@ -384,6 +385,7 @@ "version": "7.19.6", "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.19.6.tgz", "integrity": "sha512-D2Ue4KHpc6Ys2+AxpIx1BZ8+UegLLLE2p3KJEuJRKmokHOtl49jQ5ny1773KsGLZs8MQvBidAF6yWUJxRqtKtg==", + "peer": true, "dependencies": { "@ampproject/remapping": "^2.1.0", "@babel/code-frame": "^7.18.6", @@ -2844,7 +2846,6 @@ "resolved": "https://registry.npmjs.org/@nicolo-ribaudo/eslint-scope-5-internals/-/eslint-scope-5-internals-5.1.1-v1.tgz", "integrity": "sha512-54/JRvkLIzzDWshCWfuhadfrfZVPiElY8Fcgmg1HroEly/EDSszzhBAsarCux+D/kOslTRquNzuyGSmUSTTHGg==", "dev": true, - "peer": true, "dependencies": { "eslint-scope": "5.1.1" } @@ -4970,7 +4971,8 @@ "node_modules/@types/node": { "version": "17.0.45", "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.45.tgz", - "integrity": "sha512-w+tIMs3rq2afQdsPJlODhoUEKzFP1ayaoyl1CcnwtIlsVe7K7bA1NGm4s3PraqTLlXnbIN84zuBlxBWo1u9BLw==" + "integrity": "sha512-w+tIMs3rq2afQdsPJlODhoUEKzFP1ayaoyl1CcnwtIlsVe7K7bA1NGm4s3PraqTLlXnbIN84zuBlxBWo1u9BLw==", + "peer": true }, "node_modules/@types/node-fetch": { "version": "2.6.2", @@ -5007,6 +5009,7 @@ "version": "18.0.21", "resolved": "https://registry.npmjs.org/@types/react/-/react-18.0.21.tgz", "integrity": "sha512-7QUCOxvFgnD5Jk8ZKlUAhVcRj7GuJRjnjjiY/IUBWKgOlnvDvTMLD4RTF7NPyVmbRhNrbomZiOepg7M/2Kj1mA==", + "peer": true, "dependencies": { "@types/prop-types": "*", "@types/scheduler": "*", @@ -5119,6 +5122,7 @@ "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.40.1.tgz", "integrity": "sha512-IK6x55va5w4YvXd4b3VrXQPldV9vQTxi5ov+g4pMANsXPTXOcfjx08CRR1Dfrcc51syPtXHF5bgLlMHYFrvQtg==", "dev": true, + "peer": true, "dependencies": { "@typescript-eslint/scope-manager": "5.40.1", "@typescript-eslint/types": "5.40.1", @@ -5387,6 +5391,7 @@ "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.0.tgz", "integrity": "sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w==", "dev": true, + "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -5514,7 +5519,6 @@ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", "dev": true, - "peer": true, "dependencies": { "color-convert": "^1.9.0" }, @@ -5539,6 +5543,7 @@ "version": "3.36.3", "resolved": "https://registry.npmjs.org/apexcharts/-/apexcharts-3.36.3.tgz", "integrity": "sha512-8/FXEs0ohXMff07Gv28XjhPwEJphIUdq2/wii/pcvi54Tw6z1mjrV8ydN8rlWi/ve8BAPBefJkLmRWv7UOBsLw==", + "peer": true, "dependencies": { "svg.draggable.js": "^2.2.2", "svg.easing.js": "^2.0.0", @@ -5929,6 +5934,12 @@ "readable-stream": "^3.4.0" } }, + "node_modules/bottleneck": { + "version": "2.19.5", + "resolved": "https://registry.npmjs.org/bottleneck/-/bottleneck-2.19.5.tgz", + "integrity": "sha512-VHiNCbI1lKdl44tGrhNfU3lup0Tj/ZBMJB5/2ZbNXRCPuRCO7ed2mgcK4r17y+KB2EfuYuRaVlwNbAeaWGSpbw==", + "license": "MIT" + }, "node_modules/brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -5965,6 +5976,7 @@ "url": "https://tidelift.com/funding/github/npm/browserslist" } ], + "peer": true, "dependencies": { "caniuse-lite": "^1.0.30001400", "electron-to-chromium": "^1.4.251", @@ -6086,9 +6098,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001431", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001431.tgz", - "integrity": "sha512-zBUoFU0ZcxpvSt9IU66dXVT/3ctO1cy4y9cscs1szkPlcWb6pasYM144GqrUygUbT+k7cmUCW61cvskjcv0enQ==", + "version": "1.0.30001766", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001766.tgz", + "integrity": "sha512-4C0lfJ0/YPjJQHagaE9x2Elb69CIqEPZeG0anQt9SIvIoOH4a4uaRl73IavyO+0qZh6MDLH//DrXThEYKHkmYA==", "funding": [ { "type": "opencollective", @@ -6097,8 +6109,13 @@ { "type": "tidelift", "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" } - ] + ], + "license": "CC-BY-4.0" }, "node_modules/capital-case": { "version": "1.0.4", @@ -6138,7 +6155,6 @@ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "dev": true, - "peer": true, "dependencies": { "ansi-styles": "^3.2.1", "escape-string-regexp": "^1.0.5", @@ -6367,7 +6383,6 @@ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", "dev": true, - "peer": true, "dependencies": { "color-name": "1.1.3" } @@ -6376,8 +6391,7 @@ "version": "1.1.3", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true, - "peer": true + "dev": true }, "node_modules/colorette": { "version": "2.0.19", @@ -6478,6 +6492,7 @@ "version": "7.0.1", "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.0.1.tgz", "integrity": "sha512-a1YWNUV2HwGimB7dU2s1wUMurNKjpx60HxBB6xUM8Re+2s1g1IIfJvFR0/iCF+XHdE0GMTKTuLR32UQff4TEyQ==", + "peer": true, "dependencies": { "@types/parse-json": "^4.0.0", "import-fresh": "^3.2.1", @@ -7064,6 +7079,7 @@ "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.25.0.tgz", "integrity": "sha512-DVlJOZ4Pn50zcKW5bYH7GQK/9MsoQG2d5eDH0ebEkE8PbgzTTmtt/VTH9GGJ4BfeZCpBLqFfvsjX35UacUL83A==", "dev": true, + "peer": true, "dependencies": { "@eslint/eslintrc": "^1.3.3", "@humanwhocodes/config-array": "^0.10.5", @@ -7225,6 +7241,7 @@ "resolved": "https://registry.npmjs.org/eslint-plugin-babel/-/eslint-plugin-babel-5.3.1.tgz", "integrity": "sha512-VsQEr6NH3dj664+EyxJwO4FCYm/00JhYb3Sk3ft8o+fpKuIfQ9TaW6uVUfvwMXHcf/lsnRIoyFPsLMyiWCSL/g==", "dev": true, + "peer": true, "dependencies": { "eslint-rule-composer": "^0.3.0" }, @@ -7315,6 +7332,7 @@ "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.26.0.tgz", "integrity": "sha512-hYfi3FXaM8WPLf4S1cikh/r4IxnO6zrhZbEGz2b660EJRbuxgpDS5gkCuYgGWg2xxh2rBuIr4Pvhve/7c31koA==", "dev": true, + "peer": true, "dependencies": { "array-includes": "^3.1.4", "array.prototype.flat": "^1.2.5", @@ -7369,6 +7387,7 @@ "resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.6.1.tgz", "integrity": "sha512-sXgFVNHiWffBq23uiS/JaP6eVR622DqwB4yTzKvGZGcPq6/yZ3WmOZfuBks/vHWo9GaFOqC2ZK4i6+C35knx7Q==", "dev": true, + "peer": true, "dependencies": { "@babel/runtime": "^7.18.9", "aria-query": "^4.2.2", @@ -7402,6 +7421,7 @@ "resolved": "https://registry.npmjs.org/eslint-plugin-node/-/eslint-plugin-node-11.1.0.tgz", "integrity": "sha512-oUwtPJ1W0SKD0Tr+wqu92c5xuCeQqB3hSCHasn/ZgjFdA9iDGNkNf2Zi9ztY7X+hNuMib23LNGRm6+uN+KLE3g==", "dev": true, + "peer": true, "dependencies": { "eslint-plugin-es": "^3.0.0", "eslint-utils": "^2.0.0", @@ -7446,6 +7466,7 @@ "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.31.10.tgz", "integrity": "sha512-e4N/nc6AAlg4UKW/mXeYWd3R++qUano5/o+t+wnWxIf+bLsOaH3a4q74kX3nDjYym3VBN4HyO9nEn1GcAqgQOA==", "dev": true, + "peer": true, "dependencies": { "array-includes": "^3.1.5", "array.prototype.flatmap": "^1.3.0", @@ -7535,7 +7556,6 @@ "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.2.tgz", "integrity": "sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ==", "dev": true, - "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -7548,7 +7568,6 @@ "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz", "integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==", "dev": true, - "peer": true, "engines": { "node": ">=4" } @@ -7558,7 +7577,6 @@ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.1.tgz", "integrity": "sha512-+O9Jct8wf++lXxxFc4hc8LsjaSq0HFzzL7cVsw8pRDIPdjKD2mT4ytDZlLuSBZ4cLKZFXIrMGO7DbQCtMJJMKw==", "dev": true, - "peer": true, "engines": { "node": ">=4" } @@ -7568,7 +7586,6 @@ "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", "dev": true, - "peer": true, "dependencies": { "sprintf-js": "~1.0.2" } @@ -7578,7 +7595,6 @@ "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", "integrity": "sha512-8lgKz8LmCRYZZQDpRyT2m5rKJ08TnU4tR9FFFW2rxpxR1FzWi4PQ/NfyODchAatHaUgnSPVcx/R5w6NuTBzFiw==", "dev": true, - "peer": true, "dependencies": { "restore-cursor": "^2.0.0" }, @@ -7590,15 +7606,13 @@ "version": "2.2.1", "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.1.tgz", "integrity": "sha512-GRMWDxpOB6Dgk2E5Uo+3eEBvtOOlimMmpbFiKuLFnQzYDavtLFY3K5ona41jgN/WdRZtG7utuVSVTL4HbZHGkw==", - "dev": true, - "peer": true + "dev": true }, "node_modules/eslint-plugin-styled-components-a11y/node_modules/cross-spawn": { "version": "6.0.5", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", "dev": true, - "peer": true, "dependencies": { "nice-try": "^1.0.4", "path-key": "^2.0.1", @@ -7704,7 +7718,6 @@ "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-4.0.3.tgz", "integrity": "sha512-p7VutNr1O/QrxysMo3E45FjYDTeXBy0iTltPFNSqKAIfjDSXC+4dj+qfyuD8bfAXrW/y6lW3O76VaYNPKfpKrg==", "dev": true, - "peer": true, "dependencies": { "esrecurse": "^4.1.0", "estraverse": "^4.1.1" @@ -7718,7 +7731,6 @@ "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-1.4.3.tgz", "integrity": "sha512-fbBN5W2xdY45KulGXmLHZ3c3FHfVYmKg0IrAKGOkT/464PQsx2UeIzfz1RmEci+KLm1bBaAzZAh8+/E+XAeZ8Q==", "dev": true, - "peer": true, "dependencies": { "eslint-visitor-keys": "^1.1.0" }, @@ -7731,7 +7743,6 @@ "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", "dev": true, - "peer": true, "engines": { "node": ">=4" } @@ -7741,7 +7752,6 @@ "resolved": "https://registry.npmjs.org/espree/-/espree-5.0.1.tgz", "integrity": "sha512-qWAZcWh4XE/RwzLJejfcofscgMc9CamR6Tn1+XRXNzrvUSSbiAjGOI/fggztjIi7y9VLPqnICMIPiGyr8JaZ0A==", "dev": true, - "peer": true, "dependencies": { "acorn": "^6.0.7", "acorn-jsx": "^5.0.0", @@ -7756,7 +7766,6 @@ "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", "dev": true, - "peer": true, "engines": { "node": ">=4.0" } @@ -7766,7 +7775,6 @@ "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz", "integrity": "sha512-Oa2M9atig69ZkfwiApY8F2Yy+tzMbazyvqv21R0NsSC8floSOC09BbT1ITWAdoMGQvJ/aZnR1KMwdx9tvHnTNA==", "dev": true, - "peer": true, "dependencies": { "escape-string-regexp": "^1.0.5" }, @@ -7779,7 +7787,6 @@ "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-5.0.1.tgz", "integrity": "sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g==", "dev": true, - "peer": true, "dependencies": { "flat-cache": "^2.0.1" }, @@ -7792,7 +7799,6 @@ "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-2.0.1.tgz", "integrity": "sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA==", "dev": true, - "peer": true, "dependencies": { "flatted": "^2.0.0", "rimraf": "2.6.3", @@ -7806,15 +7812,13 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.2.tgz", "integrity": "sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA==", - "dev": true, - "peer": true + "dev": true }, "node_modules/eslint-plugin-styled-components-a11y/node_modules/ignore": { "version": "4.0.6", "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", "dev": true, - "peer": true, "engines": { "node": ">= 4" } @@ -7824,7 +7828,6 @@ "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-6.5.2.tgz", "integrity": "sha512-cntlB5ghuB0iuO65Ovoi8ogLHiWGs/5yNrtUcKjFhSSiVeAIVpD7koaSU9RM8mpXw5YDi9RdYXGQMaOURB7ycQ==", "dev": true, - "peer": true, "dependencies": { "ansi-escapes": "^3.2.0", "chalk": "^2.4.2", @@ -7849,7 +7852,6 @@ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz", "integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==", "dev": true, - "peer": true, "engines": { "node": ">=6" } @@ -7859,7 +7861,6 @@ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", "dev": true, - "peer": true, "dependencies": { "ansi-regex": "^4.1.0" }, @@ -7872,7 +7873,6 @@ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", "integrity": "sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w==", "dev": true, - "peer": true, "engines": { "node": ">=4" } @@ -7882,7 +7882,6 @@ "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", "dev": true, - "peer": true, "dependencies": { "argparse": "^1.0.7", "esprima": "^4.0.0" @@ -7896,7 +7895,6 @@ "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", "integrity": "sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA==", "dev": true, - "peer": true, "dependencies": { "prelude-ls": "~1.1.2", "type-check": "~0.3.2" @@ -7910,7 +7908,6 @@ "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==", "dev": true, - "peer": true, "engines": { "node": ">=4" } @@ -7920,7 +7917,6 @@ "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", "dev": true, - "peer": true, "dependencies": { "minimist": "^1.2.6" }, @@ -7932,15 +7928,13 @@ "version": "0.0.7", "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz", "integrity": "sha512-r65nCZhrbXXb6dXOACihYApHw2Q6pV0M3V0PSxd74N0+D8nzAdEAITq2oAjA1jVnKI+tGvEBUpqiMh0+rW6zDQ==", - "dev": true, - "peer": true + "dev": true }, "node_modules/eslint-plugin-styled-components-a11y/node_modules/onetime": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", "integrity": "sha512-oyyPpiMaKARvvcgip+JV+7zci5L8D1W9RZIz2l1o08AM3pfspitVWnPt3mzHcBPp12oYMTy0pqrFs/C+m3EwsQ==", "dev": true, - "peer": true, "dependencies": { "mimic-fn": "^1.0.0" }, @@ -7953,7 +7947,6 @@ "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", "dev": true, - "peer": true, "dependencies": { "deep-is": "~0.1.3", "fast-levenshtein": "~2.0.6", @@ -7971,7 +7964,6 @@ "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", "integrity": "sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==", "dev": true, - "peer": true, "engines": { "node": ">=4" } @@ -7981,7 +7973,6 @@ "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", "integrity": "sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==", "dev": true, - "peer": true, "engines": { "node": ">= 0.8.0" } @@ -7991,7 +7982,6 @@ "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-2.0.1.tgz", "integrity": "sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw==", "dev": true, - "peer": true, "engines": { "node": ">=6.5.0" } @@ -8001,7 +7991,6 @@ "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", "integrity": "sha512-6IzJLuGi4+R14vwagDHX+JrXmPVtPpn4mffDJ1UdR7/Edm87fl6yi8mMBIVvFtJaNTUvjughmW4hwLhRG7gC1Q==", "dev": true, - "peer": true, "dependencies": { "onetime": "^2.0.0", "signal-exit": "^3.0.2" @@ -8015,7 +8004,6 @@ "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", "dev": true, - "peer": true, "dependencies": { "glob": "^7.1.3" }, @@ -8028,7 +8016,6 @@ "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", "dev": true, - "peer": true, "dependencies": { "tslib": "^1.9.0" }, @@ -8041,7 +8028,6 @@ "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", "dev": true, - "peer": true, "bin": { "semver": "bin/semver" } @@ -8051,7 +8037,6 @@ "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", "integrity": "sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==", "dev": true, - "peer": true, "dependencies": { "shebang-regex": "^1.0.0" }, @@ -8064,7 +8049,6 @@ "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", "integrity": "sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==", "dev": true, - "peer": true, "engines": { "node": ">=0.10.0" } @@ -8074,7 +8058,6 @@ "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", "dev": true, - "peer": true, "dependencies": { "is-fullwidth-code-point": "^2.0.0", "strip-ansi": "^4.0.0" @@ -8088,7 +8071,6 @@ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", "integrity": "sha512-4XaJ2zQdCzROZDivEVIDPkcQn8LMFSa8kj8Gxb/Lnwzv9A8VctNZ+lfivC/sV3ivW8ElJTERXZoPBRrZKkNKow==", "dev": true, - "peer": true, "dependencies": { "ansi-regex": "^3.0.0" }, @@ -8101,7 +8083,6 @@ "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", "dev": true, - "peer": true, "engines": { "node": ">=0.10.0" } @@ -8110,15 +8091,13 @@ "version": "1.14.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "dev": true, - "peer": true + "dev": true }, "node_modules/eslint-plugin-styled-components-a11y/node_modules/type-check": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", "integrity": "sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg==", "dev": true, - "peer": true, "dependencies": { "prelude-ls": "~1.1.2" }, @@ -8131,7 +8110,6 @@ "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", "dev": true, - "peer": true, "dependencies": { "isexe": "^2.0.0" }, @@ -8765,8 +8743,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", "integrity": "sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==", - "dev": true, - "peer": true + "dev": true }, "node_modules/functions-have-names": { "version": "1.2.3", @@ -8915,6 +8892,7 @@ "version": "16.6.0", "resolved": "https://registry.npmjs.org/graphql/-/graphql-16.6.0.tgz", "integrity": "sha512-KPIBPDlW7NxrbT/eh4qPXz5FiFdL5UbaA0XUNz2Rp3Z3hqBSkbj0GVjwFDztsWVauZUWsbKHgMg++sk8UX0bkw==", + "peer": true, "engines": { "node": "^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0" } @@ -9019,6 +8997,7 @@ "resolved": "https://registry.npmjs.org/graphql-ws/-/graphql-ws-5.11.2.tgz", "integrity": "sha512-4EiZ3/UXYcjm+xFGP544/yW1+DVI8ZpKASFbzrV5EDTFWJp0ZvLl4Dy2fSZAzz9imKp5pZMIcjB0x/H69Pv/6w==", "devOptional": true, + "peer": true, "engines": { "node": ">=10" }, @@ -11157,6 +11136,7 @@ "version": "12.3.1", "resolved": "https://registry.npmjs.org/next/-/next-12.3.1.tgz", "integrity": "sha512-l7bvmSeIwX5lp07WtIiP9u2ytZMv7jIeB8iacR28PuUEFG5j0HGAPnMqyG5kbZNBG2H7tRsrQ4HCjuMOPnANZw==", + "peer": true, "dependencies": { "@next/env": "12.3.1", "@swc/helpers": "0.4.11", @@ -11295,8 +11275,7 @@ "version": "1.0.5", "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", - "dev": true, - "peer": true + "dev": true }, "node_modules/no-case": { "version": "3.0.4", @@ -11357,16 +11336,6 @@ "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.6.tgz", "integrity": "sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg==" }, - "node_modules/nodemailer": { - "version": "6.8.0", - "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-6.8.0.tgz", - "integrity": "sha512-EjYvSmHzekz6VNkNd12aUqAco+bOkRe3Of5jVhltqKhEsjw/y0PYPJfp83+s9Wzh1dspYAkUW/YNQ350NATbSQ==", - "optional": true, - "peer": true, - "engines": { - "node": ">=6.0.0" - } - }, "node_modules/normalize-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", @@ -11844,8 +11813,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", "integrity": "sha512-DUWJr3+ULp4zXmol/SZkFf3JGsS9/SIv+Y3Rt93/UjPpDpklB5f1er4O3POIbUuUJ3FXgqte2Q7SrU6zAqwk8w==", - "dev": true, - "peer": true + "dev": true }, "node_modules/path-key": { "version": "3.1.1", @@ -11947,6 +11915,7 @@ "url": "https://tidelift.com/funding/github/npm/postcss" } ], + "peer": true, "dependencies": { "nanoid": "^3.3.4", "picocolors": "^1.0.0", @@ -12062,6 +12031,7 @@ "version": "10.11.2", "resolved": "https://registry.npmjs.org/preact/-/preact-10.11.2.tgz", "integrity": "sha512-skAwGDFmgxhq1DCBHke/9e12ewkhc7WYwjuhHB8HHS8zkdtITXLRmUMTeol2ldxvLwYtwbFeifZ9uDDWuyL4Iw==", + "peer": true, "funding": { "type": "opencollective", "url": "https://opencollective.com/preact" @@ -12092,6 +12062,7 @@ "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.7.1.tgz", "integrity": "sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g==", "dev": true, + "peer": true, "bin": { "prettier": "bin-prettier.js" }, @@ -12124,7 +12095,6 @@ "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", "dev": true, - "peer": true, "engines": { "node": ">=0.4.0" } @@ -12233,6 +12203,7 @@ "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz", "integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==", "license": "MIT", + "peer": true, "dependencies": { "loose-envify": "^1.1.0" }, @@ -12272,6 +12243,7 @@ "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz", "integrity": "sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==", "license": "MIT", + "peer": true, "dependencies": { "loose-envify": "^1.1.0", "scheduler": "^0.23.0" @@ -12364,8 +12336,7 @@ "node_modules/react-is": { "version": "18.2.0", "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", - "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", - "peer": true + "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==" }, "node_modules/react-lite-youtube-embed": { "version": "2.3.52", @@ -13344,6 +13315,7 @@ "resolved": "https://registry.npmjs.org/styled-components/-/styled-components-5.3.11.tgz", "integrity": "sha512-uuzIIfnVkagcVHv9nE0VPlHPSCmXIUGKfJ42LNjxCCTDTL5sgnJ8Z7GZBq0EnLYGln77tPpEpExt2+qa+cZqSw==", "license": "MIT", + "peer": true, "dependencies": { "@babel/helper-module-imports": "^7.0.0", "@babel/traverse": "^7.4.5", @@ -13397,6 +13369,7 @@ "version": "5.1.5", "resolved": "https://registry.npmjs.org/styled-system/-/styled-system-5.1.5.tgz", "integrity": "sha512-7VoD0o2R3RKzOzPK0jYrVnS8iJdfkKsQJNiLRDjikOpQVqQHns/DXWaPZOH4tIKkhAT7I6wIsy9FWTWh2X3q+A==", + "peer": true, "dependencies": { "@styled-system/background": "^5.1.2", "@styled-system/border": "^5.1.5", @@ -13569,7 +13542,6 @@ "resolved": "https://registry.npmjs.org/table/-/table-5.4.6.tgz", "integrity": "sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug==", "dev": true, - "peer": true, "dependencies": { "ajv": "^6.10.2", "lodash": "^4.17.14", @@ -13585,7 +13557,6 @@ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz", "integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==", "dev": true, - "peer": true, "engines": { "node": ">=6" } @@ -13595,7 +13566,6 @@ "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz", "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==", "dev": true, - "peer": true, "engines": { "node": ">=4" } @@ -13604,15 +13574,13 @@ "version": "7.0.3", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", - "dev": true, - "peer": true + "dev": true }, "node_modules/table/node_modules/is-fullwidth-code-point": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", "integrity": "sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w==", "dev": true, - "peer": true, "engines": { "node": ">=4" } @@ -13622,7 +13590,6 @@ "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz", "integrity": "sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ==", "dev": true, - "peer": true, "dependencies": { "ansi-styles": "^3.2.0", "astral-regex": "^1.0.0", @@ -13637,7 +13604,6 @@ "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", "dev": true, - "peer": true, "dependencies": { "emoji-regex": "^7.0.1", "is-fullwidth-code-point": "^2.0.0", @@ -13652,7 +13618,6 @@ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", "dev": true, - "peer": true, "dependencies": { "ansi-regex": "^4.1.0" }, @@ -13851,6 +13816,7 @@ "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz", "integrity": "sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==", "dev": true, + "peer": true, "dependencies": { "@cspotcode/source-map-support": "^0.8.0", "@tsconfig/node10": "^1.0.7", @@ -13967,6 +13933,7 @@ "version": "4.8.4", "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.8.4.tgz", "integrity": "sha512-QCh+85mCy+h0IGff8r5XWzOVSbBO+KfeYrMQh7NJ58QujwcE22u+NUSmUxqF+un70P9GXKxa2HCNiTTMJknyjQ==", + "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -14545,7 +14512,6 @@ "resolved": "https://registry.npmjs.org/write/-/write-1.0.3.tgz", "integrity": "sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig==", "dev": true, - "peer": true, "dependencies": { "mkdirp": "^0.5.1" }, @@ -14558,7 +14524,6 @@ "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", "dev": true, - "peer": true, "dependencies": { "minimist": "^1.2.6" }, @@ -14571,6 +14536,7 @@ "resolved": "https://registry.npmjs.org/ws/-/ws-8.9.0.tgz", "integrity": "sha512-Ja7nszREasGaYUYCI2k4lCKIRTt+y7XuqVoHR44YpI49TtryyqbqvDMn5eqfW7e6HzTukDRIsXqzVHScqRcafg==", "dev": true, + "peer": true, "engines": { "node": ">=10.0.0" }, @@ -14931,6 +14897,7 @@ "version": "7.19.6", "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.19.6.tgz", "integrity": "sha512-D2Ue4KHpc6Ys2+AxpIx1BZ8+UegLLLE2p3KJEuJRKmokHOtl49jQ5ny1773KsGLZs8MQvBidAF6yWUJxRqtKtg==", + "peer": true, "requires": { "@ampproject/remapping": "^2.1.0", "@babel/code-frame": "^7.18.6", @@ -16737,7 +16704,6 @@ "resolved": "https://registry.npmjs.org/@nicolo-ribaudo/eslint-scope-5-internals/-/eslint-scope-5-internals-5.1.1-v1.tgz", "integrity": "sha512-54/JRvkLIzzDWshCWfuhadfrfZVPiElY8Fcgmg1HroEly/EDSszzhBAsarCux+D/kOslTRquNzuyGSmUSTTHGg==", "dev": true, - "peer": true, "requires": { "eslint-scope": "5.1.1" } @@ -18052,7 +18018,8 @@ "@types/node": { "version": "17.0.45", "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.45.tgz", - "integrity": "sha512-w+tIMs3rq2afQdsPJlODhoUEKzFP1ayaoyl1CcnwtIlsVe7K7bA1NGm4s3PraqTLlXnbIN84zuBlxBWo1u9BLw==" + "integrity": "sha512-w+tIMs3rq2afQdsPJlODhoUEKzFP1ayaoyl1CcnwtIlsVe7K7bA1NGm4s3PraqTLlXnbIN84zuBlxBWo1u9BLw==", + "peer": true }, "@types/node-fetch": { "version": "2.6.2", @@ -18089,6 +18056,7 @@ "version": "18.0.21", "resolved": "https://registry.npmjs.org/@types/react/-/react-18.0.21.tgz", "integrity": "sha512-7QUCOxvFgnD5Jk8ZKlUAhVcRj7GuJRjnjjiY/IUBWKgOlnvDvTMLD4RTF7NPyVmbRhNrbomZiOepg7M/2Kj1mA==", + "peer": true, "requires": { "@types/prop-types": "*", "@types/scheduler": "*", @@ -18178,6 +18146,7 @@ "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.40.1.tgz", "integrity": "sha512-IK6x55va5w4YvXd4b3VrXQPldV9vQTxi5ov+g4pMANsXPTXOcfjx08CRR1Dfrcc51syPtXHF5bgLlMHYFrvQtg==", "dev": true, + "peer": true, "requires": { "@typescript-eslint/scope-manager": "5.40.1", "@typescript-eslint/types": "5.40.1", @@ -18346,7 +18315,8 @@ "version": "8.8.0", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.0.tgz", "integrity": "sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w==", - "dev": true + "dev": true, + "peer": true }, "acorn-jsx": { "version": "5.3.2", @@ -18437,7 +18407,6 @@ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", "dev": true, - "peer": true, "requires": { "color-convert": "^1.9.0" } @@ -18456,6 +18425,7 @@ "version": "3.36.3", "resolved": "https://registry.npmjs.org/apexcharts/-/apexcharts-3.36.3.tgz", "integrity": "sha512-8/FXEs0ohXMff07Gv28XjhPwEJphIUdq2/wii/pcvi54Tw6z1mjrV8ydN8rlWi/ve8BAPBefJkLmRWv7UOBsLw==", + "peer": true, "requires": { "svg.draggable.js": "^2.2.2", "svg.easing.js": "^2.0.0", @@ -18748,6 +18718,11 @@ "readable-stream": "^3.4.0" } }, + "bottleneck": { + "version": "2.19.5", + "resolved": "https://registry.npmjs.org/bottleneck/-/bottleneck-2.19.5.tgz", + "integrity": "sha512-VHiNCbI1lKdl44tGrhNfU3lup0Tj/ZBMJB5/2ZbNXRCPuRCO7ed2mgcK4r17y+KB2EfuYuRaVlwNbAeaWGSpbw==" + }, "brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -18771,6 +18746,7 @@ "version": "4.21.4", "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.4.tgz", "integrity": "sha512-CBHJJdDmgjl3daYjN5Cp5kbTf1mUhZoS+beLklHIvkOWscs83YAhLlF3Wsh/lciQYAcbBJgTOD44VtG31ZM4Hw==", + "peer": true, "requires": { "caniuse-lite": "^1.0.30001400", "electron-to-chromium": "^1.4.251", @@ -18854,9 +18830,9 @@ "integrity": "sha512-dU+Tx2fsypxTgtLoE36npi3UqcjSSMNYfkqgmoEhtZrraP5VWq0K7FkWVTYa8eMPtnU/G2txVsfdCJTn9uzpuQ==" }, "caniuse-lite": { - "version": "1.0.30001431", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001431.tgz", - "integrity": "sha512-zBUoFU0ZcxpvSt9IU66dXVT/3ctO1cy4y9cscs1szkPlcWb6pasYM144GqrUygUbT+k7cmUCW61cvskjcv0enQ==" + "version": "1.0.30001766", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001766.tgz", + "integrity": "sha512-4C0lfJ0/YPjJQHagaE9x2Elb69CIqEPZeG0anQt9SIvIoOH4a4uaRl73IavyO+0qZh6MDLH//DrXThEYKHkmYA==" }, "capital-case": { "version": "1.0.4", @@ -18887,7 +18863,6 @@ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "dev": true, - "peer": true, "requires": { "ansi-styles": "^3.2.1", "escape-string-regexp": "^1.0.5", @@ -19049,7 +19024,6 @@ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", "dev": true, - "peer": true, "requires": { "color-name": "1.1.3" } @@ -19058,8 +19032,7 @@ "version": "1.1.3", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true, - "peer": true + "dev": true }, "colorette": { "version": "2.0.19", @@ -19135,6 +19108,7 @@ "version": "7.0.1", "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.0.1.tgz", "integrity": "sha512-a1YWNUV2HwGimB7dU2s1wUMurNKjpx60HxBB6xUM8Re+2s1g1IIfJvFR0/iCF+XHdE0GMTKTuLR32UQff4TEyQ==", + "peer": true, "requires": { "@types/parse-json": "^4.0.0", "import-fresh": "^3.2.1", @@ -19584,6 +19558,7 @@ "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.25.0.tgz", "integrity": "sha512-DVlJOZ4Pn50zcKW5bYH7GQK/9MsoQG2d5eDH0ebEkE8PbgzTTmtt/VTH9GGJ4BfeZCpBLqFfvsjX35UacUL83A==", "dev": true, + "peer": true, "requires": { "@eslint/eslintrc": "^1.3.3", "@humanwhocodes/config-array": "^0.10.5", @@ -19805,6 +19780,7 @@ "resolved": "https://registry.npmjs.org/eslint-plugin-babel/-/eslint-plugin-babel-5.3.1.tgz", "integrity": "sha512-VsQEr6NH3dj664+EyxJwO4FCYm/00JhYb3Sk3ft8o+fpKuIfQ9TaW6uVUfvwMXHcf/lsnRIoyFPsLMyiWCSL/g==", "dev": true, + "peer": true, "requires": { "eslint-rule-composer": "^0.3.0" } @@ -19867,6 +19843,7 @@ "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.26.0.tgz", "integrity": "sha512-hYfi3FXaM8WPLf4S1cikh/r4IxnO6zrhZbEGz2b660EJRbuxgpDS5gkCuYgGWg2xxh2rBuIr4Pvhve/7c31koA==", "dev": true, + "peer": true, "requires": { "array-includes": "^3.1.4", "array.prototype.flat": "^1.2.5", @@ -19914,6 +19891,7 @@ "resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.6.1.tgz", "integrity": "sha512-sXgFVNHiWffBq23uiS/JaP6eVR622DqwB4yTzKvGZGcPq6/yZ3WmOZfuBks/vHWo9GaFOqC2ZK4i6+C35knx7Q==", "dev": true, + "peer": true, "requires": { "@babel/runtime": "^7.18.9", "aria-query": "^4.2.2", @@ -19943,6 +19921,7 @@ "resolved": "https://registry.npmjs.org/eslint-plugin-node/-/eslint-plugin-node-11.1.0.tgz", "integrity": "sha512-oUwtPJ1W0SKD0Tr+wqu92c5xuCeQqB3hSCHasn/ZgjFdA9iDGNkNf2Zi9ztY7X+hNuMib23LNGRm6+uN+KLE3g==", "dev": true, + "peer": true, "requires": { "eslint-plugin-es": "^3.0.0", "eslint-utils": "^2.0.0", @@ -19974,6 +19953,7 @@ "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.31.10.tgz", "integrity": "sha512-e4N/nc6AAlg4UKW/mXeYWd3R++qUano5/o+t+wnWxIf+bLsOaH3a4q74kX3nDjYym3VBN4HyO9nEn1GcAqgQOA==", "dev": true, + "peer": true, "requires": { "array-includes": "^3.1.5", "array.prototype.flatmap": "^1.3.0", @@ -20042,29 +20022,25 @@ "version": "6.4.2", "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.2.tgz", "integrity": "sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ==", - "dev": true, - "peer": true + "dev": true }, "ansi-escapes": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz", "integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==", - "dev": true, - "peer": true + "dev": true }, "ansi-regex": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.1.tgz", "integrity": "sha512-+O9Jct8wf++lXxxFc4hc8LsjaSq0HFzzL7cVsw8pRDIPdjKD2mT4ytDZlLuSBZ4cLKZFXIrMGO7DbQCtMJJMKw==", - "dev": true, - "peer": true + "dev": true }, "argparse": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", "dev": true, - "peer": true, "requires": { "sprintf-js": "~1.0.2" } @@ -20074,7 +20050,6 @@ "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", "integrity": "sha512-8lgKz8LmCRYZZQDpRyT2m5rKJ08TnU4tR9FFFW2rxpxR1FzWi4PQ/NfyODchAatHaUgnSPVcx/R5w6NuTBzFiw==", "dev": true, - "peer": true, "requires": { "restore-cursor": "^2.0.0" } @@ -20083,15 +20058,13 @@ "version": "2.2.1", "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.1.tgz", "integrity": "sha512-GRMWDxpOB6Dgk2E5Uo+3eEBvtOOlimMmpbFiKuLFnQzYDavtLFY3K5ona41jgN/WdRZtG7utuVSVTL4HbZHGkw==", - "dev": true, - "peer": true + "dev": true }, "cross-spawn": { "version": "6.0.5", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", "dev": true, - "peer": true, "requires": { "nice-try": "^1.0.4", "path-key": "^2.0.1", @@ -20172,7 +20145,6 @@ "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-4.0.3.tgz", "integrity": "sha512-p7VutNr1O/QrxysMo3E45FjYDTeXBy0iTltPFNSqKAIfjDSXC+4dj+qfyuD8bfAXrW/y6lW3O76VaYNPKfpKrg==", "dev": true, - "peer": true, "requires": { "esrecurse": "^4.1.0", "estraverse": "^4.1.1" @@ -20183,7 +20155,6 @@ "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-1.4.3.tgz", "integrity": "sha512-fbBN5W2xdY45KulGXmLHZ3c3FHfVYmKg0IrAKGOkT/464PQsx2UeIzfz1RmEci+KLm1bBaAzZAh8+/E+XAeZ8Q==", "dev": true, - "peer": true, "requires": { "eslint-visitor-keys": "^1.1.0" } @@ -20192,15 +20163,13 @@ "version": "1.3.0", "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", - "dev": true, - "peer": true + "dev": true }, "espree": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/espree/-/espree-5.0.1.tgz", "integrity": "sha512-qWAZcWh4XE/RwzLJejfcofscgMc9CamR6Tn1+XRXNzrvUSSbiAjGOI/fggztjIi7y9VLPqnICMIPiGyr8JaZ0A==", "dev": true, - "peer": true, "requires": { "acorn": "^6.0.7", "acorn-jsx": "^5.0.0", @@ -20211,15 +20180,13 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "dev": true, - "peer": true + "dev": true }, "figures": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz", "integrity": "sha512-Oa2M9atig69ZkfwiApY8F2Yy+tzMbazyvqv21R0NsSC8floSOC09BbT1ITWAdoMGQvJ/aZnR1KMwdx9tvHnTNA==", "dev": true, - "peer": true, "requires": { "escape-string-regexp": "^1.0.5" } @@ -20229,7 +20196,6 @@ "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-5.0.1.tgz", "integrity": "sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g==", "dev": true, - "peer": true, "requires": { "flat-cache": "^2.0.1" } @@ -20239,7 +20205,6 @@ "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-2.0.1.tgz", "integrity": "sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA==", "dev": true, - "peer": true, "requires": { "flatted": "^2.0.0", "rimraf": "2.6.3", @@ -20250,22 +20215,19 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.2.tgz", "integrity": "sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA==", - "dev": true, - "peer": true + "dev": true }, "ignore": { "version": "4.0.6", "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", - "dev": true, - "peer": true + "dev": true }, "inquirer": { "version": "6.5.2", "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-6.5.2.tgz", "integrity": "sha512-cntlB5ghuB0iuO65Ovoi8ogLHiWGs/5yNrtUcKjFhSSiVeAIVpD7koaSU9RM8mpXw5YDi9RdYXGQMaOURB7ycQ==", "dev": true, - "peer": true, "requires": { "ansi-escapes": "^3.2.0", "chalk": "^2.4.2", @@ -20286,15 +20248,13 @@ "version": "4.1.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz", "integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==", - "dev": true, - "peer": true + "dev": true }, "strip-ansi": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", "dev": true, - "peer": true, "requires": { "ansi-regex": "^4.1.0" } @@ -20305,15 +20265,13 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", "integrity": "sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w==", - "dev": true, - "peer": true + "dev": true }, "js-yaml": { "version": "3.14.1", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", "dev": true, - "peer": true, "requires": { "argparse": "^1.0.7", "esprima": "^4.0.0" @@ -20324,7 +20282,6 @@ "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", "integrity": "sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA==", "dev": true, - "peer": true, "requires": { "prelude-ls": "~1.1.2", "type-check": "~0.3.2" @@ -20334,15 +20291,13 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==", - "dev": true, - "peer": true + "dev": true }, "mkdirp": { "version": "0.5.6", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", "dev": true, - "peer": true, "requires": { "minimist": "^1.2.6" } @@ -20351,15 +20306,13 @@ "version": "0.0.7", "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz", "integrity": "sha512-r65nCZhrbXXb6dXOACihYApHw2Q6pV0M3V0PSxd74N0+D8nzAdEAITq2oAjA1jVnKI+tGvEBUpqiMh0+rW6zDQ==", - "dev": true, - "peer": true + "dev": true }, "onetime": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", "integrity": "sha512-oyyPpiMaKARvvcgip+JV+7zci5L8D1W9RZIz2l1o08AM3pfspitVWnPt3mzHcBPp12oYMTy0pqrFs/C+m3EwsQ==", "dev": true, - "peer": true, "requires": { "mimic-fn": "^1.0.0" } @@ -20369,7 +20322,6 @@ "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", "dev": true, - "peer": true, "requires": { "deep-is": "~0.1.3", "fast-levenshtein": "~2.0.6", @@ -20383,29 +20335,25 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", "integrity": "sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==", - "dev": true, - "peer": true + "dev": true }, "prelude-ls": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", "integrity": "sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==", - "dev": true, - "peer": true + "dev": true }, "regexpp": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-2.0.1.tgz", "integrity": "sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw==", - "dev": true, - "peer": true + "dev": true }, "restore-cursor": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", "integrity": "sha512-6IzJLuGi4+R14vwagDHX+JrXmPVtPpn4mffDJ1UdR7/Edm87fl6yi8mMBIVvFtJaNTUvjughmW4hwLhRG7gC1Q==", "dev": true, - "peer": true, "requires": { "onetime": "^2.0.0", "signal-exit": "^3.0.2" @@ -20416,7 +20364,6 @@ "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", "dev": true, - "peer": true, "requires": { "glob": "^7.1.3" } @@ -20426,7 +20373,6 @@ "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", "dev": true, - "peer": true, "requires": { "tslib": "^1.9.0" } @@ -20435,15 +20381,13 @@ "version": "5.7.1", "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true, - "peer": true + "dev": true }, "shebang-command": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", "integrity": "sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==", "dev": true, - "peer": true, "requires": { "shebang-regex": "^1.0.0" } @@ -20452,15 +20396,13 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", "integrity": "sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==", - "dev": true, - "peer": true + "dev": true }, "string-width": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", "dev": true, - "peer": true, "requires": { "is-fullwidth-code-point": "^2.0.0", "strip-ansi": "^4.0.0" @@ -20471,7 +20413,6 @@ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", "integrity": "sha512-4XaJ2zQdCzROZDivEVIDPkcQn8LMFSa8kj8Gxb/Lnwzv9A8VctNZ+lfivC/sV3ivW8ElJTERXZoPBRrZKkNKow==", "dev": true, - "peer": true, "requires": { "ansi-regex": "^3.0.0" } @@ -20480,22 +20421,19 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", - "dev": true, - "peer": true + "dev": true }, "tslib": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "dev": true, - "peer": true + "dev": true }, "type-check": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", "integrity": "sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg==", "dev": true, - "peer": true, "requires": { "prelude-ls": "~1.1.2" } @@ -20505,7 +20443,6 @@ "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", "dev": true, - "peer": true, "requires": { "isexe": "^2.0.0" } @@ -20871,8 +20808,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", "integrity": "sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==", - "dev": true, - "peer": true + "dev": true }, "functions-have-names": { "version": "1.2.3", @@ -20979,7 +20915,8 @@ "graphql": { "version": "16.6.0", "resolved": "https://registry.npmjs.org/graphql/-/graphql-16.6.0.tgz", - "integrity": "sha512-KPIBPDlW7NxrbT/eh4qPXz5FiFdL5UbaA0XUNz2Rp3Z3hqBSkbj0GVjwFDztsWVauZUWsbKHgMg++sk8UX0bkw==" + "integrity": "sha512-KPIBPDlW7NxrbT/eh4qPXz5FiFdL5UbaA0XUNz2Rp3Z3hqBSkbj0GVjwFDztsWVauZUWsbKHgMg++sk8UX0bkw==", + "peer": true }, "graphql-config": { "version": "4.3.6", @@ -21055,6 +20992,7 @@ "resolved": "https://registry.npmjs.org/graphql-ws/-/graphql-ws-5.11.2.tgz", "integrity": "sha512-4EiZ3/UXYcjm+xFGP544/yW1+DVI8ZpKASFbzrV5EDTFWJp0ZvLl4Dy2fSZAzz9imKp5pZMIcjB0x/H69Pv/6w==", "devOptional": true, + "peer": true, "requires": {} }, "gray-matter": { @@ -22528,6 +22466,7 @@ "version": "12.3.1", "resolved": "https://registry.npmjs.org/next/-/next-12.3.1.tgz", "integrity": "sha512-l7bvmSeIwX5lp07WtIiP9u2ytZMv7jIeB8iacR28PuUEFG5j0HGAPnMqyG5kbZNBG2H7tRsrQ4HCjuMOPnANZw==", + "peer": true, "requires": { "@next/env": "12.3.1", "@next/swc-android-arm-eabi": "12.3.1", @@ -22608,8 +22547,7 @@ "version": "1.0.5", "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", - "dev": true, - "peer": true + "dev": true }, "no-case": { "version": "3.0.4", @@ -22646,13 +22584,6 @@ "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.6.tgz", "integrity": "sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg==" }, - "nodemailer": { - "version": "6.8.0", - "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-6.8.0.tgz", - "integrity": "sha512-EjYvSmHzekz6VNkNd12aUqAco+bOkRe3Of5jVhltqKhEsjw/y0PYPJfp83+s9Wzh1dspYAkUW/YNQ350NATbSQ==", - "optional": true, - "peer": true - }, "normalize-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", @@ -23003,8 +22934,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", "integrity": "sha512-DUWJr3+ULp4zXmol/SZkFf3JGsS9/SIv+Y3Rt93/UjPpDpklB5f1er4O3POIbUuUJ3FXgqte2Q7SrU6zAqwk8w==", - "dev": true, - "peer": true + "dev": true }, "path-key": { "version": "3.1.1", @@ -23070,6 +23000,7 @@ "version": "8.4.19", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.19.tgz", "integrity": "sha512-h+pbPsyhlYj6N2ozBmHhHrs9DzGmbaarbLvWipMRO7RLS+v4onj26MPFXA5OBYFxyqYhUJK456SwDcY9H2/zsA==", + "peer": true, "requires": { "nanoid": "^3.3.4", "picocolors": "^1.0.0", @@ -23133,7 +23064,8 @@ "preact": { "version": "10.11.2", "resolved": "https://registry.npmjs.org/preact/-/preact-10.11.2.tgz", - "integrity": "sha512-skAwGDFmgxhq1DCBHke/9e12ewkhc7WYwjuhHB8HHS8zkdtITXLRmUMTeol2ldxvLwYtwbFeifZ9uDDWuyL4Iw==" + "integrity": "sha512-skAwGDFmgxhq1DCBHke/9e12ewkhc7WYwjuhHB8HHS8zkdtITXLRmUMTeol2ldxvLwYtwbFeifZ9uDDWuyL4Iw==", + "peer": true }, "preact-render-to-string": { "version": "5.2.5", @@ -23153,7 +23085,8 @@ "version": "2.7.1", "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.7.1.tgz", "integrity": "sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g==", - "dev": true + "dev": true, + "peer": true }, "prettier-plugin-tailwindcss": { "version": "0.1.13", @@ -23171,8 +23104,7 @@ "version": "2.0.3", "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", - "dev": true, - "peer": true + "dev": true }, "promise": { "version": "7.3.1", @@ -23249,6 +23181,7 @@ "version": "18.2.0", "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz", "integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==", + "peer": true, "requires": { "loose-envify": "^1.1.0" } @@ -23273,6 +23206,7 @@ "version": "18.2.0", "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz", "integrity": "sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==", + "peer": true, "requires": { "loose-envify": "^1.1.0", "scheduler": "^0.23.0" @@ -23347,8 +23281,7 @@ "react-is": { "version": "18.2.0", "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", - "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", - "peer": true + "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==" }, "react-lite-youtube-embed": { "version": "2.3.52", @@ -24048,6 +23981,7 @@ "version": "5.3.11", "resolved": "https://registry.npmjs.org/styled-components/-/styled-components-5.3.11.tgz", "integrity": "sha512-uuzIIfnVkagcVHv9nE0VPlHPSCmXIUGKfJ42LNjxCCTDTL5sgnJ8Z7GZBq0EnLYGln77tPpEpExt2+qa+cZqSw==", + "peer": true, "requires": { "@babel/helper-module-imports": "^7.0.0", "@babel/traverse": "^7.4.5", @@ -24078,6 +24012,7 @@ "version": "5.1.5", "resolved": "https://registry.npmjs.org/styled-system/-/styled-system-5.1.5.tgz", "integrity": "sha512-7VoD0o2R3RKzOzPK0jYrVnS8iJdfkKsQJNiLRDjikOpQVqQHns/DXWaPZOH4tIKkhAT7I6wIsy9FWTWh2X3q+A==", + "peer": true, "requires": { "@styled-system/background": "^5.1.2", "@styled-system/border": "^5.1.5", @@ -24204,7 +24139,6 @@ "resolved": "https://registry.npmjs.org/table/-/table-5.4.6.tgz", "integrity": "sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug==", "dev": true, - "peer": true, "requires": { "ajv": "^6.10.2", "lodash": "^4.17.14", @@ -24216,36 +24150,31 @@ "version": "4.1.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz", "integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==", - "dev": true, - "peer": true + "dev": true }, "astral-regex": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz", "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==", - "dev": true, - "peer": true + "dev": true }, "emoji-regex": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", - "dev": true, - "peer": true + "dev": true }, "is-fullwidth-code-point": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", "integrity": "sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w==", - "dev": true, - "peer": true + "dev": true }, "slice-ansi": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz", "integrity": "sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ==", "dev": true, - "peer": true, "requires": { "ansi-styles": "^3.2.0", "astral-regex": "^1.0.0", @@ -24257,7 +24186,6 @@ "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", "dev": true, - "peer": true, "requires": { "emoji-regex": "^7.0.1", "is-fullwidth-code-point": "^2.0.0", @@ -24269,7 +24197,6 @@ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", "dev": true, - "peer": true, "requires": { "ansi-regex": "^4.1.0" } @@ -24427,6 +24354,7 @@ "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz", "integrity": "sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==", "dev": true, + "peer": true, "requires": { "@cspotcode/source-map-support": "^0.8.0", "@tsconfig/node10": "^1.0.7", @@ -24506,7 +24434,8 @@ "typescript": { "version": "4.8.4", "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.8.4.tgz", - "integrity": "sha512-QCh+85mCy+h0IGff8r5XWzOVSbBO+KfeYrMQh7NJ58QujwcE22u+NUSmUxqF+un70P9GXKxa2HCNiTTMJknyjQ==" + "integrity": "sha512-QCh+85mCy+h0IGff8r5XWzOVSbBO+KfeYrMQh7NJ58QujwcE22u+NUSmUxqF+un70P9GXKxa2HCNiTTMJknyjQ==", + "peer": true }, "ua-parser-js": { "version": "0.7.32", @@ -24905,7 +24834,6 @@ "resolved": "https://registry.npmjs.org/write/-/write-1.0.3.tgz", "integrity": "sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig==", "dev": true, - "peer": true, "requires": { "mkdirp": "^0.5.1" }, @@ -24915,7 +24843,6 @@ "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", "dev": true, - "peer": true, "requires": { "minimist": "^1.2.6" } @@ -24927,6 +24854,7 @@ "resolved": "https://registry.npmjs.org/ws/-/ws-8.9.0.tgz", "integrity": "sha512-Ja7nszREasGaYUYCI2k4lCKIRTt+y7XuqVoHR44YpI49TtryyqbqvDMn5eqfW7e6HzTukDRIsXqzVHScqRcafg==", "dev": true, + "peer": true, "requires": {} }, "xtend": { diff --git a/package.json b/package.json index 5bae917..caae082 100644 --- a/package.json +++ b/package.json @@ -20,7 +20,7 @@ "lint": "eslint . --ignore-path .gitignore", "lint:fix": "npm run lint -- --fix", "lint:quiet": "npm run lint -- --quiet", - "prettier": "prettier \"*.@(js|ts|jsx|tsx|json|md)\" \"@(components|lib|pages|scripts|server|test|stories)/**/*.@(js|json|md|mdx)\"", + "prettier": "prettier \"*.@(js|ts|jsx|tsx|json|md|mdx)\" \"@(components|lib|pages|scripts|server|test|stories)/**/*.@(js|ts|jsx|tsx|json|md|mdx)\"", "prettier:check": "npm run prettier -- --check", "prettier:write": "npm run prettier -- --write", "start": "next start", @@ -40,6 +40,7 @@ "babel-plugin-formatjs": "^10.3.31", "babel-plugin-react-remove-properties": "^0.3.0", "babel-plugin-transform-react-remove-prop-types": "^0.4.24", + "bottleneck": "^2.19.5", "class-variance-authority": "^0.3.0", "dayjs": "^1.11.6", "deepmerge": "4.2.2", diff --git a/pages/[slug].tsx b/pages/[slug].tsx index 3e7bdf6..b1b2ed6 100644 --- a/pages/[slug].tsx +++ b/pages/[slug].tsx @@ -36,7 +36,7 @@ export const getStaticProps: GetStaticProps = async ({ params }) => { name: collective.name, slug: collective.slug, imageUrl: collective.imageUrl.replace('-staging', ''), - host: { name: collective.host.name, slug: collective.host.slug }, + host: collective.host ? { name: collective.host.name, slug: collective.host.slug } : null, tags: transformTags(collective), stats: collective.stats, ...(location && { location }), diff --git a/public/gift-collective-logo.png b/public/gift-collective-logo.png new file mode 100644 index 0000000..ca28def Binary files /dev/null and b/public/gift-collective-logo.png differ diff --git a/public/raft-logo.png b/public/raft-logo.png new file mode 100644 index 0000000..5543757 Binary files /dev/null and b/public/raft-logo.png differ diff --git a/public/social-change-nest-logo.png b/public/social-change-nest-logo.png new file mode 100644 index 0000000..2685c00 Binary files /dev/null and b/public/social-change-nest-logo.png differ diff --git a/scripts/fetch-data.ts b/scripts/fetch-data.ts index 5a5ef88..3a4c387 100644 --- a/scripts/fetch-data.ts +++ b/scripts/fetch-data.ts @@ -7,6 +7,7 @@ import dayjsPluginUTC from 'dayjs/plugin/utc'; import dotenv from 'dotenv'; import nodeFetch from 'node-fetch'; +import { additionalCollectiveSlugs } from '../lib/additional-collectives'; import { hosts } from '../lib/hosts'; // Load environment @@ -19,109 +20,229 @@ for (const env of ['local', process.env.NODE_ENV || 'development']) { } import { initializeApollo } from '../lib/apollo-client'; -import { accountsQuery, totalCountQuery } from '../lib/graphql/queries'; +import { accountBySlugQuery, accountsQuery, totalCountQuery } from '../lib/graphql/queries'; +import { rateLimiter } from '../utils/rate-limiter'; import { getAllCollectiveStats } from '../utils/stats'; dayjs.extend(dayjsPluginUTC); dayjs.extend(dayjsPluginIsoWeek); -const apolloClient = initializeApollo({ fetch: nodeFetch }); +function sleep(ms: number) { + return new Promise(resolve => setTimeout(resolve, ms)); +} -async function graphqlRequest(query, variables: any = {}) { - let data; - // retry fetch 5 times +// Wrap fetch to track rate limit headers +const fetchWithRateLimit = async (url, options) => { + const response = await nodeFetch(url, options); + rateLimiter.update(response.headers); + return response; +}; + +const apolloClient = initializeApollo({ fetch: fetchWithRateLimit }); + +const hasValidStats = account => + account.ALL?.totalAmountReceivedTimeSeries && + account.PAST_YEAR?.totalAmountReceivedTimeSeries && + account.PAST_QUARTER?.totalAmountReceivedTimeSeries; + +async function graphqlRequest(query, variables: any = {}): Promise<{ data: any; elapsed: string }> { + await rateLimiter.waitIfNeeded(); + + const maxRetries = 5; + const requestStart = Date.now(); + + try { + for (let attempt = 1; attempt <= maxRetries; attempt++) { + const attemptStart = Date.now(); + try { + const { data } = await apolloClient.query({ query, variables }); + const elapsed = ((Date.now() - requestStart) / 1000).toFixed(2); + return { data, elapsed }; + } catch (error) { + const elapsed = ((Date.now() - attemptStart) / 1000).toFixed(2); + const statusCode = error.networkError?.statusCode || error.statusCode; + const is429 = statusCode === 429 || error.message?.includes('429'); + const bodyText = error.networkError?.bodyText || error.bodyText; + const headers = error.networkError?.response?.headers; + console.error(`Request failed after ${elapsed}s:`, error.message); + console.error(`Variables:`, JSON.stringify(variables)); + if (statusCode) { + console.error(`Status code: ${statusCode}`); + } + if (bodyText) { + console.error(`Response body: ${bodyText.substring(0, 500)}`); + } + if (headers) { + console.error('Response headers:', Object.fromEntries(headers.entries?.() || [])); + } - for (let i = 0; i <= 5; i++) { - try { - if (i === 0) { - ({ data } = await apolloClient.query({ - query, - variables, - })); - } else { - console.log('Retrying with half limit, attempt', i, 'of 5'); - const halfLimit = Math.floor(variables.limit / 2); - const { data: dataFirst } = await apolloClient.query({ - query, - variables: { ...variables, offset: variables.offset, limit: halfLimit }, - }); - console.log('first half success'); - const { data: dataSecond } = await apolloClient.query({ - query, - variables: { ...variables, offset: variables.offset + halfLimit, limit: variables.limit - halfLimit }, - }); - console.log('second half success'); - data = { - accounts: { - nodes: [...dataFirst.accounts.nodes, ...dataSecond.accounts.nodes], - totalCount: dataFirst.accounts.totalCount, - limit: dataFirst.accounts.limit + dataSecond.accounts.limit, - offset: dataFirst.accounts.offset, - }, - }; - } + // Retry on 429 (rate limit) and 503 (server overload) + const is503 = statusCode === 503; + const shouldRetry = (is429 || is503) && attempt < maxRetries; - if (data) { - break; + if (shouldRetry) { + const backoff = is429 ? Math.pow(2, attempt) * 1000 : attempt * 1000; + console.log(`Retrying in ${backoff}ms (attempt ${attempt}/${maxRetries})...`); + await sleep(backoff); + } else { + throw error; + } } - } catch (error) { - console.error('Error while fetching data', error); } - } - if (!data) { - throw new Error('Failed to fetch data'); + throw new Error(`Failed to fetch data after multiple retries`); + } finally { + rateLimiter.done(); } +} - return data; +async function fetchBatchWithSplit(baseVariables: any, offset: number, limit: number, depth = 0): Promise { + const indent = ' '.repeat(depth); + try { + const { data, elapsed } = await graphqlRequest(accountsQuery, { ...baseVariables, offset, limit }); + console.log( + `${indent}Fetched offset ${offset}, limit ${limit}: ${data.accounts.nodes.length} accounts in ${elapsed}s`, + ); + return data.accounts.nodes; + } catch (error) { + if (limit <= 1) { + console.error(`${indent}Failed to fetch single account at offset ${offset}, skipping: ${error.message}`); + return []; + } + // Split the batch in half and retry each half + const half = Math.ceil(limit / 2); + console.log( + `${indent}Splitting batch at offset ${offset} (limit ${limit}) into two halves of ${half} and ${limit - half}`, + ); + const [firstHalf, secondHalf] = await Promise.all([ + fetchBatchWithSplit(baseVariables, offset, half, depth + 1), + fetchBatchWithSplit(baseVariables, offset + half, limit - half, depth + 1), + ]); + return [...firstHalf, ...secondHalf]; + } } async function fetchDataForPage(host) { - const { slug, currency, root } = host; + const { slug, hostSlugs, currency } = host; const quarterFrom = dayjs.utc().subtract(12, 'week').startOf('isoWeek').toISOString(); const quarterTo = dayjs.utc().subtract(1, 'week').endOf('isoWeek').toISOString(); const yearFrom = dayjs.utc().subtract(12, 'month').startOf('month').toISOString(); const yearTo = dayjs.utc().subtract(1, 'month').endOf('month').toISOString(); - const variables = { - ...(root ? { host: host.hostSlugs.map(slug => ({ slug })) } : { host: { slug } }), + const pageSize = 16; + const baseVariables = { + host: hostSlugs ? hostSlugs.map(s => ({ slug: s })) : { slug }, currency, quarterFrom, quarterTo, yearFrom, yearTo, - offset: 0, - limit: 250, }; - let data = await graphqlRequest(accountsQuery, variables); - - if (data.accounts.totalCount > data.accounts.limit) { - let nodes = [...data.accounts.nodes]; - do { - variables.offset += data.accounts.limit; - console.log(`Paginating with offset ${variables.offset}`); - const startTime = Date.now(); - data = await graphqlRequest(accountsQuery, variables); - const endTime = Date.now(); - console.log(`Fetched in ${(endTime - startTime) / 1000} s`); - nodes = [...nodes, ...data.accounts.nodes]; - } while (data.accounts.totalCount > data.accounts.limit + data.accounts.offset); - - data = { - accounts: { - ...data.accounts, - offset: 0, - limit: data.accounts.totalCount, - nodes, - }, - }; + // First request to get total count and first batch + const { data: firstData } = await graphqlRequest(accountsQuery, { ...baseVariables, offset: 0, limit: pageSize }); + const totalCount = firstData.accounts.totalCount; + + console.log(`Total accounts to fetch: ${totalCount} (batch size: ${pageSize})`); + + if (totalCount <= pageSize) { + return firstData; } - if (data) { - return data; + // Calculate remaining batches needed + const remainingCount = totalCount - pageSize; + const remainingBatches = Math.ceil(remainingCount / pageSize); + const batches = Array.from({ length: remainingBatches }, (_, i) => ({ + offset: (i + 1) * pageSize, + limit: Math.min(pageSize, totalCount - (i + 1) * pageSize), + })); + + console.log(`Fetching ${totalCount} accounts in ${remainingBatches + 1} batches`); + + // Fetch all remaining batches concurrently with rate limiting and split-on-failure + const startTime = Date.now(); + const batchResults = await Promise.all( + batches.map(batch => fetchBatchWithSplit(baseVariables, batch.offset, batch.limit)), + ); + const allNodes = [firstData.accounts.nodes, ...batchResults].flat(); + + const elapsed = ((Date.now() - startTime) / 1000).toFixed(2); + console.log(`Total: fetched ${allNodes.length} accounts in ${elapsed}s`); + + return { + accounts: { + ...firstData.accounts, + totalCount, + offset: 0, + limit: totalCount, + nodes: allNodes, + }, + }; +} + +async function fetchAdditionalCollectives(currency: string, existingSlugs: Set) { + const quarterFrom = dayjs.utc().subtract(12, 'week').startOf('isoWeek').toISOString(); + const quarterTo = dayjs.utc().subtract(1, 'week').endOf('isoWeek').toISOString(); + const yearFrom = dayjs.utc().subtract(12, 'month').startOf('month').toISOString(); + const yearTo = dayjs.utc().subtract(1, 'month').endOf('month').toISOString(); + + const slugsToFetch = additionalCollectiveSlugs.filter(slug => !existingSlugs.has(slug)); + + console.log( + `Fetching ${slugsToFetch.length} additional collectives (${ + additionalCollectiveSlugs.length - slugsToFetch.length + } already in host data)`, + ); + + const fetchAccount = async (slug: string) => { + try { + const { data } = await graphqlRequest(accountBySlugQuery, { + slug, + currency, + quarterFrom, + quarterTo, + yearFrom, + yearTo, + }); + return data.account; + } catch (error) { + console.error(`Failed to fetch ${slug}:`, error.message); + return null; + } + }; + + // Progress tracking + let completed = 0; + const total = slugsToFetch.length; + + const results = await Promise.all( + slugsToFetch.map(async slug => { + const result = await fetchAccount(slug); + completed++; + if (completed % 10 === 0 || completed === total) { + console.log(`Progress: ${completed}/${total}`); + } + return result; + }), + ); + + // Filter out null results and accounts without proper stats structure + const collectives = []; + for (let i = 0; i < results.length; i++) { + const account = results[i]; + const slug = slugsToFetch[i]; + if (!account) { + console.warn(`Warning: Account not found: ${slug}`); + } else if (!hasValidStats(account)) { + console.warn(`Warning: Account has incomplete stats data: ${slug}`); + } else { + collectives.push(account); + } } + console.log(`Fetched ${collectives.length} valid collectives out of ${total} slugs`); + + return collectives; } async function run() { @@ -130,9 +251,7 @@ async function run() { data: { accounts: { totalCount }, }, - } = await apolloClient.query({ - query: totalCountQuery, - }); + } = await graphqlRequest(totalCountQuery); const directory = path.join(__dirname, '..', '_data'); @@ -169,6 +288,17 @@ async function run() { const updatedAccounts = { ...data.accounts, nodes: data.accounts.nodes + .filter(account => { + if (!hasValidStats(account)) { + console.warn( + `Warning: Account has incomplete stats data: ${ + account?.slug || account?.name || JSON.stringify(account) + }`, + ); + return false; + } + return true; + }) .map(account => { const stats = getAllCollectiveStats(account); return { @@ -185,6 +315,35 @@ async function run() { }; if (host.root) { + // Fetch additional collectives and merge them into root data + const existingSlugs = new Set(data.accounts.nodes.map(a => a.slug)); + console.log('Fetching additional collectives...'); + const additionalCollectives = await fetchAdditionalCollectives(host.currency, existingSlugs); + + // Process stats for additional collectives and filter those with no activity + const processedAdditional = []; + for (const account of additionalCollectives) { + const stats = getAllCollectiveStats(account); + if (stats) { + processedAdditional.push({ ...account, stats }); + } else { + console.warn(`Warning: Account has no activity: ${account.slug}`); + } + } + + console.log(`Adding ${processedAdditional.length} additional collectives with activity`); + + // Merge additional collectives into root data + data = { + ...data, + accounts: { + ...data.accounts, + totalCount: data.accounts.totalCount + processedAdditional.length, + limit: data.accounts.limit + processedAdditional.length, + nodes: [...data.accounts.nodes, ...processedAdditional], + }, + }; + rootData = data; } } diff --git a/utils/rate-limiter.ts b/utils/rate-limiter.ts new file mode 100644 index 0000000..ec970e8 --- /dev/null +++ b/utils/rate-limiter.ts @@ -0,0 +1,85 @@ +function sleep(ms: number) { + return new Promise(resolve => setTimeout(resolve, ms)); +} + +// Simple API-driven rate limiter that spaces requests evenly across the window +export const rateLimiter = { + remaining: 100, // Local estimate (decremented on start, synced on response) + limit: 100, + minRemaining: 1, // Buffer to avoid hitting exact limit + resetAt: 0, // Unix timestamp in seconds + nextAllowedAt: 0, // Next request allowed at (ms timestamp) + running: 0, + maxConcurrent: 5, + acquireLock: Promise.resolve(), // Serialize acquire calls + + async waitIfNeeded() { + // Serialize access so requests are released one at a time with proper spacing + const previousLock = this.acquireLock; + let releaseLock: () => void; + this.acquireLock = new Promise(resolve => { + releaseLock = resolve; + }); + + await previousLock; + + try { + // Wait if too many concurrent requests + while (this.running >= this.maxConcurrent) { + await sleep(50); + } + + // If rate limit is exhausted, wait for reset + if (this.remaining <= this.minRemaining && this.resetAt > 0) { + const waitMs = this.resetAt * 1000 - Date.now() + 1000; // +1s buffer + if (waitMs > 0) { + // console.log(`[Rate Limit] Waiting ${(waitMs / 1000).toFixed(1)}s for API reset (${this.remaining}/${this.limit} remaining)`); + await sleep(waitMs); + this.remaining = this.limit; + this.nextAllowedAt = 0; + } + } + + // Wait until next allowed time (spaced evenly) + const now = Date.now(); + if (this.nextAllowedAt > now) { + await sleep(this.nextAllowedAt - now); + } + + // Calculate interval for next request + if (this.resetAt > 0 && this.remaining > 0) { + const msUntilReset = this.resetAt * 1000 - Date.now(); + if (msUntilReset > 0) { + const interval = msUntilReset / this.remaining; + this.nextAllowedAt = Date.now() + interval; + } + } + + // Decrement remaining NOW (API counts on receive, not on response) + this.remaining--; + this.running++; + } finally { + releaseLock(); + } + }, + + update(headers: { get: (name: string) => string | null }) { + const remaining = headers.get('x-ratelimit-remaining'); + const limit = headers.get('x-ratelimit-limit'); + const reset = headers.get('x-ratelimit-reset'); + + if (remaining !== null) { + this.remaining = parseInt(remaining); + this.limit = parseInt(limit) || 100; + this.resetAt = parseInt(reset) || 0; + + // const msUntilReset = this.resetAt * 1000 - Date.now(); + // const interval = msUntilReset > 0 && this.remaining > 0 ? (msUntilReset / this.remaining).toFixed(0) : '?'; + // console.log(`[Rate Limit] ${this.remaining}/${this.limit} remaining, ${(msUntilReset / 1000).toFixed(0)}s until reset, ~${interval}ms/req | ${this.running} running`); + } + }, + + done() { + this.running--; + }, +};