commit d60c6ac3bba5164d0db448579efdd4388fe2eee1
Author: Chris Grimmett
Date: Sat Jan 20 08:16:14 2024 -0800
init
diff --git a/.dockerignore b/.dockerignore
new file mode 100644
index 0000000..7da9ff0
--- /dev/null
+++ b/.dockerignore
@@ -0,0 +1,15 @@
+Dockerfile
+.dockerignore
+node_modules
+npm-debug.log
+README.md
+.next
+.git
+LICENSE
+.nvmrc
+CHECKS
+app.json
+.env*
+compose/
+docker-compose.*
+.vscode
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..04a0ccf
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,148 @@
+compose/
+.env
+
+# Created by https://www.toptal.com/developers/gitignore/api/node
+# Edit at https://www.toptal.com/developers/gitignore?templates=node
+
+### Node ###
+# Logs
+logs
+*.log
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+lerna-debug.log*
+.pnpm-debug.log*
+
+# Diagnostic reports (https://nodejs.org/api/report.html)
+report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
+
+# Runtime data
+pids
+*.pid
+*.seed
+*.pid.lock
+
+# Directory for instrumented libs generated by jscoverage/JSCover
+lib-cov
+
+# Coverage directory used by tools like istanbul
+coverage
+*.lcov
+
+# nyc test coverage
+.nyc_output
+
+# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
+.grunt
+
+# Bower dependency directory (https://bower.io/)
+bower_components
+
+# node-waf configuration
+.lock-wscript
+
+# Compiled binary addons (https://nodejs.org/api/addons.html)
+build/Release
+
+# Dependency directories
+node_modules/
+jspm_packages/
+
+# Snowpack dependency directory (https://snowpack.dev/)
+web_modules/
+
+# TypeScript cache
+*.tsbuildinfo
+
+# Optional npm cache directory
+.npm
+
+# Optional eslint cache
+.eslintcache
+
+# Optional stylelint cache
+.stylelintcache
+
+# Microbundle cache
+.rpt2_cache/
+.rts2_cache_cjs/
+.rts2_cache_es/
+.rts2_cache_umd/
+
+# Optional REPL history
+.node_repl_history
+
+# Output of 'npm pack'
+*.tgz
+
+# Yarn Integrity file
+.yarn-integrity
+
+# dotenv environment variable files
+.env
+.env.development.local
+.env.test.local
+.env.production.local
+.env.local
+
+# parcel-bundler cache (https://parceljs.org/)
+.cache
+.parcel-cache
+
+# Next.js build output
+.next
+out
+
+# Nuxt.js build / generate output
+.nuxt
+dist
+
+# Gatsby files
+.cache/
+# Comment in the public line in if your project uses Gatsby and not Next.js
+# https://nextjs.org/blog/next-9-1#public-directory-support
+# public
+
+# vuepress build output
+.vuepress/dist
+
+# vuepress v2.x temp and cache directory
+.temp
+
+# Docusaurus cache and generated files
+.docusaurus
+
+# Serverless directories
+.serverless/
+
+# FuseBox cache
+.fusebox/
+
+# DynamoDB Local files
+.dynamodb/
+
+# TernJS port file
+.tern-port
+
+# Stores VSCode versions used for testing VSCode extensions
+.vscode-test
+
+# yarn v2
+.yarn/cache
+.yarn/unplugged
+.yarn/build-state.yml
+.yarn/install-state.gz
+.pnp.*
+
+### Node Patch ###
+# Serverless Webpack directories
+.webpack/
+
+# Optional stylelint cache
+
+# SvelteKit build / generate output
+.svelte-kit
+
+# End of https://www.toptal.com/developers/gitignore/api/node
+
diff --git a/Dockerfile b/Dockerfile
new file mode 100644
index 0000000..aac7ccf
--- /dev/null
+++ b/Dockerfile
@@ -0,0 +1,19 @@
+FROM node:20-slim AS base
+ENV NEXT_TELEMETRY_DISABLED 1
+RUN corepack enable
+
+FROM base AS build
+WORKDIR /usr/src/fp-monorepo
+RUN mkdir /usr/src/next
+COPY ./pnpm-lock.yaml ./
+COPY ./pnpm-workspace.yaml ./
+COPY ./packages/next/package.json ./packages/next/
+RUN --mount=type=cache,id=pnpm-store,target=/root/.pnpm-store pnpm install
+COPY . .
+RUN pnpm deploy --filter=fp-next /usr/src/next
+
+FROM base AS dev
+WORKDIR /app
+COPY --from=build /usr/src/next /app
+CMD ["pnpm", "run", "dev"]
+
diff --git a/compose.prod.yml b/compose.prod.yml
new file mode 100644
index 0000000..a1c6841
--- /dev/null
+++ b/compose.prod.yml
@@ -0,0 +1,103 @@
+version: '3.4'
+
+
+services:
+
+ link2cid:
+ container_name: fp-link2cid
+ image: insanity54/link2cid:latest
+ ports:
+ - "3939:3939"
+ environment:
+ API_KEY: ${LINK2CID_API_KEY}
+ IPFS_URL: "http://ipfs0:5001"
+
+ ipfs0:
+ container_name: fp-ipfs0
+ image: ipfs/kubo:release
+ ports:
+ - "5001:5001"
+ volumes:
+ - ./packages/ipfs0:/data/ipfs
+
+ cluster0:
+ container_name: fp-cluster0
+ image: ipfs/ipfs-cluster:latest
+ depends_on:
+ - ipfs0
+ environment:
+ CLUSTER_PEERNAME: cluster0
+ CLUSTER_SECRET: ${CLUSTER_SECRET} # From shell variable if set
+ CLUSTER_IPFSHTTP_NODEMULTIADDRESS: /dns4/ipfs0/tcp/5001
+ CLUSTER_CRDT_TRUSTEDPEERS: '*' # Trust all peers in Cluster
+ CLUSTER_RESTAPI_HTTPLISTENMULTIADDRESS: /ip4/0.0.0.0/tcp/9094 # Expose API
+ CLUSTER_RESTAPI_BASICAUTHCREDENTIALS: ${CLUSTER_RESTAPI_BASICAUTHCREDENTIALS}
+ CLUSTER_MONITORPINGINTERVAL: 2s # Speed up peer discovery
+ ports:
+ - "127.0.0.1:9094:9094"
+ volumes:
+ - ./packages/cluster0:/data/ipfs-cluster
+
+ strapi:
+ container_name: fp-strapi
+ image: elestio/strapi-development
+ depends_on:
+ - db
+ environment:
+ ADMIN_PASSWORD: ${STRAPI_ADMIN_PASSWORD}
+ ADMIN_EMAIL: ${STRAPI_ADMIN_EMAIL}
+ BASE_URL: ${STRAPI_BASE_URL}
+ SMTP_HOST: 172.17.0.1
+ SMTP_PORT: 25
+ SMTP_AUTH_STRATEGY: NONE
+ SMTP_FROM_EMAIL: sender@email.com
+ DATABASE_CLIENT: postgres
+ DATABASE_PORT: ${DATABASE_PORT}
+ DATABASE_NAME: ${DATABASE_NAME}
+ DATABASE_USERNAME: ${DATABASE_USERNAME}
+ DATABASE_PASSWORD: ${DATABASE_PASSWORD}
+ JWT_SECRET: ${STRAPI_JWT_SECRET}
+ ADMIN_JWT_SECRET: ${STRAPI_ADMIN_JWT_SECRET}
+ APP_KEYS: ${STRAPI_APP_KEYS}
+ NODE_ENV: development
+ DATABASE_HOST: db
+ API_TOKEN_SALT: ${STRAPI_API_TOKEN_SALT}
+ TRANSFER_TOKEN_SALT: ${STRAPI_TRANSFER_TOKEN_SALT}
+ ports:
+ - "1337:1337"
+ volumes:
+ - ./packages/strapi/config:/opt/app/config
+ - ./packages/strapi/src:/opt/app/src
+ # - ./packages/strapi/package.json:/opt/package.json
+ # - ./packages/strapi/yarn.lock:/opt/yarn.lock
+ - ./packages/strapi/.env:/opt/app/.env
+ - ./packages/strapi/public/uploads:/opt/app/public/uploads
+ # - ./packages/strapi/entrypoint.sh:/opt/app/entrypoint.sh
+
+ next:
+ container_name: fp-next
+ build:
+ context: ./packages/next
+ dockerfile: Dockerfile
+ environment:
+ REVALIDATION_TOKEN: ${NEXT_REVALIDATION_TOKEN}
+ NODE_ENV: production
+ ports:
+ - "3000:3000"
+ volumes:
+ - ./packages/next/
+
+
+ db:
+ container_name: fp-db
+ image: postgres:latest
+ restart: always
+ environment:
+ POSTGRES_DB: ${DATABASE_NAME}
+ POSTGRES_USER: ${DATABASE_USERNAME}
+ POSTGRES_PASSWORD: ${DATABASE_PASSWORD}
+ PGDATA: /var/lib/postgresql/data
+ volumes:
+ - ./packages/db/pgdata:/var/lib/postgresql/data
+ ports:
+ - "5433:5432"
\ No newline at end of file
diff --git a/compose.yml b/compose.yml
new file mode 100644
index 0000000..f220045
--- /dev/null
+++ b/compose.yml
@@ -0,0 +1,190 @@
+version: '3.4'
+
+
+services:
+
+ chisel:
+ container_name: fp-chisel
+ image: jpillora/chisel
+ ports:
+ - "9312:9312"
+ restart: on-failure
+ command: "client --auth=${CHISEL_AUTH} ${CHISEL_SERVER} R:8899:cluster0:9094 R:8901:link2cid:3939 R:8900:strapi:1337 R:8902:next:3000 R:8903:uppy:3020"
+
+ link2cid:
+ container_name: fp-link2cid
+ restart: on-failure
+ image: insanity54/link2cid:latest
+ ports:
+ - "3939:3939"
+ environment:
+ API_KEY: ${LINK2CID_API_KEY}
+ IPFS_URL: "http://ipfs0:5001"
+
+ ipfs0:
+ container_name: fp-ipfs0
+ restart: on-failure
+ image: ipfs/kubo:release
+ ports:
+ - "5001:5001"
+ volumes:
+ - ./compose/ipfs0:/data/ipfs
+
+ cluster0:
+ container_name: fp-cluster0
+ image: ipfs/ipfs-cluster:latest
+ restart: on-failure
+ depends_on:
+ - ipfs0
+ environment:
+ CLUSTER_PEERNAME: cluster0
+ CLUSTER_SECRET: ${CLUSTER_SECRET} # From shell variable if set
+ CLUSTER_IPFSHTTP_NODEMULTIADDRESS: /dns4/ipfs0/tcp/5001
+ CLUSTER_CRDT_TRUSTEDPEERS: '*' # Trust all peers in Cluster
+ CLUSTER_RESTAPI_HTTPLISTENMULTIADDRESS: /ip4/0.0.0.0/tcp/9094 # Expose API
+ CLUSTER_RESTAPI_BASICAUTHCREDENTIALS: ${CLUSTER_RESTAPI_BASICAUTHCREDENTIALS}
+ CLUSTER_MONITORPINGINTERVAL: 2s # Speed up peer discovery
+ ports:
+ - "127.0.0.1:9094:9094"
+ volumes:
+ - ./compose/cluster0:/data/ipfs-cluster
+
+ strapi:
+ container_name: fp-strapi
+ image: fp-strapi:14
+ build:
+ context: ./packages/strapi
+ dockerfile: Dockerfile
+ restart: on-failure
+ depends_on:
+ - db
+ # env_file: ./packages/strapi/.env
+ environment:
+ # ADMIN_PASSWORD: ${STRAPI_ADMIN_PASSWORD}
+ # ADMIN_EMAIL: ${STRAPI_ADMIN_EMAIL}
+ BASE_URL: ${STRAPI_BASE_URL}
+ SMTP_HOST: 172.17.0.1
+ SMTP_PORT: 25
+ SMTP_AUTH_STRATEGY: NONE
+ SMTP_FROM_EMAIL: sender@example.com
+ SENDGRID_API_KEY: ${SENDGRID_API_KEY}
+ DATABASE_CLIENT: postgres
+ DATABASE_HOST: db
+ DATABASE_PORT: ${POSTGRES_PORT}
+ DATABASE_NAME: ${POSTGRES_DB}
+ DATABASE_USERNAME: ${POSTGRES_USER}
+ DATABASE_PASSWORD: ${POSTGRES_PASSWORD}
+ JWT_SECRET: ${STRAPI_JWT_SECRET}
+ ADMIN_JWT_SECRET: ${STRAPI_ADMIN_JWT_SECRET}
+ APP_KEYS: ${STRAPI_APP_KEYS}
+ NODE_ENV: ${NODE_ENV}
+ API_TOKEN_SALT: ${STRAPI_API_TOKEN_SALT}
+ TRANSFER_TOKEN_SALT: ${STRAPI_TRANSFER_TOKEN_SALT}
+ MUX_SIGNING_KEY_PRIVATE_KEY: ${MUX_SIGNING_KEY_PRIVATE_KEY}
+ MUX_SIGNING_KEY_ID: ${MUX_SIGNING_KEY_ID}
+ MUX_PLAYBACK_RESTRICTION_ID: ${MUX_PLAYBACK_RESTRICTION_ID}
+ STRAPI_URL: ${STRAPI_URL}
+ CDN_BUCKET_URL: ${CDN_BUCKET_URL}
+ CDN_BUCKET_USC_URL: ${CDN_BUCKET_USC_URL}
+ S3_USC_BUCKET_KEY_ID: ${S3_USC_BUCKET_KEY_ID}
+ S3_USC_BUCKET_APPLICATION_KEY: ${S3_USC_BUCKET_APPLICATION_KEY}
+ S3_USC_BUCKET_NAME: ${S3_USC_BUCKET_NAME}
+ S3_USC_BUCKET_ENDPOINT: ${S3_USC_BUCKET_ENDPOINT}
+ S3_USC_BUCKET_REGION: ${S3_USC_BUCKET_REGION}
+ AWS_ACCESS_KEY_ID: ${S3_USC_BUCKET_KEY_ID}
+ AWS_SECRET_ACCESS_KEY: ${S3_USC_BUCKET_APPLICATION_KEY}
+
+ ports:
+ - "1337:1337"
+ volumes:
+ - ./packages/strapi/config:/opt/app/config
+ - ./packages/strapi/src:/opt/app/src
+ - ./packages/strapi/database:/opt/app/database
+ - ./packages/strapi/public/uploads:/opt/app/public/uploads
+ - ./packages/strapi/package.json:/opt/app/package.json
+ - ./packages/strapi/yarn.lock:/opt/app/yarn.lock
+ # - ./packages/strapi/.env:/opt/app/.env
+ # - ./packages/strapi/entrypoint.sh:/opt/app/entrypoint.sh
+
+ next:
+ container_name: fp-next
+ build:
+ context: .
+ dockerfile: Dockerfile
+ target: dev
+ restart: on-failure
+ environment:
+ REVALIDATION_TOKEN: ${NEXT_REVALIDATION_TOKEN}
+ NODE_ENV: development
+ NEXT_PUBLIC_STRAPI_URL: ${NEXT_PUBLIC_STRAPI_URL}
+ NEXT_PUBLIC_UPPY_COMPANION_URL: ${NEXT_PUBLIC_UPPY_COMPANION_URL}
+ NEXT_PUBLIC_SITE_URL: ${NEXT_PUBLIC_SITE_URL}
+ ports:
+ - "3000:3000"
+ volumes:
+ # - /app/node_modules
+ # - /app/.next
+ # - /app/.pnpm-store
+ - ./packages/next/app:/app/app
+
+
+ db:
+ container_name: fp-db
+ image: postgres:16
+ restart: on-failure
+ environment:
+ POSTGRES_DB: ${POSTGRES_DB}
+ POSTGRES_USER: ${POSTGRES_USER}
+ POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
+ PGDATA: /var/lib/postgresql/data
+ PGPORT: ${POSTGRES_PORT}
+ volumes:
+ - ./compose/db/pgdata:/var/lib/postgresql/data
+ ports:
+ - "15432:15432"
+
+ pgadmin:
+ container_name: fp-pgadmin
+ image: dpage/pgadmin4:8
+ restart: on-failure
+ environment:
+ PGADMIN_DEFAULT_EMAIL: ${PGADMIN_DEFAULT_EMAIL}
+ PGADMIN_DEFAULT_PASSWORD: ${PGADMIN_DEFAULT_PASSWORD}
+ PGADMIN_DISABLE_POSTFIX: yessir
+ GUNICORN_ACCESS_LOGFILE: /tmp/pgadmin-gunicorn-access.log # this makes console output less noisy
+ ports:
+ - "5050:80"
+
+
+ uppy:
+ container_name: fp-uppy
+ build:
+ context: .
+ dockerfile: ./packages/uppy/Dockerfile
+ target: run
+ restart: on-failure
+ environment:
+ SESSION_SECRET: ${UPPY_SESSION_SECRET}
+ PORT: ${UPPY_PORT}
+ FILEPATH: ${UPPY_FILEPATH}
+ NEXT_PUBLIC_SITE_URL: ${NEXT_PUBLIC_SITE_URL}
+ HOST: ${UPPY_HOST}
+ UPLOAD_URLS: ${UPPY_UPLOAD_URLS}
+ SECRET: ${UPPY_SECRET}
+ SERVER_BASE_URL: ${UPPY_SERVER_BASE_URL}
+ B2_ENDPOINT: ${UPPY_B2_ENDPOINT}
+ B2_BUCKET: ${UPPY_B2_BUCKET}
+ B2_SECRET: ${UPPY_B2_SECRET}
+ B2_KEY: ${UPPY_B2_KEY}
+ B2_REGION: ${UPPY_B2_REGION}
+ DRIVE_KEY: ${UPPY_DRIVE_KEY}
+ DRIVE_SECRET: ${UPPY_DRIVE_SECRET}
+ DROPBOX_KEY: ${UPPY_DROPBOX_KEY}
+ DROPBOX_SECRET: ${UPPY_DROPBOX_SECRET}
+ JWT_SECRET: ${STRAPI_JWT_SECRET} # we use strapi's JWT secret so we can verify that uploads are from account holders
+ STRAPI_API_KEY: ${UPPY_STRAPI_API_KEY}
+ STRAPI_URL: ${UPPY_STRAPI_URL}
+ ports:
+ - "3020:3020"
+ volumes:
+ - ./packages/uppy/index.js:/app/index.js
\ No newline at end of file
diff --git a/packages/next/.eslintrc.json b/packages/next/.eslintrc.json
new file mode 100644
index 0000000..bffb357
--- /dev/null
+++ b/packages/next/.eslintrc.json
@@ -0,0 +1,3 @@
+{
+ "extends": "next/core-web-vitals"
+}
diff --git a/packages/next/.gitignore b/packages/next/.gitignore
new file mode 100644
index 0000000..473707c
--- /dev/null
+++ b/packages/next/.gitignore
@@ -0,0 +1,47 @@
+# Created by https://www.toptal.com/developers/gitignore/api/nextjs
+# Edit at https://www.toptal.com/developers/gitignore?templates=nextjs
+
+
+.vscode/
+
+.env
+.env.*
+dist/
+
+### NextJS ###
+# dependencies
+/node_modules
+/.pnp
+.pnp.js
+
+# testing
+/coverage
+
+# next.js
+/.next/
+/out/
+
+# production
+/build
+
+# misc
+.DS_Store
+*.pem
+
+# debug
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+.pnpm-debug.log*
+
+# local env files
+.env*.local
+
+# vercel
+.vercel
+
+# typescript
+*.tsbuildinfo
+next-env.d.ts
+
+# End of https://www.toptal.com/developers/gitignore/api/nextjs
diff --git a/packages/next/.nvmrc b/packages/next/.nvmrc
new file mode 100644
index 0000000..9de2256
--- /dev/null
+++ b/packages/next/.nvmrc
@@ -0,0 +1 @@
+lts/iron
diff --git a/packages/next/CHECKS b/packages/next/CHECKS
new file mode 100644
index 0000000..6731352
--- /dev/null
+++ b/packages/next/CHECKS
@@ -0,0 +1 @@
+/ futureporn.net
\ No newline at end of file
diff --git a/packages/next/Dockerfile.old b/packages/next/Dockerfile.old
new file mode 100644
index 0000000..98094ed
--- /dev/null
+++ b/packages/next/Dockerfile.old
@@ -0,0 +1,35 @@
+## @greetz https://medium.com/@elifront/best-next-js-docker-compose-hot-reload-production-ready-docker-setup-28a9125ba1dc
+
+FROM node:20-slim AS base
+ENV PNPM_HOME="/pnpm"
+ENV PATH="$PNPM_HOME:$PATH"
+RUN corepack enable
+RUN apt-get update && apt-get install -y -qq dumb-init
+COPY . /app
+WORKDIR /app
+
+
+FROM base AS deps
+RUN --mount=type=cache,id=pnpm,target=/pnpm/store pnpm install --frozen-lockfile
+
+
+FROM base AS taco
+WORKDIR /app
+COPY --from=deps /app/node_modules ./node_modules
+COPY . .
+
+
+FROM deps AS build
+ENV NEXT_TELEMETRY_DISABLED 1
+RUN pnpm run -r build
+
+
+FROM deps AS runner
+ENV NEXT_TELEMETRY_DISABLED 1
+WORKDIR /app
+COPY --from=build /usr/src/app/public ./public
+COPY --from=build /usr/src/app/.next/standalone ./
+COPY --from=build /usr/src/app/.next/static ./.next/static
+EXPOSE 3000
+ENV HOSTNAME="0.0.0.0"
+CMD [ "dumb-init", "node", "server.js" ]
diff --git a/packages/next/LICENSE b/packages/next/LICENSE
new file mode 100644
index 0000000..7c53cea
--- /dev/null
+++ b/packages/next/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2020 Rogier van den Berg
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
\ No newline at end of file
diff --git a/packages/next/README.md b/packages/next/README.md
new file mode 100644
index 0000000..1bd2474
--- /dev/null
+++ b/packages/next/README.md
@@ -0,0 +1,27 @@
+# futureporn-next
+
+## Dev notes
+
+When adding a new module via pnpm, docker compose needs to be restarted or something. I'm not sure the exact steps just yet, but I think it's something like the following.
+
+```
+pnpm add @uppy/react
+docker compose build next
+```
+
+> fp-next | Module not found: Can't resolve '@uppy/react'
+
+hmm... It looks like I'm missing something. Is the new package not getting into the container? Maybe it's something to do with the pnpm cache?
+
+Must we build without cache?
+
+ docker compose build --no-cache next; docker compose up
+
+YES. that solved the issue.
+
+However, it's really slow to purge cache and download all packages once again. Is there a way we can speed this up?
+
+* make it work
+* make it right
+* make it fast
+
diff --git a/packages/next/app.json b/packages/next/app.json
new file mode 100644
index 0000000..31825ab
--- /dev/null
+++ b/packages/next/app.json
@@ -0,0 +1,14 @@
+{
+ "healthchecks": {
+ "web": [
+ {
+ "type": "startup",
+ "name": "web check",
+ "description": "Checking for expecting string at /api",
+ "path": "/api",
+ "content": "Application Programmable Interface",
+ "attempts": 3
+ }
+ ]
+ }
+}
\ No newline at end of file
diff --git a/packages/next/app/about/page.tsx b/packages/next/app/about/page.tsx
new file mode 100644
index 0000000..87de407
--- /dev/null
+++ b/packages/next/app/about/page.tsx
@@ -0,0 +1,64 @@
+import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
+import { faExternalLinkAlt } from "@fortawesome/free-solid-svg-icons";
+import Link from 'next/link';
+// import { getProgress } from '../lib/vods'
+
+export default async function Page() {
+ // const { complete, total } = await getProgress('projektmelody')
+
+ return (
+ <>
+
+
+
+
+
+
About
+
+
Futureporn is a fanmade public archive of NSFW R18 vtuber livestreams.
+
+
+
Mission
+
+
+
It's a lofty goal, but Futureporn aims to become the Galaxy's best VTuber hentai site.
+
+
+
How do we get there?
+
+
+
1. Solve the viewer's common problems
+
+
Viewers want to watch livestream VODs on their own time. Futureporn collects vods from public streams, and caches them for later viewing.
+
+
Viewers want to find content that interests them. Futureporn enables vod tagging for easy browsing.
+
+
+
+
2. Solve the streamer's common problems
+
+
Platforms like PH are not rising to the needs of VTubers. Instead of offering support and resources, they restrict and ban top talent.
+
+
Futureporn is different, embracing the medium and leveraging emerging technologies to amplify VTuber success.
+
+
+
+
3. Scale beyond Earth
+
+
Piggybacking on IPFS' content-addressable capabilities and potential to end 404s, VODs preserved here can withstand the test of time, and eventually persist off-world.
+
+
+
+
+
+
Futureporn needs financial support to continue improving. If you enjoy this website, please consider becoming a patron .
+
+
+
+
+
+
+
+ >
+ )
+}
diff --git a/packages/next/app/api/blogs/route.ts b/packages/next/app/api/blogs/route.ts
new file mode 100644
index 0000000..dca5232
--- /dev/null
+++ b/packages/next/app/api/blogs/route.ts
@@ -0,0 +1,10 @@
+import { NextResponse } from 'next/server'
+
+export async function GET() {
+ const res = await fetch('https://dummyjson.com/posts', {
+ next: { revalidate: 60 },
+ });
+ const data = await res.json();
+
+ return NextResponse.json(data);
+}
diff --git a/packages/next/app/api/page.tsx b/packages/next/app/api/page.tsx
new file mode 100644
index 0000000..f1a47d8
--- /dev/null
+++ b/packages/next/app/api/page.tsx
@@ -0,0 +1,118 @@
+'use client';
+
+import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
+import { faExternalLinkAlt } from "@fortawesome/free-solid-svg-icons";
+import Link from 'next/link'
+import { Highlight, themes } from "prism-react-renderer";
+
+const bootstrapScript = `#!/bin/bash
+
+## bootstrap.sh
+## tested on Ubuntu 22.04
+
+## install dependencies
+cd
+apt install -y screen
+
+## Open necessary firewall ports
+ufw allow 9096/tcp
+ufw allow 9094/tcp
+ufw allow 4001/tcp
+ufw allow 4001/udp
+
+## Download kubo
+wget 'https://dist.ipfs.tech/kubo/v0.24.0/kubo_v0.24.0_linux-amd64.tar.gz'
+tar xvzf ./kubo_v0.24.0_linux-amd64.tar.gz
+chmod +x ./kubo/install.sh
+./kubo/install.sh
+
+## Download ipfs-cluster-follow
+wget 'https://dist.ipfs.tech/ipfs-cluster-follow/v1.0.7/ipfs-cluster-follow_v1.0.7_linux-amd64.tar.gz'
+tar xvzf ./ipfs-cluster-follow_v1.0.7_linux-amd64.tar.gz
+chmod +x ./ipfs-cluster-follow/ipfs-cluster-follow
+mv ./ipfs-cluster-follow/ipfs-cluster-follow /usr/local/bin/
+
+## initialize ipfs
+ipfs init
+
+## run ipfs in a screen session
+screen -d -m ipfs daemon
+
+## run ipfs-cluster-follow
+CLUSTER_PEERNAME="my-cluster-peer-name" ipfs-cluster-follow futureporn.net run --init https://futureporn.net/api/service.json
+`
+
+export default function Page() {
+ return (
+
+
+
Futureporn API
+
Futureporn Application Programmable Interface (API) for developers and power users
+
+
+
+
+
RSS Feed
+
Keep up to date with new VODs using Real Simple Syndication (RSS).
+
+
Don't have a RSS reader? Futureporn recommends Fraidycat
+
+
+
+
+
+
+
+
Data API
+
The Data API contains all the data served by this website in JSON format, including IPFS Content IDs (CID), VOD titles, dates, and stream announcement links.
+
Futureporn API Version 1
+
+
+
+
+
+
IPFS Cluster Template
+
The IPFS Cluster Template allows other IPFS cluster instances to join the Futureporn.net IPFS cluster as a follower peer . Cluster peers automatically pin (replicate) the IPFS content listed on this website.
+
+
Basic instructions are as follows
+
1. Download & install both kubo and ipfs-cluster-follow onto your server.
+
2. Initialize your ipfs repo & start the ipfs daemon
+
3. Join the cluster using ipfs-cluster-follow
+
+
Below is an example bash script to get everything you need to run an IPFS follower peer. This is only an example and may need tweaks to run in your environment.
+
+
+ {({ className, style, tokens, getLineProps, getTokenProps }) => (
+
+ {tokens.map((line, i) => (
+
+ {line.map((token, key) => (
+
+ ))}
+
+ ))}
+
+ )}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ )
+}
\ No newline at end of file
diff --git a/packages/next/app/api/revalidate/route.ts b/packages/next/app/api/revalidate/route.ts
new file mode 100644
index 0000000..bad85ce
--- /dev/null
+++ b/packages/next/app/api/revalidate/route.ts
@@ -0,0 +1,26 @@
+import { NextRequest, NextResponse } from 'next/server';
+import { revalidateTag } from 'next/cache';
+
+export const dynamic = 'force-dynamic';
+
+export async function GET(request: NextRequest) {
+ const token = request.nextUrl.searchParams.get('token')
+ const tag = request.nextUrl.searchParams.get('tag')
+
+
+
+ if (!token) {
+ return NextResponse.json({ message: 'Missing token param' }, { status: 400})
+ }
+
+ if (!tag) {
+ return NextResponse.json({ message: 'Missing tag param' }, { status: 400 })
+ }
+
+ if (token !== process.env.REVALIDATION_TOKEN) {
+ return NextResponse.json({ message: 'Invalid token' }, { status: 401 })
+ }
+
+ revalidateTag(tag)
+ return NextResponse.json({ revalidated: true, now: Date.now() })
+}
\ No newline at end of file
diff --git a/packages/next/app/api/service.json/route.ts b/packages/next/app/api/service.json/route.ts
new file mode 100644
index 0000000..9aed096
--- /dev/null
+++ b/packages/next/app/api/service.json/route.ts
@@ -0,0 +1,139 @@
+import { NextResponse } from 'next/server'
+
+
+const serviceConfig = {
+ "cluster": {
+ "peername": "replace-this-with-a-super-cool-peer-name",
+ "secret": "3acade7f761c91f5fe3d34c4f4d15a17f817bc3463ab4395958f302b222a023b",
+ "leave_on_shutdown": false,
+ "listen_multiaddress": [
+ "/ip4/0.0.0.0/tcp/9096"
+ ],
+ "connection_manager": {
+ "high_water": 400,
+ "low_water": 100,
+ "grace_period": "2m0s"
+ },
+ "dial_peer_timeout": "3s",
+ "state_sync_interval": "10m",
+ "pin_recover_interval": "12m",
+ "ipfs_sync_interval": "130s",
+ "replication_factor_min": -1,
+ "replication_factor_max": -1,
+ "monitor_ping_interval": "30s",
+ "peer_watch_interval": "10s",
+ "mdns_interval": "10s",
+ "disable_repinning": true,
+ "follower_mode": true,
+ "peer_addresses": [
+ "/dns4/cluster.sbtp.xyz/tcp/9096/p2p/12D3KooWJmCsFadow1UvqAqCGtuKpqrS3puyPUYujJj4dRRCTfXf"
+ ]
+ },
+ "consensus": {
+ "crdt": {
+ "cluster_name": "futureporn.net",
+ "trusted_peers": [
+ "12D3KooWJmCsFadow1UvqAqCGtuKpqrS3puyPUYujJj4dRRCTfXf"
+ ],
+ "rebroadcast_interval": "1m",
+ "peerset_metric": "ping",
+ "batching": {
+ "max_batch_size": 0,
+ "max_batch_age": "0s",
+ "max_queue_size": 50000
+ }
+ }
+ },
+ "ipfs_connector": {
+ "ipfshttp": {
+ "node_multiaddress": "/ip4/127.0.0.1/tcp/5001",
+ "connect_swarms_delay": "30s",
+ "ipfs_request_timeout": "5m",
+ "repogc_timeout": "24h",
+ "pin_timeout": "3m",
+ "unpin_timeout": "3h",
+ "unpin_disable": false
+ }
+ },
+ "pin_tracker": {
+ "stateless": {
+ "max_pin_queue_size": 1000000,
+ "concurrent_pins": 8,
+ "priority_pin_max_age" : "24h",
+ "priority_pin_max_retries" : 5
+ }
+ },
+ "monitor": {
+ "pubsubmon": {
+ "check_interval": "15s",
+ "failure_threshold": 3
+ }
+ },
+ "informer": {
+ "disk": {
+ "metric_ttl": "5m",
+ "metric_type": "freespace"
+ },
+ "tags": {
+ "metric_ttl": "30s",
+ "tags": {}
+ }
+ },
+ "allocator": {
+ "balanced": {
+ "allocate_by": ["freespace"]
+ }
+ },
+ "observations": {
+ "metrics": {
+ "enable_stats": false,
+ "prometheus_endpoint": "/ip4/0.0.0.0/tcp/8888",
+ "reporting_interval": "2s"
+ },
+ "tracing": {
+ "enable_tracing": false,
+ "jaeger_agent_endpoint": "/ip4/0.0.0.0/udp/6831",
+ "sampling_prob": 0.3,
+ "service_name": "cluster-daemon"
+ }
+ },
+ "datastore": {
+ "badger": {
+ "gc_discard_ratio": 0.2,
+ "gc_interval": "15m0s",
+ "gc_sleep": "10s",
+ "badger_options": {
+ "dir": "",
+ "value_dir": "",
+ "sync_writes": true,
+ "table_loading_mode": 0,
+ "value_log_loading_mode": 0,
+ "num_versions_to_keep": 1,
+ "max_table_size": 67108864,
+ "level_size_multiplier": 10,
+ "max_levels": 7,
+ "value_threshold": 32,
+ "num_memtables": 5,
+ "num_level_zero_tables": 5,
+ "num_level_zero_tables_stall": 10,
+ "level_one_size": 268435456,
+ "value_log_file_size": 1073741823,
+ "value_log_max_entries": 1000000,
+ "num_compactors": 2,
+ "compact_l_0_on_close": true,
+ "read_only": false,
+ "truncate": false
+ }
+ }
+ }
+ }
+
+export const dynamic = 'force-dynamic'
+export async function GET() {
+ const options = {
+ headers: {
+ "Content-Type": "application/json",
+ }
+ };
+ return new NextResponse(JSON.stringify(serviceConfig), options);
+}
\ No newline at end of file
diff --git a/packages/next/app/api/v1.json/route.ts b/packages/next/app/api/v1.json/route.ts
new file mode 100644
index 0000000..4433dc1
--- /dev/null
+++ b/packages/next/app/api/v1.json/route.ts
@@ -0,0 +1,91 @@
+
+import { getVodTitle } from '@/components/vod-page';
+import { getUrl, getAllVods } from "@/lib/vods"
+import { IVod } from "@/lib/vods"
+
+
+/*
+ * this is a legacy format
+ *
+ * for API version 1.
+ *
+ * @deprecated
+ */
+interface IVod1 {
+ title: string;
+ videoSrcHash: string;
+ video720Hash: string;
+ video480Hash: string;
+ video360Hash: string;
+ video240Hash: string;
+ thinHash: string;
+ thiccHash: string;
+ announceTitle: string;
+ announceUrl: string;
+ date: string;
+ note: string;
+ url: string;
+}
+
+interface IAPI1 {
+ vods: IVod1[]
+}
+
+
+export async function GET(): Promise {
+ try {
+ const vodsRaw = await getAllVods();
+ if (!vodsRaw) {
+ const options = {
+ headers: {
+ "Content-Type": "application/json",
+ },
+ status: 500,
+ };
+ return new Response('{}', options);
+ }
+
+ const vods: IVod1[] = vodsRaw.map((v: IVod): IVod1 => ({
+ title: getVodTitle(v),
+ videoSrcHash: v.attributes.videoSrcHash,
+ video720Hash: '',
+ video480Hash: '',
+ video360Hash: '',
+ video240Hash: v.attributes.video240Hash,
+ thinHash: '',
+ thiccHash: '',
+ announceTitle: v.attributes.announceTitle,
+ announceUrl: v.attributes.announceUrl,
+ date: v.attributes.date2,
+ note: v.attributes.note || '',
+ url: getUrl(v, v.attributes.vtuber.data.attributes.slug, v.attributes.date2),
+ }));
+
+ const response = {
+ vods: vods,
+ };
+
+ const options = {
+ headers: {
+ "Content-Type": "application/json",
+ },
+ };
+
+ return new Response(JSON.stringify(response), options);
+ } catch (error) {
+ console.error("Error fetching VODs:", error);
+
+ const errorResponse = {
+ error: "An error occurred while fetching VODs",
+ };
+
+ const options = {
+ headers: {
+ "Content-Type": "application/json",
+ },
+ status: 500,
+ };
+
+ return new Response(JSON.stringify(errorResponse), options);
+ }
+}
\ No newline at end of file
diff --git a/packages/next/app/blog/2021-10-29-the-story-of-futureporn/page.tsx b/packages/next/app/blog/2021-10-29-the-story-of-futureporn/page.tsx
new file mode 100644
index 0000000..a91a0bf
--- /dev/null
+++ b/packages/next/app/blog/2021-10-29-the-story-of-futureporn/page.tsx
@@ -0,0 +1,54 @@
+
+import Link from "next/link"
+import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"
+import { faExternalLinkAlt } from "@fortawesome/free-solid-svg-icons"
+
+export default async function Page() {
+
+
+
+ return (
+
+
+
+
+
+
+
+
+
The Story of Futureporn
+
+
2020 was a busy time for me. I started a small business, attended lots of support group meetings, and rode my bicycle more than ever before. I often found myself away from home during times when Melody was streaming on Chaturbate.
+
+
You probably know that unlike other video streaming platforms, Chaturbate doesn’t store any VODs. When I missed a stream, I felt sad. I felt like I had missed out and there’s no way I’d ever find out what happened.
+
+
I’m pretty handy with computer software. Creating programs and websites has been my biggest passion for my entire life. In order to never miss a ProjektMelody livestream again, I resolved to create some software that would automatically record Melody’s Chaturbate streams.
+
+
I put the project on hold for a few months, because I didn’t think I could make a website that could handle the traffic that the Science Team would generate.
+
+
I couldn’t shake the idea, though. I wanted Futureporn to exist no matter what!
+
+
I’ve been working on this project off and on for about a year and a half. It’s gone through several iterations, and each iteration has taught me something new. Right now, the website is usable for finding and downloading ProjektMelody Chaturbate VODs. Every VOD has a link to Melody’s tweet which originally announced the stream, and a title/description derived from said tweet. I have archived all of her known Chaturbate streams.
+
+
The project has evolved over time. Originally, I wanted to have a place to go when I missed one of Melody’s livestreams. Now, the project is becoming a sort of a time capsule. We’ve all seen how Melody has been de-platformed a half dozen times, and I’ve taken this to heart. Platforms are a problem for data preservation! This is one of the reasons for why I chose to use the Inter-Planetary File System ( IPFS .)
+
+
IPFS can end 404s through “pinning,” a way of mirroring a file across several different computers. It’s a way for computers to work together to serve content instead of working independently, thus gaining redundancy and performance benefits. I see a future where pinning files on IPFS becomes as easy as pinning a photo on Pinterest. Fans of ProjektMelody can pin the VODs on Futureporn, increasing that VOD’s replication and servability to future viewers.
+
+
But wait, there’s more! I have been thinking about a bunch of other stuff that could be done with past VODs. I think the most exciting thing would be to use computer vision to parse Melody’s vibrator activity from the video, and export to a data file. This data file could be used to send good vibes to a viewer’s vibrator in-sync with VOD playback. Feel what Melody feels! Very exciting, very sexy! This is a long-term goal for Futureporn.
+
+
I have several goals for Futureporn, as listed on the Goals page. A bunch of them have to do with increasing video playback performance, user interface design, but there’s a few that are pretty eccentric… Serving ProjektMelody VODs to Mars, for example!
+
+
I hope this site is useful to all the Science Team!
+
+
+
+
Futureporn needs financial support to continue improving. If you enjoy this website, please consider becoming a patron .
+
+
+
+
+
+
+
+ )
+}
\ No newline at end of file
diff --git a/packages/next/app/blog/page.tsx b/packages/next/app/blog/page.tsx
new file mode 100644
index 0000000..994e452
--- /dev/null
+++ b/packages/next/app/blog/page.tsx
@@ -0,0 +1,35 @@
+import Link from 'next/link';
+import { siteUrl } from '@/lib/constants';
+import { IBlogPost } from '@/lib/blog';
+
+
+export default async function PostsPage() {
+ const res = await fetch(`${siteUrl}/api/blogs`);
+ const posts: IBlogPost[] = [
+ {
+ id: 1,
+ slug: '2021-10-29-the-story-of-futureporn',
+ title: 'The Story Of Futureporn'
+ }
+ ]
+
+ return (
+
+
+
+
All Blog Posts
+
+
+
+ {posts.map((post: IBlogPost) => (
+
+
+ > {post.title}
+
+
+ ))}
+
+
+
+ );
+}
\ No newline at end of file
diff --git a/packages/next/app/components/archive-progress.tsx b/packages/next/app/components/archive-progress.tsx
new file mode 100644
index 0000000..2de480b
--- /dev/null
+++ b/packages/next/app/components/archive-progress.tsx
@@ -0,0 +1,23 @@
+import { getAllStreamsForVtuber } from "@/lib/streams";
+import { IVtuber } from "@/lib/vtubers";
+
+export interface IArchiveProgressProps {
+ vtuber: IVtuber;
+}
+
+export default async function ArchiveProgress ({ vtuber }: IArchiveProgressProps) {
+ const streams = await getAllStreamsForVtuber(vtuber.id);
+ const goodStreams = await getAllStreamsForVtuber(vtuber.id, ['good']);
+ const issueStreams = await getAllStreamsForVtuber(vtuber.id, ['issue']);
+ const totalStreams = streams.length;
+ const eligibleStreams = issueStreams.length+goodStreams.length;
+
+ // Check if totalStreams is not zero before calculating completedPercentage
+ const completedPercentage = (totalStreams !== 0) ? Math.round(eligibleStreams / totalStreams * 100) : 0;
+ return (
+
+
{eligibleStreams}/{totalStreams} Streams Archived ({completedPercentage}%)
+
{completedPercentage}%
+
+ )
+}
\ No newline at end of file
diff --git a/packages/next/app/components/auth.tsx b/packages/next/app/components/auth.tsx
new file mode 100644
index 0000000..e732be5
--- /dev/null
+++ b/packages/next/app/components/auth.tsx
@@ -0,0 +1,131 @@
+'use client';
+
+import { createContext, useContext, ReactNode } from 'react';
+import { useRouter } from 'next/navigation';
+import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
+import { faPatreon } from '@fortawesome/free-brands-svg-icons';
+import { useLocalStorageValue } from '@react-hookz/web';
+import { faRightFromBracket } from '@fortawesome/free-solid-svg-icons';
+import Skeleton from 'react-loading-skeleton';
+import { strapiUrl } from '@/lib/constants';
+
+export interface IJWT {
+ jwt: string;
+ user: IUser;
+}
+
+export interface IUser {
+ id: number;
+ username: string;
+ email: string;
+ provider: string;
+ confirmed: boolean;
+ blocked: boolean;
+ createdAt: string;
+ updatedAt: string;
+ isNamePublic: boolean;
+ avatar: string | null;
+ isLinkPublic: boolean;
+ vanityLink: string | null;
+ patreonBenefits: string;
+}
+
+export interface IAuthData {
+ accessToken: string | null;
+ user: IUser | null;
+}
+
+export interface IUseAuth {
+ authData: IAuthData | null | undefined;
+ setAuthData: (data: IAuthData | null) => void;
+ lastVisitedPath: string | undefined;
+ login: () => void;
+ logout: () => void;
+}
+
+export const AuthContext = createContext(null);
+
+interface IAuthContextProps {
+ children: ReactNode;
+}
+export function AuthProvider({ children }: IAuthContextProps): React.JSX.Element {
+ const { value: authData, set: setAuthData } = useLocalStorageValue('authData', {
+ defaultValue: null,
+ });
+
+ const { value: lastVisitedPath, set: setLastVisitedPath } = useLocalStorageValue('lastVisitedPath', {
+ defaultValue: '/profile',
+ initializeWithValue: false,
+ });
+ const router = useRouter();
+
+ const login = async () => {
+ const currentPath = window.location.pathname;
+ setLastVisitedPath(currentPath);
+ router.push(`${strapiUrl}/api/connect/patreon`);
+ };
+
+ const logout = () => {
+ setAuthData({ accessToken: null, user: null });
+ };
+
+ return (
+
+ {children}
+
+ );
+}
+
+export function LoginButton() {
+ const context = useContext(AuthContext);
+ if (!context) return ;
+ const { login } = context;
+ return (
+ {
+ login();
+ }}
+ >
+
+
+
+ Login
+
+ );
+}
+
+export function LogoutButton() {
+ const context = useContext(AuthContext);
+ if (!context) return <>>;
+ const { logout } = context;
+ return (
+ {
+ logout();
+ }}
+ >
+
+
+
+ Logout
+
+ );
+}
+
+export function useAuth(): IUseAuth {
+ const context = useContext(AuthContext);
+ if (!context) {
+ throw new Error('useAuth must be used within an AuthProvider');
+ }
+ return context;
+}
diff --git a/packages/next/app/components/cal.tsx b/packages/next/app/components/cal.tsx
new file mode 100644
index 0000000..81ee719
--- /dev/null
+++ b/packages/next/app/components/cal.tsx
@@ -0,0 +1,125 @@
+'use client';
+// greets https://github.com/wa0x6e/cal-heatmap-react-starter/blob/main/src/components/cal-heatmap.tsx
+
+import CalHeatmap from 'cal-heatmap';
+// @ts-ignore cal-heatmap is jenk
+import Legend from 'cal-heatmap/plugins/Legend';
+// @ts-ignore cal-heatmap is jenk
+import Tooltip from 'cal-heatmap/plugins/Tooltip';
+import { DataRecord } from 'cal-heatmap/src/options/Options';
+import 'cal-heatmap/cal-heatmap.css';
+import dayjs from 'dayjs';
+import { useEffect, useState, useRef } from 'react';
+import { useRouter } from 'next/navigation';
+import { getSafeDate } from '@/lib/dates';
+
+export interface ICalProps {
+ data: DataRecord[];
+ slug: string;
+}
+
+
+export function Cal({ data, slug }: ICalProps) {
+ const router = useRouter();
+ const [cellSize, setCellSize] = useState(13);
+ const [targetElementId, setTargetElementId] = useState('');
+
+ const generateUniqueId = () => {
+ return `cal-${Math.random().toString(36).substring(2, 9)}`;
+ };
+
+
+
+ useEffect(() => {
+ const updateCellSize = () => {
+ const windowWidth = window.innerWidth;
+ if (windowWidth > 1400) {
+ setCellSize(15); // Adjust the cell size for width > 1400px
+ } else if (windowWidth > 730) {
+ setCellSize(10); // Adjust the cell size for width > 730px
+ } else {
+ setCellSize(3); // Adjust the cell size for width <= 730px
+ }
+ }
+ updateCellSize();
+ // Event listener to update cell size on window resize
+ window.addEventListener('resize', updateCellSize);
+
+ return () => {
+ window.removeEventListener('resize', updateCellSize);
+ };
+
+ }, [])
+
+
+ useEffect(() => {
+ setTargetElementId(generateUniqueId());
+ }, []);
+
+ useEffect(() => {
+ if (!targetElementId) return;
+ const cal = new CalHeatmap();
+ // @ts-ignore
+ cal.on('click', (
+ event: string,
+ timestamp: number,
+ value: number
+ ) => {
+ router.push(`/vt/${slug}/stream/${getSafeDate(new Date(timestamp))}`);
+ // console.log(`slug=${slug} safeDate=${getSafeDate(new Date(timestamp))}`);
+ });
+
+ cal.paint(
+ {
+ itemSelector: `#${targetElementId}`,
+ scale: {
+ color: {
+ // @ts-ignore this shit is straight from the example website
+ domain: ['missing', 'issue', 'good'],
+ type: 'ordinal',
+ range: ['red', 'yellow', 'green']
+ }
+ },
+ theme: 'dark',
+ verticalOrientation: false,
+ data: {
+ source: data,
+ x: 'date',
+ y: 'value',
+ // @ts-ignore this shit is straight from the example website
+ groupY: d => d[0]
+ },
+ range: 12,
+ date: { start: data[0].date },
+ domain: {
+ type: 'month',
+ gutter: 4,
+ label: { text: 'MMM', textAlign: 'start', position: 'top' }
+ },
+ subDomain: {
+ type: 'ghDay',
+ radius: 2,
+ width: cellSize,
+ height: cellSize,
+ gutter: 4,
+ }
+ }, [
+ [
+ Tooltip,
+ {
+ text: ((ts: number, value: string, dayjsDate: dayjs.Dayjs) => {
+ return `${!!value ? value+' - '+dayjsDate.toString() : dayjsDate.toString() }`;
+ })
+ }
+ ]
+ ]);
+
+ }, [targetElementId, data, cellSize, router, slug]);
+
+
+ return (
+ <>
+
+ >
+ )
+}
\ No newline at end of file
diff --git a/packages/next/app/components/contributors.tsx b/packages/next/app/components/contributors.tsx
new file mode 100644
index 0000000..74f877c
--- /dev/null
+++ b/packages/next/app/components/contributors.tsx
@@ -0,0 +1,33 @@
+import Skeleton, { SkeletonTheme } from "react-loading-skeleton";
+import { getContributors } from "../lib/contributors";
+import Link from 'next/link';
+import { faExternalLinkAlt } from "@fortawesome/free-solid-svg-icons";
+import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
+
+export default async function Contributors() {
+ const contributors = await getContributors();
+ if (!contributors || contributors.length < 1) return (
+
+
+
+ )
+ const contributorList = contributors.map((contributor, index) => (
+
+ {contributor.attributes.url ? (
+
+ {contributor.attributes.name}
+
+
+ ) : (
+ contributor.attributes.name
+ )}
+ {index !== contributors.length - 1 ? ", " : ""}
+
+ ));
+ return (
+ <>{contributorList}>
+ )
+}
\ No newline at end of file
diff --git a/packages/next/app/components/custom-hls-player.tsx b/packages/next/app/components/custom-hls-player.tsx
new file mode 100644
index 0000000..f46724c
--- /dev/null
+++ b/packages/next/app/components/custom-hls-player.tsx
@@ -0,0 +1,80 @@
+import React, { useEffect, useRef, useState, forwardRef, MutableRefObject } from "react";
+import { APITypes, PlyrProps, usePlyr } from "plyr-react";
+import "plyr-react/plyr.css";
+import { Options } from "plyr";
+import Hls from "hls.js";
+
+
+export function UnsupportedHlsMessage(): React.JSX.Element {
+ return (
+
+ HLS is not supported in your browser. Please try a different browser.
+
+ );
+}
+
+const useHls = (src: string, options: Options | null) => {
+ const hls = useRef(new Hls());
+ const hasQuality = useRef(false);
+ const [plyrOptions, setPlyrOptions] = useState(options);
+
+
+
+ useEffect(() => {
+ hasQuality.current = false;
+ }, [options]);
+
+ useEffect(() => {
+ hls.current.loadSource(src);
+ hls.current.attachMedia(document.querySelector(".plyr-react")!);
+
+ hls.current.on(Hls.Events.MANIFEST_PARSED, () => {
+ if (hasQuality.current) return; // early quit if already set
+
+ const levels = hls.current.levels;
+ const quality: Options["quality"] = {
+ default: levels[levels.length - 1].height,
+ options: levels.map((level) => level.height),
+ forced: true,
+ onChange: (newQuality: number) => {
+ levels.forEach((level, levelIndex) => {
+ if (level.height === newQuality) {
+ hls.current.currentLevel = levelIndex;
+ }
+ });
+ },
+ };
+
+ setPlyrOptions({ ...plyrOptions, quality });
+ hasQuality.current = true;
+ });
+ });
+
+ return { options: plyrOptions };
+};
+
+const CustomPlyrInstance = forwardRef<
+ APITypes,
+ PlyrProps & { hlsSource: string; mainColor: string; plyrOptions: Options }
+>((props, ref) => {
+ const { source, plyrOptions, hlsSource, mainColor } = props;
+ const plyrRef = usePlyr(ref, {
+ ...useHls(hlsSource, plyrOptions),
+ source,
+ }) as MutableRefObject;
+
+ return (
+ <>
+
+ >
+ );
+});
+
+
+CustomPlyrInstance.displayName = 'CustomPlyrInstance'
+
+export { CustomPlyrInstance }
\ No newline at end of file
diff --git a/packages/next/app/components/footer.tsx b/packages/next/app/components/footer.tsx
new file mode 100644
index 0000000..ff4431e
--- /dev/null
+++ b/packages/next/app/components/footer.tsx
@@ -0,0 +1,118 @@
+import Link from "next/link";
+import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
+import { faExternalLinkAlt } from "@fortawesome/free-solid-svg-icons";
+import { faGit, faReddit, faDiscord, faPatreon } from "@fortawesome/free-brands-svg-icons";
+import Contributors from "./contributors";
+import PatronsList from "./patrons-list";
+
+export default function Footer() {
+ return (
+ <>
+
+
+
+
+
+
Sitemap
+
+ ↑ Top of page
+ Vtubers
+ Stream Archive
+ About
+ FAQ
+ Goals
+ Patrons
+ Tags
+ RSS Feed
+ API
+ Blog
+ Status
+ Upload
+ Profile
+
+
+
+
+ Futureporn.net is made with ❤️ by CJ_Clippy
+
+
+ Made possible by generous
+
+ donations
+
+
+
+ from
+
+
+
+ VOD contributions by
+
+
+
+
+ Git Repo
+
+
+
+
+
+
+
+ Reddit Thread
+
+
+
+
+
+
+
+ Discord Server
+
+
+
+
+
+
+
+
+
+ >
+ )
+}
\ No newline at end of file
diff --git a/packages/next/app/components/funding-goal.tsx b/packages/next/app/components/funding-goal.tsx
new file mode 100644
index 0000000..12b4119
--- /dev/null
+++ b/packages/next/app/components/funding-goal.tsx
@@ -0,0 +1,81 @@
+
+import { getCampaign } from "@/lib/patreon";
+import { getGoals, IGoals } from '@/lib/pm'
+import Image from 'next/image';
+import React from 'react';
+import Link from 'next/link'
+
+
+
+export default async function FundingGoal(): Promise {
+ const campaignData = await getCampaign();
+ const { pledgeSum, patronCount } = campaignData;
+
+ const goals = await getGoals(pledgeSum);
+ if (!goals || !goals?.featuredFunded?.amountCents || !goals?.featuredUnfunded?.amountCents || !goals?.featuredFunded?.amountCents || !goals?.featuredUnfunded?.completedPercentage || !goals?.featuredFunded?.completedPercentage ) return <>>
+
+ return (
+ <>
+ {/*
+ pledgeSum:{JSON.stringify(pledgeSum, null, 2)}
+
+
+ patronCount:{JSON.stringify(patronCount, null, 2)}
+
+ featuredFunded:{JSON.stringify(goals.featuredFunded)}
+ featuredUnfunded:{JSON.stringify(goals.featuredUnfunded)}
*/}
+
+ {/*
+
+ {JSON.stringify(goals, null, 2)}
+
+ */}
+
+
+
+ Funding Goal
+
+
+
+
+
+
+
+
+ {/* the most recently funded goal */}
+
+ {/* const { featuredFunded, featuredUnfunded } = goals;
+ if (!featuredFunded?.amountCents || !featuredFunded?.completedPercentage) return <>>
+ if (!featuredUnfunded?.amountCents || !featuredUnfunded?.completedPercentage) return <>> */}
+
+
${(goals.featuredFunded.amountCents * (goals.featuredFunded.completedPercentage * 0.01) / 100)} of {goals.featuredFunded.amountCents / 100} ({goals.featuredFunded.completedPercentage}%)
+
+
+ FUNDED
+
+
{goals.featuredFunded.description}
+
+
+ {/* the next unfunded goal */}
+
+
${(goals.featuredUnfunded.amountCents * (goals.featuredUnfunded.completedPercentage * 0.01) / 100) | 0} of ${goals.featuredUnfunded.amountCents / 100} ({goals.featuredUnfunded.completedPercentage}%)
+
+ {goals.featuredUnfunded.completedPercentage}%
+
+
{goals.featuredUnfunded.description}
+
+
+
+
+ Thank you, Patrons!
+
+
+
+ >
+ );
+};
+
diff --git a/packages/next/app/components/icons/carrd.tsx b/packages/next/app/components/icons/carrd.tsx
new file mode 100644
index 0000000..d900cda
--- /dev/null
+++ b/packages/next/app/components/icons/carrd.tsx
@@ -0,0 +1,8 @@
+import * as React from "react"
+const SvgComponent = (props: any) => (
+
+ {"Carrd"}
+
+
+)
+export default SvgComponent
diff --git a/packages/next/app/components/icons/chaturbate.tsx b/packages/next/app/components/icons/chaturbate.tsx
new file mode 100644
index 0000000..31c641f
--- /dev/null
+++ b/packages/next/app/components/icons/chaturbate.tsx
@@ -0,0 +1,14 @@
+import * as React from "react"
+const SvgComponent = (props: any) => (
+
+
+
+)
+export default SvgComponent
diff --git a/packages/next/app/components/icons/fansly.tsx b/packages/next/app/components/icons/fansly.tsx
new file mode 100644
index 0000000..03a78dc
--- /dev/null
+++ b/packages/next/app/components/icons/fansly.tsx
@@ -0,0 +1,20 @@
+import * as React from "react"
+const SvgComponent = (props: any) => (
+
+
+
+
+)
+export default SvgComponent
diff --git a/packages/next/app/components/icons/linktree.tsx b/packages/next/app/components/icons/linktree.tsx
new file mode 100644
index 0000000..3e17f8b
--- /dev/null
+++ b/packages/next/app/components/icons/linktree.tsx
@@ -0,0 +1,30 @@
+import * as React from "react"
+const SvgComponent = (props: any) => (
+
+
+
+
+
+
+
+
+
+
+
+)
+export default SvgComponent
diff --git a/packages/next/app/components/icons/onlyfans.tsx b/packages/next/app/components/icons/onlyfans.tsx
new file mode 100644
index 0000000..81a568a
--- /dev/null
+++ b/packages/next/app/components/icons/onlyfans.tsx
@@ -0,0 +1,55 @@
+import * as React from "react"
+const SvgComponent = (props: any) => (
+
+
+
+
+
+
+)
+export default SvgComponent
diff --git a/packages/next/app/components/icons/pornhub.tsx b/packages/next/app/components/icons/pornhub.tsx
new file mode 100644
index 0000000..5f7a746
--- /dev/null
+++ b/packages/next/app/components/icons/pornhub.tsx
@@ -0,0 +1,23 @@
+import * as React from "react"
+const SvgComponent = (props: any) => (
+
+
+
+
+
+
+
+)
+export default SvgComponent
diff --git a/packages/next/app/components/icons/throne.tsx b/packages/next/app/components/icons/throne.tsx
new file mode 100644
index 0000000..897285c
--- /dev/null
+++ b/packages/next/app/components/icons/throne.tsx
@@ -0,0 +1,31 @@
+import * as React from "react"
+const SvgComponent = (props: any) => (
+
+
+
+
+
+
+
+
+
+
+
+
+)
+export default SvgComponent
diff --git a/packages/next/app/components/ipfs-cid.tsx b/packages/next/app/components/ipfs-cid.tsx
new file mode 100644
index 0000000..efbde66
--- /dev/null
+++ b/packages/next/app/components/ipfs-cid.tsx
@@ -0,0 +1,42 @@
+'use client';
+
+import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
+import { faCopy, faCheck } from "@fortawesome/free-solid-svg-icons";
+import { useState } from "react";
+import styles from '@/assets/styles/cid.module.css'
+
+interface IIpfsCidProps {
+ label?: string;
+ cid: string;
+}
+
+
+export function IpfsCid({ label, cid }: IIpfsCidProps) {
+
+ const [isCopied, setIsCopied] = useState(false);
+
+
+
+ return (
+
+
{label}
+
{cid}
+ {(isCopied) ?
+
+ :
+
{
+ navigator.clipboard.writeText(cid)
+ setIsCopied(true)
+ setTimeout(() => setIsCopied(false), 3000)
+ }}
+ >
+ }
+
+ )
+}
diff --git a/packages/next/app/components/ipfs-logo.tsx b/packages/next/app/components/ipfs-logo.tsx
new file mode 100644
index 0000000..3875418
--- /dev/null
+++ b/packages/next/app/components/ipfs-logo.tsx
@@ -0,0 +1,18 @@
+import React from 'react';
+
+interface LogoProps {
+ size: number;
+ color: string;
+}
+
+const IPFSLogo: React.FC = ({ size = 32, color = '#65C2CB' }) => {
+
+ return (
+
+ IPFS
+
+
+ );
+};
+
+export default IPFSLogo;
\ No newline at end of file
diff --git a/packages/next/app/components/ipfs.tsx b/packages/next/app/components/ipfs.tsx
new file mode 100644
index 0000000..cacfea8
--- /dev/null
+++ b/packages/next/app/components/ipfs.tsx
@@ -0,0 +1,39 @@
+'use client';
+
+// import { type Helia, createHelia } from 'helia';
+// import React, { useState, useEffect } from 'react';
+
+// export default function Ipfs () {
+// const [id, setId] = useState(null)
+// const [helia, setHelia] = useState(null)
+// const [isOnline, setIsOnline] = useState(false)
+
+// useEffect(() => {
+// const init = async () => {
+// if (helia) return
+
+// const heliaNode = await createHelia();
+
+// const nodeId = heliaNode.libp2p.peerId.toString();
+// const nodeIsOnline = heliaNode.libp2p.isStarted();
+
+// setHelia(heliaNode);
+// setId(nodeId);
+// setIsOnline(nodeIsOnline);
+// }
+
+// init()
+// }, [helia])
+
+// if (!helia || !id) {
+// return Connecting to IPFS...
+// }
+
+// return (
+//
+//
ID: {id.toString()}
+// Status: {isOnline ? 'Online' : 'Offline'}
+//
+// )
+// }
+
diff --git a/packages/next/app/components/linkable-heading.tsx b/packages/next/app/components/linkable-heading.tsx
new file mode 100644
index 0000000..c5e782a
--- /dev/null
+++ b/packages/next/app/components/linkable-heading.tsx
@@ -0,0 +1,28 @@
+import Link from "next/link";
+import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
+import { IconDefinition, faLink } from "@fortawesome/free-solid-svg-icons";
+
+interface ILinkableHeadingProps {
+ icon?: IconDefinition;
+ text: string;
+ slug: string;
+}
+
+export default function LinkableHeading({ icon, text, slug }: ILinkableHeadingProps) {
+ return (
+
+ {icon && }
+ {text}
+
+
+
+
+
+ )
+}
\ No newline at end of file
diff --git a/packages/next/app/components/localized-date.tsx b/packages/next/app/components/localized-date.tsx
new file mode 100644
index 0000000..65ec1c5
--- /dev/null
+++ b/packages/next/app/components/localized-date.tsx
@@ -0,0 +1,15 @@
+import { formatISO } from "date-fns";
+
+interface ILocalizedDateProps {
+ date: Date;
+}
+
+export function LocalizedDate ({ date }: ILocalizedDateProps) {
+ const isoDateTime = formatISO(date);
+ const isoDate = formatISO(date, { representation: 'date' });
+ return (
+ <>
+ {isoDate}
+ >
+ )
+}
\ No newline at end of file
diff --git a/packages/next/app/components/navbar.tsx b/packages/next/app/components/navbar.tsx
new file mode 100644
index 0000000..57fca00
--- /dev/null
+++ b/packages/next/app/components/navbar.tsx
@@ -0,0 +1,98 @@
+'use client'
+
+import { useEffect, useState } from 'react'
+import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
+import { faExternalLinkAlt } from "@fortawesome/free-solid-svg-icons";
+import { faUser, faUpload } from "@fortawesome/free-solid-svg-icons";
+import Link from 'next/link'
+import { LoginButton, useAuth } from '@/components/auth'
+
+
+export default function Navbar() {
+ const [isExpanded, setExpanded] = useState(false);
+ const [isProfileButton, setIsProfileButton] = useState(false);
+
+ const handleBurgerClick = () => {
+ setExpanded(!isExpanded);
+ };
+
+ const { authData } = useAuth()
+
+ useEffect(() => {
+ if (!!authData?.accessToken && !!authData?.user?.username) setIsProfileButton(true)
+ else setIsProfileButton(false)
+ }, [authData])
+
+ return (
+ <>
+
+
+
+
🔞💦 Futureporn.net
+
+
+
+
+
+
+
+
+
+
+ >
+ )
+}
\ No newline at end of file
diff --git a/packages/next/app/components/notification-center.tsx b/packages/next/app/components/notification-center.tsx
new file mode 100644
index 0000000..31218c6
--- /dev/null
+++ b/packages/next/app/components/notification-center.tsx
@@ -0,0 +1,13 @@
+'use client';
+
+import { ToastContainer } from 'react-toastify';
+import 'react-toastify/dist/ReactToastify.css';
+
+
+export default function NotificationCenter() {
+ return (
+
+ )
+}
\ No newline at end of file
diff --git a/packages/next/app/components/notifications.tsx b/packages/next/app/components/notifications.tsx
new file mode 100644
index 0000000..1968ecd
--- /dev/null
+++ b/packages/next/app/components/notifications.tsx
@@ -0,0 +1,10 @@
+
+export function DangerNotification ({ errors }: { errors: String[] }): JSX.Element {
+ return (
+
+ {errors && errors.map((error, index) => (
+
Error:{error}
+ ))}
+
+ );
+}
\ No newline at end of file
diff --git a/packages/next/app/components/pager.tsx b/packages/next/app/components/pager.tsx
new file mode 100644
index 0000000..01f67ab
--- /dev/null
+++ b/packages/next/app/components/pager.tsx
@@ -0,0 +1,82 @@
+import Link from 'next/link';
+
+interface IPagerProps {
+ baseUrl: string; // Pass the base URL as a prop
+ page: number;
+ pageCount: number;
+}
+
+export default function Pager({ baseUrl, page, pageCount }: IPagerProps): React.JSX.Element {
+ const pageNumbers = Array.from({ length: pageCount }, (_, i) => i + 1);
+
+ const getPagePath = (page: any) => {
+ const pageNumber = parseInt(page);
+ return `${baseUrl}/${pageNumber}`;
+ };
+
+ // Define the number of page links to show around the current page
+ const maxPageLinksToShow = 3;
+
+ // Calculate the range of page numbers to display
+ const startPage = Math.max(1, page - Math.floor(maxPageLinksToShow / 2));
+ const endPage = Math.min(pageCount, startPage + maxPageLinksToShow - 1);
+
+ return (
+
+
+ {page > 1 && (
+
+ Previous
+
+ )}
+ {page < pageCount && (
+
+ Next
+
+ )}
+
+
+ {startPage > 1 && (
+
+
+ 1
+
+
+ )}
+
+ {startPage > 2 && (
+
+ …
+
+ )}
+
+ {pageNumbers.slice(startPage - 1, endPage).map((pageNumber) => (
+
+
+
+ {pageNumber}
+
+
+
+ ))}
+
+ {endPage < pageCount - 1 && (
+
+ …
+
+ )}
+
+ {endPage !== pageCount && (
+
+
+
+ {pageCount}
+
+
+
+ )}
+
+
+
+ );
+}
diff --git a/packages/next/app/components/patrons-list.tsx b/packages/next/app/components/patrons-list.tsx
new file mode 100644
index 0000000..f54961e
--- /dev/null
+++ b/packages/next/app/components/patrons-list.tsx
@@ -0,0 +1,55 @@
+import Skeleton, { SkeletonTheme } from 'react-loading-skeleton';
+import 'react-loading-skeleton/dist/skeleton.css';
+import { getPatrons } from '../lib/patreon';
+import Link from 'next/link'
+
+interface PatronsListProps {
+ displayStyle: string;
+}
+
+export default async function PatronsList({ displayStyle }: PatronsListProps) {
+ const patrons = await getPatrons()
+
+ if (!patrons) return (
+
+
+
+ );
+ if (displayStyle === 'box') {
+ return (
+
+ {patrons.map((patron) => (
+
+
+
+
+
+ {patron.username && (
+
+ {patron.username}
+
+ )}
+ {patron.vanityLink && (
+
+ {patron.vanityLink}
+
+
+
+
+ )}
+
+
+
+
+
+ ))}
+
+ );
+ } else if (displayStyle === 'list') {
+ const patronNames = patrons.map((patron) => patron.username.trim()).join(', ');
+ return {patronNames} ;
+ } else {
+ return ; // Handle unsupported display styles or provide a default display style
+ }
+}
+
diff --git a/packages/next/app/components/sortable-tags.tsx b/packages/next/app/components/sortable-tags.tsx
new file mode 100644
index 0000000..669b02d
--- /dev/null
+++ b/packages/next/app/components/sortable-tags.tsx
@@ -0,0 +1,70 @@
+'use client'
+
+import React, { useState } from 'react';
+import { ITag } from '../lib/tags';
+import Link from 'next/link';
+import slugify from 'slugify';
+import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
+import { faFilter } from "@fortawesome/free-solid-svg-icons";
+
+interface ISortableTagsProps {
+ tags: ITag[];
+}
+
+export default function SortableTags({ tags }: ISortableTagsProps) {
+ const [filterText, setFilterText] = useState('');
+ const [sortOption, setSortOption] = useState('Sort');
+
+ const filteredTags = tags.filter((tag: ITag) =>
+ tag.attributes.name.toLowerCase().includes(filterText.toLowerCase())
+ );
+
+ const sortedTags = [...filteredTags].sort((a, b) => {
+ if (sortOption === 'Alphabetical') {
+ return a.attributes.name.localeCompare(b.attributes.name);
+ } else if (sortOption === 'Frequency') {
+ return b.attributes.count - a.attributes.count;
+ }
+ return 0;
+ });
+
+ return (
+ <>
+
+
+ setFilterText(e.target.value)}
+ />
+
+
+
+
+
+
+ setSortOption(e.target.value)}
+ >
+ Sort
+ Alphabetical
+ Frequency
+
+
+
+
+
+ {sortedTags.map((tag: ITag) => (
+
+
+ {tag.attributes.name} ({tag.attributes.count})
+
+
+ ))}
+
+ >
+ );
+}
diff --git a/packages/next/app/components/stream-button.tsx b/packages/next/app/components/stream-button.tsx
new file mode 100644
index 0000000..5c20280
--- /dev/null
+++ b/packages/next/app/components/stream-button.tsx
@@ -0,0 +1,19 @@
+import { IStream } from "@/lib/streams";
+import Link from "next/link"
+import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
+import { faCalendar } from "@fortawesome/free-solid-svg-icons";
+
+export function StreamButton({ stream }: { stream: IStream }) {
+ if (!stream) return <>>
+ // return {JSON.stringify(stream, null, 2)}
+ // return {new Date(stream.attributes.date).toLocaleDateString()}
+
+ return (
+
+ {new Date(stream.attributes.date).toLocaleDateString()}
+
+ )
+}
\ No newline at end of file
diff --git a/packages/next/app/components/stream-page.tsx b/packages/next/app/components/stream-page.tsx
new file mode 100644
index 0000000..7264b2b
--- /dev/null
+++ b/packages/next/app/components/stream-page.tsx
@@ -0,0 +1,187 @@
+'use client';
+
+import { IStream } from "@/lib/streams";
+import NotFound from "app/streams/[cuid]/not-found";
+import { IVod } from "@/lib/vods";
+import Link from "next/link";
+import Image from "next/image";
+import { LocalizedDate } from "./localized-date";
+import { FontAwesomeIcon, FontAwesomeIconProps } from "@fortawesome/react-fontawesome";
+import { faTriangleExclamation, faCircleInfo, faThumbsUp, IconDefinition, faO, faX, faExternalLinkAlt } from "@fortawesome/free-solid-svg-icons";
+import { Hemisphere, Moon } from "lunarphase-js";
+import { useEffect, useState } from "react";
+import { faXTwitter } from "@fortawesome/free-brands-svg-icons";
+
+export interface IStreamProps {
+ stream: IStream;
+}
+type Status = 'missing' | 'issue' | 'good';
+interface StyleDef {
+ heading: string;
+ icon: IconDefinition;
+ desc1: string;
+ desc2: string;
+}
+
+function capitalizeFirstLetter(string: string): string {
+ return string.charAt(0).toUpperCase() + string.slice(1);
+}
+
+function hasNote(vod: IVod) {
+ if (!!vod?.attributes?.note) return true;
+ else return false;
+}
+
+function determineStatus(stream: IStream): Status {
+ if (stream.attributes.vods.data.length < 1) {
+ return 'missing'
+ } else {
+ if (stream.attributes.vods.data.some(vod => !hasNote(vod))) {
+ return 'good';
+ } else {
+ return 'issue';
+ }
+ }
+}
+
+export default function StreamPage({ stream }: IStreamProps) {
+ const displayName = stream.attributes.vtuber.data.attributes.displayName;
+ const date = new Date(stream.attributes.date);
+ const [hemisphere, setHemisphere] = useState(Hemisphere.NORTHERN);
+ const [selectedStatus, setSelectedStatus] = useState(determineStatus(stream));
+
+ const styleMap: Record = {
+ 'missing': {
+ heading: 'is-danger',
+ icon: faTriangleExclamation,
+ desc1: "We don't have a VOD for this stream.",
+ desc2: 'Know someone who does?'
+ },
+ 'issue': {
+ heading: 'is-warning',
+ icon: faCircleInfo,
+ desc1: "We have a VOD for this stream, but it's not full quality.",
+ desc2: 'Have a better copy?'
+ },
+ 'good': {
+ heading: 'is-success',
+ icon: faThumbsUp,
+ desc1: "We have a VOD for this stream, and we think it's the best quality possible.",
+ desc2: "Have one that's even better?"
+ }
+ };
+ const { heading, icon, desc1, desc2 } = styleMap[selectedStatus] || {};
+
+ useEffect(() => {
+ const randomHemisphere = (Math.random() < 0.5 ? 0 : 1) ? Hemisphere.NORTHERN : Hemisphere.SOUTHERN;
+ setHemisphere(randomHemisphere);
+ }, []);
+
+ if (!stream) return
+
+ // return
+ //
+ //
+ // {JSON.stringify(stream, null, 2)}
+
+ //
+ //
+
+ //
+ // const platformsList = '???';
+ const { isChaturbateInvite, isFanslyInvite } = stream.attributes.tweet.data.attributes;
+ const platformsArray = [
+ isChaturbateInvite ? 'Chaturbate' : null,
+ isFanslyInvite ? 'Fansly' : null
+ ].filter(Boolean);
+ const platformsList = platformsArray.length > 0 ? platformsArray.join(', ') : 'None';
+
+
+ return (
+ <>
+
+
+
+
+
{displayName} Stream Archive
+
+
+
+
+
+
Details
+
+
+ Announcement
+ Platform {platformsList}
+ UTC Datetime {date.toISOString()}
+ Local Datetime {date.toLocaleDateString()} {date.toLocaleTimeString()}
+ Lunar Phase {Moon.lunarPhase(date)} {Moon.lunarPhaseEmoji(date, { hemisphere })}
+
+ {/* setSelectedStatus(e.target.value as Status)}
+ >
+ good
+ issue
+ missing
+ */}
+
+
+
+
+
+
+
+
+
+ VOD {capitalizeFirstLetter(selectedStatus)}
+
+
+
+
{desc1}
+
{desc2}
+ Upload it here.
+
+
+
+
+
+
+
+
+
VODs
+
+
+
+ ID
+ Upload Date
+ {/* Thumbnail
+ Duration */}
+ Tags
+ Timestamps
+ Note
+
+
+
+ {stream.attributes.vods.data.map((vod: IVod) => (
+
+ {/* {JSON.stringify(vod, null, 2)}
*/}
+ {vod.attributes.cuid}
+ {vod.attributes.publishedAt}
+ {/* {(!!vod?.attributes?.thumbnail?.data?.attributes?.cdnUrl) ? : }
+ {(!!vod?.attributes?.duration) ? vod.attributes.duration : } */}
+ {vod.attributes.tagVodRelations.data.length}
+ {vod.attributes.timestamps.data.length}
+ {(!!vod.attributes.note) ? : }
+
+ ))}
+
+
+
+
+
+
+ >
+ )
+}
diff --git a/packages/next/app/components/stream.tsx b/packages/next/app/components/stream.tsx
new file mode 100644
index 0000000..3e54a19
--- /dev/null
+++ b/packages/next/app/components/stream.tsx
@@ -0,0 +1,86 @@
+import { IStream } from "@/lib/streams";
+import NotFound from "app/vt/[slug]/not-found";
+import { LocalizedDate } from "./localized-date";
+import Link from "next/link";
+import ChaturbateIcon from "@/components/icons/chaturbate";
+import FanslyIcon from "@/components/icons/fansly";
+import Image from "next/image";
+
+export interface IStreamProps {
+ stream: IStream;
+}
+
+
+export function Stream({ stream }: IStreamProps) {
+ if (!stream) return
+ return (
+
+
+
+ {JSON.stringify(stream, null, 2)}
+
+
+ {/*
Stream {stream.attributes.date} */}
+
+ )
+}
+
+
+
+export function StreamSummary ({ stream }: IStreamProps) {
+ if (!stream) return
+
+ // return (
+ //
+ //
+ // {JSON.stringify(stream, null, 2)}
+ //
+ //
+ // )
+
+ const archiveStatus = stream.attributes.archiveStatus;
+ const archiveStatusClassName = (() => {
+ if (archiveStatus === 'missing') return 'is-danger';
+ if (archiveStatus === 'good') return 'is-success';
+ if (archiveStatus === 'issue') return 'is-warning';
+ })();
+
+ return (
+
+
+ {/*
+
+ {JSON.stringify(stream, null, 2)}
+
+ */}
+
+
+
+
+
+
+ {stream.attributes.vtuber.data.attributes.displayName}
+
+
+
+
+
+ {(stream.attributes.isChaturbateStream) && }
+ {(stream.attributes.isFanslyStream) && }
+
+
+
{stream.attributes.archiveStatus}
+
+
+
+
+ )
+}
\ No newline at end of file
diff --git a/packages/next/app/components/streams-calendar.tsx b/packages/next/app/components/streams-calendar.tsx
new file mode 100644
index 0000000..fb04263
--- /dev/null
+++ b/packages/next/app/components/streams-calendar.tsx
@@ -0,0 +1,83 @@
+'use client';
+
+import FullCalendar from "@fullcalendar/react";
+import interactionPlugin, { DateClickArg } from '@fullcalendar/interaction';
+import dayGridPlugin from '@fullcalendar/daygrid';
+import multiMonthPlugin from '@fullcalendar/multimonth'
+
+import { IStream } from "@/lib/streams";
+import { useRouter } from 'next/navigation';
+import { AppRouterInstance } from "next/dist/shared/lib/app-router-context.shared-runtime";
+
+
+
+interface IStreamsCalendarProps {
+ missingStreams: IStream[];
+ issueStreams: IStream[];
+ goodStreams: IStream[];
+}
+
+interface IEvent {
+ cuid: string;
+ start: Date;
+ end?: Date;
+ title: string;
+ vtuber: string;
+}
+
+// function buildStreamPageUrlFromDate(date: Date) {
+// // const cuid =
+// return `/s/${safeDate}`;
+// }
+
+function handleEventClick(info: any, router: AppRouterInstance) {
+ var eventObj = info.event;
+ const { cuid } = eventObj._def.extendedProps;
+ router.push(`/streams/${cuid}`);
+
+}
+
+function convertStreamToEvent(stream: IStream): IEvent {
+ console.log(stream)
+ const displayName = stream.attributes.vtuber.data.attributes.displayName;
+ return {
+ cuid: stream.attributes.cuid,
+ start: new Date(stream.attributes.date),
+ title: `${displayName}`,
+ vtuber: displayName
+ }
+}
+
+export default function StreamsCalendar({ missingStreams, issueStreams, goodStreams }: IStreamsCalendarProps) {
+ const router = useRouter();
+ const eventSources = [
+ {
+ events: missingStreams.map(convertStreamToEvent),
+ color: 'red'
+ },
+ {
+ events: issueStreams.map(convertStreamToEvent),
+ color: 'yellow',
+ },
+ {
+ events: goodStreams.map(convertStreamToEvent),
+ color: 'green'
+ }
+ ]
+
+ return (
+ <>
+ {
+ handleEventClick(args, router);
+ }}
+ />
+ >
+ )
+}
\ No newline at end of file
diff --git a/packages/next/app/components/streams-list.tsx b/packages/next/app/components/streams-list.tsx
new file mode 100644
index 0000000..b70110a
--- /dev/null
+++ b/packages/next/app/components/streams-list.tsx
@@ -0,0 +1,61 @@
+import React from 'react'
+import Link from 'next/link';
+import VodCard from './vod-card';
+import { IVtuber } from '@/lib/vtubers';
+import { IVod } from '@/lib/vods';
+import { getVodTitle } from './vod-page';
+import { notFound } from 'next/navigation';
+import { IStream, getStreamsForVtuber, getAllStreams } from '@/lib/streams';
+import { StreamSummary } from '@/components/stream';
+
+interface IStreamsListProps {
+ vtubers: IVtuber[];
+ page: number;
+ pageSize: number;
+}
+
+
+interface IStreamsListHeadingProps {
+ slug: string;
+ displayName: string;
+}
+
+export function StreamsListHeading({ slug, displayName }: IStreamsListHeadingProps): React.JSX.Element {
+ return (
+
+
+ {displayName} Streams
+
+
+ )
+}
+
+
+export default async function StreamsList({ vtubers, page = 1, pageSize = 24 }: IStreamsListProps): Promise {
+ if (!vtubers) return vtubers is not defined. vtubers:{JSON.stringify(vtubers, null, 2)}
+
+ // const streams = await getStreamsForVtuber(vtubers[0].id);
+ const streams = await getAllStreams(['missing', 'issue', 'good']);
+
+ if (!streams) return notFound();
+
+
+ // @todo [ ] pagination
+ // @todo [ ] sortability
+ return (
+ <>
+
+ Stream Archive
+
+
+ {streams.length < 1 && There are no streams
}
+ {streams.map((stream: IStream) => (
+
+
+
+ ))}
+
+
+ >
+ );
+}
diff --git a/packages/next/app/components/tag-button.tsx b/packages/next/app/components/tag-button.tsx
new file mode 100644
index 0000000..dda1ea5
--- /dev/null
+++ b/packages/next/app/components/tag-button.tsx
@@ -0,0 +1,8 @@
+
+import { useState } from 'react';
+
+export function TagButton ({ name, selectedTag, setSelectedTag }: { name: string, selectedTag: string | null, setSelectedTag: Function }) {
+ return (
+ (selectedTag === name) ? setSelectedTag('') : setSelectedTag(name)} className={`button is-small mr-2 mb-1 ${(selectedTag === name) ? 'is-info' : ''}`}>{name}
+ )
+}
\ No newline at end of file
diff --git a/packages/next/app/components/tag.tsx b/packages/next/app/components/tag.tsx
new file mode 100644
index 0000000..cc043dd
--- /dev/null
+++ b/packages/next/app/components/tag.tsx
@@ -0,0 +1,57 @@
+'use client';
+
+import { ITagVodRelation, ITagVodRelationsResponse } from "@/lib/tag-vod-relations"
+import { isWithinInterval, subHours } from "date-fns";
+import { faTrash } from "@fortawesome/free-solid-svg-icons";
+import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
+import { AuthContext, IUseAuth } from "./auth";
+import { useContext, useEffect, useState } from "react";
+import { useRouter } from 'next/navigation';
+import { strapiUrl } from "@/lib/constants";
+
+export interface ITagParams {
+ tvr: ITagVodRelation;
+}
+
+
+function isCreatedByMeRecently(userId: number | undefined, tvr: ITagVodRelation) {
+ if (!userId) return false;
+ if (userId !== tvr.attributes.creatorId) return false;
+ const last24H: Interval = { start: subHours(new Date(), 24), end: new Date() };
+ if (!isWithinInterval(new Date(tvr.attributes.createdAt), last24H)) return false;
+ return true;
+}
+
+async function handleDelete(authContext: IUseAuth | null, tvr: ITagVodRelation): Promise {
+ if (!authContext) return;
+ const { authData } = authContext;
+ const res = await fetch(`${strapiUrl}/api/tag-vod-relations/deleteMine/${tvr.id}`, {
+ method: 'DELETE',
+ headers: {
+ 'Authorization': `Bearer ${authData?.accessToken}`,
+ 'Content-Type': 'application/json'
+ }
+ })
+ if (!res.ok) throw new Error(res.statusText)
+}
+
+export function Tag({ tvr }: ITagParams) {
+ const authContext = useContext(AuthContext);
+ const router = useRouter()
+ const [shouldRenderDeleteButton, setShouldRenderDeleteButton] = useState(false);
+
+ useEffect(() => {
+ setShouldRenderDeleteButton(isCreatedByMeRecently(authContext?.authData?.user?.id, tvr));
+ }, [authContext?.authData?.user?.id, tvr]);
+
+ return (
+
+ {tvr.attributes.tag.data.attributes.name}
+ {shouldRenderDeleteButton && {
+ handleDelete(authContext, tvr); router.refresh()
+ }
+ } className="tag"> }
+
+ )
+}
\ No newline at end of file
diff --git a/packages/next/app/components/tagger.tsx b/packages/next/app/components/tagger.tsx
new file mode 100644
index 0000000..2918642
--- /dev/null
+++ b/packages/next/app/components/tagger.tsx
@@ -0,0 +1,240 @@
+'use client';
+
+import { useState, useCallback, useEffect, useContext } from 'react';
+import { IVod } from '@/lib/vods';
+import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
+import { faPlus, faX, faTags } from "@fortawesome/free-solid-svg-icons";
+import { formatTimestamp } from '@/lib/dates';
+import { readOrCreateTagVodRelation } from '@/lib/tag-vod-relations';
+import { readOrCreateTag } from '@/lib/tags';
+import { useAuth } from './auth';
+import { debounce } from 'lodash';
+import { strapiUrl } from '@/lib/constants';
+import { VideoContext } from './video-context';
+import { useForm } from "react-hook-form";
+import { ITimestamp, createTimestamp } from '@/lib/timestamps';
+import { useRouter } from 'next/navigation';
+import styles from '@/assets/styles/fp.module.css'
+import qs from 'qs';
+import { toast } from 'react-toastify';
+import slugify from 'slugify';
+
+interface ITaggerProps {
+ vod: IVod;
+ setTimestamps: Function;
+}
+
+export interface ITagSuggestion {
+ id: number;
+ name: string;
+ createdAt: string;
+}
+
+
+type FormData = {
+ tagName: string;
+ isTimestamp: boolean;
+};
+
+
+
+
+
+export function Tagger({ vod, setTimestamps }: ITaggerProps): React.JSX.Element {
+
+ const { register, setValue, setError, setFocus, handleSubmit, watch, clearErrors, formState: { errors } } = useForm({
+ defaultValues: {
+ tagName: '',
+ isTimestamp: true
+ }
+ });
+ const [isEditor, setIsEditor] = useState(false);
+ const [isAuthed, setIsAuthed] = useState(false);
+ const [tagSuggestions, setTagSuggestions] = useState([]);
+ const { authData } = useAuth();
+ const { timeStamp, tvrs, setTvrs } = useContext(VideoContext);
+ const router = useRouter();
+
+ const request = debounce((value: string) => {
+ search(value);
+ }, 300);
+
+ const debounceRequest = useCallback((v: string) => request(v), [request]);
+
+
+ // Callback version of watch. It's your responsibility to unsubscribe when done.
+ useEffect(() => {
+ const subscription = watch((value, { name, type }) => {
+ const tagNameValue = value.tagName as string;
+ if (name === 'tagName' && type === 'change' && value.tagName !== '') debounceRequest(tagNameValue);
+ });
+ return () => subscription.unsubscribe();
+ }, [watch, debounceRequest]);
+
+
+ useEffect(() => {
+ if (isEditor) {
+ setFocus('tagName');
+ getRandomSuggestions();
+ }
+ }, [isEditor, setFocus]);
+
+ useEffect(() => {
+ if (authData?.accessToken) {
+ setIsAuthed(true);
+ }
+ }, [isAuthed]);
+
+
+ async function getRandomSuggestions() {
+ const res = await fetch(`${strapiUrl}/api/tag/random`);
+ const tags = await res.json();
+ setTagSuggestions(tags)
+ }
+
+ async function search(value: string) {
+ const query = qs.stringify(
+ {
+ filters: {
+ tags: {
+ publishedAt: {
+ $notNull: true
+ }
+ }
+ },
+ query: value
+ }
+ )
+ if (!value) return;
+ const res = await fetch(`${strapiUrl}/api/fuzzy-search/search?${query}`, {
+ headers: {
+ 'Authorization': `Bearer ${authData?.accessToken}`
+ }
+ })
+ const json = await res.json()
+ if (!res.ok) {
+ toast('failed to get recomended tags', { type: 'error', theme: 'dark' });
+ } else {
+ setTagSuggestions(json.tags)
+ }
+ }
+
+
+ async function onError(errors: any) {
+ console.error('submit handler encoutnered an error');
+ console.error(errors);
+ toast('there was an error');
+ }
+
+ async function onSubmit(values: { tagName: string, isTimestamp: boolean }) {
+ if (!authData?.accessToken) {
+ toast('must be logged in', { type: 'error', theme: 'dark' });
+ return
+ }
+ try {
+
+ const tag = await readOrCreateTag(authData.accessToken, slugify(values.tagName));
+ if (!tag) throw new Error(`readOrCreateTag failed`);
+
+
+ const tvr = await readOrCreateTagVodRelation(authData.accessToken, tag.id, vod.id);
+ console.log(`now we check to see if we have a TVR`);
+ console.log(tvr)
+
+ if (values.isTimestamp) {
+ console.log(`user specified that we must create a timestamp`);
+ const timestamp = await createTimestamp(authData, tag.id, vod.id, timeStamp);
+ console.log(timestamp)
+ if (!timestamp) throw new Error(`failed to create timestamp`)
+ setTimestamps((prevTimestamps: ITimestamp[]) => [...prevTimestamps, timestamp]);
+ }
+
+ setValue('tagName', '');
+ router.refresh();
+ } catch (e) {
+ toast(`${e}`, { type: 'error', theme: 'dark' });
+ }
+ }
+
+ if (!isAuthed) {
+ return <>>
+ } else {
+ if (isEditor) {
+ return (
+
+
+
+
+ Tagger
+ {
+ setIsEditor(false);
+ setValue('tagName', '');
+ setTagSuggestions([]);
+ clearErrors();
+ }} className='card-header-icon'>
+
+
+
+
+
+
+
+ )
+ } else {
+ return (
+ setIsEditor(true)}>
+
+ Add a Tag
+
+ );
+ }
+ }
+
+
+}
diff --git a/packages/next/app/components/timestamps-list.tsx b/packages/next/app/components/timestamps-list.tsx
new file mode 100644
index 0000000..e2ad0a0
--- /dev/null
+++ b/packages/next/app/components/timestamps-list.tsx
@@ -0,0 +1,72 @@
+import React, { useContext, useState, useEffect } from "react";
+import { IVod } from "@/lib/vods";
+import {
+ ITimestamp,
+ deleteTimestamp
+} from "@/lib/timestamps";
+import {
+ formatTimestamp,
+ formatUrlTimestamp,
+} from "@/lib/dates";
+import Link from 'next/link';
+import { faClock, faLink, faTrash } from "@fortawesome/free-solid-svg-icons";
+import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
+import { AuthContext, IAuthData } from "./auth";
+import { isWithinInterval, subHours, Interval } from 'date-fns';
+import { useRouter } from 'next/navigation';
+
+export interface ITimestampsProps {
+ vod: IVod;
+ timestamps: ITimestamp[];
+ setTimestamps: Function;
+}
+
+function isCreatedByMeRecently(authData: IAuthData, ts: ITimestamp) {
+ if (!authData?.user) return false;
+ if (authData.user.id !== ts.attributes.creatorId) return false;
+ const last24H: Interval = { start: subHours(new Date(), 24), end: new Date() };
+ return isWithinInterval(new Date(ts.attributes.createdAt), last24H);
+}
+
+
+export function TimestampsList({ vod, timestamps, setTimestamps }: ITimestampsProps): React.JSX.Element {
+ // const throttledTimestampFetch = throttle(getRawTimestampsForVod);
+ const authContext = useContext(AuthContext);
+
+
+ const hasTimestamps = timestamps.length > 0;
+
+ return (
+
+
+
+ {hasTimestamps && (
+ timestamps.map((ts: ITimestamp) => (
+
+ {/* {JSON.stringify(ts, null, 2)} */}
+
+ {formatTimestamp(ts.attributes.time)}
+ {' '}
+ {ts.attributes.tag.data.attributes.name}
+ {authContext?.authData && isCreatedByMeRecently(authContext.authData, ts) && (
+ {
+ if (!authContext?.authData) return;
+ deleteTimestamp(authContext.authData, ts.id);
+ setTimestamps((prevTimestamps: ITimestamp[]) => prevTimestamps.filter((timestamp) => timestamp.id !== ts.id));
+ }}
+ className={`button icon`}
+ >
+
+
+ )}
+
+ ))
+ )}
+
+ {!hasTimestamps &&
This VOD has no timestamps
}
+
+ );
+}
diff --git a/packages/next/app/components/toys.tsx b/packages/next/app/components/toys.tsx
new file mode 100644
index 0000000..564d0ef
--- /dev/null
+++ b/packages/next/app/components/toys.tsx
@@ -0,0 +1,81 @@
+import React from 'react';
+import { IToy, IToysResponse } from '@/lib/toys';
+import { IVtuber } from '@/lib/vtubers';
+import Link from 'next/link';
+import Image from 'next/image';
+
+export interface IToyProps {
+ toy: IToy;
+}
+
+export interface IToysListsProps {
+ vtuber: IVtuber;
+ toys: IToysResponse;
+ page: number;
+ pageSize: number;
+}
+
+// interface VodsListProps {
+// vtuber: IVtuber;
+// vods: IVods;
+// page: number;
+// pageSize: number;
+// }
+
+
+
+export function ToysListHeading({ slug, displayName }: { slug: string, displayName: string }): React.JSX.Element {
+ return (
+
+
+ {displayName}'s Toys
+
+
+ )
+}
+
+// export interface IToy {
+// id: number;
+// tags: ITag[];
+// linkTag: ITag;
+// make: string;
+// model: string;
+// aspectRatio: string;
+// image2: string;
+// }
+
+export function ToyItem({ toy }: IToyProps) {
+ const displayName = `${toy.attributes.make} ${toy.attributes.model}`;
+ // if (!toy?.linkTag) return toy.linkTag is missing which is a problem
+ return (
+
+
+
+
+
+
+
{toy.attributes.model}
+
+
+ );
+};
+
+export function ToysList({ vtuber, toys, page = 1, pageSize = 24 }: IToysListsProps) {
+ return (
+
+ {/*
{JSON.stringify(toys, null, 2)} toys:{toys.data.length} page:{page} pageSize:{pageSize}
*/}
+
+ {toys.data.map((toy: IToy) => (
+ //
{JSON.stringify(toy, null, 2)}
+
+ ))}
+
+
+ )
+};
diff --git a/packages/next/app/components/upload-form.tsx b/packages/next/app/components/upload-form.tsx
new file mode 100644
index 0000000..9283822
--- /dev/null
+++ b/packages/next/app/components/upload-form.tsx
@@ -0,0 +1,327 @@
+'use client';
+
+import { IVtuber } from "@/lib/vtubers";
+import { useSearchParams } from 'next/navigation';
+import React, { useContext, useState, useEffect } from 'react';
+import { UppyContext } from 'app/uppy';
+import { LoginButton, useAuth } from '@/components/auth';
+import { Dashboard } from '@uppy/react';
+import styles from '@/assets/styles/fp.module.css'
+import { projektMelodyEpoch } from "@/lib/constants";
+import add from "date-fns/add";
+import sub from "date-fns/sub";
+import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
+import { faCheckCircle, faPaperPlane, faXmark } from "@fortawesome/free-solid-svg-icons";
+import { useForm, useFieldArray, ValidationMode } from 'react-hook-form';
+import { yupResolver } from '@hookform/resolvers/yup';
+import * as Yup from 'yup';
+
+
+interface IUploadFormProps {
+ vtubers: IVtuber[];
+}
+
+interface IValidationResults {
+ valid: boolean;
+ issues: string[] | null;
+}
+
+interface IFormSchema extends Yup.InferType { };
+
+
+const validationSchema = Yup.object().shape({
+ vtuber: Yup.number()
+ .required('VTuber is required'),
+ date: Yup.date()
+ .typeError('Invalid date') // https://stackoverflow.com/a/72985532/1004931
+ .min(sub(projektMelodyEpoch, { days: 1 }), 'Date must be after February 7 2020')
+ .max(add(new Date(), { days: 1 }), 'Date cannot be in the future')
+ .required('Date is required'),
+ notes: Yup.string().optional(),
+ attribution: Yup.boolean().optional(),
+ files: Yup.array()
+ .of(
+ Yup.object().shape({
+ key: Yup.string().required('key is required'),
+ uploadId: Yup.string().required('uploadId is required')
+ }),
+ )
+ .min(1, 'At least one file is required'),
+});
+
+
+
+export default function UploadForm({ vtubers }: IUploadFormProps) {
+ const searchParams = useSearchParams();
+ const cuid = searchParams.get('cuid');
+ const uppy = useContext(UppyContext);
+ const { authData } = useAuth();
+
+ const formOptions = {
+ resolver: yupResolver(validationSchema),
+ mode: 'onChange' as keyof ValidationMode,
+ };
+ const {
+ register,
+ handleSubmit,
+ formState: {
+ errors,
+ isValid
+ },
+ setValue,
+ watch,
+ } = useForm(formOptions);
+
+
+ const files = watch('files');
+
+
+
+ async function createUSC(data: IFormSchema) {
+ const res = await fetch(`${process.env.NEXT_PUBLIC_STRAPI_URL}/api/user-submitted-contents/createFromUppy`, {
+ method: 'POST',
+ headers: {
+ 'authorization': `Bearer ${authData?.accessToken}`,
+ 'content-type': 'application/json',
+ 'accept': 'application/json'
+ },
+ body: JSON.stringify({
+ data: {
+ files: data.files,
+ attribution: data.attribution,
+ notes: data.notes,
+ vtuber: data.vtuber,
+ date: data.date
+ }
+ })
+ });
+
+ if (!res.ok) {
+ console.error('failed to fetch /api/user-submitted-contents/createFromUppy');
+ }
+ }
+
+
+ uppy.on('complete', async (result: any) => {
+ let files = result.successful.map((f: any) => ({ key: f.s3Multipart.key, uploadId: f.s3Multipart.uploadId }));
+ setValue('files', files);
+ });
+
+ return (
+ <>
+
+
+
Upload VOD
+
+
Together we can archive all lewdtuber livestreams!
+
+ {(!authData?.accessToken)
+ ?
+ <>
+
+
+ >
+ : (
+
+
+
+
+
+
+ )
+ }
+
+
+
+ >
+ )
+
+}
diff --git a/packages/next/app/components/user-controls.tsx b/packages/next/app/components/user-controls.tsx
new file mode 100644
index 0000000..8fa4b8a
--- /dev/null
+++ b/packages/next/app/components/user-controls.tsx
@@ -0,0 +1,229 @@
+'use client';
+
+import React, { useState } from 'react';
+import { LogoutButton, useAuth } from "../components/auth"
+import { patreonQuantumSupporterId, strapiUrl } from '../lib/constants';
+import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
+import { faSave, faTimes, faCheck } from "@fortawesome/free-solid-svg-icons";
+import Skeleton from 'react-loading-skeleton';
+
+interface IArchiveSupporterProps {
+ isNamePublic: boolean;
+ setIsNamePublic: Function;
+}
+
+interface ISaveButtonProps {
+ isDirty: boolean;
+ isLoading: boolean;
+ isSuccess: boolean;
+ isNamePublic: boolean;
+ isLinkPublic: boolean;
+ vanityLink: string;
+ setVanityLink: Function;
+ setIsLoading: Function;
+ setIsSuccess: Function;
+ setIsDirty: Function;
+ setAuthData: Function;
+ errors: String[];
+ setErrors: Function;
+}
+
+interface IQuantumSupporterProps {
+ isLinkPublic: boolean;
+ hasUrlBenefit: boolean;
+ setIsLinkPublic: Function;
+ vanityLink: string;
+ setVanityLink: Function;
+}
+
+
+export default function UserControls() {
+ const [isLoading, setIsLoading] = useState(false);
+ const [isSuccess, setIsSuccess] = useState(false);
+ const [isDirty, setIsDirty] = useState(false);
+ const [isNamePublic, setIsNamePublic] = useState(false);
+ const [isLinkPublic, setIsLinkPublic] = useState(false);
+ const [errors, setErrors] = useState([])
+ const [vanityLink, setVanityLink] = useState('')
+
+ const { authData, setAuthData } = useAuth()
+
+
+ if (!authData) return Loading...
+
+
+ const hasUrlBenefit = (authData?.user?.patreonBenefits) ? authData.user.patreonBenefits.split(' ').includes(patreonQuantumSupporterId) : false;
+
+ return (
+
+
+ Patron Perks
+
+
+
+
+
+
+
+
+ );
+};
+
+
+export function SaveButton({
+ isDirty,
+ setIsDirty,
+ isLoading,
+ setIsLoading,
+ setIsSuccess,
+ isSuccess,
+ isNamePublic,
+ isLinkPublic,
+ vanityLink,
+ setVanityLink,
+ setAuthData,
+ errors,
+ setErrors,
+}: ISaveButtonProps) {
+ const { authData } = useAuth();
+ const handleClick = async () => {
+ if (!authData?.user) return;
+ try {
+ setIsLoading(true);
+
+ const response = await fetch(`${strapiUrl}/api/profile/${authData.user.id}`, {
+ method: 'PUT',
+ headers: {
+ 'Content-Type': 'application/json',
+ 'Authorization': `Bearer ${authData.accessToken}`
+ },
+ body: JSON.stringify({
+ isNamePublic,
+ isLinkPublic,
+ vanityLink
+ })
+ });
+
+ setIsLoading(false);
+ setIsDirty(true);
+
+ if (!response.ok) {
+ setIsSuccess(false);
+ } else {
+ setIsSuccess(true);
+
+ // Update authData if needed
+ const updatedAuthData = { ...authData };
+ if (!updatedAuthData?.user) return;
+ updatedAuthData.user.vanityLink = vanityLink;
+ updatedAuthData.user.isNamePublic = isNamePublic;
+ updatedAuthData.user.isLinkPublic = isLinkPublic;
+ setAuthData(updatedAuthData);
+ }
+ } catch (error) {
+ if (error instanceof Error) {
+ setErrors(errors.concat([error.message]))
+ }
+ }
+ };
+
+
+ return (
+
+
+
+
+
+
+
+
+
+
+ Save
+
+ )
+}
+
+export function Thanks() {
+ return Thank you so much for supporting Futureporn!
+}
+
+export function QuantumSupporterPerks({ isLinkPublic, setIsLinkPublic, setVanityLink, vanityLink, hasUrlBenefit }: IQuantumSupporterProps) {
+ const { authData } = useAuth()
+
+ return (
+
+
URL
+
+
+ setIsLinkPublic(!isLinkPublic)}
+ />
+ Publicly display my URL {vanityLink} on the patrons page.
+
+
+
+ setVanityLink(e.target.value)}
+ />
+
+
+
+ )
+}
+
+export function AdvancedArchiveSupporterPerks() {
+
+}
+
+export function ArchiveSupporterPerks({ isNamePublic, setIsNamePublic }: IArchiveSupporterProps) {
+ const { authData } = useAuth()
+
+ return (
+
+
Username
+
+
+ setIsNamePublic(!isNamePublic)}
+ />
+ Publicly display {(authData?.user?.username) ? authData.user.username : } on the patrons page.
+
+
+
+ )
+}
\ No newline at end of file
diff --git a/packages/next/app/components/video-context.tsx b/packages/next/app/components/video-context.tsx
new file mode 100644
index 0000000..4281a25
--- /dev/null
+++ b/packages/next/app/components/video-context.tsx
@@ -0,0 +1,56 @@
+
+import VideoApiElement from "@mux/mux-player/dist/types/video-api";
+import { MutableRefObject, createContext, useState } from "react";
+import { ITagVodRelation } from "@/lib/tag-vod-relations";
+
+export interface IVideoContextValue {
+ timeStamp: number;
+ setTimeStamp: Function;
+ tvrs: ITagVodRelation[];
+ setTvrs: Function;
+}
+
+// const defaultContextValue = {
+// timeStamp: 3,
+// setTimeStamp: () => null,
+// ref: null,
+// }
+
+export const VideoContext = createContext({} as IVideoContextValue);
+
+
+// export function VideoContextProvider({ children }: IAuthContextProps): React.JSX.Element {
+// const { value: authData, set: setAuthData } = useLocalStorageValue('authData', {
+// defaultValue: null,
+// });
+
+// const { value: lastVisitedPath, set: setLastVisitedPath } = useLocalStorageValue('lastVisitedPath', {
+// defaultValue: '/profile',
+// initializeWithValue: false,
+// });
+// const router = useRouter();
+
+// const login = async () => {
+// const currentPath = window.location.pathname;
+// setLastVisitedPath(currentPath);
+// router.push(`${strapiUrl}/api/connect/patreon`);
+// };
+
+// const logout = () => {
+// setAuthData({ accessToken: null, user: null });
+// };
+
+// return (
+//
+// {children}
+//
+// );
+// }
\ No newline at end of file
diff --git a/packages/next/app/components/video-interactive.tsx b/packages/next/app/components/video-interactive.tsx
new file mode 100644
index 0000000..28617d3
--- /dev/null
+++ b/packages/next/app/components/video-interactive.tsx
@@ -0,0 +1,134 @@
+'use client';
+
+import { IVod } from "@/lib/vods";
+import { useRef, useState, useEffect, useCallback } from "react";
+import { VideoPlayer } from "./video-player";
+import { Tagger } from './tagger';
+import { ITimestamp, getTimestampsForVod } from "@/lib/timestamps";
+import { TimestampsList } from "./timestamps-list";
+import { ITagVodRelation } from "@/lib/tag-vod-relations";
+import { VideoContext } from "./video-context";
+import { getVodTitle } from "./vod-page";
+import { useSearchParams } from 'next/navigation';
+import VideoApiElement from "@mux/mux-player/dist/types/video-api";
+import { parseUrlTimestamp } from "@/lib/dates";
+import { faTags, faNoteSticky, faClock } from "@fortawesome/free-solid-svg-icons";
+import { Tag } from './tag';
+import VodNav from './vod-nav';
+import LinkableHeading from "./linkable-heading";
+
+
+export interface IVideoInteractiveProps {
+ vod: IVod;
+}
+
+
+function secondsToHumanReadable(timestampInSeconds: number): string {
+ const hours = Math.floor(timestampInSeconds / 3600);
+ const minutes = Math.floor((timestampInSeconds % 3600) / 60);
+ const seconds = timestampInSeconds % 60;
+
+ return `${hours}h${minutes}m${seconds}s`;
+}
+
+
+function humanReadableTimestampToSeconds(timestamp: string): number | null {
+ const parts = timestamp.split(':');
+
+ if (parts.length !== 3) {
+ // Invalid format, return null or throw an error as appropriate
+ return null;
+ }
+
+ const hours = parseInt(parts[0], 10);
+ const minutes = parseInt(parts[1], 10);
+ const seconds = parseInt(parts[2], 10);
+
+ if (isNaN(hours) || isNaN(minutes) || isNaN(seconds)) {
+ // Invalid numeric values, return null or throw an error as appropriate
+ return null;
+ }
+
+ const totalSeconds = hours * 3600 + minutes * 60 + seconds;
+
+ return totalSeconds;
+}
+
+
+
+
+export function VideoInteractive({ vod }: IVideoInteractiveProps): React.JSX.Element {
+
+ const [timeStamp, setTimeStamp] = useState(0);
+ const [tvrs, setTvrs] = useState([]);
+ const [isPlayerReady, setIsPlayerReady] = useState(false);
+ const [timestamps, setTimestamps] = useState([]);
+ const [currentTsPage, setCurrentTsPage] = useState(1);
+
+ const getTimestampPage = useCallback(async (page: number) => {
+ const timestamps = await getTimestampsForVod(vod.id, page);
+ setTimestamps(timestamps);
+ }, [vod.id, setTimestamps]); // IGNORE TS LINTER! DO NOT PUT timestamps HERE! IT CAUSES SELF-DDOS!
+
+ const ref = useRef(null);
+ const searchParams = useSearchParams();
+ const t = searchParams.get('t');
+
+
+
+ useEffect(() => {
+ getTimestampPage(currentTsPage);
+ }, [vod.id, getTimestampPage, currentTsPage]);
+
+ useEffect(() => {
+ if (!t) return;
+ if (!ref?.current) return;
+ const videoRef = ref.current as VideoApiElement;
+ const seconds = parseUrlTimestamp(t)
+ if (seconds === null) return;
+ videoRef.currentTime = seconds;
+ }, [t, isPlayerReady, ref])
+
+
+ return (
+
+
+
+
+ {getVodTitle(vod)}
+
+
+
+
+ {vod.attributes.note && (
+ <>
+
+
{vod.attributes.note}
+ >
+ )}
+
+
+
+
+ {vod.attributes.tagVodRelations.data.length === 0 &&
}
+ {vod.attributes.tagVodRelations.data.map((tvr: ITagVodRelation) => (
+
+ ))}
+
+
+
+
+
+
+
+ )
+}
\ No newline at end of file
diff --git a/packages/next/app/components/video-player.tsx b/packages/next/app/components/video-player.tsx
new file mode 100644
index 0000000..25bd69d
--- /dev/null
+++ b/packages/next/app/components/video-player.tsx
@@ -0,0 +1,151 @@
+'use client';
+
+import { useEffect, useState, forwardRef, useContext, Ref } from 'react';
+import { IVod } from '@/lib/vods';
+import "plyr-react/plyr.css";
+import { useAuth } from '@/components/auth';
+import { getVodTitle } from './vod-page';
+import { VideoSourceSelector } from '@/components/video-source-selector'
+import { buildIpfsUrl } from '@/lib/ipfs';
+import { strapiUrl } from '@/lib/constants';
+import MuxPlayer from '@mux/mux-player-react/lazy';
+import { VideoContext } from './video-context';
+import MuxPlayerElement from '@mux/mux-player';
+import VideoApiElement from "@mux/mux-player/dist/types/video-api";
+
+interface IPlayerProps {
+ vod: IVod;
+ setIsPlayerReady: Function;
+}
+
+interface ITokens {
+ playbackToken: string;
+ storyboardToken: string;
+ thumbnailToken: string;
+}
+
+async function getMuxPlaybackTokens(playbackId: string, jwt: string): Promise {
+ const res = await fetch(`${strapiUrl}/api/mux-asset/secure?id=${playbackId}`, {
+ headers: {
+ 'Authorization': `Bearer ${jwt}`
+ }
+ })
+ const json = await res.json()
+
+ return {
+ playbackToken: json.playbackToken,
+ storyboardToken: json.storyboardToken,
+ thumbnailToken: json.thumbnailToken
+ }
+}
+
+function hexToRgba(hex: string, alpha: number) {
+ const r = parseInt(hex.slice(1, 3), 16);
+ const g = parseInt(hex.slice(3, 5), 16);
+ const b = parseInt(hex.slice(5, 7), 16);
+ return `rgba(${r}, ${g}, ${b}, ${alpha})`;
+}
+
+
+
+export const VideoPlayer = forwardRef(function VideoPlayer( props: IPlayerProps, ref: Ref ): React.JSX.Element {
+ const { vod, setIsPlayerReady } = props
+ const title: string = getVodTitle(vod);
+ const { authData } = useAuth();
+ const [selectedVideoSource, setSelectedVideoSource] = useState('');
+ const [isEntitledToCDN, setIsEntitledToCDN] = useState(false);
+ const [hlsSource, setHlsSource] = useState('');
+ const [isClient, setIsClient] = useState(false);
+ const [playbackId, setPlaybackId] = useState('');
+ const [src, setSrc] = useState('');
+ const [tokens, setTokens] = useState({});
+ const { setTimeStamp } = useContext(VideoContext);
+
+
+
+ useEffect(() => {
+ setIsClient(true);
+ const token = authData?.accessToken;
+ const playbackId = vod?.attributes.muxAsset?.data?.attributes?.playbackId;
+
+ if (token) setIsEntitledToCDN(true);
+
+ if (selectedVideoSource === 'Mux') {
+ if (!!token && !!playbackId) {
+ try {
+ getMuxPlaybackTokens(vod.attributes.muxAsset.data.attributes.playbackId, token)
+ .then((tokens) => {
+ setTokens({
+ playback: tokens.playbackToken,
+ storyboard: tokens.storyboardToken,
+ thumbnail: tokens.thumbnailToken
+ })
+ setHlsSource(vod.attributes.muxAsset.data.attributes.playbackId)
+ setPlaybackId(vod.attributes.muxAsset.data.attributes.playbackId)
+ });
+ }
+
+ catch (e) {
+ console.error(e)
+ }
+ }
+ } else if (selectedVideoSource === 'B2') {
+ if (!vod.attributes.videoSrcB2) return; // This shouldn't happen because videoSourceSelector won't choose B2 if there is no b2. This return is only for satisfying TS
+ setHlsSource(vod.attributes.videoSrcB2.data.attributes.cdnUrl);
+ setPlaybackId('');
+ setSrc(vod.attributes.videoSrcB2.data.attributes.cdnUrl);
+ } else if (selectedVideoSource === 'IPFSSource') {
+ setHlsSource('');
+ setPlaybackId('');
+ setSrc(buildIpfsUrl(vod.attributes.videoSrcHash))
+ } else if (selectedVideoSource === 'IPFS240') {
+ setHlsSource('');
+ setPlaybackId('');
+ setSrc(buildIpfsUrl(vod.attributes.video240Hash))
+ }
+ }, [selectedVideoSource, authData, vod, setHlsSource]);
+
+
+ if (!isClient) return <>>
+
+
+ return (
+ <>
+ {
+ setIsPlayerReady(true)}
+ }
+ ref={ref}
+ preload="auto"
+ crossOrigin="*"
+ loading="viewport"
+ playbackId={playbackId}
+ src={src}
+ tokens={tokens}
+ primaryColor="#FFFFFF"
+ secondaryColor={hexToRgba(vod.attributes.vtuber.data.attributes.themeColor, 0.85)}
+ metadata={{
+ video_title: getVodTitle(vod)
+ }}
+
+ streamType="on-demand"
+ onTimeUpdate={(evt) => {
+ const muxPlayer = evt.target as VideoApiElement
+ const { currentTime } = muxPlayer;
+ setTimeStamp(currentTime)
+ }}
+ muted
+ >
+
+
+ >
+ )
+})
\ No newline at end of file
diff --git a/packages/next/app/components/video-source-selector.tsx b/packages/next/app/components/video-source-selector.tsx
new file mode 100644
index 0000000..5f011a9
--- /dev/null
+++ b/packages/next/app/components/video-source-selector.tsx
@@ -0,0 +1,130 @@
+'use client';
+import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"
+import { faPatreon } from "@fortawesome/free-brands-svg-icons";
+import { faGlobe } from "@fortawesome/free-solid-svg-icons";
+import { useState, useEffect } from 'react';
+
+interface IVSSProps {
+ isMux: boolean;
+ isB2: boolean;
+ isIPFSSource: boolean;
+ isIPFS240: boolean;
+ isEntitledToCDN: boolean;
+ setSelectedVideoSource: (option: string) => void;
+ selectedVideoSource: string;
+}
+
+export function VideoSourceSelector({
+ isMux,
+ isB2,
+ isIPFSSource,
+ isIPFS240,
+ isEntitledToCDN,
+ selectedVideoSource,
+ setSelectedVideoSource,
+}: IVSSProps): React.JSX.Element {
+
+ // Check for user's entitlements and saved preference when component mounts
+ useEffect(() => {
+ // Function to determine the best video source based on entitlements and preferences
+ const determineBestVideoSource = () => {
+ if (isEntitledToCDN) {
+ if (selectedVideoSource === 'Mux' && isMux) {
+ return 'Mux';
+ } else if (selectedVideoSource === 'B2' && isB2) {
+ return 'B2';
+ }
+ }
+ // If the user doesn't have entitlements or their preference is not available, default to IPFS
+ if (isIPFSSource) {
+ return 'IPFSSource';
+ } else if (isIPFS240) {
+ return 'IPFS240';
+ }
+ // If no sources are available, return an empty string
+ return '';
+ };
+
+ // If selectedVideoSource is unset, find the value to use
+ if (selectedVideoSource === '') {
+ // Load the user's saved preference from storage (e.g., local storage)
+ const savedPreference = localStorage.getItem('videoSourcePreference');
+
+ // Check if the saved preference is valid based on entitlements and available sources
+ if (savedPreference === 'Mux' && isMux && isEntitledToCDN) {
+ setSelectedVideoSource('Mux');
+ } else if (savedPreference === 'B2' && isB2 && isEntitledToCDN) {
+ setSelectedVideoSource('B2');
+ } else {
+ // Determine the best video source if the saved preference is invalid or not available
+ const bestSource = determineBestVideoSource();
+ setSelectedVideoSource(bestSource);
+ }
+ }
+
+
+ }, [isMux, isB2, isIPFSSource, isIPFS240, isEntitledToCDN, selectedVideoSource, setSelectedVideoSource]);
+
+ // Handle button click to change the selected video source
+ const handleSourceClick = (source: string) => {
+ if (
+ (source === 'Mux' && isMux && isEntitledToCDN) ||
+ (source === 'B2' && isB2 && isEntitledToCDN) ||
+ (source === 'IPFSSource') ||
+ (source === 'IPFS240')
+ ) {
+ setSelectedVideoSource(source);
+ // Save the user's preference to storage (e.g., local storage)
+ localStorage.setItem('videoSourcePreference', source);
+ }
+ };
+
+ return (
+ <>
+
+
+
+ Video Source Selector
+
+ {(!isMux && !isB2 && !isIPFSSource && !isIPFS240) &&
+
+ No video sources available
+
+
}
+ {(isMux) &&
+ handleSourceClick('Mux')} disabled={!isEntitledToCDN} className={`button ${selectedVideoSource === 'Mux' && 'is-active'}`}>
+
+
+
+ CDN 1
+
+
}
+ {(isB2) &&
+ handleSourceClick('B2')} disabled={!isEntitledToCDN} className={`button ${selectedVideoSource === 'B2' && 'is-active'}`}>
+
+
+
+ CDN 2
+
+
}
+ {(isIPFSSource) &&
+ handleSourceClick('IPFSSource')} className={`button ${(selectedVideoSource === 'IPFSSource') && 'is-active'}`}>
+
+
+
+ IPFS Src
+
+
}
+ {(isIPFS240) &&
+ handleSourceClick('IPFS240')} className={`button ${(selectedVideoSource === 'IPFS240') && 'is-active'}`}>
+
+
+
+ IPFS 240p
+
+
}
+
+
+ >
+ )
+}
\ No newline at end of file
diff --git a/packages/next/app/components/vod-card.tsx b/packages/next/app/components/vod-card.tsx
new file mode 100644
index 0000000..175ed40
--- /dev/null
+++ b/packages/next/app/components/vod-card.tsx
@@ -0,0 +1,72 @@
+import Link from "next/link";
+import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
+import { faPatreon } from "@fortawesome/free-brands-svg-icons";
+import { faVideo } from "@fortawesome/free-solid-svg-icons";
+import { getSafeDate, getDateFromSafeDate } from '@/lib/dates';
+import { IVtuber } from '@/lib/vtubers';
+import Image from 'next/image'
+import { LocalizedDate } from '@/components/localized-date'
+import { IMuxAsset, IMuxAssetResponse } from "@/lib/types";
+import { IB2File } from "@/lib/b2File";
+
+interface IVodCardProps {
+ id: number;
+ title: string;
+ date: string;
+ muxAsset: string | undefined;
+ thumbnail: string | undefined;
+ vtuber: IVtuber;
+}
+
+
+export default function VodCard({id, title, date, muxAsset, thumbnail = 'https://futureporn-b2.b-cdn.net/default-thumbnail.webp', vtuber}: IVodCardProps) {
+
+ if (!vtuber?.attributes?.slug) return VOD {id} is missing VTuber
+
+ return (
+
+
+
+
+
+
+
+
+
+
{title}
+
+
+
+
+
+
+ {muxAsset && (
+
+
+
+ )}
+
+
+
+
+
+
+ )
+ }
+
+
+
+
+
diff --git a/packages/next/app/components/vod-nav.tsx b/packages/next/app/components/vod-nav.tsx
new file mode 100644
index 0000000..c760ed1
--- /dev/null
+++ b/packages/next/app/components/vod-nav.tsx
@@ -0,0 +1,90 @@
+'use client';
+
+import { faVideo, faExternalLinkAlt, faShareAlt } from "@fortawesome/free-solid-svg-icons";
+import { faXTwitter } from '@fortawesome/free-brands-svg-icons';
+import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
+import Image from 'next/image';
+import Link from 'next/link';
+import { IVod } from '@/lib/vods';
+import { buildIpfsUrl } from '@/lib/ipfs';
+import { getSafeDate } from "@/lib/dates";
+import { StreamButton } from '@/components/stream-button';
+import VtuberButton from "./vtuber-button";
+
+export function getDownloadLink(cid: string, safeDate: string, slug: string, quality: string) {
+ return buildIpfsUrl(`${cid}?filename=${slug}-${safeDate}-${quality}.mp4`)
+}
+
+
+export interface IVodNavProps {
+ vod: IVod;
+}
+
+export default function VodNav ({ vod }: IVodNavProps) {
+ const safeDate = getSafeDate(vod.attributes.date2);
+ return (
+
+
+
+ {vod.attributes.videoSrcHash && (
+ <>
+
+
+
+ Source
+
+
+
+ >
+ )}
+ {vod.attributes.video240Hash && (
+
+
+
+
+ 240p
+
+
+
+
+ )}
+ {vod.attributes.announceUrl && (
+
+
+
+
+
+ )}
+
+
+ )
+}
\ No newline at end of file
diff --git a/packages/next/app/components/vod-page.tsx b/packages/next/app/components/vod-page.tsx
new file mode 100644
index 0000000..9d81faa
--- /dev/null
+++ b/packages/next/app/components/vod-page.tsx
@@ -0,0 +1,96 @@
+import { getUrl, getNextVod, getPreviousVod, getLocalizedDate } from '@/lib/vods';
+import { IVod } from '@/lib/vods';
+import Link from 'next/link';
+import { VideoInteractive } from './video-interactive';
+import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
+import { faChevronLeft, faChevronRight, faGlobe, faLink } from "@fortawesome/free-solid-svg-icons";
+import { notFound } from 'next/navigation';
+import { IpfsCid } from './ipfs-cid';
+import LinkableHeading from './linkable-heading';
+
+
+export function getVodTitle(vod: IVod): string {
+ return vod.attributes.title || vod.attributes.announceTitle || `${vod.attributes.vtuber.data.attributes.displayName} ${vod.attributes.date2}`;
+}
+
+export function buildMuxUrl(playbackId: string, token: string) {
+ return `https://stream.mux.com/${playbackId}.m3u8?token=${token}`
+}
+
+export function buildMuxSignedPlaybackId(playbackId: string, token: string) {
+ return `${playbackId}?token=${token}`
+}
+
+export function buildMuxThumbnailUrl(playbackId: string, token: string) {
+ return `https://image.mux.com/${playbackId}/storyboard.vtt?token=${token}`
+}
+
+
+export default async function VodPage({vod}: { vod: IVod }) {
+
+ if (!vod) notFound();
+ const slug = vod.attributes.vtuber.data.attributes.slug;
+ const previousVod = await getPreviousVod(vod);
+ const nextVod = await getNextVod(vod);
+
+
+ return (
+
+
+
+
+
+
+ {(vod.attributes.videoSrcHash || vod.attributes.video240Hash) && (
+ <>
+
+ {vod.attributes.videoSrcHash && (
+
+ )}
+ {vod.attributes.video240Hash && (
+
+ )}
+ >
+ )}
+
+
+
+
+
+ {!!previousVod && (
+
+
+ Prev VOD {getLocalizedDate(previousVod)}
+
+ )}
+
+
+
+
+
UID {vod.attributes.cuid}
+
+
+
+
+ {!!nextVod && (
+
+ Next VOD {getLocalizedDate(nextVod)}
+
+
+ )}
+
+
+
+
+
+
+
+
+ );
+}
diff --git a/packages/next/app/components/vods-list.tsx b/packages/next/app/components/vods-list.tsx
new file mode 100644
index 0000000..1eb8b96
--- /dev/null
+++ b/packages/next/app/components/vods-list.tsx
@@ -0,0 +1,66 @@
+import React from 'react'
+import Link from 'next/link';
+import VodCard from './vod-card';
+import { IVtuber, IVtuberResponse } from '@/lib/vtubers';
+import { IVodsResponse, IVod } from '@/lib/vods';
+import { getVodTitle } from './vod-page';
+import { notFound } from 'next/navigation';
+
+interface IVodsListProps {
+ vtuber?: IVtuber;
+ vods: IVod[];
+ page: number;
+ pageSize: number;
+}
+
+
+interface IVodsListHeadingProps {
+ slug: string;
+ displayName: string;
+}
+
+export function VodsListHeading({ slug, displayName }: IVodsListHeadingProps): React.JSX.Element {
+ return (
+
+
+ {displayName} Vods
+
+
+ )
+}
+
+
+export default function VodsList({ vods, page = 1, pageSize = 24 }: IVodsListProps): React.JSX.Element {
+ // if (!vtuber) return vtuber is not defined. vtuber:{JSON.stringify(vtuber, null, 2)}
+ // if (!vods) return failed to load vods
;
+ if (!vods) return notFound()
+
+ // @todo [x] pagination
+ // @todo [x] sortability
+ return (
+ <>
+ {/* VodsList on page {page}, pageSize {pageSize}, with {vods.data.length} vods
*/}
+
+ {/*
+
+ {JSON.stringify(vods.data, null, 2)}
+
+ */}
+
+
+
+ {vods.map((vod: IVod) => (
+
+ ))}
+
+ >
+ );
+}
diff --git a/packages/next/app/components/vtuber-button.tsx b/packages/next/app/components/vtuber-button.tsx
new file mode 100644
index 0000000..6826a28
--- /dev/null
+++ b/packages/next/app/components/vtuber-button.tsx
@@ -0,0 +1,29 @@
+import Image from "next/image"
+
+interface VtuberButtonProps {
+ image: string;
+ displayName: string;
+ size?: string;
+}
+
+export default function VtuberButton ({ image, displayName, size }: VtuberButtonProps) {
+ const sizeClass = (() => {
+ if (size === 'large') return 'is-large';
+ if (size === 'medium') return 'is-medium';
+ if (size === 'small') return 'is-small'
+ })();
+ return (
+
+
+
+
+ {displayName}
+
+ );
+}
\ No newline at end of file
diff --git a/packages/next/app/components/vtuber-card.tsx b/packages/next/app/components/vtuber-card.tsx
new file mode 100644
index 0000000..a324dc2
--- /dev/null
+++ b/packages/next/app/components/vtuber-card.tsx
@@ -0,0 +1,43 @@
+import Link from "next/link";
+import type { IVtuber } from '@/lib/vtubers';
+import { getVodsForVtuber } from "@/lib/vods";
+import Image from 'next/image'
+import NotFound from "app/vt/[slug]/not-found";
+import ArchiveProgress from "./archive-progress";
+
+export default async function VTuberCard(vtuber: IVtuber) {
+ const { id, attributes: { slug, displayName, imageBlur, image }} = vtuber;
+ if (!imageBlur) return this is a vtubercard with an invalid imageBlur={imageBlur}
+ const vods = await getVodsForVtuber(id)
+ if (!vods) return
+ return (
+
+
+
+ )
+ }
\ No newline at end of file
diff --git a/packages/next/app/connect/patreon/redirect/page.tsx b/packages/next/app/connect/patreon/redirect/page.tsx
new file mode 100644
index 0000000..382ad44
--- /dev/null
+++ b/packages/next/app/connect/patreon/redirect/page.tsx
@@ -0,0 +1,123 @@
+'use client'
+
+import { useSearchParams, useRouter } from 'next/navigation'
+import Link from 'next/link'
+import { useEffect, useState } from 'react'
+import { strapiUrl } from '@/lib/constants'
+import { useAuth, IAuthData, IUser, IJWT } from '@/components/auth'
+import { DangerNotification } from '@/components/notifications'
+
+export type AccessToken = string | null;
+
+
+export default function Page() {
+ const searchParams = useSearchParams()
+ const router = useRouter()
+ const { authData, setAuthData, lastVisitedPath } = useAuth()
+ const [errors, setErrors] = useState([])
+
+ const initAuth = async () => {
+ try {
+ const accessToken: AccessToken = getAccessTokenFromURL();
+ const json = await getJwt(accessToken);
+ if (!json) {
+ setErrors(errors.concat(['Unable to get access token from portal. Please try again later or check Futureporn Discord.']))
+ } else {
+ storeJwtJson(json)
+ redirect();
+ }
+ } catch (error) {
+ console.error(error);
+ }
+ };
+
+ const storeJwtJson = (json: IJWT) => {
+
+
+ // Store the JWT and other relevant data in your state management system
+ const data: IAuthData = {
+ accessToken: json.jwt,
+ user: json.user,
+ }
+ setAuthData(data);
+ }
+
+
+ const getAccessTokenFromURL = () => {
+ const accessToken: AccessToken = searchParams?.get('access_token');
+ if (!accessToken) {
+ throw new Error('Failed to get access_token from auth portal.');
+ }
+ return accessToken;
+ };
+
+ const getJwt = async (accessToken: AccessToken): Promise => {
+
+ try {
+ const response = await fetch(`${strapiUrl}/api/auth/patreon/callback?access_token=${accessToken}`);
+
+ if (!response.ok) {
+ // Handle non-2xx HTTP response status
+ throw new Error(`Failed to fetch. Status: ${response.status}`);
+ }
+
+ const json = await response.json();
+
+ if (!json.jwt) {
+ throw new Error('Failed to get auth token. Please try again later.');
+ }
+
+ return json;
+ } catch (error) {
+ console.error(error);
+ return null; // Return null or handle the error in an appropriate way
+ }
+ };
+
+
+ const redirect = () => {
+ if (!lastVisitedPath) return; // on first render, it's likely null
+ router.push(lastVisitedPath);
+ };
+
+
+ useEffect(() => {
+ initAuth()
+ })
+
+
+
+
+
+
+ {/*
+ After user auths,
+ they are redirected to this page.
+
+ This page grabs the access_token from the query string,
+ exchanges it with strapi for a jwt
+ then persists the jwt
+
+ After a jwt is stored, this page redirects the user
+ to whatever page they were previously on.
+ */}
+
+ // @todo get query parameters
+ // @todo save account info to session
+ // @todo ???
+ // @todo profit
+ // const searchParams = useSearchParams()
+ // const accessToken = searchParams?.get('access_token');
+ // const refreshToken = searchParams?.get('refresh_token');
+ // const lastVisitedPath = '@todo!'
+
+ return (
+
+ {errors && errors.length > 0 && (
+
+ )}
+
Redirecting...
+
Click here if you are not automatically redirected
+
+ )
+}
\ No newline at end of file
diff --git a/packages/next/app/faq/page.tsx b/packages/next/app/faq/page.tsx
new file mode 100644
index 0000000..6caeca4
--- /dev/null
+++ b/packages/next/app/faq/page.tsx
@@ -0,0 +1,104 @@
+import Link from 'next/link';
+import { getVtuberBySlug } from '../lib/vtubers'
+import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
+import { faExternalLinkAlt } from "@fortawesome/free-solid-svg-icons";
+import { faLink } from '@fortawesome/free-solid-svg-icons';
+import { projektMelodyEpoch } from '@/lib/constants';
+import LinkableHeading from '@/components/linkable-heading';
+
+export default async function Page() {
+ return (
+
+
+
+
Frequently Asked Questions (FAQ)
+
+
+
+
+
+
VTuber is a portmantou of the words Virtual and Youtuber. Originally started in Japan, VTubing uses cameras and/or motion capture technology to replicate human movement and facial expressions onto a virtual character in realtime.
+
+
+
+
+
Lewdtubers are sexually explicit vtubers. ProjektMelody was the first Vtuber to livestream on Chaturbate on {projektMelodyEpoch.toDateString()}. Many more followed after her.
+
+
+
+
+
Interplanetary File System (IPFS) is a new-ish technology which gives a unique address to every file. This address is called a Content ID, or CID for short. A CID can be used to request the file from the IPFS network.
+
IPFS is a distributed, decentralized protocol with no central point of failure. IPFS provider nodes can come and go, providing file serving capacity to the network. As long as there is at least one node pinning the content you want, you can download it.
+
There are a few ways to use IPFS, each with their own tradeoffs. Firstly, you can use a public gateway. IPFS public gateways can be overloaded and unreliable at times, but it's simple to use. All you have to do is visit a gateway URL containing the CID. One such example is https://ipfs.io/ipfs/bafkreigaknpexyvxt76zgkitavbwx6ejgfheup5oybpm77f3pxzrvwpfdi
+
The next way to use IPFS consists of running IPFS Desktop on your computer. A local IPFS node runs for as long as IPFS Desktop is active, and you can query this node for the content you want. This setup works best with IPFS Companion , or a web browser that natively supports IPFS, such as Brave browser.
+
+
+
+
+
+
+
+
+
+
+
You may get an error when clicking on a video link. Errors such as DNS_PROBE_FINISHED_NXDOMAIN
+
+
This is a DNS server error that occurs when a web browser isn't able to translate the domain name into an IP address.
+
+
If this happens, using a different DNS server can fix it. There are many gratis services to choose from, including Cloudflare DNS or Google DNS .
+
+
Often, using a DNS server other than the one provided to you by your ISP can improve your internet browsing experience for all websites.
+
+
+
+
+
+
+
+
+
+
+
+
Bandwidth is prohibitively expensive, so that's the free-to-play experience at the moment. ( Patrons get access to CDN which is much faster.)
+
If the video isn't loading fast enough to stream, you can download the entire video then playback later on your device.
+
+
+
+
+
+
+
+
+
+
Yes! The recommended way is to use either IPFS Desktop or ipget .
+
ipget example is as follows.
+
+
+ ipget --progress -o projektmelody-chaturbate-2023-12-03.mp4 bafybeiejms45zzonfe7ndr3mp4vmrqrg3btgmuche3xkeq5b77uauuaxkm
+
+
+
+
+
+
+
+
+
+
+
Yes. Futureporn aims to become the galaxy's best VTuber hentai site.
+
+
+
+
+
+
Bandwidth and rental fees are expensive, so Futureporn needs financial assistance to keep servers online and videos streaming.
+
Patrons gain access to perks like our video Content Delivery Network (CDN), and optional shoutouts on the patrons page.
+
Additionally, help is needed populating our archive with vods from past lewdtuber streams.
+
+
+
+
+
+
+ )
+}
\ No newline at end of file
diff --git a/packages/next/app/favicon.ico b/packages/next/app/favicon.ico
new file mode 100644
index 0000000..2ed11c7
Binary files /dev/null and b/packages/next/app/favicon.ico differ
diff --git a/packages/next/app/feed/feed.json/route.ts b/packages/next/app/feed/feed.json/route.ts
new file mode 100644
index 0000000..f7b17ca
--- /dev/null
+++ b/packages/next/app/feed/feed.json/route.ts
@@ -0,0 +1,11 @@
+import { generateFeeds } from "@/lib/rss"
+
+export async function GET() {
+ const feeds = await generateFeeds()
+ const options = {
+ headers: {
+ "Content-Type": "application/json"
+ }
+ }
+ return new Response(feeds.json1, options)
+}
\ No newline at end of file
diff --git a/packages/next/app/feed/feed.xml/route.ts b/packages/next/app/feed/feed.xml/route.ts
new file mode 100644
index 0000000..16a53bd
--- /dev/null
+++ b/packages/next/app/feed/feed.xml/route.ts
@@ -0,0 +1,11 @@
+import { generateFeeds } from "@/lib/rss"
+
+export async function GET() {
+ const { atom1 } = await generateFeeds()
+ const options = {
+ headers: {
+ "Content-Type": "application/atom+xml"
+ }
+ }
+ return new Response(atom1, options)
+}
\ No newline at end of file
diff --git a/packages/next/app/feed/page.tsx b/packages/next/app/feed/page.tsx
new file mode 100644
index 0000000..e87e056
--- /dev/null
+++ b/packages/next/app/feed/page.tsx
@@ -0,0 +1,28 @@
+
+import Link from 'next/link'
+
+export default async function Page() {
+ return (
+ <>
+
+
+
+
+
RSS Feed
+
+
Keep up to date with new VODs using Real Simple Syndication (RSS).
+
+
Don't have a RSS reader? Futureporn recommends Fraidycat
+
+
+
+
+
+ >
+ )
+}
+
diff --git a/packages/next/app/feed/rss.xml/route.ts b/packages/next/app/feed/rss.xml/route.ts
new file mode 100644
index 0000000..f8b4747
--- /dev/null
+++ b/packages/next/app/feed/rss.xml/route.ts
@@ -0,0 +1,11 @@
+import { generateFeeds } from "@/lib/rss"
+
+export async function GET() {
+ const { rss2 } = await generateFeeds()
+ const options = {
+ headers: {
+ "Content-Type": "application/rss+xml"
+ }
+ }
+ return new Response(rss2, options)
+}
\ No newline at end of file
diff --git a/packages/next/app/goals/page.tsx b/packages/next/app/goals/page.tsx
new file mode 100644
index 0000000..4bf4f05
--- /dev/null
+++ b/packages/next/app/goals/page.tsx
@@ -0,0 +1,75 @@
+import { getGoals } from "@/lib/pm";
+import { getCampaign } from "@/lib/patreon";
+
+interface IFundingStatusBadgeProps {
+ completedPercentage: number;
+}
+
+function FundingStatusBadge({ completedPercentage }: IFundingStatusBadgeProps) {
+ if (completedPercentage === 100) return Funded ;
+ return (
+
+
+ {completedPercentage}% Funded
+
+
+ );
+}
+
+
+
+// export interface IGoals {
+// complete: IIssue[];
+// inProgress: IIssue[];
+// planned: IIssue[];
+// featuredFunded: IIssue;
+// featuredUnfunded: IIssue;
+// }
+export default async function Page() {
+ const { pledgeSum } = await getCampaign()
+ const goals = await getGoals(pledgeSum);
+ if (!goals) return failed to get goals
+ const { inProgress, planned, complete } = goals;
+ return (
+ <>
+
+
+
+
+
Goals
+
+ In Progress
+
+
+ {inProgress.map((goal) => (
+
+ ☐ {goal.title} {(!!goal?.amountCents && !!goal.completedPercentage) && }
+
+ ))}
+
+
+ Planned
+
+
+ {planned.map((goal) => (
+
+ ☐ {goal.title} {(!!goal?.amountCents && !!goal.completedPercentage) && }
+
+ ))}
+
+
+ Completed
+
+
+ {complete.map((goal) => (
+
+ ✅ {goal.title} {(!!goal?.amountCents && !!goal.completedPercentage) && }
+
+ ))}
+
+
+
+
+ >
+ )
+}
\ No newline at end of file
diff --git a/packages/next/app/health/page.tsx b/packages/next/app/health/page.tsx
new file mode 100644
index 0000000..657976e
--- /dev/null
+++ b/packages/next/app/health/page.tsx
@@ -0,0 +1,12 @@
+import Tes from '@/assets/svg/tes';
+
+export default async function Page() {
+ return (
+
+ )
+}
\ No newline at end of file
diff --git a/packages/next/app/latest-vods/[page]/page.tsx b/packages/next/app/latest-vods/[page]/page.tsx
new file mode 100644
index 0000000..1c03ece
--- /dev/null
+++ b/packages/next/app/latest-vods/[page]/page.tsx
@@ -0,0 +1,32 @@
+import VodsList from '@/components/vods-list';
+import { getVods } from '@/lib/vods';
+import Pager from '@/components/pager';
+
+interface IPageParams {
+ params: {
+ page: number;
+ };
+}
+
+export default async function Page({ params: { page } }: IPageParams) {
+ let vods;
+ try {
+ vods = await getVods(page, 24, true);
+ } catch (error) {
+ console.error("An error occurred:", error);
+ return Error: {JSON.stringify(error)}
;
+ }
+
+ return (
+ <>
+ Latest VODs
+ page {page}
+
+
+ >
+ );
+}
diff --git a/packages/next/app/latest-vods/page.tsx b/packages/next/app/latest-vods/page.tsx
new file mode 100644
index 0000000..2c1edc7
--- /dev/null
+++ b/packages/next/app/latest-vods/page.tsx
@@ -0,0 +1,24 @@
+
+import VodsList from '@/components/vods-list';
+import { IVodsResponse } from '@/lib/vods';
+import Pager from '@/components/pager';
+import { getVods } from '@/lib/vods';
+
+interface IPageParams {
+ params: {
+ slug: string;
+ }
+}
+
+export default async function Page({ params }: IPageParams) {
+ const vods: IVodsResponse = await getVods(1, 24);
+
+ return (
+ <>
+ Latest VODs
+ page 1
+
+
+ >
+ )
+}
\ No newline at end of file
diff --git a/packages/next/app/layout.tsx b/packages/next/app/layout.tsx
new file mode 100644
index 0000000..26d3b81
--- /dev/null
+++ b/packages/next/app/layout.tsx
@@ -0,0 +1,70 @@
+import { ReactNode } from 'react'
+import Footer from "./components/footer"
+import Navbar from "./components/navbar"
+import "../assets/styles/global.sass";
+import "@fortawesome/fontawesome-svg-core/styles.css";
+import { AuthProvider } from './components/auth';
+import type { Metadata } from 'next';
+import NotificationCenter from './components/notification-center';
+import UppyProvider from './uppy';
+// import NextTopLoader from 'nextjs-toploader';
+// import Ipfs from './components/ipfs'; // slows down the page too much
+
+
+
+export const metadata: Metadata = {
+ title: 'Futureporn.net',
+ description: "The Galaxy's Best VTuber Hentai Site",
+ other: {
+ RATING: 'RTA-5042-1996-1400-1577-RTA'
+ },
+ metadataBase: new URL('https://futureporn.net'),
+ twitter: {
+ site: '@futureporn_net',
+ creator: '@cj_clippy'
+ },
+ alternates: {
+ types: {
+ 'application/atom+xml': '/feed/feed.xml',
+ 'application/rss+xml': '/feed/rss.xml',
+ 'application/json': '/feed/feed.json'
+ }
+ }
+}
+
+type Props = {
+ children: ReactNode;
+}
+
+
+export default function RootLayout({
+ children,
+}: Props) {
+ return (
+
+
+ {/* */}
+
+
+
+
+
+ {children}
+
+
+
+
+
+
+ )
+}
diff --git a/packages/next/app/lib/b2File.ts b/packages/next/app/lib/b2File.ts
new file mode 100644
index 0000000..876f3a8
--- /dev/null
+++ b/packages/next/app/lib/b2File.ts
@@ -0,0 +1,15 @@
+import { IMeta } from "./types";
+
+export interface IB2File {
+ id: number;
+ attributes: {
+ url: string;
+ key: string;
+ uploadId: string;
+ cdnUrl: string;
+ }
+}
+export interface IB2FileResponse {
+ data: IB2File;
+ meta: IMeta;
+}
\ No newline at end of file
diff --git a/packages/next/app/lib/blog.ts b/packages/next/app/lib/blog.ts
new file mode 100644
index 0000000..222b7f6
--- /dev/null
+++ b/packages/next/app/lib/blog.ts
@@ -0,0 +1,5 @@
+export interface IBlogPost {
+ slug: string;
+ title: string;
+ id: number;
+}
\ No newline at end of file
diff --git a/packages/next/app/lib/constants.ts b/packages/next/app/lib/constants.ts
new file mode 100644
index 0000000..174bccd
--- /dev/null
+++ b/packages/next/app/lib/constants.ts
@@ -0,0 +1,20 @@
+// export const strapiUrl = (process.env.NODE_ENV === 'production') ? 'https://portal.futureporn.net' : 'https://chisel.sbtp:1337'
+// export const siteUrl = (process.env.NODE_ENV === 'production') ? 'https://futureporn.net' : 'http://localhost:3000'
+export const siteUrl = process.env.NEXT_PUBLIC_SITE_URL
+export const strapiUrl = process.env.NEXT_PUBLIC_STRAPI_URL
+export const patreonSupporterBenefitId: string = '4760169'
+export const patreonQuantumSupporterId: string = '10663202'
+export const patreonVideoAccessBenefitId: string = '13462019'
+export const skeletonHeight = '32pt'
+export const skeletonBaseColor = '#000'
+export const skeletonHighlightColor = '#000'
+export const skeletonBorderRadius = 0
+export const description = "The Galaxy's Best VTuber Hentai Site"
+export const title = "Futureporn.net"
+export const siteImage = 'https://futureporn.net/images/futureporn-icon.png'
+export const favicon = 'https://futureporn.net/favicon.ico'
+export const authorName = 'CJ_Clippy'
+export const authorEmail = 'cj@futureporn.net'
+export const authorLink = 'https://futureporn.net'
+export const giteaUrl = 'https://gitea.futureporn.net'
+export const projektMelodyEpoch = new Date('2020-02-07T23:21:48.000Z')
\ No newline at end of file
diff --git a/packages/next/app/lib/contributors.ts b/packages/next/app/lib/contributors.ts
new file mode 100644
index 0000000..e2e0788
--- /dev/null
+++ b/packages/next/app/lib/contributors.ts
@@ -0,0 +1,24 @@
+import { strapiUrl } from "./constants";
+import fetchAPI from "./fetch-api";
+
+export interface IContributor {
+ id: number;
+ attributes: {
+ name: string;
+ url?: string;
+ isFinancialDonor: boolean;
+ isVodProvider: boolean;
+ }
+}
+
+
+export async function getContributors(): Promise {
+ try {
+ const res = await fetchAPI(`/contributors`);
+ return res.data;
+ } catch (e) {
+ console.error(`error while fetching contributors`)
+ console.error(e);
+ return null;
+ }
+}
diff --git a/packages/next/app/lib/dates.ts b/packages/next/app/lib/dates.ts
new file mode 100644
index 0000000..5d7c8ca
--- /dev/null
+++ b/packages/next/app/lib/dates.ts
@@ -0,0 +1,59 @@
+import { parse } from 'date-fns';
+import { format } from 'date-fns-tz'
+import utcToZonedTime from 'date-fns-tz/utcToZonedTime'
+import zonedTimeToUtc from 'date-fns-tz/zonedTimeToUtc'
+
+const safeDateFormatString: string = "yyyyMMdd'T'HHmmss'Z'"
+const localTimeZone = Intl.DateTimeFormat().resolvedOptions().timeZone;
+
+
+export function getSafeDate(date: string | Date): string {
+ let dateString: string;
+
+ if (typeof date === 'string') {
+ const dateObject = utcToZonedTime(date, 'UTC');
+ dateString = format(dateObject, safeDateFormatString, { timeZone: 'UTC' });
+ } else {
+ dateString = format(date, safeDateFormatString, { timeZone: 'UTC' });
+ }
+
+ return dateString;
+}
+
+
+export function getDateFromSafeDate(safeDate: string): Date {
+ const date = parse(safeDate, safeDateFormatString, new Date())
+ const utcDate = zonedTimeToUtc(date, 'UTC')
+ return utcDate;
+}
+
+
+export function formatTimestamp(seconds: number = 0): string {
+ return new Date(seconds * 1000).toISOString().slice(11, 19);
+}
+
+export function formatUrlTimestamp(timestampInSeconds: number): string {
+ const hours = Math.floor(timestampInSeconds / 3600);
+ const minutes = Math.floor((timestampInSeconds % 3600) / 60);
+ const seconds = timestampInSeconds % 60;
+ return `${hours}h${minutes}m${seconds}s`;
+}
+
+export function parseUrlTimestamp(timestamp: string): number | null {
+ // Regular expression to match the "XhYmZs" format
+ const regex = /^(\d+)h(\d+)m(\d+)s$/;
+ const match = timestamp.match(regex);
+
+ if (match) {
+ const hours = parseInt(match[1], 10);
+ const minutes = parseInt(match[2], 10);
+ const seconds = parseInt(match[3], 10);
+
+ if (!isNaN(hours) && !isNaN(minutes) && !isNaN(seconds)) {
+ return hours * 3600 + minutes * 60 + seconds;
+ }
+ }
+
+ // If the format doesn't match or parsing fails, return null
+ return null;
+}
\ No newline at end of file
diff --git a/packages/next/app/lib/fetch-api.ts b/packages/next/app/lib/fetch-api.ts
new file mode 100644
index 0000000..1130079
--- /dev/null
+++ b/packages/next/app/lib/fetch-api.ts
@@ -0,0 +1,34 @@
+// greets https://github.com/strapi/nextjs-corporate-starter/blob/main/frontend/src/app/%5Blang%5D/utils/fetch-api.tsx#L4
+
+import qs from "qs";
+import { strapiUrl } from "./constants";
+
+export default async function fetchAPI(
+ path: string,
+ urlParamsObject = {},
+ options = {}
+) {
+ try {
+ // Merge default and user options
+ const mergedOptions = {
+ next: { revalidate: 60 },
+ headers: {
+ "Content-Type": "application/json",
+ },
+ ...options,
+ };
+
+ // Build request URL
+ const queryString = qs.stringify(urlParamsObject);
+ const requestUrl = `${strapiUrl}/api${path}${queryString ? `?${queryString}` : ""}`;
+
+ // Trigger API call
+ const response = await fetch(requestUrl, mergedOptions);
+ const data = await response.json();
+ return data;
+
+ } catch (error) {
+ console.error(error);
+ throw new Error(`Error while fetching data from API.`);
+ }
+}
\ No newline at end of file
diff --git a/packages/next/app/lib/fetchers.ts b/packages/next/app/lib/fetchers.ts
new file mode 100644
index 0000000..3e28468
--- /dev/null
+++ b/packages/next/app/lib/fetchers.ts
@@ -0,0 +1,32 @@
+import { strapiUrl } from "./constants";
+
+export async function fetchPaginatedData(apiEndpoint: string, pageSize: number, queryParams: Record = {}): Promise {
+ let data: any[] = [];
+ let totalDataCount: number = 0;
+ let totalRequestsNeeded: number = 1;
+
+ for (let requestCounter = 0; requestCounter < totalRequestsNeeded; requestCounter++) {
+ const humanReadableRequestCount = requestCounter + 1;
+ const params = new URLSearchParams({
+ 'pagination[page]': humanReadableRequestCount.toString(),
+ 'pagination[pageSize]': pageSize.toString(),
+ ...queryParams,
+ });
+ const url = `${strapiUrl}${apiEndpoint}?${params}`;
+
+ const response = await fetch(url, {
+ method: 'GET'
+ });
+
+ const responseData = await response.json();
+
+
+ if (requestCounter === 0) {
+ totalDataCount = responseData.meta.pagination.total;
+ totalRequestsNeeded = Math.ceil(totalDataCount / pageSize);
+ }
+ data = data.concat(responseData.data);
+ }
+
+ return data;
+}
diff --git a/packages/next/app/lib/ipfs.ts b/packages/next/app/lib/ipfs.ts
new file mode 100644
index 0000000..ffb3f04
--- /dev/null
+++ b/packages/next/app/lib/ipfs.ts
@@ -0,0 +1,7 @@
+export function buildIpfsUrl (urlFragment: string): string {
+ return `https://ipfs.io/ipfs/${urlFragment}`
+}
+
+export function buildPatronIpfsUrl (cid: string, token: string): string {
+ return `https://gw.futureporn.net/ipfs/${cid}?token=${token}`
+}
diff --git a/packages/next/app/lib/patreon.ts b/packages/next/app/lib/patreon.ts
new file mode 100644
index 0000000..420356c
--- /dev/null
+++ b/packages/next/app/lib/patreon.ts
@@ -0,0 +1,55 @@
+import { strapiUrl, patreonVideoAccessBenefitId, giteaUrl } from './constants'
+import { IAuthData } from '@/components/auth';
+
+export interface IPatron {
+ username: string;
+ vanityLink?: string;
+}
+
+
+export interface ICampaign {
+ pledgeSum: number;
+ patronCount: number;
+}
+
+
+export interface IMarshalledCampaign {
+ data: {
+ attributes: {
+ pledge_sum: number,
+ patron_count: number
+ }
+ }
+}
+
+
+
+export function isEntitledToPatronVideoAccess(authData: IAuthData): boolean {
+ if (!authData.user?.patreonBenefits) return false;
+ const patreonBenefits = authData.user.patreonBenefits
+ return (patreonBenefits.includes(patreonVideoAccessBenefitId))
+}
+
+
+export async function getPatrons(): Promise {
+ const res = await fetch(`${strapiUrl}/api/patreon/patrons`);
+ return res.json();
+}
+
+
+export async function getCampaign(): Promise {
+ const res = await fetch('https://www.patreon.com/api/campaigns/8012692', {
+ headers: {
+ accept: 'application/json'
+ },
+ next: {
+ revalidate: 43200 // 12 hour cache
+ }
+ })
+ const campaignData = await res.json();
+ const data = {
+ patronCount: campaignData.data.attributes.patron_count,
+ pledgeSum: campaignData.data.attributes.campaign_pledge_sum
+ }
+ return data
+}
diff --git a/packages/next/app/lib/pm.ts b/packages/next/app/lib/pm.ts
new file mode 100644
index 0000000..9eb3183
--- /dev/null
+++ b/packages/next/app/lib/pm.ts
@@ -0,0 +1,139 @@
+import matter from 'gray-matter';
+
+const CACHE_TIME = 3600;
+const GOAL_LABEL = 'Goal';
+
+export interface IIssue {
+ id: number;
+ title: string;
+ comments: number;
+ updatedAt: string;
+ createdAt: string;
+ assignee: string | null;
+ name: string | null;
+ completedPercentage: number | null;
+ amountCents: number | null;
+ description: string | null;
+}
+
+export interface IGoals {
+ complete: IIssue[];
+ inProgress: IIssue[];
+ planned: IIssue[];
+ featuredFunded: IIssue;
+ featuredUnfunded: IIssue;
+}
+
+
+export interface IGiteaIssue {
+ id: number;
+ title: string;
+ body: string;
+ comments: number;
+ updated_at: string;
+ created_at: string;
+ assignee: string | null;
+}
+
+const bigHairyAudaciousGoal: IIssue = {
+ id: 55234234,
+ title: 'BHAG',
+ comments: 0,
+ updatedAt: '2023-09-20T08:54:01.373Z',
+ createdAt: '2023-09-20T08:54:01.373Z',
+ assignee: null,
+ name: 'Big Hairy Audacious Goal',
+ description: 'World domination!!!!!1',
+ amountCents: 100000000,
+ completedPercentage: 0.04
+};
+
+const defaultGoal: IIssue = {
+ id: 55234233,
+ title: 'e',
+ comments: 0,
+ updatedAt: '2023-09-20T08:54:01.373Z',
+ createdAt: '2023-09-20T08:54:01.373Z',
+ assignee: null,
+ name: 'Generic',
+ description: 'Getting started',
+ amountCents: 200,
+ completedPercentage: 1
+};
+
+export function calcPercent(goalAmountCents: number, totalPledgeSumCents: number): number {
+ if (!goalAmountCents || totalPledgeSumCents <= 0) {
+ return 0;
+ }
+ const output = Math.min(100, Math.floor((totalPledgeSumCents / goalAmountCents) * 100));
+ return output;
+}
+
+export async function getGoals(pledgeSum: number): Promise {
+ try {
+ const openData = await fetchAndParseData('open', pledgeSum);
+ const closedData = await fetchAndParseData('closed', pledgeSum);
+
+
+ const inProgress = filterByAssignee(openData);
+ const planned = filterByAssignee(openData, true);
+ const funded = filterAndSortGoals(openData.concat(closedData), true);
+ const unfunded = filterAndSortGoals(openData.concat(closedData), false);
+
+ console.log('the following are unfunded goals')
+ console.log(unfunded)
+
+ return {
+ complete: closedData,
+ inProgress,
+ planned,
+ featuredFunded: funded[funded.length - 1] || defaultGoal,
+ featuredUnfunded: unfunded[0] || bigHairyAudaciousGoal
+ };
+ } catch (error) {
+ console.error('Error fetching goals:', error);
+ return null;
+ }
+}
+
+function filterByAssignee(issues: IIssue[], isPlanned: boolean = false): IIssue[] {
+ return issues.filter((issue) => (isPlanned ? issue.assignee === null : issue.assignee !== null))
+}
+
+async function fetchAndParseData(state: 'open' | 'closed', pledgeSum: number): Promise {
+ const response = await fetch(`https://gitea.futureporn.net/api/v1/repos/futureporn/pm/issues?state=${state}&labels=${GOAL_LABEL}`, {
+ next: {
+ revalidate: CACHE_TIME,
+ tags: ['goals']
+ },
+ });
+
+ if (!response.ok) return [];
+
+ return response.json().then(issues => issues.map((g: IGiteaIssue) => parseGiteaGoal(g, pledgeSum)));
+}
+
+
+
+function filterAndSortGoals(issues: IIssue[], isFunded: boolean): IIssue[] {
+ return issues
+ .filter((issue) => issue.amountCents)
+ .filter((issue) => (issue.completedPercentage === 100) === isFunded)
+ .sort((b, a) => b.amountCents! - a.amountCents!);
+}
+
+function parseGiteaGoal(giteaIssue: IGiteaIssue, pledgeSum: number): IIssue {
+ const headMatter: any = matter(giteaIssue.body);
+ return {
+ id: giteaIssue.id,
+ title: giteaIssue.title,
+ comments: giteaIssue.comments,
+ updatedAt: giteaIssue.updated_at,
+ createdAt: giteaIssue.created_at,
+ assignee: giteaIssue.assignee,
+ name: headMatter.data.name || '',
+ description: headMatter.data.description || '',
+ amountCents: headMatter.data.amountCents || 0,
+ completedPercentage: calcPercent(headMatter.data.amountCents, pledgeSum)
+ };
+}
diff --git a/packages/next/app/lib/retry.ts b/packages/next/app/lib/retry.ts
new file mode 100644
index 0000000..68a4d7d
--- /dev/null
+++ b/packages/next/app/lib/retry.ts
@@ -0,0 +1,13 @@
+export async function retry(fn: Function, maxRetries: number) {
+ let retries = 0;
+ while (retries < maxRetries) {
+ try {
+ return await fn();
+ } catch (error) {
+ console.error(`Error during fetch attempt ${retries + 1}:`, error);
+ retries++;
+ }
+ }
+ console.error(`Max retries (${maxRetries}) reached. Giving up.`);
+ return null;
+}
\ No newline at end of file
diff --git a/packages/next/app/lib/rss.ts b/packages/next/app/lib/rss.ts
new file mode 100644
index 0000000..121d43b
--- /dev/null
+++ b/packages/next/app/lib/rss.ts
@@ -0,0 +1,51 @@
+import { authorName, authorEmail, siteUrl, title, description, siteImage, favicon, authorLink } from './constants'
+import { Feed } from "feed";
+import { getVods, getUrl, IVod } from '@/lib/vods'
+import { ITagVodRelation } from '@/lib/tag-vod-relations';
+
+export async function generateFeeds() {
+ const feedOptions = {
+ id: siteUrl,
+ title: title,
+ description: description,
+ link: siteUrl,
+ language: 'en',
+ image: siteImage,
+ favicon: favicon,
+ copyright: '',
+ generator: ' ',
+ feedLinks: {
+ json: `${siteUrl}/feed/feed.json`,
+ atom: `${siteUrl}/feed/feed.xml`
+ },
+ author: {
+ name: authorName,
+ email: authorEmail,
+ link: authorLink
+ }
+ };
+
+ const feed = new Feed(feedOptions);
+
+ const vods = await getVods()
+
+ vods.data.map((vod: IVod) => {
+ feed.addItem({
+ title: vod.attributes.title || vod.attributes.announceTitle,
+ description: vod.attributes.title, // @todo vod.attributes.spoiler or vod.attributes.note could go here
+ content: vod.attributes.tagVodRelations.data.map((tvr: ITagVodRelation) => tvr.attributes.tag.data.attributes.name).join(' '),
+ link: getUrl(vod, vod.attributes.vtuber.data.attributes.slug, vod.attributes.date2),
+ date: new Date(vod.attributes.date2),
+ image: vod.attributes.vtuber.data.attributes.image
+ })
+ })
+
+
+ return {
+ atom1: feed.atom1(),
+ rss2: feed.rss2(),
+ json1: feed.json1()
+ }
+}
+
+
diff --git a/packages/next/app/lib/shareRef.ts b/packages/next/app/lib/shareRef.ts
new file mode 100644
index 0000000..5a6dddc
--- /dev/null
+++ b/packages/next/app/lib/shareRef.ts
@@ -0,0 +1,16 @@
+import type { MutableRefObject, RefCallback } from 'react';
+
+type RefType = MutableRefObject | RefCallback | null;
+
+export const shareRef = (refA: RefType, refB: RefType): RefCallback => instance => {
+ if (typeof refA === 'function') {
+ refA(instance);
+ } else if (refA && 'current' in refA) {
+ (refA as MutableRefObject).current = instance as T; // Use type assertion to tell TypeScript the type
+ }
+ if (typeof refB === 'function') {
+ refB(instance);
+ } else if (refB && 'current' in refB) {
+ (refB as MutableRefObject).current = instance as T; // Use type assertion to tell TypeScript the type
+ }
+};
diff --git a/packages/next/app/lib/streams.ts b/packages/next/app/lib/streams.ts
new file mode 100644
index 0000000..1a45abf
--- /dev/null
+++ b/packages/next/app/lib/streams.ts
@@ -0,0 +1,369 @@
+
+import { strapiUrl, siteUrl } from './constants';
+import { getSafeDate } from './dates';
+import { IVodsResponse } from './vods';
+import { IVtuber, IVtuberResponse } from './vtubers';
+import { ITweetResponse } from './tweets';
+import { IMeta } from './types';
+import qs from 'qs';
+
+
+export interface IStream {
+ id: number;
+ attributes: {
+ date: string;
+ archiveStatus: 'good' | 'issue' | 'missing';
+ vods: IVodsResponse;
+ cuid: string;
+ vtuber: IVtuberResponse;
+ tweet: ITweetResponse;
+ isChaturbateStream: boolean;
+ isFanslyStream: boolean;
+ }
+}
+
+export interface IStreamResponse {
+ data: IStream;
+ meta: IMeta;
+}
+
+export interface IStreamsResponse {
+ data: IStream[];
+ meta: IMeta;
+}
+
+
+const fetchStreamsOptions = {
+ next: {
+ tags: ['streams']
+ }
+}
+
+
+export async function getStreamByCuid(cuid: string): Promise {
+ const query = qs.stringify({
+ filters: {
+ cuid: {
+ $eq: cuid
+ }
+ },
+ pagination: {
+ limit: 1
+ },
+ populate: {
+ vtuber: {
+ fields: ['slug', 'displayName']
+ },
+ tweet: {
+ fields: ['isChaturbateInvite', 'isFanslyInvite', 'url']
+ },
+ vods: {
+ fields: ['note', 'cuid', 'publishedAt'],
+ populate: {
+ tagVodRelations: {
+ fields: ['id']
+ },
+ timestamps: '*'
+ }
+ }
+ }
+ });
+ const res = await fetch(`${strapiUrl}/api/streams?${query}`);
+ const json = await res.json();
+ return json.data[0];
+}
+
+export function getUrl(stream: IStream, slug: string, date: string): string {
+ return `${siteUrl}/vt/${slug}/stream/${getSafeDate(date)}`
+}
+
+
+export function getPaginatedUrl(): (slug: string, pageNumber: number) => string {
+ return (slug: string, pageNumber: number) => {
+ return `${siteUrl}/vt/${slug}/streams/${pageNumber}`
+ }
+}
+
+
+
+export function getLocalizedDate(stream: IStream): string {
+ return new Date(stream.attributes.date).toLocaleDateString()
+}
+
+
+
+
+export async function getStreamsForYear(year: number): Promise {
+ const startOfYear = new Date(year, 0, 0);
+ const endOfYear = new Date(year, 11, 31);
+
+ const pageSize = 100; // Number of records per page
+ let currentPage = 0;
+ let allStreams: IStream[] = [];
+
+ while (true) {
+ const query = qs.stringify({
+ filters: {
+ date: {
+ $gte: startOfYear,
+ $lte: endOfYear,
+ },
+ },
+ populate: {
+ vtuber: {
+ fields: ['displayName']
+ }
+ },
+ pagination: {
+ page: currentPage,
+ pageSize: pageSize,
+ }
+ });
+
+ const res = await fetch(`${strapiUrl}/api/streams?${query}`, fetchStreamsOptions);
+
+ if (!res.ok) {
+ // Handle error if needed
+ console.error('here is the res.body')
+
+ console.error((await res.text()));
+ throw new Error(`Error fetching streams: ${res.status}`);
+ }
+
+ const json = await res.json();
+ const streams = json as IStreamsResponse;
+
+ if (streams.data.length === 0) {
+ // No more records, break the loop
+ break;
+ }
+
+ allStreams = [...allStreams, ...streams.data];
+ currentPage += pageSize;
+ }
+
+ return allStreams;
+ }
+
+export async function getStream(id: number): Promise {
+ const query = qs.stringify({
+ filters: {
+ id: {
+ $eq: id
+ }
+ }
+ });
+ const res = await fetch(`${strapiUrl}/api/vods?${query}`, fetchStreamsOptions);
+ const json = await res.json();
+ return json.data;
+}
+
+
+
+
+export async function getAllStreams(archiveStatuses = ['missing', 'issue', 'good']): Promise {
+ const pageSize = 100; // Adjust this value as needed
+ const sortDesc = true; // Adjust the sorting direction as needed
+
+ const allStreams: IStream[] = [];
+ let currentPage = 1;
+
+ while (true) {
+ const query = qs.stringify({
+ populate: {
+ vtuber: {
+ fields: ['slug', 'displayName', 'image', 'imageBlur', 'themeColor'],
+ },
+ muxAsset: {
+ fields: ['playbackId', 'assetId'],
+ },
+ thumbnail: {
+ fields: ['cdnUrl', 'url'],
+ },
+ tagstreamRelations: {
+ fields: ['tag'],
+ populate: ['tag'],
+ },
+ videoSrcB2: {
+ fields: ['url', 'key', 'uploadId', 'cdnUrl'],
+ },
+ tweet: {
+ fields: ['isChaturbateInvite', 'isFanslyInvite']
+ }
+ },
+ filters: {
+ archiveStatus: {
+ '$in': archiveStatuses
+ }
+ },
+ sort: {
+ date: sortDesc ? 'desc' : 'asc',
+ },
+ pagination: {
+ pageSize,
+ page: currentPage,
+ },
+ });
+ const response = await fetch(`${strapiUrl}/api/streams?${query}`, fetchStreamsOptions);
+ const responseData = await response.json();
+
+ if (!responseData.data || responseData.data.length === 0) {
+ // No more data to fetch
+ break;
+ }
+
+ allStreams.push(...responseData.data);
+ currentPage++;
+ }
+
+ return allStreams;
+}
+
+export async function getStreamForVtuber(vtuberId: number, safeDate: string): Promise {
+ const query = qs.stringify({
+ populate: {
+ vods: {
+ fields: [
+ 'id',
+ 'date'
+ ]
+ },
+ tweet: {
+ fields: [
+ 'id'
+ ]
+ }
+ }
+ });
+
+ const response = await fetch(`${strapiUrl}/api/streams?${query}`, fetchStreamsOptions);
+
+ if (response.status !== 200) throw new Error('network fetch error while attempting to getStreamForVtuber');
+
+ const responseData = await response.json();
+ return responseData;
+}
+
+export async function getAllStreamsForVtuber(vtuberId: number, archiveStatuses = ['missing', 'issue', 'good']): Promise {
+ const maxRetries = 3;
+
+ let retries = 0;
+ let allStreams: IStream[] = [];
+ let currentPage = 1;
+
+ while (retries < maxRetries) {
+ try {
+ const query = qs.stringify({
+ populate: '*',
+ filters: {
+ archiveStatus: {
+ '$in': archiveStatuses
+ },
+ vtuber: {
+ id: {
+ $eq: vtuberId
+ }
+ }
+ },
+ sort: {
+ date: 'desc',
+ },
+ pagination: {
+ pageSize: 100,
+ page: currentPage,
+ },
+ });
+
+ console.log(`strapiUrl=${strapiUrl}`)
+ const response = await fetch(`${strapiUrl}/api/streams?${query}`, fetchStreamsOptions);
+
+ if (response.status !== 200) {
+ // If the response status is not 200 (OK), consider it a network failure
+ const bod = await response.text();
+ console.log(response.status);
+ console.log(bod);
+ retries++;
+ continue;
+ }
+
+ const responseData = await response.json();
+
+ if (!responseData.data || responseData.data.length === 0) {
+ // No more data to fetch
+ break;
+ }
+
+ allStreams.push(...responseData.data);
+ currentPage++;
+ } catch (error) {
+ // Network failure or other error occurred
+ retries++;
+ }
+ }
+
+ if (retries === maxRetries) {
+ throw new Error(`Failed to fetch streams after ${maxRetries} retries.`);
+ }
+
+ return allStreams;
+}
+
+export async function getStreamsForVtuber(vtuberId: number, page: number = 1, pageSize: number = 25, sortDesc = true): Promise {
+ const query = qs.stringify(
+ {
+ populate: {
+ vtuber: {
+ fields: [
+ 'id',
+ ]
+ }
+ },
+ filters: {
+ vtuber: {
+ id: {
+ $eq: vtuberId
+ }
+ }
+ },
+ pagination: {
+ page: page,
+ pageSize: pageSize
+ },
+ sort: {
+ date: (sortDesc) ? 'desc' : 'asc'
+ }
+ }
+ )
+ return fetch(`${strapiUrl}/api/streams?${query}`, fetchStreamsOptions)
+ .then((res) => res.json())
+}
+
+
+// /**
+// * This returns stale data, because futureporn-historian is broken.
+// * @todo get live data from historian
+// * @see https://gitea.futureporn.net/futureporn/futureporn-historian/issues/1
+// */
+// export async function getProgress(vtuberSlug: string): Promise<{ complete: number; total: number }> {
+// const query = qs.stringify({
+// filters: {
+// vtuber: {
+// slug: {
+// $eq: vtuberSlug
+// }
+// }
+// }
+// })
+// const data = await fetch(`${strapiUrl}/api/streams?${query}`, fetchStreamsOptions)
+// .then((res) => res.json())
+// .then((g) => {
+// return g
+// })
+
+// const total = data.meta.pagination.total
+
+// return {
+// complete: total,
+// total: total
+// }
+// }
\ No newline at end of file
diff --git a/packages/next/app/lib/tag-vod-relations.ts b/packages/next/app/lib/tag-vod-relations.ts
new file mode 100644
index 0000000..71d6e52
--- /dev/null
+++ b/packages/next/app/lib/tag-vod-relations.ts
@@ -0,0 +1,191 @@
+/**
+ * Tag Vod Relations are an old name for what I'm now calling, "VodTag"
+ *
+ * VodTags are Tags related to Vods
+ *
+ */
+
+
+import qs from 'qs';
+import { strapiUrl } from './constants'
+import { ITagResponse, IToyTagResponse } from './tags';
+import { IVod, IVodResponse } from './vods';
+import { IAuthData } from '@/components/auth';
+import { IMeta } from './types';
+
+export interface ITagVodRelation {
+ id: number;
+ attributes: {
+ tag: ITagResponse | IToyTagResponse;
+ vod: IVodResponse;
+ creatorId: number;
+ createdAt: string;
+ }
+}
+
+
+export interface ITagVodRelationsResponse {
+ data: ITagVodRelation[];
+ meta: IMeta;
+}
+
+
+
+
+export async function deleteTvr(authData: IAuthData, tagId: number) {
+ return fetch(`${strapiUrl}/api/tag-vod-relations/deleteMine/${tagId}`, {
+ method: 'DELETE',
+ headers: {
+ 'Authorization': `Bearer ${authData.accessToken}`,
+ 'Content-Type': 'application/json'
+ }
+ })
+ .then((res) => {
+ if (!res.ok) throw new Error(res.statusText);
+ else return res.json();
+ })
+ .catch((e) => {
+ console.error(e);
+ // setError('root.serverError', { message: e.message })
+ })
+}
+
+export async function readTagVodRelation(accessToken: string, tagId: number, vodId: number): Promise {
+ if (!tagId) throw new Error('readTagVodRelation requires tagId as second param');
+ if (!vodId) throw new Error('readTagVodRelation requires vodId as second param');
+ const findQuery = qs.stringify({
+ filters: {
+ $and: [
+ {
+ tag: tagId
+ }, {
+ vod: vodId
+ }
+ ]
+ }
+ });
+ const res = await fetch(`${strapiUrl}/api/tag-vod-relations?${findQuery}`);
+ const json = await res.json();
+ return json.data[0];
+}
+
+export async function createTagVodRelation(accessToken: string, tagId: number, vodId: number): Promise {
+ if (!accessToken) throw new Error('Must be logged in');
+ if (!tagId) throw new Error('tagId is required.');
+ if (!vodId) throw new Error('vodId is required.');
+ const payload = {
+ tag: tagId,
+ vod: vodId
+ }
+ const res = await fetch(`${strapiUrl}/api/tag-vod-relations`, {
+ method: 'POST',
+ body: JSON.stringify({ data: payload }),
+ headers: {
+ authorization: `Bearer ${accessToken}`,
+ 'content-type': 'application/json'
+ }
+ })
+ const json = await res.json();
+ console.log(json)
+ return json.data;
+}
+
+export async function readOrCreateTagVodRelation (accessToken: string, tagId: number, vodId: number): Promise {
+ console.log(`Checking if the tagVodRelation with tagId=${tagId}, vodId=${vodId} already exists`);
+ const existingTagVodRelation = await readTagVodRelation(accessToken, tagId, vodId);
+ if (!!existingTagVodRelation) {
+ console.log(`there is an existing TVR so we return it`);
+ console.log(existingTagVodRelation);
+ return existingTagVodRelation
+ }
+ const newTagVodRelation = await createTagVodRelation(accessToken, tagId, vodId);
+ return newTagVodRelation;
+}
+
+// export async function createTagAndTvr(setError: Function, authData: IAuthData, tagName: string, vodId: number) {
+// if (!authData) throw new Error('Must be logged in');
+// if (!tagName || tagName === '') throw new Error('tagName cannot be empty');
+// const data = {
+// tagName: tagName,
+// vodId: vodId
+// };
+// try {
+// const res = await fetch(`${strapiUrl}/api/tag-vod-relations/tag`, {
+// method: 'POST',
+// body: JSON.stringify({ data }),
+// headers: {
+// 'Content-Type': 'application/json',
+// 'Authorization': `Bearer ${authData.accessToken}`
+// },
+// });
+// const json = await res.json();
+// return json.data;
+// } catch (e) {
+// setError('global', { type: 'idk', message: e })
+// }
+// }
+
+
+export async function getTagVodRelationsForVtuber(vtuberId: number, page: number = 1, pageSize: number = 25): Promise {
+ // get the tag-vod-relations where the vtuber is the vtuber we are interested in.
+ const query = qs.stringify(
+ {
+ populate: {
+ tag: {
+ fields: ['id', 'name'],
+ populate: {
+ toy: {
+ fields: ['linkTag', 'make', 'model', 'image2'],
+ populate: {
+ linkTag: {
+ fields: ['name']
+ }
+ }
+ }
+ }
+ },
+ vod: {
+ populate: {
+ vtuber: {
+ fields: ['slug']
+ }
+ }
+ }
+ },
+ filters: {
+ vod: {
+ vtuber: {
+ id: {
+ $eq: vtuberId
+ }
+ }
+ },
+ tag: {
+ toy: {
+ linkTag: {
+ name: {
+ $notNull: true
+ }
+ }
+ }
+ }
+ },
+ pagination: {
+ page: page,
+ pageSize: pageSize
+ },
+ sort: {
+ id: 'desc'
+ }
+ }
+ )
+ // we need to return an IToys object
+ // to get an IToys object, we have to get a list of toys from tvrs.
+
+
+ const res = await fetch(`${strapiUrl}/api/tag-vod-relations?${query}`);
+ if (!res.ok) return null;
+ const tvrs = await res.json()
+ return tvrs;
+}
+
diff --git a/packages/next/app/lib/tags.ts b/packages/next/app/lib/tags.ts
new file mode 100644
index 0000000..ee5385d
--- /dev/null
+++ b/packages/next/app/lib/tags.ts
@@ -0,0 +1,139 @@
+import { strapiUrl } from './constants'
+import { fetchPaginatedData } from './fetchers';
+import { IVod } from './vods';
+import slugify from 'slugify';
+import { IToy } from './toys';
+import { IAuthData } from '@/components/auth';
+import qs from 'qs';
+import { IMeta } from './types';
+
+
+export interface ITag {
+ id: number;
+ attributes: {
+ name: string;
+ count: number;
+ }
+}
+
+export interface ITagsResponse {
+ data: ITag[];
+ meta: IMeta;
+}
+
+export interface ITagResponse {
+ data: ITag;
+ meta: IMeta;
+}
+
+export interface IToyTagResponse {
+ data: IToyTag;
+ meta: IMeta;
+}
+
+
+export interface IToyTag extends ITag {
+ toy: IToy;
+}
+
+
+
+export function getTagHref(name: string): string {
+ return `/tags/${slugify(name)}`
+}
+
+
+export async function createTag(accessToken: string, tagName: string): Promise {
+ const payload = {
+ name: slugify(tagName)
+ };
+ const res = await fetch(`${strapiUrl}/api/tags`, {
+ method: 'POST',
+ headers: {
+ 'authorization': `Bearer ${accessToken}`,
+ 'accept': 'application/json',
+ 'content-type': 'application/json'
+ },
+ body: JSON.stringify({ data: payload })
+ });
+ const json = await res.json();
+ console.log(json);
+ if (!!json?.error) throw new Error(json.error.message);
+ if (!json?.data) throw new Error('created tag was missing data');
+ return json.data as ITag;
+}
+
+export async function readTag(accessToken: string, tagName: string): Promise {
+
+ const findQuery = qs.stringify({
+ filters: {
+ name: {
+ $eq: tagName
+ }
+ }
+ });
+ const findResponse = await fetch(`${strapiUrl}/api/tags?${findQuery}`, {
+ method: 'GET',
+ headers: {
+ 'Authorization': `Bearer ${accessToken}`,
+ 'Accept': 'application/json',
+ 'Content-Type': 'application/json'
+ }
+ });
+
+ const json = await findResponse.json();
+ return json.data[0];
+}
+
+export async function readOrCreateTag(accessToken: string, tagName: string): Promise {
+ console.log(`Checking if the tagName=${tagName} already exists`);
+
+ const existingTag = await readTag(accessToken, tagName);
+ if (!!existingTag) {
+ console.log('there is an existing tag so we return it');
+ console.log(existingTag);
+ return existingTag;
+ }
+
+ const newTag = await createTag(accessToken, tagName);
+ return newTag;
+
+
+}
+
+export async function getTags(): Promise {
+ const tagVodRelations = await fetchPaginatedData('/api/tag-vod-relations', 100, { 'populate[0]': 'tag', 'populate[1]': 'vod' });
+
+ // Create a Map to store tag data, including counts and IDs
+ const tagDataMap = new Map();
+
+ // Populate the tag data map with counts and IDs
+ tagVodRelations.forEach(tvr => {
+ const tagName = tvr.attributes.tag.data.attributes.name;
+ const tagId = tvr.attributes.tag.data.id;
+
+ if (!tagDataMap.has(tagName)) {
+ tagDataMap.set(tagName, { id: tagId, count: 1 });
+ } else {
+ const existingData = tagDataMap.get(tagName);
+ if (existingData) {
+ tagDataMap.set(tagName, { id: existingData.id, count: existingData.count + 1 });
+ }
+ }
+ });
+
+ // Create an array of Tag objects with id, name, and count
+ const tags = Array.from(tagDataMap.keys()).map(tagName => {
+ const tagData = tagDataMap.get(tagName);
+ return {
+ id: tagData ? tagData.id : -1,
+ attributes: {
+ name: tagName,
+ count: tagData ? tagData.count : 0,
+ }
+ };
+ });
+
+
+ return tags;
+}
diff --git a/packages/next/app/lib/timestamps.ts b/packages/next/app/lib/timestamps.ts
new file mode 100644
index 0000000..e80cf54
--- /dev/null
+++ b/packages/next/app/lib/timestamps.ts
@@ -0,0 +1,127 @@
+
+
+import qs from 'qs';
+import { strapiUrl } from './constants'
+import { IAuthData } from '@/components/auth';
+import { ITagsResponse, ITag, ITagResponse } from './tags';
+import { IMeta } from './types';
+
+export interface ITimestamp {
+ id: number;
+ attributes: {
+ time: number;
+ tagName: string;
+ tnShort: string;
+ tagId: number;
+ vodId: number;
+ tag: ITagResponse;
+ createdAt: string;
+ creatorId: number;
+ }
+}
+
+
+
+export interface ITimestampResponse {
+ data: ITimestamp;
+ meta: IMeta;
+}
+
+export interface ITimestampsResponse {
+ data: ITimestamp[];
+ meta: IMeta;
+}
+
+function truncateString(str: string, maxLength: number) {
+ if (str.length <= maxLength) {
+ return str;
+ }
+ return str.substring(0, maxLength - 1) + '…';
+}
+
+export function deleteTimestamp(authData: IAuthData, tsId: number) {
+ return fetch(`${strapiUrl}/api/timestamps/deleteMine/${tsId}`, {
+ method: 'DELETE',
+ headers: {
+ 'Authorization': `Bearer ${authData.accessToken}`,
+ 'Content-Type': 'application/json'
+ }
+ })
+ .then((res) => {
+ if (!res.ok) throw new Error(res.statusText);
+ else return res.json();
+ })
+ .catch((e) => {
+ console.error(e);
+ // setError('root.serverError', { message: e.message })
+ })
+}
+
+export async function createTimestamp(
+ authData: IAuthData,
+ tagId: number,
+ vodId: number,
+ time: number
+): Promise {
+ if (!authData?.user?.id || !authData?.accessToken) throw new Error('User must be logged in to create timestamps');
+ const query = qs.stringify({
+ populate: '*'
+ });
+ const response = await fetch(`${strapiUrl}/api/timestamps?${query}`, {
+ method: 'POST',
+ headers: {
+ 'Authorization': `Bearer ${authData.accessToken}`,
+ 'Content-Type': 'application/json'
+ },
+ body: JSON.stringify({
+ data: {
+ time: Math.floor(time),
+ tag: tagId,
+ vod: vodId,
+ creatorId: authData.user.id
+ }
+ })
+ });
+
+ const json = await response.json();
+
+ if (!response.ok) {
+ throw new Error(json?.error?.message || response.statusText);
+ }
+
+ return json.data;
+}
+
+
+
+export async function getTimestampsForVod(vodId: number, page: number = 1, pageSize: number = 25): Promise {
+ const query = qs.stringify({
+ filters: {
+ vod: {
+ id: {
+ $eq: vodId,
+ },
+ },
+ },
+ populate: '*',
+ sort: 'time:asc',
+ pagination: {
+ page: page,
+ pageSize: pageSize,
+ },
+ });
+
+ const response = await fetch(`${strapiUrl}/api/timestamps?${query}`);
+ const data = await response.json() as ITimestampsResponse;
+
+ const timestamps: ITimestamp[] = data.data || [];
+
+ // If there are more pages, recursively fetch them and concatenate the results
+ if (data.meta.pagination && (data.meta.pagination.page < data.meta.pagination.pageCount)) {
+ const nextPage = (data.meta.pagination.page + 1);
+ const nextPageTimestamps = await getTimestampsForVod(vodId, nextPage, pageSize);
+ timestamps.push(...nextPageTimestamps);
+ }
+
+ return timestamps;
+}
\ No newline at end of file
diff --git a/packages/next/app/lib/toys.ts b/packages/next/app/lib/toys.ts
new file mode 100644
index 0000000..dee0e7b
--- /dev/null
+++ b/packages/next/app/lib/toys.ts
@@ -0,0 +1,42 @@
+
+import { ITag, ITagResponse, ITagsResponse } from '@/lib/tags'
+import { IMeta } from './types';
+
+
+export interface IToysResponse {
+ data: IToy[];
+ meta: IMeta;
+}
+
+export interface IToy {
+ id: number;
+ attributes: {
+ tags: ITagsResponse;
+ linkTag: ITagResponse;
+ make: string;
+ model: string;
+ aspectRatio: string;
+ image2: string;
+ }
+}
+
+
+interface IToysListProps {
+ toys: IToysResponse;
+ page: number;
+ pageSize: number;
+}
+
+
+/** This endpoint doesn't exist at the moment, but definitely could in the future */
+// export function getUrl(toy: IToy): string {
+// return `${siteUrl}/toy/${toy.name}`
+// }
+
+// export function getToysForVtuber(vtuberId: number, page: number = 1, pageSize: number = 25): Promise {
+// const tvrs = await getTagVodRelationsForVtuber(vtuberId, page, pageNumber);
+// return {
+// data: tvrs.data.
+// pagination: tvrs.pagination
+// }
+// }
diff --git a/packages/next/app/lib/tweets.ts b/packages/next/app/lib/tweets.ts
new file mode 100644
index 0000000..caf9607
--- /dev/null
+++ b/packages/next/app/lib/tweets.ts
@@ -0,0 +1,28 @@
+import { IVtuberResponse } from "./vtubers";
+import { IMeta } from "./types";
+
+export interface ITweet {
+ id: number;
+ attributes: {
+ date: string;
+ date2: string;
+ isChaturbateInvite: boolean;
+ isFanslyInvite: boolean;
+ cuid: string;
+ json: string;
+ id_str: string;
+ url: string;
+ vtuber: IVtuberResponse;
+ }
+}
+
+export interface ITweetResponse {
+ data: ITweet;
+ meta: IMeta;
+}
+
+export interface ITweetsResponse {
+ data: ITweet[];
+ meta: IMeta;
+}
+
diff --git a/packages/next/app/lib/types.ts b/packages/next/app/lib/types.ts
new file mode 100644
index 0000000..8a2cc29
--- /dev/null
+++ b/packages/next/app/lib/types.ts
@@ -0,0 +1,28 @@
+
+
+
+
+
+export interface IMuxAsset {
+ id: number;
+ attributes: {
+ playbackId: string;
+ assetId: string;
+ }
+}
+
+export interface IPagination {
+ page: number;
+ pageSize: number;
+ pageCount: number;
+ total: number;
+}
+
+export interface IMuxAssetResponse {
+ data: IMuxAsset;
+ meta: IMeta;
+}
+
+export interface IMeta {
+ pagination: IPagination;
+}
diff --git a/packages/next/app/lib/useForwardRef.ts b/packages/next/app/lib/useForwardRef.ts
new file mode 100644
index 0000000..7220d13
--- /dev/null
+++ b/packages/next/app/lib/useForwardRef.ts
@@ -0,0 +1,27 @@
+/**
+ * greetz https://github.com/facebook/react/issues/24722#issue-1270749463
+ */
+
+import React, { useEffect, useRef, type ForwardedRef } from 'react';
+
+const useForwardRef = (
+ ref: ForwardedRef,
+ initialValue: any = null
+) => {
+ const targetRef = useRef(initialValue);
+
+ useEffect(() => {
+ if (!ref) return;
+
+ if (typeof ref === 'function') {
+ ref(targetRef.current);
+ } else {
+ ref.current = targetRef.current;
+ }
+ }, [ref]);
+
+ return targetRef;
+};
+
+
+export default useForwardRef
\ No newline at end of file
diff --git a/packages/next/app/lib/users.ts b/packages/next/app/lib/users.ts
new file mode 100644
index 0000000..c3fa3ed
--- /dev/null
+++ b/packages/next/app/lib/users.ts
@@ -0,0 +1,16 @@
+import { IMeta } from "./types";
+
+
+export interface IUser {
+ id: number;
+ attributes: {
+ username: string;
+ vanityLink?: string;
+ image: string;
+ }
+}
+
+export interface IUserResponse {
+ data: IUser;
+ meta: IMeta;
+}
\ No newline at end of file
diff --git a/packages/next/app/lib/vods.ts b/packages/next/app/lib/vods.ts
new file mode 100644
index 0000000..b4ad2ac
--- /dev/null
+++ b/packages/next/app/lib/vods.ts
@@ -0,0 +1,502 @@
+
+import { strapiUrl, siteUrl } from './constants';
+import { getDateFromSafeDate, getSafeDate } from './dates';
+import { IVtuber, IVtuberResponse } from './vtubers';
+import { IStream, IStreamResponse } from './streams';
+import qs from 'qs';
+import { ITagVodRelationsResponse } from './tag-vod-relations';
+import { ITimestampsResponse } from './timestamps';
+import { IMeta, IMuxAsset, IMuxAssetResponse } from './types';
+import { IB2File, IB2FileResponse } from '@/lib/b2File';
+import fetchAPI from './fetch-api';
+import { IUserResponse } from './users';
+
+/**
+ * Dec 2023 CUIDs were introduced.
+ * Going forward, use CUIDs where possible.
+ * safeDates are retained for backwards compatibility.
+ *
+ * @see https://www.w3.org/Provider/Style/URI
+ */
+export interface IVodPageProps {
+ params: {
+ safeDateOrCuid: string;
+ slug: string;
+ };
+}
+
+export interface IVodsResponse {
+ data: IVod[];
+ meta: IMeta;
+}
+
+export interface IVodResponse {
+ data: IVod;
+ meta: IMeta;
+}
+
+export interface IVod {
+ id: number;
+ attributes: {
+ stream: IStreamResponse;
+ publishedAt?: string;
+ cuid: string;
+ title?: string;
+ duration?: number;
+ date: string;
+ date2: string;
+ muxAsset: IMuxAssetResponse;
+ thumbnail?: IB2FileResponse;
+ vtuber: IVtuberResponse;
+ tagVodRelations: ITagVodRelationsResponse;
+ timestamps: ITimestampsResponse;
+ video240Hash: string;
+ videoSrcHash: string;
+ videoSrcB2: IB2FileResponse | null;
+ announceTitle: string;
+ announceUrl: string;
+ uploader: IUserResponse;
+ note: string;
+ }
+}
+
+const fetchVodsOptions = {
+ next: {
+ tags: ['vods']
+ }
+}
+
+
+export async function getVodFromSafeDateOrCuid(safeDateOrCuid: string): Promise {
+ let vod: IVod|null;
+ let date: Date;
+ if (!safeDateOrCuid) {
+ console.log(`safeDateOrCuid was missing`);
+ return null;
+ } else if (/^[0-9a-z]{10}$/.test(safeDateOrCuid)) {
+ console.log('this is a CUID!');
+ vod = await getVodByCuid(safeDateOrCuid);
+ if (!vod) return null;
+ } else {
+ console.log('This is a safeDate!');
+ date = await getDateFromSafeDate(safeDateOrCuid);
+ if (!date) {
+ console.log('there is no date')
+ return null;
+ } else {
+ console.log(`date=${date}`)
+ }
+ vod = await getVodForDate(date);
+ }
+ return vod;
+}
+
+export function getUrl(vod: IVod, slug: string, date: string): string {
+ return `${siteUrl}/vt/${slug}/vod/${getSafeDate(date)}`
+}
+
+
+export function getPaginatedUrl(): (slug: string, pageNumber: number) => string {
+ return (slug: string, pageNumber: number) => {
+ return `${siteUrl}/vt/${slug}/vods/${pageNumber}`
+ }
+}
+
+
+/** @deprecated old format for futureporn.net/api/v1.json, which is deprecated. Please use getUrl() instead */
+export function getDeprecatedUrl(vod: IVod): string {
+ return `${siteUrl}/vods/${getSafeDate(vod.attributes.date2)}`
+}
+
+export async function getNextVod(vod: IVod): Promise {
+ const query = qs.stringify({
+ filters: {
+ date2: {
+ $gt: vod.attributes.date2
+ },
+ vtuber: {
+ slug: {
+ $eq: vod.attributes.vtuber.data.attributes.slug
+ }
+ },
+ publishedAt: {
+ $notNull: true
+ }
+ },
+ sort: {
+ date2: 'asc'
+ },
+ fields: ['date2', 'title', 'announceTitle'],
+ populate: {
+ vtuber: {
+ fields: ['slug']
+ }
+ }
+ })
+ const res = await fetch(`${strapiUrl}/api/vods?${query}`, fetchVodsOptions);
+ if (!res.ok) throw new Error('could not fetch next vod');
+ const json = await res.json();
+ const nextVod = json.data[0];
+ if (!nextVod) return null;
+ return nextVod
+
+}
+
+export function getLocalizedDate(vod: IVod): string {
+ return new Date(vod.attributes.date2).toLocaleDateString()
+}
+
+export async function getPreviousVod(vod: IVod): Promise {
+ const res = await fetchAPI(
+ '/vods',
+ {
+ filters: {
+ date2: {
+ $lt: vod.attributes.date2
+ },
+ vtuber: {
+ slug: {
+ $eq: vod.attributes.vtuber.data.attributes.slug
+ }
+ }
+ },
+ sort: {
+ date2: 'desc'
+ },
+ fields: ['date2', 'title', 'announceTitle'],
+ populate: {
+ vtuber: {
+ fields: ['slug']
+ }
+ },
+ pagination: {
+ limit: 1
+ }
+ },
+ fetchVodsOptions
+ )
+ return res.data[0];
+}
+
+export async function getVodByCuid(cuid: string): Promise {
+ const query = qs.stringify(
+ {
+ filters: {
+ cuid: {
+ $eq: cuid
+ }
+ },
+ populate: {
+ vtuber: {
+ fields: ['slug', 'displayName', 'image', 'imageBlur', 'themeColor']
+ },
+ muxAsset: {
+ fields: ['playbackId', 'assetId']
+ },
+ thumbnail: {
+ fields: ['cdnUrl', 'url']
+ },
+ tagVodRelations: {
+ fields: ['tag', 'createdAt', 'creatorId'],
+ populate: ['tag']
+ },
+ videoSrcB2: {
+ fields: ['url', 'key', 'uploadId', 'cdnUrl']
+ },
+ stream: {
+ fields: ['archiveStatus', 'date', 'tweet', 'cuid']
+ }
+ }
+ })
+
+ try {
+ const res = await fetch(`${strapiUrl}/api/vods?${query}`, { cache: 'no-store', next: { tags: ['vods'] } })
+ if (!res.ok) {
+ throw new Error('failed to fetch vodForDate')
+ }
+ const json = await res.json()
+ const vod = json.data[0]
+ if (!vod) return null;
+ return vod;
+ } catch (e) {
+ if (e instanceof Error) {
+ console.error(e)
+ }
+ return null;
+ }
+}
+
+export async function getVodForDate(date: Date): Promise {
+ // if (!date) return null;
+ // console.log(date)
+ // console.log(`getting vod for ${date.toISOString()}`)
+ try {
+ const iso8601DateString = date.toISOString().split('T')[0];
+ const query = qs.stringify(
+ {
+ filters: {
+ date2: {
+ $eq: date.toISOString()
+ }
+ },
+ populate: {
+ vtuber: {
+ fields: ['slug', 'displayName', 'image', 'imageBlur', 'themeColor']
+ },
+ muxAsset: {
+ fields: ['playbackId', 'assetId']
+ },
+ thumbnail: {
+ fields: ['cdnUrl', 'url']
+ },
+ tagVodRelations: {
+ fields: ['tag', 'createdAt', 'creatorId'],
+ populate: ['tag']
+ },
+ videoSrcB2: {
+ fields: ['url', 'key', 'uploadId', 'cdnUrl']
+ },
+ stream: {
+ fields: ['archiveStatus', 'date', 'tweet', 'cuid']
+ }
+ }
+ }
+ )
+ const res = await fetch(`${strapiUrl}/api/vods?${query}`, { cache: 'no-store', next: { tags: ['vods'] } })
+ if (!res.ok) {
+ throw new Error('failed to fetch vodForDate')
+ }
+ const json = await res.json()
+ const vod = json.data[0]
+ if (!vod) return null;
+ return vod;
+ } catch (e) {
+
+ return null;
+ }
+}
+
+export async function getVod(id: number): Promise {
+ const query = qs.stringify(
+ {
+ filters: {
+ id: {
+ $eq: id
+ }
+ }
+ }
+ )
+ const res = await fetch(`${strapiUrl}/api/vods?${query}`, fetchVodsOptions);
+ if (!res.ok) return null;
+ const data = await res.json();
+ return data;
+}
+
+export async function getVods(page: number = 1, pageSize: number = 25, sortDesc = true): Promise {
+ const query = qs.stringify(
+ {
+ populate: {
+ vtuber: {
+ fields: ['slug', 'displayName', 'image', 'imageBlur']
+ },
+ muxAsset: {
+ fields: ['playbackId', 'assetId']
+ },
+ thumbnail: {
+ fields: ['cdnUrl', 'url']
+ },
+ tagVodRelations: {
+ fields: ['tag'],
+ populate: ['tag']
+ },
+ videoSrcB2: {
+ fields: ['url', 'key', 'uploadId', 'cdnUrl']
+ }
+ },
+ sort: {
+ date: (sortDesc) ? 'desc' : 'asc'
+ },
+ pagination: {
+ pageSize: pageSize,
+ page: page
+ }
+ }
+ )
+
+ const res = await fetch(`${strapiUrl}/api/vods?${query}`, fetchVodsOptions);
+ if (!res.ok) {
+ throw new Error('Failed to fetch vods');
+ }
+ const json = await res.json()
+ return json;
+}
+
+
+
+export async function getAllVods(): Promise {
+ const pageSize = 100; // Adjust this value as needed
+ const sortDesc = true; // Adjust the sorting direction as needed
+
+ const allVods: IVod[] = [];
+ let currentPage = 1;
+
+ while (true) {
+ const query = qs.stringify({
+ populate: {
+ vtuber: {
+ fields: ['slug', 'displayName', 'image', 'imageBlur'],
+ },
+ muxAsset: {
+ fields: ['playbackId', 'assetId'],
+ },
+ thumbnail: {
+ fields: ['cdnUrl', 'url'],
+ },
+ tagVodRelations: {
+ fields: ['tag'],
+ populate: ['tag'],
+ },
+ videoSrcB2: {
+ fields: ['url', 'key', 'uploadId', 'cdnUrl'],
+ },
+ },
+ sort: {
+ date: sortDesc ? 'desc' : 'asc',
+ },
+ pagination: {
+ pageSize,
+ page: currentPage,
+ },
+ });
+
+ try {
+ const response = await fetch(`${strapiUrl}/api/vods?${query}`, fetchVodsOptions);
+
+ if (!response.ok) {
+ // Handle non-successful response (e.g., HTTP error)
+ throw new Error(`HTTP error! Status: ${response.status}`);
+ }
+
+ const responseData = await response.json();
+
+ if (!responseData.data || responseData.data.length === 0) {
+ // No more data to fetch
+ break;
+ }
+
+ allVods.push(...responseData.data);
+ currentPage++;
+ } catch (error) {
+ // Handle fetch error
+ if (error instanceof Error) {
+ console.error('Error fetching data:', error.message);
+ }
+ return null;
+ }
+ }
+
+ return allVods;
+}
+
+
+
+export async function getVodsForVtuber(vtuberId: number, page: number = 1, pageSize: number = 25, sortDesc = true): Promise {
+ const query = qs.stringify(
+ {
+ populate: {
+ thumbnail: {
+ fields: ['cdnUrl', 'url']
+ },
+ vtuber: {
+ fields: [
+ 'id',
+ 'slug',
+ 'displayName',
+ 'image',
+ 'imageBlur'
+ ]
+ },
+ videoSrcB2: {
+ fields: ['url', 'key', 'uploadId', 'cdnUrl']
+ }
+ },
+ filters: {
+ vtuber: {
+ id: {
+ $eq: vtuberId
+ }
+ }
+ },
+ pagination: {
+ page: page,
+ pageSize: pageSize
+ },
+ sort: {
+ date: (sortDesc) ? 'desc' : 'asc'
+ }
+ }
+ )
+ const res = await fetch(`${strapiUrl}/api/vods?${query}`, fetchVodsOptions)
+ if (!res.ok) return null;
+ const data = await res.json() as IVodsResponse;
+ return data;
+
+}
+
+
+export async function getVodsForTag(tag: string): Promise {
+ const query = qs.stringify(
+ {
+ populate: {
+ vtuber: {
+ fields: ['slug', 'displayName', 'image', 'imageBlur']
+ },
+ videoSrcB2: {
+ fields: ['url', 'key', 'uploadId', 'cdnUrl']
+ }
+ },
+ filters: {
+ tagVodRelations: {
+ tag: {
+ name: {
+ $eq: tag
+ }
+ }
+ }
+ }
+ }
+ )
+ const res = await fetch(`${strapiUrl}/api/vods?${query}`, fetchVodsOptions)
+ if (!res.ok) return null;
+ const vods = await res.json()
+ return vods;
+}
+
+/**
+ * This returns stale data, because futureporn-historian is broken.
+ * @todo get live data from historian
+ * @see https://git.futureporn.net/futureporn/futureporn-historian/issues/1
+ */
+export async function getProgress(vtuberSlug: string): Promise<{ complete: number; total: number }> {
+ const query = qs.stringify({
+ filters: {
+ vtuber: {
+ slug: {
+ $eq: vtuberSlug
+ }
+ }
+ }
+ })
+ const data = await fetch(`${strapiUrl}/api/vods?${query}`, fetchVodsOptions)
+ .then((res) => res.json())
+ .then((g) => {
+ return g
+ })
+
+ const total = data.meta.pagination.total
+
+ return {
+ complete: total,
+ total: total
+ }
+}
\ No newline at end of file
diff --git a/packages/next/app/lib/vtubers.ts b/packages/next/app/lib/vtubers.ts
new file mode 100644
index 0000000..d671ee3
--- /dev/null
+++ b/packages/next/app/lib/vtubers.ts
@@ -0,0 +1,171 @@
+
+
+import { IVod } from './vods'
+import { strapiUrl, siteUrl } from './constants';
+import { getSafeDate } from './dates';
+import qs from 'qs';
+import { resourceLimits } from 'worker_threads';
+import { IMeta } from './types';
+
+
+const fetchVtubersOptions = {
+ next: {
+ tags: ['vtubers']
+ }
+}
+
+
+export interface IVtuber {
+ id: number;
+ attributes: {
+ slug: string;
+ displayName: string;
+ chaturbate?: string;
+ twitter?: string;
+ patreon?: string;
+ twitch?: string;
+ tiktok?: string;
+ onlyfans?: string;
+ youtube?: string;
+ linktree?: string;
+ carrd?: string;
+ fansly?: string;
+ pornhub?: string;
+ discord?: string;
+ reddit?: string;
+ throne?: string;
+ instagram?: string;
+ facebook?: string;
+ merch?: string;
+ vods: IVod[];
+ description1: string;
+ description2?: string;
+ image: string;
+ imageBlur?: string;
+ themeColor: string;
+ }
+}
+
+export interface IVtuberResponse {
+ data: IVtuber;
+ meta: IMeta;
+}
+
+export interface IVtubersResponse {
+ data: IVtuber[];
+ meta: IMeta;
+}
+
+
+export function getUrl(slug: string): string {
+ return `${siteUrl}/vt/${slug}`
+}
+
+
+
+
+export async function getVtuberBySlug(slug: string): Promise {
+ const query = qs.stringify(
+ {
+ filters: {
+ slug: {
+ $eq: slug
+ }
+ }
+ }
+ )
+
+ const res = await fetch(`${strapiUrl}/api/vtubers?${query}`);
+ if (!res.ok) {
+ console.error(`error inside getVtuberBySlug-- ${res.statusText}`);
+ return null;
+ }
+ const vtuber = await res.json();
+ return vtuber.data[0];
+}
+
+export async function getVtuberById(id: number): Promise {
+ const res = await fetch(`${strapiUrl}/api/vtubers?filters[id][$eq]=${id}`);
+ if (!res.ok) {
+ console.error(`error inside getVtuberById-- ${res.statusText}`);
+ return null;
+ }
+ const vtuber = await res.json();
+ return vtuber
+}
+
+export async function getVtubers(): Promise {
+ const res = await fetch(`${strapiUrl}/api/vtubers`);
+ if (!res.ok) {
+ console.error(`error inside getVtubers-- ${res.statusText}`);
+ return null;
+ }
+ const vtubers = await res.json();
+ return vtubers;
+
+}
+
+export async function getAllVtubers(): Promise {
+ const pageSize = 100;
+
+ const allVtubers: IVtuber[] = [];
+ let currentPage = 1;
+
+ while (true) {
+ const query = qs.stringify({
+ // populate: {
+ // vtuber: {
+ // fields: ['slug', 'displayName', 'image', 'imageBlur'],
+ // },
+ // muxAsset: {
+ // fields: ['playbackId', 'assetId'],
+ // },
+ // thumbnail: {
+ // fields: ['cdnUrl', 'url'],
+ // },
+ // tagVodRelations: {
+ // fields: ['tag'],
+ // populate: ['tag'],
+ // },
+ // videoSrcB2: {
+ // fields: ['url', 'key', 'uploadId', 'cdnUrl'],
+ // },
+ // },
+ // sort: {
+ // date: sortDesc ? 'desc' : 'asc',
+ // },
+ pagination: {
+ pageSize,
+ page: currentPage,
+ },
+ });
+
+ try {
+ console.log(`getting /api/vtubers page=${currentPage}`);
+ const response = await fetch(`${strapiUrl}/api/vtubers?${query}`, fetchVtubersOptions);
+
+ if (!response.ok) {
+ // Handle non-successful response (e.g., HTTP error)
+ throw new Error(`HTTP error! Status: ${response.status}`);
+ }
+
+ const responseData = await response.json();
+
+ if (!responseData.data || responseData.data.length === 0) {
+ // No more data to fetch
+ break;
+ }
+
+ allVtubers.push(...responseData.data);
+ currentPage++;
+ } catch (error) {
+ // Handle fetch error
+ if (error instanceof Error) {
+ console.error('Error fetching data:', error.message);
+ }
+ return null;
+ }
+ }
+
+ return allVtubers;
+}
\ No newline at end of file
diff --git a/packages/next/app/page.tsx b/packages/next/app/page.tsx
new file mode 100644
index 0000000..cd59161
--- /dev/null
+++ b/packages/next/app/page.tsx
@@ -0,0 +1,72 @@
+
+import FundingGoal from "@/components/funding-goal";
+import VodCard from "@/components/vod-card";
+import { getVodTitle } from "@/components/vod-page";
+import { getVods } from '@/lib/vods';
+import { IVod } from "@/lib/vods";
+import { getVtubers, IVtuber } from "./lib/vtubers";
+import VTuberCard from "./components/vtuber-card";
+import Link from 'next/link';
+import { notFound } from "next/navigation";
+
+export default async function Page() {
+ const vods = await getVods(1, 9, true);
+ const vtubers = await getVtubers();
+ if (!vtubers) notFound();
+
+ // return (
+ //
+ //
+ // {JSON.stringify(vods.data, null, 2)}
+ //
+ //
+ // )
+ return (
+ <>
+
+
+
+
+ The Galaxy's Best VTuber Hentai Site
+
+ For adults only (NSFW)
+
+
+
+
+
+
+
+ Latest VODs
+
+
+ {vods.data.map((vod: IVod) => (
+
+ ))}
+
+
+ See all Latest Vods
+
+
+
+ VTubers
+ {/*
+ {vtubers.data.map((vtuber: IVtuber) =>
+
+ )}
+ */}
+
+
+ >
+ );
+}
diff --git a/packages/next/app/patrons/page.tsx b/packages/next/app/patrons/page.tsx
new file mode 100644
index 0000000..9b10c62
--- /dev/null
+++ b/packages/next/app/patrons/page.tsx
@@ -0,0 +1,42 @@
+
+import PatronsList from '../components/patrons-list';
+import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
+import { faExternalLinkAlt } from "@fortawesome/free-solid-svg-icons";
+import Link from 'next/link'
+import { getCampaign } from '../lib/patreon';
+
+export default async function Page() {
+
+ const patreonCampaign = await getCampaign()
+
+ return (
+ <>
+
+
+
+
Patron List
+
+ Futureporn.net continues to improve thanks to
+ {patreonCampaign.patronCount} generous supporters.
+
+
+
+
+
Want to get your name on this list, and get perks like FAST video streaming?
+
+
Become a patron today!
+
+
+
+ Patron names are private by default--{' '}
+ Opt-in to have your name displayed.
+
+
+
+
+ >
+ );
+}
diff --git a/packages/next/app/profile/page.tsx b/packages/next/app/profile/page.tsx
new file mode 100644
index 0000000..8c5dcdb
--- /dev/null
+++ b/packages/next/app/profile/page.tsx
@@ -0,0 +1,62 @@
+'use client'
+
+import { useAuth, LoginButton, LogoutButton } from "../components/auth"
+import { patreonVideoAccessBenefitId } from "../lib/constants";
+import UserControls from "../components/user-controls";
+import Skeleton, { SkeletonTheme } from "react-loading-skeleton"
+import { skeletonHeight, skeletonBorderRadius, skeletonBaseColor, skeletonHighlightColor } from '../lib/constants'
+
+export default function Page() {
+ const { authData } = useAuth()
+ const isLoggedIn = (!!authData?.accessToken)
+ const isEntitledToCDN = (!!authData?.user?.patreonBenefits.split(',').includes(patreonVideoAccessBenefitId))
+
+ if (!authData) {
+ return
+
+
+
+
+ }
+
+
+ return (
+ <>
+
+
+
{authData?.user?.username} Profile
+
+ {/* if not logged in, show login button */}
+ {
+ (!authData?.user) && (
+
+ )
+ }
+
+ {/* if logged in and not patron, display welcome */}
+ {
+ (!!authData?.accessToken && !isEntitledToCDN) &&
+ <>
+
Welcome to Futureporn, {authData?.user?.username || 'chatmember'}! It seems that you are not a patron yet. Please log out and log in again if you believe this is an error. Thank you for your interest!
+
+ >
+ }
+
+ {/* if logged in and patron, display profile*/}
+ {
+ (!!authData?.user?.patreonBenefits && isEntitledToCDN) &&
+
+ }
+
+
+
+
+
+ >
+ )
+}
\ No newline at end of file
diff --git a/packages/next/app/streams/[cuid]/not-found.tsx b/packages/next/app/streams/[cuid]/not-found.tsx
new file mode 100644
index 0000000..b9d167b
--- /dev/null
+++ b/packages/next/app/streams/[cuid]/not-found.tsx
@@ -0,0 +1,12 @@
+import Link from 'next/link'
+
+export default function NotFound() {
+ return (
+
+
404 Not Found
+
Could not find that stream.
+
+
Return to streams list
+
+ )
+}
\ No newline at end of file
diff --git a/packages/next/app/streams/[cuid]/page.tsx b/packages/next/app/streams/[cuid]/page.tsx
new file mode 100644
index 0000000..e4971e0
--- /dev/null
+++ b/packages/next/app/streams/[cuid]/page.tsx
@@ -0,0 +1,20 @@
+
+import StreamPage from '@/components/stream-page';
+import { getStreamByCuid } from '@/lib/streams';
+
+
+interface IPageParams {
+ params: {
+ cuid: string;
+ }
+}
+
+
+export default async function Page ({ params: { cuid } }: IPageParams) {
+ const stream = await getStreamByCuid(cuid);
+ return (
+ <>
+
+ >
+ )
+}
\ No newline at end of file
diff --git a/packages/next/app/streams/page.tsx b/packages/next/app/streams/page.tsx
new file mode 100644
index 0000000..1709cc3
--- /dev/null
+++ b/packages/next/app/streams/page.tsx
@@ -0,0 +1,34 @@
+import Pager from "@/components/pager";
+import StreamsCalendar from "@/components/streams-calendar";
+import StreamsList from "@/components/streams-list";
+import { getAllStreams } from "@/lib/streams";
+import { getAllVtubers } from "@/lib/vtubers";
+import { MissingStaticPage } from "next/dist/shared/lib/utils";
+import { notFound } from "next/navigation";
+// import { useState } from "react";
+
+
+export default async function Page() {
+ const vtubers = await getAllVtubers();
+ const pageSize = 100;
+ const page = 1;
+ if (!vtubers) notFound();
+ const missingStreams = await getAllStreams(['missing']);
+ const issueStreams = await getAllStreams(['issue']);
+ const goodStreams = await getAllStreams(['good']);
+
+ return (
+
+ {/*
+
+ {JSON.stringify(vtubers, null, 2)}
+
+ */}
+
+
+ {/*
*/}
+
+
+
+ )
+}
\ No newline at end of file
diff --git a/packages/next/app/tags/[slug]/page.tsx b/packages/next/app/tags/[slug]/page.tsx
new file mode 100644
index 0000000..04a9d47
--- /dev/null
+++ b/packages/next/app/tags/[slug]/page.tsx
@@ -0,0 +1,35 @@
+import { getVodsForTag, IVod } from '@/lib/vods'
+import VodCard from '@/components/vod-card'
+import Link from 'next/link'
+import { getVodTitle } from '@/components/vod-page'
+import { notFound } from 'next/navigation'
+
+export default async function Page({ params }: { params: { slug: string }}) {
+ const vods = await getVodsForTag(params.slug)
+ if (!vods) return notFound()
+ return (
+
+
+
Tagged “{params.slug}”
+
+
+
+ {vods.data.map((vod: IVod) => (
+
+ ))}
+
+
+
+
+ )
+}
\ No newline at end of file
diff --git a/packages/next/app/tags/page.tsx b/packages/next/app/tags/page.tsx
new file mode 100644
index 0000000..77c05b6
--- /dev/null
+++ b/packages/next/app/tags/page.tsx
@@ -0,0 +1,15 @@
+import { getTags } from '../lib/tags'
+import SortableTags from '../components/sortable-tags'
+
+export default async function Page() {
+ const tags = await getTags();
+
+ return (
+
+ )
+}
\ No newline at end of file
diff --git a/packages/next/app/upload/page.tsx b/packages/next/app/upload/page.tsx
new file mode 100644
index 0000000..0006657
--- /dev/null
+++ b/packages/next/app/upload/page.tsx
@@ -0,0 +1,26 @@
+
+import { getAllVtubers } from '@/lib/vtubers';
+import UploadForm from '@/components/upload-form';
+
+import '@uppy/core/dist/style.min.css';
+import '@uppy/dashboard/dist/style.min.css';
+import { getStreamByCuid } from '@/lib/streams';
+
+
+export default async function Page() {
+
+ const vtubers = await getAllVtubers();
+
+
+ return (
+ <>
+
+ {!vtubers
+ ? Failed to fetch vtubers list. Please try again later.
+ :
+ }
+
+
+ >
+ )
+}
\ No newline at end of file
diff --git a/packages/next/app/upload/page.tsx.old b/packages/next/app/upload/page.tsx.old
new file mode 100644
index 0000000..80213e3
--- /dev/null
+++ b/packages/next/app/upload/page.tsx.old
@@ -0,0 +1,240 @@
+'use client'
+
+import React, { useEffect } from 'react';
+import Uppy from '@uppy/core';
+import { Dashboard } from '@uppy/react';
+import RemoteSources from '@uppy/remote-sources';
+import AwsS3Multipart from '@uppy/aws-s3-multipart';
+import '@uppy/core/dist/style.min.css';
+import '@uppy/dashboard/dist/style.min.css';
+import Image from 'next/image';
+import Link from 'next/link';
+
+const uppy = new Uppy()
+
+
+
+// uppy.use(AwsS3Multipart, {
+// limit: 6,
+// companionUrl: process.env.NEXT_PUBLIC_UPPY_COMPANION_URL,
+// // companionHeaders: {
+// // // @todo
+// // // Authorization: `Bearer ${Alpine.store('auth').jwt}`
+// // }
+// })
+
+
+// Dashboard,
+// {
+// inline: true,
+// target: '#uppy-dashboard',
+// theme: 'auto',
+// proudlyDisplayPoweredByUppy: false,
+// disableInformer: false,
+// // metaFields: [
+// // @todo maybe add meta fields once https://github.com/transloadit/uppy/issues/4427 is fixed
+// // {
+// // id: 'announceUrl',
+// // name: 'Stream Announcement URL',
+// // placeholder: 'this is a placeholder'
+// // },
+// // {
+// // id: 'note',
+// // name: 'Note'
+// // }
+// // {
+// // id: 'date',
+// // name: 'Stream Date (ISO 8601)',
+// // placeholder: '2022-12-30'
+// // },
+// // ]
+// }
+// )
+
+// import Uppy from '@uppy/core';
+// import Dashboard from '@uppy/dashboard';
+// import '/@root/node_modules/@uppy/core/dist/style.min.css';
+// import '/@root/node_modules/@uppy/dashboard/dist/style.min.css';
+
+
+
+export default function Page() {
+ // const dashboard = new Dashboard({
+ // inline: true,
+ // target: '#uppy-dashboard',
+ // theme: 'dark',
+ // proudlyDisplayPoweredByUppy: false,
+ // disableInformer: false,
+ // })
+
+
+ // useEffect(() => {
+ // uppy.setOptions({
+ // Dashboard: {
+ // theme: 'dark'
+ // }
+ // })
+ // })
+
+ // useEffect(() => {
+ // uppy.setOptions({
+ // restrictions: props.restrictions
+ // })
+ // }, [props.restrictions])
+
+ // .use(
+ // Dashboard,
+ // {
+ // inline: true,
+ // target: '#uppy-dashboard',
+ // theme: 'auto',
+ // proudlyDisplayPoweredByUppy: false,
+ // disableInformer: false,
+ // // metaFields: [
+ // // @todo maybe add meta fields once https://github.com/transloadit/uppy/issues/4427 is fixed
+ // // {
+ // // id: 'announceUrl',
+ // // name: 'Stream Announcement URL',
+ // // placeholder: 'this is a placeholder'
+ // // },
+ // // {
+ // // id: 'note',
+ // // name: 'Note'
+ // // }
+ // // {
+ // // id: 'date',
+ // // name: 'Stream Date (ISO 8601)',
+ // // placeholder: '2022-12-30'
+ // // },
+ // // ]
+ // }
+ // )
+ // .use(RemoteSources, {
+ // companionUrl: process.env.NEXT_PUBLIC_UPPY_COMPANION_URL,
+ // sources: ['Box', 'OneDrive', 'Dropbox', 'GoogleDrive', 'Url'],
+ // })
+ // .use(AwsS3Multipart, {
+ // limit: 6,
+ // companionUrl: process.env.NEXT_PUBLIC_UPPY_COMPANION_URL,
+ // // companionHeaders: {
+ // // Authorization: `Bearer ${Alpine.store('auth').jwt}`
+ // // }
+ // })
+
+ return (
+ <>
+
+ >
+ )
+}
+
+// export default function upload () {
+// return {
+// date: '',
+// note: '',
+// init () {
+// const that = this
+// const uppy = new Uppy({
+// onBeforeUpload (files) {
+// if (!that.date) {
+// const msg = 'File is missing a Stream Date'
+// uppy.info(msg, 'error')
+// throw new Error(msg)
+// }
+// },
+// restrictions: {
+// maxNumberOfFiles: 1,
+// // requiredMetaFields: [
+// // 'announceUrl',
+// // 'date'
+// // ]
+// },
+// })
+// .use(
+// Dashboard,
+// {
+// inline: true,
+// target: '#uppy-dashboard',
+// theme: 'auto',
+// proudlyDisplayPoweredByUppy: false,
+// disableInformer: false,
+// // metaFields: [
+// // @todo maybe add meta fields once https://github.com/transloadit/uppy/issues/4427 is fixed
+// // {
+// // id: 'announceUrl',
+// // name: 'Stream Announcement URL',
+// // placeholder: 'this is a placeholder'
+// // },
+// // {
+// // id: 'note',
+// // name: 'Note'
+// // }
+// // {
+// // id: 'date',
+// // name: 'Stream Date (ISO 8601)',
+// // placeholder: '2022-12-30'
+// // },
+// // ]
+// }
+// )
+// .use(RemoteSources, {
+// companionUrl: window.companionUrl,
+// sources: ['Box', 'OneDrive', 'Dropbox', 'GoogleDrive', 'Url'],
+// })
+// .use(AwsS3Multipart, {
+// limit: 6,
+// companionUrl: window.companionUrl,
+// companionHeaders: {
+// Authorization: `Bearer ${Alpine.store('auth').jwt}`
+// }
+// })
+
+
+// uppy.on('file-added', (file) => {
+// if (!that.date) {
+// uppy.info("Please add the Stream Date to metadata", 'info', 5000)
+// }
+// });
+
+
+// uppy.on('complete', (result) => {
+// // for each uploaded vod, create a Vod in Strapi
+// result.successful.forEach(async (upload) => {
+// const res = await fetch(`${Alpine.store('env').backend}/api/vod/createFromUppy`, {
+// method: 'POST',
+// headers: {
+// 'Authorization': `Bearer ${Alpine.store('auth').jwt}`,
+// 'Accept': 'application/json',
+// 'Content-Type': 'application/json'
+// },
+// body: JSON.stringify({
+// data: {
+// date: that.date,
+// videoSrcB2: {
+// key: upload.s3Multipart.key,
+// uploadId: upload.s3Multipart.uploadId
+// },
+// note: that.note,
+// }
+// })
+// })
+
+// if (res.ok) {
+// uppy.info("Thank you. The VOD is queued for approval by a moderator.", 'success', 60000)
+// } else {
+// uppy.error("There was a problem while uploading. Please try again later.", 'error', 10000)
+// }
+// })
+
+// })
+// }
+// }
+// }
\ No newline at end of file
diff --git a/packages/next/app/uppy.tsx b/packages/next/app/uppy.tsx
new file mode 100644
index 0000000..64279fc
--- /dev/null
+++ b/packages/next/app/uppy.tsx
@@ -0,0 +1,45 @@
+'use client';
+
+import React, { useState, createContext, useContext, useEffect } from 'react';
+import Uppy from '@uppy/core';
+import AwsS3 from '@uppy/aws-s3';
+import RemoteSources from '@uppy/remote-sources';
+import { useAuth } from './components/auth';
+
+const companionUrl = process.env.NEXT_PUBLIC_UPPY_COMPANION_URL!
+
+export const UppyContext = createContext(new Uppy());
+
+export default function UppyProvider({
+ children
+}: {
+ children: React.ReactNode
+}) {
+ const { authData } = useAuth();
+ const [uppy] = useState(() => new Uppy(
+ {
+ autoProceed: true
+ }
+ )
+ .use(RemoteSources, {
+ companionUrl,
+ sources: ['GoogleDrive']
+ })
+ .use(AwsS3, {
+ companionUrl,
+ shouldUseMultipart: true,
+ abortMultipartUpload: () => {}, // @see https://github.com/transloadit/uppy/issues/1197#issuecomment-491756118
+ companionHeaders: {
+ 'authorization': `Bearer ${authData?.accessToken}`
+ }
+ })
+ );
+
+
+
+ return (
+
+ {children}
+
+ )
+}
diff --git a/packages/next/app/vods/[safeDateOrCuid]/page.tsx b/packages/next/app/vods/[safeDateOrCuid]/page.tsx
new file mode 100644
index 0000000..3074670
--- /dev/null
+++ b/packages/next/app/vods/[safeDateOrCuid]/page.tsx
@@ -0,0 +1,16 @@
+
+import VodPage from '@/components/vod-page';
+import { IVodPageProps, getVodFromSafeDateOrCuid } from '@/lib/vods';
+import { notFound } from 'next/navigation';
+
+
+/**
+ * This route exists as backwards compatibility for Futureporn 0.0.0 which was on neocities
+ * @see https://www.w3.org/Provider/Style/URI
+ */
+export default async function Page({ params: { safeDateOrCuid, slug } }: IVodPageProps) {
+ const vod = await getVodFromSafeDateOrCuid(safeDateOrCuid);
+ if (!vod) notFound();
+ return
+}
+
diff --git a/packages/next/app/vods/page.tsx b/packages/next/app/vods/page.tsx
new file mode 100644
index 0000000..175ff08
--- /dev/null
+++ b/packages/next/app/vods/page.tsx
@@ -0,0 +1,6 @@
+
+import { redirect } from 'next/navigation';
+
+export default async function Page() {
+ redirect('/latest-vods/1')
+}
\ No newline at end of file
diff --git a/packages/next/app/vt/[slug]/history/page.tsx b/packages/next/app/vt/[slug]/history/page.tsx
new file mode 100644
index 0000000..4c25482
--- /dev/null
+++ b/packages/next/app/vt/[slug]/history/page.tsx
@@ -0,0 +1,70 @@
+
+import { getVtuberBySlug } from '@/lib/vtubers';
+import { getAllStreamsForVtuber } from '@/lib/streams';
+import NotFound from '../not-found';
+import { DataRecord } from 'cal-heatmap/src/options/Options';
+import { Cal } from '@/components/cal';
+
+interface IPageProps {
+ params: {
+ slug: string;
+ };
+}
+
+function getArchiveStatusValue(archiveStatus: string): number {
+ if (archiveStatus === 'good') return 2;
+ if (archiveStatus === 'issue') return 1;
+ else return 0 // missing
+}
+
+function sortDataRecordsByDate(records: DataRecord[]) {
+ return records.sort((a, b) => {
+ if (typeof a.date === 'string' && typeof b.date === 'string') {
+ return a.date.localeCompare(b.date);
+ } else {
+ // Handle comparison when date is not a string (e.g., when it's a number)
+ // For instance, you might want to convert numbers to strings or use a different comparison logic.
+ // Example assuming number to string conversion:
+ return String(a.date).localeCompare(String(b.date));
+ }
+ });
+}
+
+
+export default async function Page({ params: { slug } }: IPageProps) {
+ const vtuber = await getVtuberBySlug(slug);
+ if (!vtuber) return
+ const streams = await getAllStreamsForVtuber(vtuber.id);
+ const streamsByYear: { [year: string]: DataRecord[] } = {};
+ streams.forEach((stream) => {
+ const date = new Date(stream.attributes.date);
+ const year = date.getFullYear();
+ if (!streamsByYear[year]) {
+ streamsByYear[year] = [];
+ }
+ streamsByYear[year].push({
+ date: new Date(stream.attributes.date).toISOString(),
+ value: stream.attributes.archiveStatus,
+ });
+ });
+ // Sort the data records within each year's array
+ for (const year in streamsByYear) {
+ streamsByYear[year] = sortDataRecordsByDate(streamsByYear[year]);
+ }
+
+
+ return (
+
+ {Object.keys(streamsByYear).map((year) => {
+ return (
+
+
{year}
+ {/*
{JSON.stringify(streamsByYear[year], null, 2)}
*/}
+
+
+ )
+ })}
+
+
+ )
+}
diff --git a/packages/next/app/vt/[slug]/not-found.tsx b/packages/next/app/vt/[slug]/not-found.tsx
new file mode 100644
index 0000000..8027f63
--- /dev/null
+++ b/packages/next/app/vt/[slug]/not-found.tsx
@@ -0,0 +1,12 @@
+import Link from 'next/link'
+
+export default function NotFound() {
+ return (
+
+
404 Not Found
+
Could not find a matching vtubler.
+
+
Return to vtuber list
+
+ )
+}
\ No newline at end of file
diff --git a/packages/next/app/vt/[slug]/page.tsx b/packages/next/app/vt/[slug]/page.tsx
new file mode 100644
index 0000000..910cb64
--- /dev/null
+++ b/packages/next/app/vt/[slug]/page.tsx
@@ -0,0 +1,246 @@
+import VodsList from '@/components/vods-list';
+import Link from 'next/link';
+import { getVtuberBySlug } from '@/lib/vtubers'
+import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
+import { faExternalLinkAlt, faBagShopping } from "@fortawesome/free-solid-svg-icons";
+import { faFacebook, faInstagram, faPatreon, faYoutube, faTwitch, faTiktok, faXTwitter, faReddit, faDiscord } from "@fortawesome/free-brands-svg-icons";
+import Image from 'next/image';
+import OnlyfansIcon from "@/components/icons/onlyfans";
+import PornhubIcon from '@/components/icons/pornhub';
+import ThroneIcon from '@/components/icons/throne';
+import LinktreeIcon from '@/components/icons/linktree';
+import FanslyIcon from '@/components/icons/fansly';
+import ChaturbateIcon from '@/components/icons/chaturbate';
+import CarrdIcon from '@/components/icons/carrd';
+import styles from '@/assets/styles/icon.module.css';
+
+import { getVodsForVtuber } from '@/lib/vods';
+import { notFound } from 'next/navigation';
+import ArchiveProgress from '@/components/archive-progress';
+import StreamsCalendar from '@/components/streams-calendar';
+import { getAllStreamsForVtuber, getStreamsForVtuber } from '@/lib/streams';
+import LinkableHeading from '@/components/linkable-heading';
+
+
+
+export default async function Page({ params }: { params: { slug: string } }) {
+ const vtuber = await getVtuberBySlug(params.slug);
+ if (!vtuber) notFound();
+
+ const vods = await getVodsForVtuber(vtuber.id, 1, 9);
+ if (!vods) notFound();
+
+ const missingStreams = await getAllStreamsForVtuber(vtuber.id, ['missing']);
+ const issueStreams = await getAllStreamsForVtuber(vtuber.id, ['issue']);
+ const goodStreams = await getAllStreamsForVtuber(vtuber.id, ['good']);
+
+
+
+ // return (
+ // <>
+ // hi mom!
+ //
+ //
+ // {JSON.stringify(missingStreams, null, 2)}
+ //
+ //
+ // >
+ // )
+
+ return (
+ <>
+ {vtuber && (
+ <>
+
+
+
+
+
{vtuber.attributes.displayName}
+
+
+
+
+
+
+
+
{vtuber.attributes.description1}
+
{vtuber.attributes.description2}
+
+
+
+
+ Socials
+
+
+
+
+
+ {vtuber.attributes.patreon && (
+
+
+ Patreon
+
+
+ )}
+ {vtuber.attributes.twitter && (
+
+
+ Twitter
+
+
+ )}
+ {vtuber.attributes.youtube && (
+
+
+ YouTube
+
+
+ )}
+ {vtuber.attributes.twitch && (
+
+
+ Twitch
+
+
+ )}
+ {vtuber.attributes.tiktok && (
+
+
+ TikTok
+
+
+ )}
+ {vtuber.attributes.fansly && (
+
+
+ Fansly
+
+
+ )}
+ {vtuber.attributes.onlyfans && (
+
+
+
+
+ OnlyFans
+
+
+ )}
+ {vtuber.attributes.pornhub && (
+
+ )}
+ {vtuber.attributes.reddit && (
+
+
+ Reddit
+
+
+ )}
+ {vtuber.attributes.discord && (
+
+
+ Discord
+
+
+ )}
+ {vtuber.attributes.instagram && (
+
+
+ Instagram
+
+
+ )}
+ {vtuber.attributes.facebook && (
+
+
+ Facebook
+
+
+ )}
+ {vtuber.attributes.merch && (
+
+
+ Merch
+
+
+ )}
+ {vtuber.attributes.chaturbate && (
+
+
+ Chaturbate
+
+
+ )}
+ {vtuber.attributes.throne && (
+
+
+ Throne
+
+
+ )}
+ {vtuber.attributes.linktree && (
+
+
+ Linktree
+
+
+ )}
+ {vtuber.attributes.carrd && (
+
+
+ Carrd
+
+
+ )}
+
+
+
+
+ {/*
+ Toys
+
+
+ <>
+
+ {(toys.pagination.total > toySampleCount) &&
See all of {vtuber.displayName}'s toys}
+ > */}
+
+
+ Vods
+
+
+
+ {
+ (vtuber.attributes.vods) ? (
+
See all {vtuber.attributes.displayName} vods
+ ) : (
No VODs have been added, yet.
)
+ }
+
+
+ Streams
+
+
+{/*
+
+ Archive Progress
+
+
*/}
+
+
+
+ >
+ )}
+ >
+ );
+}
diff --git a/packages/next/app/vt/[slug]/stream/[safeDate]/page.tsx b/packages/next/app/vt/[slug]/stream/[safeDate]/page.tsx
new file mode 100644
index 0000000..4d1f71f
--- /dev/null
+++ b/packages/next/app/vt/[slug]/stream/[safeDate]/page.tsx
@@ -0,0 +1,31 @@
+
+import { Stream } from '@/components/stream';
+import { IStream, getStreamForVtuber } from '@/lib/streams';
+import { getVtuberBySlug } from '@/lib/vtubers';
+import NotFound from '../../not-found';
+
+interface IPageProps {
+ params: {
+ safeDate: string;
+ slug: string;
+ };
+}
+
+export default async function Page({ params: { safeDate, slug } }: IPageProps) {
+ const vtuber = await getVtuberBySlug(slug);
+ if (!vtuber) return
+ const stream = await getStreamForVtuber(vtuber.id, safeDate);
+ if (!stream) return
+
+ return (
+
+
+
Stream Page!
+
slug={slug} safeDate={safeDate}
+
+
+
+
+ )
+}
+
diff --git a/packages/next/app/vt/[slug]/streams/page.tsx b/packages/next/app/vt/[slug]/streams/page.tsx
new file mode 100644
index 0000000..6e6bdff
--- /dev/null
+++ b/packages/next/app/vt/[slug]/streams/page.tsx
@@ -0,0 +1,23 @@
+
+import { getVtuberBySlug } from '@/lib/vtubers';
+import { getStreamsForVtuber } from '@/lib/streams';
+import Pager from '@/components/pager';
+import { notFound } from 'next/navigation';
+
+interface IPageParams {
+ params: {
+ slug: string;
+ }
+}
+
+export default async function Page({ params }: IPageParams) {
+ const vtuber = await getVtuberBySlug(params.slug);
+ if (!vtuber) return vtuber {params.slug} not found
+ const streams = await getStreamsForVtuber(vtuber.id, 1, 24);
+ if (!streams) return streams not found
;
+ return (
+ <>
+
+ >
+ )
+}
\ No newline at end of file
diff --git a/packages/next/app/vt/[slug]/toys/[page]/page.tsx b/packages/next/app/vt/[slug]/toys/[page]/page.tsx
new file mode 100644
index 0000000..f29c912
--- /dev/null
+++ b/packages/next/app/vt/[slug]/toys/[page]/page.tsx
@@ -0,0 +1,33 @@
+
+// import VodsList, { VodsListHeading } from '@/components/vods-list'
+// import { getVtuberBySlug } from '@/lib/vtubers'
+// // import { IToys, getToysForVtuber } from '@/lib/toys'
+// import { ToysList, ToysListHeading } from '@/components/toys'
+// import Pager from '@/components/pager'
+
+// interface IPageParams {
+// params: {
+// name: string;
+// page: number;
+// }
+// }
+
+export default async function Page() {
+ // const vtuber = await getVtuberBySlug(params.slug)
+ return Toys pages coming soon
+ // const toys: IToys = await getToysForVtuber(vtuber.id, params.page, 24)
+ // return (
+ //
+ // )
+}
\ No newline at end of file
diff --git a/packages/next/app/vt/[slug]/toys/page.tsx b/packages/next/app/vt/[slug]/toys/page.tsx
new file mode 100644
index 0000000..e1b8843
--- /dev/null
+++ b/packages/next/app/vt/[slug]/toys/page.tsx
@@ -0,0 +1,33 @@
+
+// import VodsList, { VodsListHeading } from '@/components/vods-list'
+// import { getVtuberBySlug } from '@/lib/vtubers'
+// // import { IToys, getToysForVtuber } from '@/lib/toys'
+// import { ToysList } from '@/components/toys'
+// import Pager from '@/components/pager'
+
+interface IPageParams {
+ params: {
+ name: string;
+ }
+}
+
+export default async function Page({ params }: IPageParams) {
+ // const vtuber = await getVtuberBySlug(params.slug)
+ return toys pages coming soon
+ // const toys: IToys = await getToysForVtuber(vtuber.id, 1, 24)
+ // return (
+ //
+ //
+ // {/*
*/}
+ // {/*
*/}
+ //
+ //
+ //
+ //
+ // )
+}
\ No newline at end of file
diff --git a/packages/next/app/vt/[slug]/vod/[safeDateOrCuid]/page.tsx b/packages/next/app/vt/[slug]/vod/[safeDateOrCuid]/page.tsx
new file mode 100644
index 0000000..c5e615c
--- /dev/null
+++ b/packages/next/app/vt/[slug]/vod/[safeDateOrCuid]/page.tsx
@@ -0,0 +1,12 @@
+
+import VodPage from '@/components/vod-page'
+import { IVodPageProps, getVodFromSafeDateOrCuid } from '@/lib/vods'
+import { notFound } from 'next/navigation';
+
+
+export default async function Page({ params: { safeDateOrCuid } }: IVodPageProps) {
+ const vod = await getVodFromSafeDateOrCuid(safeDateOrCuid);
+ if (!vod) return notFound();
+ return
+}
+
diff --git a/packages/next/app/vt/[slug]/vod/page.tsx b/packages/next/app/vt/[slug]/vod/page.tsx
new file mode 100644
index 0000000..b62229f
--- /dev/null
+++ b/packages/next/app/vt/[slug]/vod/page.tsx
@@ -0,0 +1,15 @@
+import React from 'react';
+import Link from 'next/link';
+import { redirect } from 'next/navigation';
+
+interface IPageParams {
+ params: {
+ slug: string;
+ }
+}
+
+export default function Page({ params: { slug } }: IPageParams) {
+ redirect(`/vt/${slug}/vods`)
+ return See {`/vt/${slug}/vods`}
+}
+
diff --git a/packages/next/app/vt/[slug]/vods/[page]/page.tsx b/packages/next/app/vt/[slug]/vods/[page]/page.tsx
new file mode 100644
index 0000000..4bd6aea
--- /dev/null
+++ b/packages/next/app/vt/[slug]/vods/[page]/page.tsx
@@ -0,0 +1,43 @@
+import VodsList, { VodsListHeading } from '@/components/vods-list';
+import { getVtuberBySlug, getUrl } from '@/lib/vtubers';
+import { IVodsResponse, getVodsForVtuber } from '@/lib/vods';
+import Pager from '@/components/pager';
+import { notFound } from 'next/navigation';
+
+
+interface IPageParams {
+ params: {
+ slug: string;
+ page: string;
+ };
+}
+
+export default async function Page({ params }: IPageParams) {
+ let vtuber, vods;
+ const pageNumber = parseInt(params.page);
+
+ try {
+ vtuber = await getVtuberBySlug(params.slug);
+ if (!vtuber) notFound();
+ vods = await getVodsForVtuber(vtuber.id, pageNumber, 24, true);
+ } catch (error) {
+ // Handle the error here (e.g., display an error message)
+ console.error("An error occurred:", error);
+ // You might also want to return an error page or message
+ return Error: {JSON.stringify(error)}
;
+ }
+
+
+ if (!vods) return error
+ return (
+ <>
+
+
+
+ >
+ );
+}
diff --git a/packages/next/app/vt/[slug]/vods/page.tsx b/packages/next/app/vt/[slug]/vods/page.tsx
new file mode 100644
index 0000000..3c40c7a
--- /dev/null
+++ b/packages/next/app/vt/[slug]/vods/page.tsx
@@ -0,0 +1,26 @@
+
+import VodsList, { VodsListHeading } from '@/components/vods-list'
+import { getVtuberBySlug, getUrl } from '@/lib/vtubers'
+import { IVodsResponse, getVodsForVtuber, getPaginatedUrl } from '@/lib/vods'
+import Pager from '@/components/pager'
+import { notFound } from 'next/navigation'
+
+interface IPageParams {
+ params: {
+ slug: string;
+ }
+}
+
+export default async function Page({ params }: IPageParams) {
+ const vtuber = await getVtuberBySlug(params.slug)
+ if (!vtuber) notFound();
+ const vods = await getVodsForVtuber(vtuber.id, 1, 24)
+ if (!vods) notFound();
+ return (
+ <>
+
+
+
+ >
+ )
+}
\ No newline at end of file
diff --git a/packages/next/app/vt/page.tsx b/packages/next/app/vt/page.tsx
new file mode 100644
index 0000000..9e410eb
--- /dev/null
+++ b/packages/next/app/vt/page.tsx
@@ -0,0 +1,30 @@
+import { notFound } from 'next/navigation'
+import VTuberCard from '../components/vtuber-card'
+import { getVtubers, IVtuber } from '../lib/vtubers'
+
+
+export default async function Page() {
+ const vtubers = await getVtubers()
+ if (!vtubers) notFound()
+ // return (
+ //
+ //
+ // {JSON.stringify(vtubers, null, 2)}
+ //
+ //
+ // )
+ return (
+ <>
+
+
+
VTubers
+
+ {vtubers.data.map((vtuber: IVtuber) =>
+
+ )}
+
+
+
+ >
+ )
+}
\ No newline at end of file
diff --git a/packages/next/assets/styles/calendar-heatmap.module.scss b/packages/next/assets/styles/calendar-heatmap.module.scss
new file mode 100644
index 0000000..2e8f8bf
--- /dev/null
+++ b/packages/next/assets/styles/calendar-heatmap.module.scss
@@ -0,0 +1,89 @@
+$cell-height : 10px;
+$cell-width : 10px;
+$cell-margin:2px;
+$cell-weekdays-width: 30px;
+
+html {
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
+}
+
+html, body {
+ height: 100%;
+ width: 100%;
+}
+
+#container {
+ height: 514px;
+ width: 930px;
+ margin: 50px auto;
+}
+
+.timeline {
+ margin: 20px;
+ margin-bottom: 60px;
+
+ .timeline-months {
+ display: flex;
+ padding-left: $cell-weekdays-width;
+
+ &-month {
+ width: $cell-width;
+ margin: $cell-margin;
+ border: 1px solid transparent;
+ font-size: 10px;
+ }
+
+ .Jan~.Jan,
+ .Feb~.Feb,
+ .Mar~.Mar,
+ .Apr~.Apr,
+ .May~.May,
+ .Jun~.Jun,
+ .Jul~.Jul,
+ .Aug~.Aug,
+ .Sep~.Sep,
+ .Oct~.Oct,
+ .Nov~.Nov,
+ .Dec~.Dec {
+ visibility: hidden;
+ }
+ }
+
+ &-body {
+ display: flex;
+
+ .timeline-weekdays {
+ display: inline-flex;
+ flex-direction: column;
+ width: $cell-weekdays-width;
+
+ &-weekday {
+ font-size: 10px;
+ height: $cell-height;
+ border: 1px solid transparent;
+ margin: $cell-margin;
+ vertical-align: middle;
+ }
+ }
+
+ .timeline-cells {
+ display: inline-flex;
+ flex-direction: column;
+ flex-wrap: wrap;
+ height: #{(10 + 4) * 8}px;
+
+ &-cell {
+ height: $cell-height;
+ width: $cell-width;
+ border: 1px solid rgba(0, 0, 0, 0.1);
+ margin: $cell-margin;
+ border-radius: 2px;
+ background-color: rgba(0, 0, 0, 0.05);
+
+ &:hover {
+ border: 1px solid rgba(0, 0, 0, 0.3);
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/packages/next/assets/styles/cid.module.css b/packages/next/assets/styles/cid.module.css
new file mode 100644
index 0000000..e195bb4
--- /dev/null
+++ b/packages/next/assets/styles/cid.module.css
@@ -0,0 +1,19 @@
+.container {
+ display: flex;
+ align-items: center;
+}
+
+.cid {
+ overflow: hidden;
+ text-overflow: ellipsis;
+ text-align: center;
+ flex: 1;
+}
+
+.label {
+ width: 6em;
+}
+
+.green {
+ color: rgb(52, 168, 115);
+}
\ No newline at end of file
diff --git a/packages/next/assets/styles/fp.module.css b/packages/next/assets/styles/fp.module.css
new file mode 100644
index 0000000..946e963
--- /dev/null
+++ b/packages/next/assets/styles/fp.module.css
@@ -0,0 +1,20 @@
+
+.noselect {
+ user-select: none;
+}
+
+.tagButton {
+ height: 2em;
+ margin-bottom: 0.5rem;
+ border-radius: 4px;
+}
+
+.isTiny {
+ height: 1.5em;
+}
+
+.grade {
+ font-family: Arial, Helvetica, sans-serif;
+ font-size: 8rem;
+ font-weight: bolder;
+}
\ No newline at end of file
diff --git a/packages/next/assets/styles/global.sass b/packages/next/assets/styles/global.sass
new file mode 100644
index 0000000..7057e6d
--- /dev/null
+++ b/packages/next/assets/styles/global.sass
@@ -0,0 +1,50 @@
+@charset "utf-8"
+
+// Import a Google Font
+@import url('https://fonts.googleapis.com/css?family=Nunito:400,700')
+
+body
+ background-color: rgb(23, 24, 28)
+
+
+// Set your brand colors
+$purple: #8A4D76
+$pink: #FA7C91
+$brown: #757763
+$beige-light: #D0D1CD
+$beige-lighter: #EFF0EB
+
+// Update Bulma's global variables
+$family-sans-serif: "Nunito", sans-serif
+$grey-dark: $brown
+$grey-light: $beige-light
+$primary: $purple
+$link: $pink
+$widescreen-enabled: false
+$fullhd-enabled: false
+
+// Update some of Bulma's component variables
+$body-background-color: $beige-lighter
+$control-border-width: 2px
+$input-border-color: transparent
+$input-shadow: none
+
+// Import only what you need from Bulma
+// @import "../node_modules/bulma/sass/utilities/_all.sass"
+// @import "../node_modules/bulma/sass/base/_all.sass"
+// @import "../node_modules/bulma/sass/elements/button.sass"
+// @import "../node_modules/bulma/sass/elements/container.sass"
+// @import "../node_modules/bulma/sass/elements/title.sass"
+// @import "../node_modules/bulma/sass/form/_all.sass"
+// @import "../node_modules/bulma/sass/components/navbar.sass"
+// @import "../node_modules/bulma/sass/layout/hero.sass"
+// @import "../node_modules/bulma/sass/layout/section.sass"
+
+@import "../../node_modules/bulma/bulma.sass"
+
+@import "../../node_modules/bulma-prefers-dark/bulma-prefers-dark.sass"
+
+a.navbar-item:active,
+a.navbar-item:focus,
+a.navbar-item:focus-within
+ background-color: hsl(0, 0%, 20%)
\ No newline at end of file
diff --git a/packages/next/assets/styles/icon.module.css b/packages/next/assets/styles/icon.module.css
new file mode 100644
index 0000000..5d3efba
--- /dev/null
+++ b/packages/next/assets/styles/icon.module.css
@@ -0,0 +1,20 @@
+
+svg.icon {
+ width: 1em;
+ height: 1em;
+ vertical-align: -0.125em;
+ fill: rgb(208, 209, 205);
+}
+
+svg.icon path {
+ fill: rgb(208, 209, 205);
+}
+
+svg.icon g path {
+ fill: rgb(208, 209, 205) !important;
+}
+
+svg.bigIcon {
+ width: 10em;
+ height: 10em;
+}
\ No newline at end of file
diff --git a/packages/next/assets/styles/player.module.css b/packages/next/assets/styles/player.module.css
new file mode 100644
index 0000000..b3f531b
--- /dev/null
+++ b/packages/next/assets/styles/player.module.css
@@ -0,0 +1,4 @@
+
+.fpMediaPlayer {
+ --media-aspect-ratio: 1.7778;
+}
\ No newline at end of file
diff --git a/packages/next/assets/svg/README.md b/packages/next/assets/svg/README.md
new file mode 100644
index 0000000..bbf6f41
--- /dev/null
+++ b/packages/next/assets/svg/README.md
@@ -0,0 +1,5 @@
+# SVG in next/react
+
+see https://blog.logrocket.com/import-svgs-next-js-apps/
+
+TL;DR: use https://react-svgr.com/playground/ to convert svg to jsx
\ No newline at end of file
diff --git a/packages/next/assets/svg/carrd.svg b/packages/next/assets/svg/carrd.svg
new file mode 100644
index 0000000..9b1ead5
--- /dev/null
+++ b/packages/next/assets/svg/carrd.svg
@@ -0,0 +1 @@
+Carrd
diff --git a/packages/next/assets/svg/chaturbate.svg b/packages/next/assets/svg/chaturbate.svg
new file mode 100644
index 0000000..0ef00ed
--- /dev/null
+++ b/packages/next/assets/svg/chaturbate.svg
@@ -0,0 +1,15 @@
+import * as React from "react"
+const SvgComponent = (props) => (
+
+
+
+)
+export default SvgComponent
diff --git a/packages/next/assets/svg/checkmark.svg b/packages/next/assets/svg/checkmark.svg
new file mode 100644
index 0000000..23cce6f
--- /dev/null
+++ b/packages/next/assets/svg/checkmark.svg
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/packages/next/assets/svg/fansly.tsx b/packages/next/assets/svg/fansly.tsx
new file mode 100644
index 0000000..fcf575d
--- /dev/null
+++ b/packages/next/assets/svg/fansly.tsx
@@ -0,0 +1,20 @@
+import * as React from "react"
+const SvgComponent = (props) => (
+
+
+
+
+)
+export default SvgComponent
diff --git a/packages/next/assets/svg/ipfs.svg b/packages/next/assets/svg/ipfs.svg
new file mode 100644
index 0000000..ea32d6e
--- /dev/null
+++ b/packages/next/assets/svg/ipfs.svg
@@ -0,0 +1 @@
+IPFS
\ No newline at end of file
diff --git a/packages/next/assets/svg/linktree.svg b/packages/next/assets/svg/linktree.svg
new file mode 100644
index 0000000..0f8d400
--- /dev/null
+++ b/packages/next/assets/svg/linktree.svg
@@ -0,0 +1,64 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/packages/next/assets/svg/noun-adult-content-1731184.svg b/packages/next/assets/svg/noun-adult-content-1731184.svg
new file mode 100644
index 0000000..8509fd0
--- /dev/null
+++ b/packages/next/assets/svg/noun-adult-content-1731184.svg
@@ -0,0 +1 @@
+Created by Anatolii Babii from the Noun Project
\ No newline at end of file
diff --git a/packages/next/assets/svg/noun-anime-3890912.svg b/packages/next/assets/svg/noun-anime-3890912.svg
new file mode 100644
index 0000000..c5c376f
--- /dev/null
+++ b/packages/next/assets/svg/noun-anime-3890912.svg
@@ -0,0 +1 @@
+Created by Kevin from the Noun Project
\ No newline at end of file
diff --git a/packages/next/assets/svg/noun-avatar-3546974.svg b/packages/next/assets/svg/noun-avatar-3546974.svg
new file mode 100644
index 0000000..ec43ede
--- /dev/null
+++ b/packages/next/assets/svg/noun-avatar-3546974.svg
@@ -0,0 +1 @@
+love charger copy 2 Created by KEN111 from the Noun Project
\ No newline at end of file
diff --git a/packages/next/assets/svg/noun-girl-842331.svg b/packages/next/assets/svg/noun-girl-842331.svg
new file mode 100644
index 0000000..f609fb4
--- /dev/null
+++ b/packages/next/assets/svg/noun-girl-842331.svg
@@ -0,0 +1,4 @@
+Created by Zackary Cloe from the Noun Project
\ No newline at end of file
diff --git a/packages/next/assets/svg/noun-network-1603820.svg b/packages/next/assets/svg/noun-network-1603820.svg
new file mode 100644
index 0000000..8a3d5c0
--- /dev/null
+++ b/packages/next/assets/svg/noun-network-1603820.svg
@@ -0,0 +1 @@
+Created by Three Six Five from the Noun Project
\ No newline at end of file
diff --git a/packages/next/assets/svg/onlyfans.svg b/packages/next/assets/svg/onlyfans.svg
new file mode 100644
index 0000000..bba261f
--- /dev/null
+++ b/packages/next/assets/svg/onlyfans.svg
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/packages/next/assets/svg/pornhub.svg b/packages/next/assets/svg/pornhub.svg
new file mode 100644
index 0000000..4b1b6bd
--- /dev/null
+++ b/packages/next/assets/svg/pornhub.svg
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/packages/next/assets/svg/throne.svg b/packages/next/assets/svg/throne.svg
new file mode 100644
index 0000000..a396573
--- /dev/null
+++ b/packages/next/assets/svg/throne.svg
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/packages/next/next.config.js b/packages/next/next.config.js
new file mode 100644
index 0000000..1706724
--- /dev/null
+++ b/packages/next/next.config.js
@@ -0,0 +1,22 @@
+/** @type {import('next').NextConfig} */
+const path = require("path");
+const nextConfig = {
+ output: 'standalone',
+ reactStrictMode: false,
+ sassOptions: {
+ includePaths: [path.join(__dirname, "assets", "styles")],
+ },
+ images: {
+ remotePatterns: [
+ {
+ protocol: 'https',
+ hostname: 'futureporn-b2.b-cdn.net',
+ port: '',
+ pathname: '/**',
+ },
+ ],
+ }
+};
+
+
+module.exports = nextConfig;
diff --git a/packages/next/package.json b/packages/next/package.json
new file mode 100644
index 0000000..f97e6e2
--- /dev/null
+++ b/packages/next/package.json
@@ -0,0 +1,79 @@
+{
+ "name": "fp-next",
+ "version": "2.0.0",
+ "private": true,
+ "scripts": {
+ "dev": "next dev",
+ "build": "next build",
+ "start": "next start",
+ "lint": "next lint",
+ "preinstall": "npx only-allow pnpm"
+ },
+ "dependencies": {
+ "@fortawesome/fontawesome-free": "^6.5.1",
+ "@fortawesome/fontawesome-svg-core": "^6.5.1",
+ "@fortawesome/free-brands-svg-icons": "^6.5.1",
+ "@fortawesome/free-solid-svg-icons": "^6.5.1",
+ "@fortawesome/react-fontawesome": "^0.2.0",
+ "@fullcalendar/core": "^6.1.10",
+ "@fullcalendar/daygrid": "^6.1.10",
+ "@fullcalendar/interaction": "^6.1.10",
+ "@fullcalendar/multimonth": "^6.1.10",
+ "@fullcalendar/react": "^6.1.10",
+ "@hookform/error-message": "^2.0.1",
+ "@hookform/resolvers": "^3.3.4",
+ "@mux/blurhash": "^0.1.2",
+ "@mux/mux-player": "^2.3.1",
+ "@mux/mux-player-react": "^2.3.1",
+ "@paralleldrive/cuid2": "^2.2.2",
+ "@react-hookz/web": "^24.0.2",
+ "@types/lodash": "^4.14.202",
+ "@types/qs": "^6.9.11",
+ "@types/react": "^18.2.47",
+ "@types/react-dom": "^18.2.18",
+ "@uppy/aws-s3": "^3.6.0",
+ "@uppy/aws-s3-multipart": "^3.3.0",
+ "@uppy/core": "^3.8.0",
+ "@uppy/dashboard": "^3.7.1",
+ "@uppy/drag-drop": "^3.0.3",
+ "@uppy/file-input": "^3.0.4",
+ "@uppy/progress-bar": "^3.0.4",
+ "@uppy/react": "^3.2.1",
+ "@uppy/remote-sources": "^1.1.0",
+ "bulma": "^0.9.4",
+ "bulma-prefers-dark": "0.1.0-beta.1",
+ "cal-heatmap": "^4.2.4",
+ "date-fns": "^2.0.0",
+ "date-fns-tz": "^2.0.0",
+ "dayjs": "^1.11.10",
+ "feed": "^4.2.2",
+ "gray-matter": "^4.0.3",
+ "hls.js": "^1.5.1",
+ "lodash": "^4.17.21",
+ "lunarphase-js": "^2.0.1",
+ "multiformats": "^13.0.1",
+ "next": "^14.0.4",
+ "next-goatcounter": "^1.0.5",
+ "nextjs-toploader": "^1.6.4",
+ "plyr": "^3.7.8",
+ "plyr-react": "^5.3.0",
+ "prism-react-renderer": "^2.3.1",
+ "qs": "^6.11.2",
+ "react": "^18.2.0",
+ "react-dom": "^18.2.0",
+ "react-hook-form": "^7.49.3",
+ "react-loading-skeleton": "^3.3.1",
+ "react-toastify": "^9.1.3",
+ "sass": "^1.69.7",
+ "sharp": "^0.33.2",
+ "slugify": "^1.6.6",
+ "yup": "^1.3.3"
+ },
+ "devDependencies": {
+ "@types/node": "^20.11.0",
+ "eslint": "^8.56.0",
+ "eslint-config-next": "14.0.4",
+ "tsc": "^2.0.4",
+ "typescript": "5.3.3"
+ }
+}
diff --git a/packages/next/public/futureporn-icon.png b/packages/next/public/futureporn-icon.png
new file mode 100644
index 0000000..037e639
Binary files /dev/null and b/packages/next/public/futureporn-icon.png differ
diff --git a/packages/next/public/images/.keep b/packages/next/public/images/.keep
new file mode 100644
index 0000000..e69de29
diff --git a/packages/next/public/images/cj_clippy.jpg b/packages/next/public/images/cj_clippy.jpg
new file mode 100644
index 0000000..d1c8717
Binary files /dev/null and b/packages/next/public/images/cj_clippy.jpg differ
diff --git a/packages/next/public/images/default-thumbnail.webp b/packages/next/public/images/default-thumbnail.webp
new file mode 100644
index 0000000..d468e15
Binary files /dev/null and b/packages/next/public/images/default-thumbnail.webp differ
diff --git a/packages/next/public/images/projekt-melody.jpg b/packages/next/public/images/projekt-melody.jpg
new file mode 100644
index 0000000..41916fa
Binary files /dev/null and b/packages/next/public/images/projekt-melody.jpg differ
diff --git a/packages/next/public/images/projektmelody-thumbnail.webp b/packages/next/public/images/projektmelody-thumbnail.webp
new file mode 100644
index 0000000..dfb8073
Binary files /dev/null and b/packages/next/public/images/projektmelody-thumbnail.webp differ
diff --git a/packages/next/public/images/vercel.svg b/packages/next/public/images/vercel.svg
new file mode 100644
index 0000000..08d0cd1
--- /dev/null
+++ b/packages/next/public/images/vercel.svg
@@ -0,0 +1,3 @@
+
+
+
\ No newline at end of file
diff --git a/packages/next/tsconfig.json b/packages/next/tsconfig.json
new file mode 100644
index 0000000..2a88d71
--- /dev/null
+++ b/packages/next/tsconfig.json
@@ -0,0 +1,50 @@
+{
+ "compilerOptions": {
+ "baseUrl": ".",
+ "paths": {
+ "@/components/*": [
+ "app/components/*"
+ ],
+ "@/lib/*": [
+ "app/lib/*"
+ ],
+ "@/assets/*": [
+ "assets/*"
+ ]
+ },
+ "target": "es5",
+ "lib": [
+ "dom",
+ "dom.iterable",
+ "esnext"
+ ],
+ "allowJs": true,
+ "skipLibCheck": true,
+ "strict": true,
+ "forceConsistentCasingInFileNames": true,
+ "noEmit": true,
+ "esModuleInterop": true,
+ "module": "esnext",
+ "moduleResolution": "node",
+ "resolveJsonModule": true,
+ "isolatedModules": true,
+ "jsx": "preserve",
+ "incremental": true,
+ "plugins": [
+ {
+ "name": "next"
+ }
+ ]
+ },
+ "include": [
+ "next-env.d.ts",
+ "**/*.ts",
+ "**/*.tsx",
+ "dist/types/**/*.ts",
+ ".next/types/**/*.ts",
+ "assets/svg/tes.jsx"
+ ],
+ "exclude": [
+ "node_modules"
+ ]
+}
\ No newline at end of file
diff --git a/packages/strapi/.dockerignore b/packages/strapi/.dockerignore
new file mode 100644
index 0000000..e6fa5c0
--- /dev/null
+++ b/packages/strapi/.dockerignore
@@ -0,0 +1,8 @@
+.tmp/
+.cache/
+.git/
+build/
+node_modules/
+.env
+data/
+backup/
\ No newline at end of file
diff --git a/packages/strapi/.gitignore b/packages/strapi/.gitignore
new file mode 100644
index 0000000..afa1f1d
--- /dev/null
+++ b/packages/strapi/.gitignore
@@ -0,0 +1,118 @@
+.env*
+tunnel.conf
+
+############################
+# OS X
+############################
+
+.DS_Store
+.AppleDouble
+.LSOverride
+Icon
+.Spotlight-V100
+.Trashes
+._*
+
+
+############################
+# Linux
+############################
+
+*~
+
+
+############################
+# Windows
+############################
+
+Thumbs.db
+ehthumbs.db
+Desktop.ini
+$RECYCLE.BIN/
+*.cab
+*.msi
+*.msm
+*.msp
+
+
+############################
+# Packages
+############################
+
+*.7z
+*.csv
+*.dat
+*.dmg
+*.gz
+*.iso
+*.jar
+*.rar
+*.tar
+*.zip
+*.com
+*.class
+*.dll
+*.exe
+*.o
+*.seed
+*.so
+*.swo
+*.swp
+*.swn
+*.swm
+*.out
+*.pid
+
+
+############################
+# Logs and databases
+############################
+
+.tmp
+*.log
+*.sql
+*.sqlite
+*.sqlite3
+
+
+############################
+# Misc.
+############################
+
+*#
+ssl
+.idea
+nbproject
+public/uploads/*
+!public/uploads/.gitkeep
+
+############################
+# Node.js
+############################
+
+lib-cov
+lcov.info
+pids
+logs
+results
+node_modules
+.node_history
+
+############################
+# Tests
+############################
+
+testApp
+coverage
+
+############################
+# Strapi
+############################
+
+.env
+license.txt
+exports
+*.cache
+dist
+build
+.strapi-updater.json
diff --git a/packages/strapi/.nvmrc b/packages/strapi/.nvmrc
new file mode 100644
index 0000000..a77793e
--- /dev/null
+++ b/packages/strapi/.nvmrc
@@ -0,0 +1 @@
+lts/hydrogen
diff --git a/packages/strapi/.strapi/client/app.js b/packages/strapi/.strapi/client/app.js
new file mode 100644
index 0000000..e0f39d0
--- /dev/null
+++ b/packages/strapi/.strapi/client/app.js
@@ -0,0 +1,14 @@
+/**
+ * This file was automatically generated by Strapi.
+ * Any modifications made will be discarded.
+ */
+import i18N from "@strapi/plugin-i18n/strapi-admin";
+import usersPermissions from "@strapi/plugin-users-permissions/strapi-admin";
+import { renderAdmin } from "@strapi/strapi/admin";
+
+renderAdmin(document.getElementById("strapi"), {
+ plugins: {
+ i18n: i18N,
+ "users-permissions": usersPermissions,
+ },
+});
diff --git a/packages/strapi/.strapi/client/index.html b/packages/strapi/.strapi/client/index.html
new file mode 100644
index 0000000..08d9c27
--- /dev/null
+++ b/packages/strapi/.strapi/client/index.html
@@ -0,0 +1,62 @@
+
+
+
+
+
+
+
+
+ Strapi Admin
+
+
+
+
+
+
+
+
JavaScript disabled
+
+ Please
+ enable JavaScript
+ in your browser and reload the page to proceed.
+
+
+
+
+
diff --git a/packages/strapi/Dockerfile b/packages/strapi/Dockerfile
new file mode 100644
index 0000000..107ffc9
--- /dev/null
+++ b/packages/strapi/Dockerfile
@@ -0,0 +1,19 @@
+FROM node:18.16-alpine
+# Installing libvips-dev for sharp Compatibility
+RUN apk update && apk add --no-cache build-base gcc autoconf automake zlib-dev libpng-dev nasm bash vips-dev
+ARG NODE_ENV=development
+ENV NODE_ENV=${NODE_ENV}
+
+WORKDIR /opt/
+COPY package.json yarn.lock ./
+RUN yarn config set network-timeout 600000 -g && yarn install
+
+WORKDIR /opt/app
+COPY . .
+ENV PATH /opt/node_modules/.bin:$PATH
+RUN chown -R node:node /opt/app
+USER node
+RUN ["yarn", "build"]
+EXPOSE 1337
+# CMD ["yarn", "develop"]
+CMD yarn develop
\ No newline at end of file
diff --git a/packages/strapi/README.md b/packages/strapi/README.md
new file mode 100644
index 0000000..34338c4
--- /dev/null
+++ b/packages/strapi/README.md
@@ -0,0 +1,7 @@
+## dev notes
+
+### patreon campaign benefit ids
+
+ * ironmouse "Thank you" (for testing): 4760169
+ * cj_clippy "Full library access" (for production): 9380584
+ * cj_clippy "Your URL displayed on Futureporn.net": 10663202
diff --git a/packages/strapi/backup/Dockerfile.1704607848934 b/packages/strapi/backup/Dockerfile.1704607848934
new file mode 100644
index 0000000..9b69e59
--- /dev/null
+++ b/packages/strapi/backup/Dockerfile.1704607848934
@@ -0,0 +1,49 @@
+# FROM node:16-alpine as build
+# # Installing libvips-dev for sharp Compatibility
+# RUN apk update && apk add --no-cache build-base gcc autoconf automake zlib-dev libpng-dev vips-dev > /dev/null 2>&1
+# ARG NODE_ENV=production
+# ENV NODE_ENV=${NODE_ENV}
+# WORKDIR /opt/
+# COPY ./package.json ./yarn.lock ./
+# ENV PATH /opt/node_modules/.bin:$PATH
+# RUN yarn config set network-timeout 600000 -g && yarn install --production
+# WORKDIR /opt/app
+# COPY ./ .
+# RUN yarn build
+# FROM node:16-alpine
+# RUN apk add --no-cache vips-dev
+
+# FROM node:16-alpine
+# RUN apk add --no-cache vips-dev
+# ARG NODE_ENV=production
+# ENV NODE_ENV=${NODE_ENV}
+# WORKDIR /opt/app
+# COPY --from=build /opt/node_modules ./node_modules
+# ENV PATH /opt/node_modules/.bin:$PATH
+# COPY --from=build /opt/app ./
+# EXPOSE 5555
+# CMD ["yarn", "start"]
+
+
+
+
+# # following is from the strapi website
+FROM node:18-alpine
+# Installing libvips-dev for sharp Compatibility
+RUN apk update && apk add --no-cache build-base gcc autoconf automake zlib-dev libpng-dev nasm bash vips-dev git
+ARG NODE_ENV=development
+ENV NODE_ENV=${NODE_ENV}
+
+WORKDIR /opt/
+COPY package.json yarn.lock ./
+RUN yarn global add node-gyp
+RUN yarn config set network-timeout 600000 -g && yarn install
+ENV PATH /opt/node_modules/.bin:$PATH
+
+WORKDIR /opt/app
+COPY . .
+RUN chown -R node:node /opt/app
+USER node
+RUN ["yarn", "build"]
+EXPOSE 1337
+CMD ["yarn", "dev"]
diff --git a/packages/strapi/chisel.sh b/packages/strapi/chisel.sh
new file mode 100644
index 0000000..b612516
--- /dev/null
+++ b/packages/strapi/chisel.sh
@@ -0,0 +1,5 @@
+#!/bin/bash
+
+. .env
+chisel client --auth="${CHISEL_AUTH}" "${CHISEL_SERVER}" R:8900:localhost:1337
+
diff --git a/packages/strapi/config/admin.js b/packages/strapi/config/admin.js
new file mode 100644
index 0000000..92f535b
--- /dev/null
+++ b/packages/strapi/config/admin.js
@@ -0,0 +1,13 @@
+module.exports = ({ env }) => ({
+ auth: {
+ secret: env('ADMIN_JWT_SECRET'),
+ },
+ apiToken: {
+ salt: env('API_TOKEN_SALT'),
+ },
+ transfer: {
+ token: {
+ salt: env('TRANSFER_TOKEN_SALT'),
+ },
+ },
+});
diff --git a/packages/strapi/config/api.js b/packages/strapi/config/api.js
new file mode 100644
index 0000000..62f8b65
--- /dev/null
+++ b/packages/strapi/config/api.js
@@ -0,0 +1,7 @@
+module.exports = {
+ rest: {
+ defaultLimit: 25,
+ maxLimit: 100,
+ withCount: true,
+ },
+};
diff --git a/packages/strapi/config/database.js b/packages/strapi/config/database.js
new file mode 100644
index 0000000..63290e0
--- /dev/null
+++ b/packages/strapi/config/database.js
@@ -0,0 +1,49 @@
+const path = require('path');
+
+module.exports = ({ env }) => {
+ const client = env('DATABASE_CLIENT', 'postgres');
+
+ const connections = {
+ postgres: {
+ connection: {
+ connectionString: env('DATABASE_URL'),
+ host: env('DATABASE_HOST', 'localhost'),
+ port: env.int('DATABASE_PORT', 5432),
+ database: env('DATABASE_NAME', 'strapi'),
+ user: env('DATABASE_USERNAME', 'strapi'),
+ password: env('DATABASE_PASSWORD', 'strapi'),
+ ssl: env.bool('DATABASE_SSL', false) && {
+ key: env('DATABASE_SSL_KEY', undefined),
+ cert: env('DATABASE_SSL_CERT', undefined),
+ ca: env('DATABASE_SSL_CA', undefined),
+ capath: env('DATABASE_SSL_CAPATH', undefined),
+ cipher: env('DATABASE_SSL_CIPHER', undefined),
+ rejectUnauthorized: env.bool(
+ 'DATABASE_SSL_REJECT_UNAUTHORIZED',
+ true
+ ),
+ },
+ schema: env('DATABASE_SCHEMA', 'public'),
+ },
+ pool: { min: env.int('DATABASE_POOL_MIN', 2), max: env.int('DATABASE_POOL_MAX', 10) },
+ },
+ sqlite: {
+ connection: {
+ filename: path.join(
+ __dirname,
+ '..',
+ env('DATABASE_FILENAME', 'data.db')
+ ),
+ },
+ useNullAsDefault: true,
+ },
+ };
+
+ return {
+ connection: {
+ client,
+ ...connections[client],
+ acquireConnectionTimeout: env.int('DATABASE_CONNECTION_TIMEOUT', 60000),
+ },
+ };
+};
diff --git a/packages/strapi/config/middlewares.js b/packages/strapi/config/middlewares.js
new file mode 100644
index 0000000..c8b8699
--- /dev/null
+++ b/packages/strapi/config/middlewares.js
@@ -0,0 +1,26 @@
+module.exports = [
+ 'strapi::errors',
+ {
+ name: 'strapi::security',
+ config: {
+ contentSecurityPolicy: {
+ useDefaults: true,
+ directives: {
+ 'connect-src': ["'self'", 'https:'],
+ 'img-src': ["'self'", 'data:', 'blob:', 'dl.airtable.com', 'res.cloudinary.com'],
+ 'media-src': ["'self'", 'data:', 'blob:', 'dl.airtable.com', 'res.cloudinary.com'],
+ upgradeInsecureRequests: null,
+ },
+ },
+ },
+ },
+
+ 'strapi::cors',
+ 'strapi::poweredBy',
+ 'strapi::logger',
+ 'strapi::query',
+ 'strapi::body',
+ 'strapi::session',
+ 'strapi::favicon',
+ 'strapi::public',
+];
diff --git a/packages/strapi/config/plugins.js b/packages/strapi/config/plugins.js
new file mode 100644
index 0000000..a47d2a5
--- /dev/null
+++ b/packages/strapi/config/plugins.js
@@ -0,0 +1,75 @@
+module.exports = ({
+ env
+}) => ({
+ 'fuzzy-search': {
+ enabled: true,
+ config: {
+ contentTypes: [{
+ uid: 'api::tag.tag',
+ modelName: 'tag',
+ transliterate: false,
+ queryConstraints: {
+ where: {
+ '$and': [
+ {
+ publishedAt: {
+ '$notNull': true
+ }
+ },
+ ]
+ }
+ },
+ fuzzysortOptions: {
+ characterLimit: 32,
+ threshold: -600,
+ limit: 10,
+ keys: [{
+ name: 'name',
+ weight: 100
+ }]
+ }
+ }]
+ }
+ },
+ upload: {
+ config: {
+ provider: 'cloudinary',
+ providerOptions: {
+ cloud_name: env('CLOUDINARY_NAME'),
+ api_key: env('CLOUDINARY_KEY'),
+ api_secret: env('CLOUDINARY_SECRET'),
+ },
+ actionOptions: {
+ upload: {},
+ uploadStream: {},
+ delete: {},
+ },
+ }
+ },
+ email: {
+ config: {
+ provider: 'sendgrid',
+ providerOptions: {
+ apiKey: env('SENDGRID_API_KEY'),
+ },
+ settings: {
+ defaultFrom: 'welcome@futureporn.net',
+ defaultReplyTo: 'cj@futureporn.net',
+ testAddress: 'grimtech@fastmail.com',
+ },
+ },
+ },
+ "users-permissions": {
+ config: {
+ register: {
+ allowedFields: [
+ "isNamePublic",
+ "isLinkPublic",
+ "avatar",
+ "vanityLink",
+ "patreonBenefits"
+ ]
+ }
+ }
+ }
+});
\ No newline at end of file
diff --git a/packages/strapi/config/server.js b/packages/strapi/config/server.js
new file mode 100644
index 0000000..26a385f
--- /dev/null
+++ b/packages/strapi/config/server.js
@@ -0,0 +1,15 @@
+// greets some
+
+module.exports = ({ env }) => ({
+ host: env('HOST', '0.0.0.0'),
+ port: env.int('PORT', 1337),
+ proxy: true,
+ app: {
+ keys: env.array('APP_KEYS'),
+ },
+ webhooks: {
+ populateRelations: env.bool('WEBHOOKS_POPULATE_RELATIONS', false)
+ },
+ url: env('STRAPI_URL', 'https://portal.futureporn.net')
+});
+
diff --git a/packages/strapi/database/daily-backup.sh b/packages/strapi/database/daily-backup.sh
new file mode 100644
index 0000000..1ee0aeb
--- /dev/null
+++ b/packages/strapi/database/daily-backup.sh
@@ -0,0 +1,13 @@
+#!/bin/bash
+
+# daily-backup.sh
+# useful for the dokku server
+# dokku's backup feature is broken atm https://github.com/dokku/dokku-postgres/issues/274
+# backups are exported from dokku:postgres plugin before being sent to b2
+
+
+filename="$(date +'%Y-%m-%d_%H-%M-%S').psql"
+
+dokku postgres:export futureporn-db > "${filename}"
+b2-linux upload-file futureporn-db-backup "./${filename}" "${filename}"
+
diff --git a/packages/strapi/database/devDb.sh b/packages/strapi/database/devDb.sh
new file mode 100755
index 0000000..a293e46
--- /dev/null
+++ b/packages/strapi/database/devDb.sh
@@ -0,0 +1,22 @@
+#!/bin/bash
+
+. .env
+
+# Check if the containers already exist
+pgadmin_exists=$(docker ps -a --filter "name=pgadmin" --format '{{.Names}}')
+strapi_postgres_exists=$(docker ps -a --filter "name=strapi-postgres" --format '{{.Names}}')
+
+# Run strapi-postgres container if it doesn't exist or is not running
+if [ -z "$strapi_postgres_exists" ]; then
+ docker run -d --name strapi-postgres -p 5432:5432 -e POSTGRES_PASSWORD=$POSTGRES_PASSWORD postgres:14.7
+ echo "strapi-postgres container created and started."
+else
+ container_status=$(docker inspect -f '{{.State.Status}}' strapi-postgres)
+
+ if [ "$container_status" != "running" ]; then
+ docker start strapi-postgres
+ echo "strapi-postgres container started."
+ else
+ echo "strapi-postgres container already exists and is running. Skipping creation."
+ fi
+fi
diff --git a/packages/strapi/database/migrations/.gitkeep b/packages/strapi/database/migrations/.gitkeep
new file mode 100644
index 0000000..e69de29
diff --git a/packages/strapi/database/migrations/2023-08-01-relate-vods-to-vtubers-part2.js b/packages/strapi/database/migrations/2023-08-01-relate-vods-to-vtubers-part2.js
new file mode 100644
index 0000000..502ec0c
--- /dev/null
+++ b/packages/strapi/database/migrations/2023-08-01-relate-vods-to-vtubers-part2.js
@@ -0,0 +1,25 @@
+module.exports = {
+ async up(knex) {
+ // ... (Create vods_vtuber_links table if not already created)
+
+ // Get vtuber ID for ProjektMelody (assuming it's 1)
+ const vtuberId = 1;
+
+ // Get all VODs from the database
+ const vods = await knex.select('*').from('vods');
+
+ // For each VOD, associate it with the vtuber (vtuber with ID 1) if not already associated
+ for (const [index, vod] of vods.entries()) {
+ const existingAssociation = await knex('vods_vtuber_links')
+ .where({ vtuber_id: vtuberId, vod_id: vod.id })
+ .first();
+ if (!existingAssociation) {
+ await knex('vods_vtuber_links').insert({
+ vtuber_id: vtuberId,
+ vod_id: vod.id,
+ vod_order: index + 1, // Auto-increment the vod_order number
+ });
+ }
+ }
+ },
+};
diff --git a/packages/strapi/database/migrations/2023-08-17-reformat-cdnUrl.js b/packages/strapi/database/migrations/2023-08-17-reformat-cdnUrl.js
new file mode 100644
index 0000000..c090e12
--- /dev/null
+++ b/packages/strapi/database/migrations/2023-08-17-reformat-cdnUrl.js
@@ -0,0 +1,18 @@
+module.exports = {
+ async up(knex) {
+
+ // Get all B2 Files from the database
+ const files = await knex.select('*').from('b2_files');
+
+ // For each B2 File, update cdnUrl
+ // we do this to change
+ // erroneous https://futureporn-b2.b-cdn.net/futureporn/:key
+ // to https://futureporn-b2.b-cdn.net/:key
+ for (const [index, file] of files.entries()) {
+ const key = file.key;
+ const cdnUrl = `https://futureporn-b2.b-cdn.net/${key}`;
+ await knex('b2_files').update({ cdn_url: cdnUrl }).where({ id: file.id });
+ }
+ },
+ };
+
\ No newline at end of file
diff --git a/packages/strapi/database/migrations/2023-08-20-strip-query-string-from-cid.js b/packages/strapi/database/migrations/2023-08-20-strip-query-string-from-cid.js
new file mode 100644
index 0000000..0a254f2
--- /dev/null
+++ b/packages/strapi/database/migrations/2023-08-20-strip-query-string-from-cid.js
@@ -0,0 +1,23 @@
+const stripQueryString = function (text) {
+ if (!text) return '';
+ return text.split(/[?#]/)[0];
+}
+
+module.exports = {
+ async up(knex) {
+
+ // Get all vods
+ const vods = await knex.select('*').from('vods');
+
+ // For each vod, update videoSrcHash and video240Hash
+ // we remove any existing ?filename(...) qs from the cid
+ for (const [index, vod] of vods.entries()) {
+ const strippedVideoSrcHash = stripQueryString(vod.video_src_hash)
+ const strippedVideo240Hash = stripQueryString(vod.video_240_hash)
+ await knex('vods').update({ video_src_hash: strippedVideoSrcHash }).where({ id: vod.id });
+ await knex('vods').update({ video_240_hash: strippedVideo240Hash }).where({ id: vod.id });
+ }
+
+ },
+ };
+
\ No newline at end of file
diff --git a/packages/strapi/database/migrations/2023-08-30-remove-cloudinary.js b/packages/strapi/database/migrations/2023-08-30-remove-cloudinary.js
new file mode 100644
index 0000000..6f1f5a7
--- /dev/null
+++ b/packages/strapi/database/migrations/2023-08-30-remove-cloudinary.js
@@ -0,0 +1,13 @@
+module.exports = {
+ async up(knex) {
+
+ const toys = await knex.select('*').from('toys');
+ for (const [index, toy] of toys.entries()) {
+ if (toy.image_2) {
+ const existingImageFilename = new URL(toy.image_2).pathname.split('/').at(-1)
+ await knex('toys').update({ image_2: `https://futureporn-b2.b-cdn.net/${existingImageFilename}` }).where({ id: toy.id });
+ }
+ }
+ },
+ };
+
\ No newline at end of file
diff --git a/packages/strapi/database/migrations/2023-08-30-toy-image-field-simplify.js b/packages/strapi/database/migrations/2023-08-30-toy-image-field-simplify.js
new file mode 100644
index 0000000..66ab1de
--- /dev/null
+++ b/packages/strapi/database/migrations/2023-08-30-toy-image-field-simplify.js
@@ -0,0 +1,33 @@
+module.exports = {
+ async up(knex) {
+ // Add the `image2` field (column) as a short text field
+ await knex.schema.table('toys', (table) => {
+ table.string('image_2', 512);
+ });
+
+ // Get all toys
+ const toys = await knex.select('*').from('toys');
+
+ // Update the image2 field with the previous image URLs
+ for (const toy of toys) {
+ // lookup the file morph which maps toy to (image) file
+ const imageFileId = (await knex.select('file_id').from('files_related_morphs').where({ related_id: toy.id }))[0].file_id
+
+ // get the image data from the file
+ const imageUrl = (await knex.select('url').from('files').where({ id: imageFileId }))[0].url
+
+ if (!imageUrl) continue;
+
+ // Copy the values from image to image2
+ await knex('toys').update({ image_2: imageUrl }).where({ id: toy.id });
+ }
+
+ const hasImageColumn = await knex.schema.hasColumn('toys', 'image');
+ if (hasImageColumn) {
+ // Drop the `image` column
+ table.dropColumn('image');
+ }
+
+
+ },
+};
diff --git a/packages/strapi/database/migrations/2023-09-08-change-date-to-string.js b/packages/strapi/database/migrations/2023-09-08-change-date-to-string.js
new file mode 100644
index 0000000..3b03cc0
--- /dev/null
+++ b/packages/strapi/database/migrations/2023-09-08-change-date-to-string.js
@@ -0,0 +1,23 @@
+module.exports = {
+ async up(knex) {
+ // Check if the 'date_2' column exists in the 'vods' table
+ const hasDate2Column = await knex.schema.hasColumn('vods', 'date_2');
+
+ if (!hasDate2Column) {
+ // Add the new 'date_2' column as a string if it doesn't exist
+ await knex.schema.table('vods', (table) => {
+ table.string('date_2');
+ });
+
+ // Fetch all existing rows from the 'vods' table
+ const existingVods = await knex.select('id', 'date').from('vods');
+
+ // Loop through each row and update 'date_2' with the date value
+ for (const vod of existingVods) {
+ await knex('vods')
+ .where({ id: vod.id })
+ .update({ date_2: vod.date.toISOString() });
+ }
+ }
+ },
+};
diff --git a/packages/strapi/database/migrations/2023-09-08-drop-toys-image.js b/packages/strapi/database/migrations/2023-09-08-drop-toys-image.js
new file mode 100644
index 0000000..2119714
--- /dev/null
+++ b/packages/strapi/database/migrations/2023-09-08-drop-toys-image.js
@@ -0,0 +1,11 @@
+module.exports = {
+ async up(knex) {
+ const hasColumn = await knex.schema.hasColumn('toys', 'image');
+
+ if (hasColumn) {
+ await knex.schema.table('toys', (table) => {
+ table.dropColumn('image');
+ });
+ }
+ }
+};
diff --git a/packages/strapi/database/migrations/2023-09-08-drop-vod-videosrc.js b/packages/strapi/database/migrations/2023-09-08-drop-vod-videosrc.js
new file mode 100644
index 0000000..8d1f878
--- /dev/null
+++ b/packages/strapi/database/migrations/2023-09-08-drop-vod-videosrc.js
@@ -0,0 +1,11 @@
+module.exports = {
+ async up(knex) {
+ const hasColumn = await knex.schema.hasColumn('vods', 'video_src');
+
+ if (hasColumn) {
+ await knex.schema.table('vods', (table) => {
+ table.dropColumn('video_src');
+ });
+ }
+ }
+};
diff --git a/packages/strapi/database/migrations/2023-12-24-add-cuid-to-vods.js b/packages/strapi/database/migrations/2023-12-24-add-cuid-to-vods.js
new file mode 100644
index 0000000..5590b99
--- /dev/null
+++ b/packages/strapi/database/migrations/2023-12-24-add-cuid-to-vods.js
@@ -0,0 +1,31 @@
+
+const generateCuid = require('../../misc/generateCuid');
+
+module.exports = {
+ async up(knex) {
+
+ console.log(`MIGRATION-- 2023-12-24-add-cuid-to-vods.js`);
+
+ // Check if the 'cuid' column already exists in the 'vods' table
+ const hasCuidColumn = await knex.schema.hasColumn('vods', 'cuid');
+
+ if (!hasCuidColumn) {
+ // Add the 'cuid' column to the 'vods' table
+ await knex.schema.table('vods', (table) => {
+ table.string('cuid');
+ });
+ }
+
+ // Get all vods from the database
+ const vods = await knex.select('*').from('vods');
+
+ // For each vod, populate cuid if it's null or undefined
+ for (const [index, vod] of vods.entries()) {
+ if (!vod.cuid) {
+ await knex('vods').update({ cuid: generateCuid() }).where({ id: vod.id });
+ }
+ }
+
+ },
+};
+
diff --git a/packages/strapi/database/migrations/2023-12-26-add-cuid-to-streams.js b/packages/strapi/database/migrations/2023-12-26-add-cuid-to-streams.js
new file mode 100644
index 0000000..942854b
--- /dev/null
+++ b/packages/strapi/database/migrations/2023-12-26-add-cuid-to-streams.js
@@ -0,0 +1,33 @@
+
+const { init } = require('@paralleldrive/cuid2');
+
+module.exports = {
+ async up(knex) {
+
+ console.log(`MIGRATION-- 2023-12-26-add-cuid-to-streams.js`);
+
+ // Check if the 'cuid' column already exists in the 'streams' table
+ const hasCuidColumn = await knex.schema.hasColumn('streams', 'cuid');
+
+ if (!hasCuidColumn) {
+ // Add the 'cuid' column to the 'streams' table
+ await knex.schema.table('streams', (table) => {
+ table.string('cuid');
+ });
+ }
+
+ // Get all streams from the database
+ const streams = await knex.select('*').from('streams');
+
+ // For each stream, populate cuid if it's null or undefined
+ for (const [index, stream] of streams.entries()) {
+ if (!stream.cuid) {
+ const length = 10;
+ const genCuid = init({ length });
+ await knex('streams').update({ cuid: genCuid() }).where({ id: stream.id });
+ }
+ }
+
+ },
+};
+
diff --git a/packages/strapi/database/migrations/2023-12-27-relate-vods-to-streams.js b/packages/strapi/database/migrations/2023-12-27-relate-vods-to-streams.js
new file mode 100644
index 0000000..703275d
--- /dev/null
+++ b/packages/strapi/database/migrations/2023-12-27-relate-vods-to-streams.js
@@ -0,0 +1,35 @@
+
+const { sub, add } = require('date-fns');
+
+
+module.exports = {
+ async up(knex) {
+ console.log(`MIGRATION-- 2023-12-27-relate-vods-to-streams.js`);
+
+ // Get all VODs from the database
+ const vods = await knex.select('*').from('vods');
+
+ // For each VOD, associate it with the stream with the nearest date (if not already associated)
+ for (const [index, vod] of vods.entries()) {
+ const existingAssociation = await knex('vods_stream_links')
+ .where({ vod_id: vod.id })
+ .first();
+
+ if (!existingAssociation) {
+ // get nearest stream within +/- 3 hours
+ const date2 = new Date(vod.date_2);
+ const startDate = sub(date2, { hours: 3 })
+ const endDate = add(date2, { hours: 3 });
+ console.log(`vod.id=${vod.id}, vod.date_2=${vod.date_2}, date2=${date2}, startDate=${startDate}, endDate=${endDate}`)
+ const stream = await knex('streams')
+ .whereBetween('date', [startDate, endDate])
+
+ await knex('vods_stream_links').insert({
+ stream_id: stream.id,
+ vod_id: vod.id,
+ vod_order: 1,
+ });
+ }
+ }
+ },
+};
diff --git a/packages/strapi/database/migrations/2023.05.09-video-src-sanity.js.noexec b/packages/strapi/database/migrations/2023.05.09-video-src-sanity.js.noexec
new file mode 100644
index 0000000..cda7f9d
--- /dev/null
+++ b/packages/strapi/database/migrations/2023.05.09-video-src-sanity.js.noexec
@@ -0,0 +1,26 @@
+
+const fetch = require('node-fetch')
+
+let problemUrls = []
+
+async function checkUrl(url) {
+ const res = await fetch(url);
+ if (!res.ok || !res?.headers?.get('x-bz-file-name') || !res?.headers?.get('x-bz-file-id')) problemUrls.push(url)
+}
+
+
+
+module.exports = {
+ async up(knex) {
+
+ // Get all VODs from the database
+ const vods = await knex.select('*').from('vods');
+
+ // sanity check every B2 URL
+ for (const vod of vods) {
+ await checkUrl(vod.video_src)
+ }
+
+ process.exit(5923423)
+ },
+};
\ No newline at end of file
diff --git a/packages/strapi/database/migrations/2023.05.11T12.32.00.convert-to-video-src-b2.js.noexec b/packages/strapi/database/migrations/2023.05.11T12.32.00.convert-to-video-src-b2.js.noexec
new file mode 100644
index 0000000..41d8608
--- /dev/null
+++ b/packages/strapi/database/migrations/2023.05.11T12.32.00.convert-to-video-src-b2.js.noexec
@@ -0,0 +1,98 @@
+
+const fetch = require('node-fetch')
+
+// greets chatgpt
+async function getFileDetailsFromUrl(url) {
+ const controller = new AbortController();
+ const signal = controller.signal;
+
+ const options = {
+ signal,
+ };
+
+ let retries = 10;
+
+ while (retries) {
+ console.log(`fetching ${url}`);
+ const timeoutId = setTimeout(() => {
+ console.log('fetch timed out, aborting...');
+ controller.abort();
+ }, 5000);
+
+ try {
+ const res = await fetch(url, options);
+
+ clearTimeout(timeoutId);
+
+ console.log('finished fetch');
+ if (!res.ok) throw new Error(`problem while getting file from url with url ${url}`);
+ if (!res?.headers?.get('x-bz-file-name')) throw new Error(`${url} did not have a x-bz-file-name in the response headers`);
+ if (!res?.headers?.get('x-bz-file-id')) throw new Error(`${url} did not have a x-bz-file-id in the response headers`);
+
+ return {
+ key: res.headers.get('x-bz-file-name'),
+ url: url,
+ uploadId: res.headers.get('x-bz-file-id'),
+ };
+ } catch (err) {
+ clearTimeout(timeoutId);
+ retries--;
+
+ if (retries === 0) {
+ console.error(`Could not fetch file details from URL: ${url}.`);
+ throw err;
+ }
+
+ console.warn(`Retrying fetch (${retries} attempts left)`);
+ }
+ }
+}
+
+
+
+
+module.exports = {
+ async up(knex) {
+ // You have full access to the Knex.js API with an already initialized connection to the database
+
+ // Get all VODs from the database
+ const vods = await knex.select('*').from('vods');
+
+
+ // Process each VOD
+ for (const vod of vods) {
+
+ // courtesy timer
+ await new Promise((resolve) => setTimeout(resolve, 1000))
+
+ console.log(vod)
+ // Get the file details from the VOD's video source URL
+ if (vod?.video_src) {
+ try {
+ const fileDetails = await getFileDetailsFromUrl(vod.video_src);
+
+ // Insert the B2 file into the database
+ const [file] = await knex('b2_files').insert({
+ url: fileDetails.url,
+ key: fileDetails.key,
+ upload_id: fileDetails.uploadId,
+ }).returning('id');
+
+ console.log(file)
+ console.log(`attempting to insert vod_id:${vod.id}, b_2_file_id:${file.id} for videoSrcB2`)
+
+ // Link the B2 file to the VOD
+ await knex('vods_video_src_b_2_links').insert({
+ vod_id: vod.id,
+ b_2_file_id: file.id,
+ });
+ } catch (e) {
+ console.error(e)
+ console.log(`there was an error so we are skipping vod ${vod.id}`)
+ }
+ } else {
+ console.log(`${vod.id} has no video_src. skipping.`)
+ }
+ }
+ },
+};
\ No newline at end of file
diff --git a/packages/strapi/database/migrations/2023.05.14T00.42.00.000Z.migrate-tags-to-tag-vod-relations.js b/packages/strapi/database/migrations/2023.05.14T00.42.00.000Z.migrate-tags-to-tag-vod-relations.js
new file mode 100644
index 0000000..7c3e24a
--- /dev/null
+++ b/packages/strapi/database/migrations/2023.05.14T00.42.00.000Z.migrate-tags-to-tag-vod-relations.js
@@ -0,0 +1,43 @@
+
+// up until now, tags have been attached directly to each vod object.
+// now, tags are not attached to vods.
+// instead, tag-vod-relations are used to associate a tag with a vod
+
+// what we need to do in this migration is
+// * create a new tag-vod-relation for each tag in each vod
+// * delete tags field in vods
+
+module.exports = {
+ async up(knex) {
+
+ console.log('2023.05.14 - migrate tags to tag_vod_relations')
+
+ // get all tags_vods_links
+ // for each, create a tag-vod-relation
+ const tagsVodsLinks = await knex.select('*').from('tags_vods_links')
+
+ for (const tvl of tagsVodsLinks) {
+ // Create a tag-vod-relation entry for each tag
+ const tvr = await knex('tag_vod_relations')
+ .insert({
+ created_at: new Date(),
+ updated_at: new Date(),
+ creator_id: 1
+ })
+ .returning(
+ ['id']
+ )
+
+ await knex('tag_vod_relations_tag_links').insert({
+ tag_vod_relation_id: tvr[0].id,
+ tag_id: tvl.tag_id
+ })
+
+ await knex('tag_vod_relations_vod_links').insert({
+ tag_vod_relation_id: tvr[0].id,
+ vod_id: tvl.vod_id
+ })
+ }
+
+ },
+};
\ No newline at end of file
diff --git a/packages/strapi/database/migrations/2023.05.15T02.44.00.000Z.drop-vod-tags.js b/packages/strapi/database/migrations/2023.05.15T02.44.00.000Z.drop-vod-tags.js
new file mode 100644
index 0000000..15fc208
--- /dev/null
+++ b/packages/strapi/database/migrations/2023.05.15T02.44.00.000Z.drop-vod-tags.js
@@ -0,0 +1,12 @@
+
+// previously, we tagged vods directly on the vod content-type
+// now, we use tag-vod-relation to relate tags to vods.
+// thus, we want to get rid of vod.tags
+// and also tag.vods
+
+module.exports = {
+ async up(knex) {
+ console.log('2023.05.15 - drop tags_vods_links')
+ await knex.schema.dropTable('tags_vods_links')
+ }
+}
\ No newline at end of file
diff --git a/packages/strapi/database/migrations/2023.05.25-gimme-the-tags.js.noexec b/packages/strapi/database/migrations/2023.05.25-gimme-the-tags.js.noexec
new file mode 100644
index 0000000..65af409
--- /dev/null
+++ b/packages/strapi/database/migrations/2023.05.25-gimme-the-tags.js.noexec
@@ -0,0 +1,110 @@
+
+// const fetch = require('node-fetch')
+
+// // greets chatgpt
+// async function getFileDetailsFromUrl(url) {
+// const controller = new AbortController();
+// const signal = controller.signal;
+
+// const options = {
+// signal,
+// };
+
+// let retries = 10;
+
+// while (retries) {
+// console.log(`fetching ${url}`);
+// const timeoutId = setTimeout(() => {
+// console.log('fetch timed out, aborting...');
+// controller.abort();
+// }, 5000);
+
+// try {
+// const res = await fetch(url, options);
+
+// clearTimeout(timeoutId);
+
+// console.log('finished fetch');
+// if (!res.ok) throw new Error(`problem while getting file from url with url ${url}`);
+// if (!res?.headers?.get('x-bz-file-name')) throw new Error(`${url} did not have a x-bz-file-name in the response headers`);
+// if (!res?.headers?.get('x-bz-file-id')) throw new Error(`${url} did not have a x-bz-file-id in the response headers`);
+
+// return {
+// key: res.headers.get('x-bz-file-name'),
+// url: url,
+// uploadId: res.headers.get('x-bz-file-id'),
+// };
+// } catch (err) {
+// clearTimeout(timeoutId);
+// retries--;
+
+// if (retries === 0) {
+// console.error(`Could not fetch file details from URL: ${url}.`);
+// throw err;
+// }
+
+// console.warn(`Retrying fetch (${retries} attempts left)`);
+// }
+// }
+// }
+
+
+
+
+module.exports = {
+ async up(knex) {
+ // You have full access to the Knex.js API with an already initialized connection to the database
+
+
+ // we iterate through the local, non-strapi backup db first.
+ // get list of all tags
+ // for each tag
+ // * get list of related vods
+ // * create relation in Strapi
+ // *
+
+
+
+ // Get all VODs from the database
+ const vods = await knex.select('*').from('vods');
+
+
+ // Process each VOD
+ for (const vod of vods) {
+
+ // courtesy timer
+ await new Promise((resolve) => setTimeout(resolve, 10))
+
+ // @todo
+
+ console.log(vod)
+ // Get the file details from the VOD's video source URL
+ if (vod?.video_src) {
+ try {
+ const fileDetails = await getFileDetailsFromUrl(vod.video_src);
+
+ // Insert the B2 file into the database
+ const [file] = await knex('b2_files').insert({
+ url: fileDetails.url,
+ key: fileDetails.key,
+ upload_id: fileDetails.uploadId,
+ }).returning('id');
+
+ console.log(file)
+ console.log(`attempting to insert vod_id:${vod.id}, b_2_file_id:${file.id} for videoSrcB2`)
+
+ // Link the B2 file to the VOD
+ await knex('vods_video_src_b_2_links').insert({
+ vod_id: vod.id,
+ b_2_file_id: file.id,
+ });
+ } catch (e) {
+ console.error(e)
+ console.log(`there was an error so we are skipping vod ${vod.id}`)
+ }
+ } else {
+ console.log(`${vod.id} has no video_src. skipping.`)
+ }
+ }
+ },
+};
\ No newline at end of file
diff --git a/packages/strapi/database/migrations/2023.05.25T20.44.00.000Z.get-the-og-tags.js b/packages/strapi/database/migrations/2023.05.25T20.44.00.000Z.get-the-og-tags.js
new file mode 100644
index 0000000..a211ebb
--- /dev/null
+++ b/packages/strapi/database/migrations/2023.05.25T20.44.00.000Z.get-the-og-tags.js
@@ -0,0 +1,124 @@
+'use strict'
+
+
+require('dotenv').config()
+
+const { Client } = require('pg')
+const fetch = require('node-fetch')
+const _ = require('lodash');
+const ogVods = require('../og-tags.json')
+
+
+// const slugify = require('slugify')
+
+
+// function slugifyString (str) {
+// return slugify(str, {
+// replacement: '-', // replace spaces with replacement character, defaults to `-`
+// remove: undefined, // remove characters that match regex, defaults to `undefined`
+// lower: true, // convert to lower case, defaults to `false`
+// strict: true, // strip special characters except replacement, defaults to `false`
+// locale: 'en', // language code of the locale to use
+// trim: true // trim leading and trailing replacement chars, defaults to `true`
+// })
+// }
+
+
+async function associateTagWithVodsInStrapi (tagId, vodsIds) {
+ const res = await fetch(`${process.env.STRAPI_URL}/api/tags/${tagId}`, {
+ method: 'PUT',
+ headers: {
+ 'authorization': `Bearer ${process.env.STRAPI_API_KEY}`
+ },
+ data: {
+ vods: [vodsIds]
+ }
+ })
+ const json = await res.json()
+
+
+ if (!res.ok) throw new Error(JSON.stringify(json))
+}
+
+
+
+async function associateVodWithTagsInStrapi (knex, vodId, tagsIds) {
+ console.log(`updating vodId:${vodId} with tagsIds:${tagsIds}`)
+ for (const tagId of tagsIds) {
+ // see if it exists already
+ const rows = await knex.select('*').from('tags_vods_links').where({
+ 'vod_id': vodId,
+ 'tag_id': tagId
+ })
+ if (rows.length === 0) {
+ await knex('tags_vods_links').insert({
+ vod_id: vodId,
+ tag_id: tagId
+ });
+ }
+ }
+}
+
+async function getStrapiVodByAnnounceUrl (knex, announceUrl) {
+ const rows = await knex.select('*').from('vods').where('announce_url', announceUrl)
+ return (rows[0])
+}
+
+
+
+
+async function getStrapiTagByName (knex, tag) {
+ const rows = await knex.select('*').from('tags').where({ 'name': tag })
+ return rows[0]
+}
+
+
+
+
+
+module.exports = {
+ async up(knex) {
+ // You have full access to the Knex.js API with an already initialized connection to the database
+
+ for (const vod of ogVods) {
+ // get matching vod in strapi
+ console.log(vod)
+ if (vod.announceUrl) {
+ const strapiVod = await getStrapiVodByAnnounceUrl(knex, vod.announceUrl)
+
+ if (strapiVod) {
+ // we've got a matching vod
+
+ if (vod.tags) {
+ console.log(`source vod has tags: ${vod.tags}`)
+
+ let strapiTagsIds = []
+
+ // for each tag, get the matching strapi tag ID
+ for (const tag of vod.tags) {
+ // lookup the strapi tag id
+ const strapiTag = await getStrapiTagByName(knex, tag)
+ if (!!strapiTag) {
+ strapiTagsIds.push(strapiTag.id)
+ }
+ }
+
+ console.log(`we are adding the following strapiTagsIds to vod ID ${strapiVod.id}: ${strapiTagsIds}`)
+
+ // create relations between matching vod and the tags
+ await associateVodWithTagsInStrapi(knex, strapiVod.id, strapiTagsIds)
+
+ }
+ }
+ }
+ }
+
+ // Get all VODs from the database
+ const vods = await knex.select('*').from('vods');
+
+ // Process each VOD
+ for (const vod of vods) {
+
+ }
+ }
+}
diff --git a/packages/strapi/database/migrations/2023.07.17.relate-vods-to-vtubers.js b/packages/strapi/database/migrations/2023.07.17.relate-vods-to-vtubers.js
new file mode 100644
index 0000000..5f035a1
--- /dev/null
+++ b/packages/strapi/database/migrations/2023.07.17.relate-vods-to-vtubers.js
@@ -0,0 +1,70 @@
+module.exports = {
+ async up(knex) {
+
+ console.log('Create vtubers table')
+ await knex.schema.createTable('vtubers', (table) => {
+ table.increments('id').primary();
+ table.string('displayName').notNullable();
+ table.string('chaturbate');
+ table.string('twitter');
+ table.string('patreon');
+ table.string('twitch');
+ table.string('tiktok');
+ table.string('onlyfans');
+ table.string('youtube');
+ table.string('linktree');
+ table.string('carrd');
+ table.string('fansly');
+ table.string('pornhub');
+ table.string('discord');
+ table.string('reddit');
+ table.string('throne');
+ table.string('instagram');
+ table.string('facebook');
+ table.string('merch');
+ table.string('slug').notNullable();
+ table.text('description1').notNullable();
+ table.text('description2');
+ table.string('image').notNullable();
+ });
+
+ console.log('Create vods_vtuber_links table')
+ await knex.schema.createTable('vods_vtuber_links', (table) => {
+ table.increments('id').primary();
+ table.integer('vod_id').unsigned().references('vods.id');
+ table.integer('vtuber_id').unsigned().references('vtubers.id');
+ table.integer('vod_order').notNullable();
+ });
+
+
+ console.log('Create a vtuber entry for ProjektMelody')
+ const projektMelody = {
+ displayName: 'ProjektMelody',
+ slug: 'projektmelody', // You can customize the slug based on your preference
+ description1: 'Description for ProjektMelody', // Add your vtuber's description here
+ image: 'http://futureporn-b2.b-cdn.net/futureporn/projekt-melody.jpg', // Replace with the image filename for ProjektMelody
+ };
+
+ console.log('Get all VODs from the database')
+ const vods = await knex.select('*').from('vods');
+
+ console.log('get projektmelody id')
+ // const [projektMelodyId] = await knex('vtubers').insert(projektMelody);
+ const projektMelodyId = 1
+
+ console.log(`projektmelodyId is : ${projektMelodyId}`)
+
+ console.log(`For each VOD, associate ProjektMelody vtuber.`)
+ for (const [index, vod] of vods.entries()) {
+ console.log(`Check if vtuber_id exists in the vtubers table`)
+ const vtuber = await knex('vtubers').where('id', projektMelodyId).first();
+ if (vtuber) {
+ await knex('vods_vtuber_links').insert({
+ vtuber_id: projektMelodyId,
+ vod_id: vod.id,
+ vod_order: index + 1, // Auto-increment the vod_order number
+ });
+ }
+ }
+ },
+};
diff --git a/packages/strapi/database/migrations/2023.07.31.add-b2-file-cdnUrl.js b/packages/strapi/database/migrations/2023.07.31.add-b2-file-cdnUrl.js
new file mode 100644
index 0000000..308f159
--- /dev/null
+++ b/packages/strapi/database/migrations/2023.07.31.add-b2-file-cdnUrl.js
@@ -0,0 +1,18 @@
+module.exports = {
+ async up(knex) {
+ // Add the 'cdn_url' column to the 'b2_files' table
+ await knex.schema.table('b2_files', (table) => {
+ table.string('cdn_url'); // Change the data type if needed (e.g., text, varchar, etc.)
+ });
+
+ // Get all B2 Files from the database
+ const files = await knex.select('*').from('b2_files');
+
+ // For each B2 File, create cdnUrl
+ for (const [index, file] of files.entries()) {
+ const key = file.key;
+ const cdnUrl = `https://futureporn-b2.b-cdn.net/futureporn/${key}`;
+ await knex('b2_files').update({ cdn_url: cdnUrl }).where({ id: file.id });
+ }
+ },
+};
diff --git a/packages/strapi/database/migrations/2024-01-08-add-streams.js.noexec b/packages/strapi/database/migrations/2024-01-08-add-streams.js.noexec
new file mode 100644
index 0000000..d354107
--- /dev/null
+++ b/packages/strapi/database/migrations/2024-01-08-add-streams.js.noexec
@@ -0,0 +1,30 @@
+module.exports = {
+ async up(knex) {
+
+ await knex.schema.createTable('streams', (table) => {
+ table.increments('id').primary();
+ table.string('date_str').notNullable();
+ table.string('vods');
+ table.string('vtuber');
+ table.string('tweet');
+ table.string('date');
+ table.string('cuid');
+ });
+
+
+ // Add the 'cdn_url' column to the 'b2_files' table
+ await knex.schema.table('b2_files', (table) => {
+ table.string('cdn_url'); // Change the data type if needed (e.g., text, varchar, etc.)
+ });
+
+ // Get all B2 Files from the database
+ const files = await knex.select('*').from('b2_files');
+
+ // For each B2 File, create cdnUrl
+ for (const [index, file] of files.entries()) {
+ const key = file.key;
+ const cdnUrl = `https://futureporn-b2.b-cdn.net/futureporn/${key}`;
+ await knex('b2_files').update({ cdn_url: cdnUrl }).where({ id: file.id });
+ }
+ },
+};
diff --git a/packages/strapi/database/migrations/2024-01-14-add-date2-to-streams.js b/packages/strapi/database/migrations/2024-01-14-add-date2-to-streams.js
new file mode 100644
index 0000000..5cbd5cf
--- /dev/null
+++ b/packages/strapi/database/migrations/2024-01-14-add-date2-to-streams.js
@@ -0,0 +1,29 @@
+
+module.exports = {
+ async up(knex) {
+
+ console.log(`MIGRATION-- 2024-01-14-add-date2-to-streams.js`);
+
+ // Check if the 'date_2' column already exists in the 'streams' table
+ const hasColumn = await knex.schema.hasColumn('streams', 'date_2');
+
+ if (!hasColumn) {
+ console.log(`Adding the 'date_2' column to the 'streams' table`);
+ await knex.schema.table('streams', (table) => {
+ table.string('date_2');
+ });
+ }
+
+ // Get all streams from the database
+ const streams = await knex.select('*').from('streams');
+
+ // For each stream, populate date_2 if it's null or undefined
+ for (const [index, stream] of streams.entries()) {
+ if (stream.date_2 === null && stream.date_str !== null) {
+ const result = await knex('streams').update({ date_2: stream.date_str }).where({ id: stream.id });
+ }
+ }
+
+ },
+};
+
diff --git a/packages/strapi/database/migrations/2024-01-15-add-platform-to-streams.js b/packages/strapi/database/migrations/2024-01-15-add-platform-to-streams.js
new file mode 100644
index 0000000..a1632e9
--- /dev/null
+++ b/packages/strapi/database/migrations/2024-01-15-add-platform-to-streams.js
@@ -0,0 +1,49 @@
+
+module.exports = {
+ async up(knex) {
+
+ console.log(`MIGRATION-- 2024-01-15-add-platform-streams.js`);
+
+ // Check if the 'platform' column already exists in the 'streams' table
+ const hasColumn = await knex.schema.hasColumn('streams', 'platform');
+
+ if (!hasColumn) {
+ console.log(`Adding the 'platform' column to the 'streams' table`);
+ await knex.schema.table('streams', (table) => {
+ table.string('platform');
+ });
+ }
+
+ // Get all streams from the database
+ const streams = await knex.select('*').from('streams');
+
+ // For each stream, populate platform based on the related tweet data
+ for (const [index, stream] of streams.entries()) {
+
+ const tweetLink = await knex('streams_tweet_links')
+ .where({ stream_id: stream.id })
+ .first();
+
+ if (tweetLink) {
+ console.log(tweetLink);
+
+ const tweet = await knex('tweets')
+ .where({ id: tweetLink.tweet_id })
+ .first();
+
+ console.log(tweet);
+
+ if (!!tweet) {
+ console.log(`stream ${stream.id} tweet tweet.is_chaturbate_invite=${tweet.is_chaturbate_invite}, tweet.is_fansly_invite=${tweet.is_fansly_invite}`);
+ await knex('streams').update({
+ is_chaturbate_stream: !!tweet.is_chaturbate_invite,
+ is_fansly_stream: !!tweet.is_fansly_invite
+ }).where({ id: stream.id });
+ }
+ }
+
+ }
+
+ },
+};
+
diff --git a/packages/strapi/database/og-tags.json b/packages/strapi/database/og-tags.json
new file mode 100644
index 0000000..7d838af
--- /dev/null
+++ b/packages/strapi/database/og-tags.json
@@ -0,0 +1,1009 @@
+[{
+ "tags": null,
+ "date": "2020-02-09T18:14:25.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1226570058073362438"
+}, {
+ "tags": null,
+ "date": "2020-02-10T02:15:55.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1226691233659183104"
+}, {
+ "tags": null,
+ "date": "2020-02-12T01:11:48.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1227399871734468610"
+}, {
+ "tags": null,
+ "date": "2020-02-12T17:14:12.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1227642067733618691"
+}, {
+ "tags": null,
+ "date": "2020-02-13T02:09:11.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1227776703415693312"
+}, {
+ "tags": null,
+ "date": "2020-02-15T02:13:56.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1228502672246005760"
+}, {
+ "tags": null,
+ "date": "2020-02-18T21:17:28.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1229877618067025923"
+}, {
+ "tags": null,
+ "date": "2020-02-20T01:06:47.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1230297714719674368"
+}, {
+ "tags": null,
+ "date": "2020-02-22T02:13:38.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1231039313300901889"
+}, {
+ "tags": null,
+ "date": "2023-02-19T00:15:09.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1627099434508075008"
+}, {
+ "tags": null,
+ "date": "2020-02-09T01:40:10.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1226319848411717632"
+}, {
+ "tags": null,
+ "date": "2020-02-21T16:25:47.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1230891377422192641"
+}, {
+ "tags": null,
+ "date": "2020-03-03T21:06:17.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1234948231311876096"
+}, {
+ "tags": null,
+ "date": "2020-03-05T01:18:07.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1235373996906078208"
+}, {
+ "tags": null,
+ "date": "2020-03-07T02:40:52.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1236119594995245057"
+}, {
+ "tags": null,
+ "date": "2020-03-12T00:01:06.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1237891327922016258"
+}, {
+ "tags": null,
+ "date": "2020-03-15T20:22:40.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1239285911201988609"
+}, {
+ "tags": null,
+ "date": "2020-03-17T19:55:46.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1240003917355921412"
+}, {
+ "tags": null,
+ "date": "2020-03-22T00:11:12.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1241517748276154371"
+}, {
+ "tags": null,
+ "date": "2020-03-26T00:14:56.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1242968240894234627"
+}, {
+ "tags": null,
+ "date": "2020-03-01T21:06:17.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1234223457723961344"
+}, {
+ "tags": ["anal", "deep throat", "vore", "stuck in wall", "choking", "puddle", "squirting"],
+ "date": "2020-02-08T16:12:42.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1226177041109786625"
+}, {
+ "tags": null,
+ "date": "2020-02-28T16:38:43.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1233431346112061441"
+}, {
+ "tags": null,
+ "date": "2020-04-14T19:57:03.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1250151101174816769"
+}, {
+ "tags": null,
+ "date": "2020-04-24T00:55:16.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1253487639430410240"
+}, {
+ "tags": null,
+ "date": "2020-04-25T23:05:42.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1254184839684726786"
+}, {
+ "tags": null,
+ "date": "2020-04-26T22:54:50.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1254544493849739264"
+}, {
+ "tags": null,
+ "date": "2020-05-09T21:59:16.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1259241552016216065"
+}, {
+ "tags": null,
+ "date": "2020-05-12T19:01:53.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1260284077011238912"
+}, {
+ "tags": null,
+ "date": "2020-06-27T00:06:39.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1276668227767144452"
+}, {
+ "tags": null,
+ "date": "2020-02-17T01:05:40.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1229210268447715328"
+}, {
+ "tags": null,
+ "date": "2020-04-05T22:55:16.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1246934456927215617"
+}, {
+ "tags": null,
+ "date": "2020-05-05T19:00:56.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1257747123682119680"
+}, {
+ "tags": null,
+ "date": "2020-05-28T19:57:30.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1266096281002356736"
+}, {
+ "tags": null,
+ "date": "2020-05-29T23:02:07.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1266505128426815488"
+}, {
+ "tags": null,
+ "date": "2020-06-01T00:13:53.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1267247965464297473"
+}, {
+ "tags": null,
+ "date": "2020-06-06T00:02:11.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1269056957295583240"
+}, {
+ "tags": null,
+ "date": "2020-06-16T18:55:04.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1272965936685953024"
+}, {
+ "tags": null,
+ "date": "2020-06-18T23:37:57.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1273761903664336897"
+}, {
+ "tags": null,
+ "date": "2020-06-21T00:09:09.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1274494531312984064"
+}, {
+ "tags": null,
+ "date": "2020-06-23T20:00:12.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1275519042955153409"
+}, {
+ "tags": null,
+ "date": "2020-02-27T01:10:55.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1232835470712803328"
+}, {
+ "tags": null,
+ "date": "2020-05-23T00:02:55.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1263983714893279233"
+}, {
+ "tags": null,
+ "date": "2020-07-15T00:25:49.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1283196031648358400"
+}, {
+ "tags": null,
+ "date": "2020-07-18T01:14:51.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1284295535751499776"
+}, {
+ "tags": null,
+ "date": "2020-07-25T00:00:05.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1286813436119220225"
+}, {
+ "tags": null,
+ "date": "2020-07-29T20:03:40.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1288565878502699008"
+}, {
+ "tags": null,
+ "date": "2020-08-01T00:00:00.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1289350128436838400"
+}, {
+ "tags": null,
+ "date": "2020-08-05T19:52:40.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1291099825396748292"
+}, {
+ "tags": null,
+ "date": "2020-08-14T22:21:59.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1294398894466629634"
+}, {
+ "tags": null,
+ "date": "2020-08-19T21:00:11.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1296190247957659649"
+}, {
+ "tags": null,
+ "date": "2020-03-14T01:38:59.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1238640737668997120"
+}, {
+ "tags": null,
+ "date": "2020-07-10T23:59:34.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1281739875319009280"
+}, {
+ "tags": null,
+ "date": "2020-09-11T18:02:31.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1304480454242861056"
+}, {
+ "tags": null,
+ "date": "2020-09-13T23:00:49.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1305280300130406402"
+}, {
+ "tags": null,
+ "date": "2020-09-18T22:55:13.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1307090831011205120"
+}, {
+ "tags": null,
+ "date": "2020-09-28T20:14:36.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1310674290744995843"
+}, {
+ "tags": null,
+ "date": "2020-10-02T23:48:02.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1312177554824990720"
+}, {
+ "tags": null,
+ "date": "2020-10-06T22:59:13.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1313614818713231360"
+}, {
+ "tags": null,
+ "date": "2020-10-09T18:01:05.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1314626953803161601"
+}, {
+ "tags": null,
+ "date": "2020-04-02T00:11:39.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1245504130753404931"
+}, {
+ "tags": null,
+ "date": "2020-08-23T22:59:21.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1297669785883484160"
+}, {
+ "tags": null,
+ "date": "2020-09-20T20:00:12.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1307771561651441665"
+}, {
+ "tags": null,
+ "date": "2020-10-31T23:03:57.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1322675709379334146"
+}, {
+ "tags": null,
+ "date": "2020-11-18T21:28:43.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1329174724790915075"
+}, {
+ "tags": null,
+ "date": "2020-11-23T23:56:04.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1331023742693232646"
+}, {
+ "tags": null,
+ "date": "2020-11-26T22:03:19.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1332082533526360066"
+}, {
+ "tags": null,
+ "date": "2020-12-04T21:18:42.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1334970406025965571"
+}, {
+ "tags": null,
+ "date": "2020-12-07T23:56:41.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1336097330483916800"
+}, {
+ "tags": null,
+ "date": "2020-04-09T00:06:24.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1248039525215080449"
+}, {
+ "tags": null,
+ "date": "2020-10-18T18:59:38.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1317903180148166657"
+}, {
+ "tags": null,
+ "date": "2020-10-29T19:58:10.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1321904176637595648"
+}, {
+ "tags": null,
+ "date": "2021-01-05T23:07:36.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1346594227233427459"
+}, {
+ "tags": null,
+ "date": "2021-01-08T23:03:45.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1347680421920862209"
+}, {
+ "tags": null,
+ "date": "2021-01-12T23:03:22.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1349129873068068873"
+}, {
+ "tags": null,
+ "date": "2021-01-16T01:01:22.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1350246732391706624"
+}, {
+ "tags": null,
+ "date": "2021-01-22T23:02:24.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1352753509045776384"
+}, {
+ "tags": null,
+ "date": "2021-01-26T23:02:21.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1354203048491544581"
+}, {
+ "tags": null,
+ "date": "2021-02-03T23:00:44.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1357101745961328645"
+}, {
+ "tags": null,
+ "date": "2020-12-21T21:01:24.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1341126649329410050"
+}, {
+ "tags": null,
+ "date": "2020-12-28T23:20:13.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1343698295563153408"
+}, {
+ "tags": null,
+ "date": "2021-02-14T21:13:33.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1361061038620364812"
+}, {
+ "tags": null,
+ "date": "2021-02-18T00:01:18.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1362190417631076352"
+}, {
+ "tags": null,
+ "date": "2021-02-20T00:59:31.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1362929843759943681"
+}, {
+ "tags": null,
+ "date": "2021-02-24T23:01:00.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1364711958105194498"
+}, {
+ "tags": null,
+ "date": "2021-03-02T23:07:27.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1366887909241012233"
+}, {
+ "tags": null,
+ "date": "2021-03-12T22:53:59.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1370508398081540098"
+}, {
+ "tags": null,
+ "date": "2021-03-13T20:58:44.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1370841782506901516"
+}, {
+ "tags": null,
+ "date": "2021-03-20T21:54:09.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1373392441257103368"
+}, {
+ "tags": null,
+ "date": "2021-03-22T22:05:15.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1374120011854397442"
+}, {
+ "tags": null,
+ "date": "2021-02-10T23:26:55.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1359645050792206337"
+}, {
+ "tags": null,
+ "date": "2021-02-25T00:00:00.000Z",
+ "announceUrl": null
+}, {
+ "tags": null,
+ "date": "2021-04-03T01:26:21.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1378156887884005378"
+}, {
+ "tags": null,
+ "date": "2021-04-03T19:55:31.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1378436020081950726"
+}, {
+ "tags": null,
+ "date": "2021-04-12T23:11:23.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1381746799506030593"
+}, {
+ "tags": null,
+ "date": "2021-04-24T17:31:05.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1386009816443805699"
+}, {
+ "tags": null,
+ "date": "2021-05-01T16:59:01.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1388538459816595463"
+}, {
+ "tags": null,
+ "date": "2021-05-14T15:53:36.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1393233038298001411"
+}, {
+ "tags": null,
+ "date": "2021-05-21T22:59:03.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1395876824865988611"
+}, {
+ "tags": null,
+ "date": "2021-05-25T22:04:21.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1397312608454258690"
+}, {
+ "tags": null,
+ "date": "2021-06-05T22:02:00.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1401298283499298817"
+}, {
+ "tags": null,
+ "date": "2021-06-12T22:56:31.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1403848719695482888"
+}, {
+ "tags": null,
+ "date": "2022-01-09T23:32:49.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1480321695315640328"
+}, {
+ "tags": null,
+ "date": "2021-06-26T20:08:24.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1408879841315860486"
+}, {
+ "tags": null,
+ "date": "2021-07-03T22:04:50.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1411445858244169728"
+}, {
+ "tags": null,
+ "date": "2021-07-07T19:04:50.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1412850109608566786"
+}, {
+ "tags": null,
+ "date": "2021-07-13T19:52:08.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1415036340580884482"
+}, {
+ "tags": null,
+ "date": "2021-07-17T20:05:10.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1416489172311887876"
+}, {
+ "tags": null,
+ "date": "2021-08-04T23:11:38.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1423059078381719564"
+}, {
+ "tags": null,
+ "date": "2021-08-08T20:26:41.000Z",
+ "announceUrl": "http://twitter.com/ProjektMelody/status/1424467119006261249"
+}, {
+ "tags": null,
+ "date": "2021-08-12T19:57:20.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1425909284940955648"
+}, {
+ "tags": null,
+ "date": "2021-08-17T23:16:50.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1427771428833738755"
+}, {
+ "tags": null,
+ "date": "2021-08-21T20:13:36.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1429174868935856133"
+}, {
+ "tags": null,
+ "date": "2022-05-13T19:19:42.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1525194090299670528"
+}, {
+ "tags": null,
+ "date": "2021-09-09T23:01:37.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1436102522201116673"
+}, {
+ "tags": null,
+ "date": "2021-09-12T22:03:47.000Z",
+ "announceUrl": "http://twitter.com/ProjektMelody/status/1437175131223302146"
+}, {
+ "tags": null,
+ "date": "2021-09-19T19:47:34.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1439677566739259395"
+}, {
+ "tags": null,
+ "date": "2021-09-21T21:56:01.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1440434669305012228"
+}, {
+ "tags": null,
+ "date": "2021-09-29T18:55:41.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1443288390007508995"
+}, {
+ "tags": null,
+ "date": "2021-10-09T20:09:55.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1446930950332506117"
+}, {
+ "tags": null,
+ "date": "2021-10-11T22:06:20.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1447685023059128320"
+}, {
+ "tags": null,
+ "date": "2021-10-23T20:18:46.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1452006607626412038"
+}, {
+ "tags": null,
+ "date": "2021-11-04T22:03:43.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1456381673235492878"
+}, {
+ "tags": null,
+ "date": "2023-04-04T23:43:09.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1643398832485482497"
+}, {
+ "tags": null,
+ "date": "2022-09-07T23:13:00.000Z",
+ "announceUrl": null
+}, {
+ "tags": null,
+ "date": "2021-11-12T00:08:21.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1458949749986443268"
+}, {
+ "tags": null,
+ "date": "2021-11-19T20:01:27.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1461786722337972235"
+}, {
+ "tags": null,
+ "date": "2021-12-06T20:10:31.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1467949594252398599"
+}, {
+ "tags": null,
+ "date": "2021-12-12T23:12:01.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1470169597546479617"
+}, {
+ "tags": null,
+ "date": "2021-12-15T23:04:14.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1471254803451887625"
+}, {
+ "tags": null,
+ "date": "2021-12-17T23:05:54.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1471979997426589699"
+}, {
+ "tags": null,
+ "date": "2021-12-25T22:34:35.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1474871219610603526"
+}, {
+ "tags": null,
+ "date": "2021-12-30T23:17:45.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1476694022408261640"
+}, {
+ "tags": null,
+ "date": "2022-01-03T23:10:33.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1478141764741611527"
+}, {
+ "tags": null,
+ "date": "2022-01-13T00:03:21.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1481416541493153795"
+}, {
+ "tags": null,
+ "date": "2022-01-22T22:59:59.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1485024472105164805"
+}, {
+ "tags": null,
+ "date": "2022-01-26T01:57:25.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1486156290585882626"
+}, {
+ "tags": null,
+ "date": "2022-02-02T21:48:11.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1488992672022945793"
+}, {
+ "tags": null,
+ "date": "2022-02-16T23:00:32.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1494084309958987782"
+}, {
+ "tags": null,
+ "date": "2022-02-18T20:01:16.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1494763968535179274"
+}, {
+ "tags": null,
+ "date": "2022-03-10T23:02:20.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1502057294246424600"
+}, {
+ "tags": null,
+ "date": "2022-03-18T01:35:11.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1504632475804446721"
+}, {
+ "tags": null,
+ "date": "2022-04-06T00:02:17.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1511494467097870340"
+}, {
+ "tags": null,
+ "date": "2022-04-10T00:12:41.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1512946635655065602"
+}, {
+ "tags": null,
+ "date": "2022-04-16T23:09:42.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1515467499642531845"
+}, {
+ "tags": null,
+ "date": "2022-04-22T23:14:35.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1517643056228487168"
+}, {
+ "tags": null,
+ "date": "2022-05-06T22:59:23.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1522712662349656064"
+}, {
+ "tags": null,
+ "date": "2022-05-08T22:51:40.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1523435492657664000"
+}, {
+ "tags": null,
+ "date": "2022-05-19T00:44:58.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1527087885693878275"
+}, {
+ "tags": null,
+ "date": "2022-05-25T02:06:07.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1529282633762492417"
+}, {
+ "tags": null,
+ "date": "2022-06-05T23:30:37.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1533592158179139585"
+}, {
+ "tags": null,
+ "date": "2022-06-09T21:10:03.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1535006331119222784"
+}, {
+ "tags": null,
+ "date": "2022-06-22T23:46:31.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1539756753147117568"
+}, {
+ "tags": null,
+ "date": "2022-07-19T03:48:05.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1549239628418490368"
+}, {
+ "tags": null,
+ "date": "2022-08-03T23:32:24.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1554973488871530501"
+}, {
+ "tags": null,
+ "date": "2022-08-05T23:15:33.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1555694026376060966"
+}, {
+ "tags": null,
+ "date": "2022-08-11T20:31:00.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1557827065101127680#m"
+}, {
+ "tags": null,
+ "date": "2022-08-23T23:28:21.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1562220295683014657"
+}, {
+ "tags": null,
+ "date": "2022-09-10T21:03:36.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1568706781806821377"
+}, {
+ "tags": null,
+ "date": "2022-06-18T23:07:00.000Z",
+ "announceUrl": null
+}, {
+ "tags": null,
+ "date": "2022-09-13T23:26:31.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1569829911057031170"
+}, {
+ "tags": null,
+ "date": "2022-09-21T23:38:26.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1572732011529506817"
+}, {
+ "tags": null,
+ "date": "2022-10-02T02:05:22.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1576392868201365504"
+}, {
+ "tags": null,
+ "date": "2022-10-04T23:15:33.000Z",
+ "announceUrl": "http://twitter.com/ProjektMelody/status/1577437242716741632"
+}, {
+ "tags": null,
+ "date": "2022-10-13T02:22:45.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1580383510908399616"
+}, {
+ "tags": null,
+ "date": "2022-10-15T00:31:27.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1581080275546537984"
+}, {
+ "tags": ["squirting", "toy", "lovense-lush", "fantasy-for-her-suction", "crave-vesper-necklace", "womanizer-duo", "twitching", "licking", "unboxing", "suction", "review", "orgasm", "tongue", "vibrator", "cum-eating", "pussy-milking", "torture", "rope", "restraint", "bondage", "chains", "dildo", "deep-breathing"],
+ "date": "2022-10-20T23:21:15.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1583236936445353985"
+}, {
+ "tags": ["jumpsuit", "3d", "new-outfit", "pole-dancing", "lovense-lush", "lovense-hyfy", "blowjob", "bottomless", "ass", "dancing", "pool", "precum", "pussy"],
+ "date": "2022-11-04T20:29:53.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1588629627907473409"
+}, {
+ "tags": ["video-game", "hentai", "eroge", "daraku-gear", "mobile-game", "buffering", "sponsored", "lovense-lush", "storytime", "hentai", "games", "gacha", "waifu", "womb-tattoo", "bondage", "mind-break", "squirting", "nipple-clamps", "handcuffs", "suction-cups", "prisoner", "slave", "big-brother", "master", "hitachi-magic-wand", "double-penetration", "confusion", "cock-block", "crying", "edging", "cum", "pasties", "robocock", "milking", "hose", "self-censorship", "threesome", "blowjob", "spanking", "cucking", "feet", "sex-training"],
+ "date": "2022-12-14T00:01:45.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1602816075304935425"
+}, {
+ "tags": ["japan", "monokini", "outfit", "game-of-thrones", "gundam", "growling", "grinding", "flooring", "pool", "lovense-lush", "heavy-breathing", "moaning", "naked", "edging", "womb-tattoo", "pelvic-thrusting", "missionary", "fingering", "cum-drunk", "laughing", "c2c", "self-censorship", "sex-ed", "sex-stories", "glory-hole", "texting", "ass", "2-cooms", "orgasm", "selfie-cam", "non-euclidian", "silly-dancing"],
+ "date": "2022-12-16T00:30:34.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1603548101561696261"
+}, {
+ "tags": ["silly-music", "guest-dj", "lovense-lush", "3d", "original-outfit", "step-brother", "buffering", "screen-recording", "coffee", "anime-discussion", "monday", "topless", "pasties", "just-chatting", "moaning", "countdown", "orgasm", "hands-free-cum", "yandere", "all-fours", "malfunctioning-hand", "bed", "high-heels", "boobs", "twerking", "factoid", "cowgirl", "unzip", "belly", "femdom", "gamer-chair", "selfie-camera", "pussy-licking", "pussy-closeup", "fingering", "aftershocks", "dakimakura-discussion", "2000s-music", "ghost-in-the-shell", "lgbtq", "spread-legs", "feet", "footjob", "tit-belt"],
+ "date": "2020-05-17T00:07:30.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1261810539442946049"
+}, {
+ "tags": null,
+ "date": "2020-05-20T01:16:56.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1262915175037927425"
+}, {
+ "tags": null,
+ "date": "2020-07-05T00:02:06.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1279566184690659330"
+}, {
+ "tags": ["just-chatting", "chastity", "recovery", "live-2d", "fetish-research", "house-party", "video-game"],
+ "date": "2023-01-05T20:58:29.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1611104872484556805"
+}, {
+ "tags": ["singing", "christmas", "karaoke", "just-chatting", "holiday", "lovense-lush", "tomboy", "live2d", "debut", "pegging", "asmr", "strapon-dildo", "erotic-roleplay", "edging"],
+ "date": "2023-01-13T18:21:13.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1613964398506147853"
+}, {
+ "tags": ["just-chatting", "twintails", "g-string", "swimming-pool", "lovense-lush", "3d", "leap-motion", "orgasm-denial", "moaning", "bad-audio", "toilet", "bidet", "succubus-lingerie", "womb-tattoo", "dressup", "tv-discussion", "states-discussion", "naked", "experimental-lighting", "handjob", "asmr-discussion", "tease"],
+ "date": "2023-01-20T00:37:06.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1616233319439515648"
+}, {
+ "tags": null,
+ "date": "2020-07-06T20:03:01.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1280230795085578247"
+}, {
+ "tags": null,
+ "date": "2020-07-07T20:59:26.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1280607381605449729"
+}, {
+ "tags": null,
+ "date": "2020-08-22T00:03:48.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1296961229475512323"
+}, {
+ "tags": ["asmr", "3dio", "dominatrix", "submission", "breeding", "ai-dungeon", "tentacles", "anal", "fantasy-writing", "moaning", "cum-ban", "heavy-breathing", "orgasm", "denial", "cum-drunk"],
+ "date": "2023-01-21T20:36:06.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1616897448890273807"
+}, {
+ "tags": null,
+ "date": "2020-09-05T23:08:12.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1302383058247614465"
+}, {
+ "tags": null,
+ "date": "2021-07-04T18:50:39.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1411759377816690696"
+}, {
+ "tags": ["bepis", "pasties", "recovery", "hentai-discussion", "topless", "boobs", "live2d", "handjob", "lovense-lush", "guilty-fap", "train-molestation", "sex-dungeon", "bdsm", "santa", "moaning", "mel-noises", "rickroll", "cucked", "cbat", "punishment2-cum", "orgasm", "milking-device", "cumdrunk", "panting", "heat", "feral", "deep-breathing", "monster-girl", "roleplay", "fucking", "gratitude", "snack", "meltys-quest", "eroge", "fat-bastard", "voiceover", "girl-on-girl", "thirsty", "slut", "good-audio", "love"],
+ "date": "2023-02-17T02:10:04.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1626403575642353665"
+}, {
+ "tags": ["social-media", "aspirations", "first-time", "lovense-lush", "bad-audio", "ahegao", "3d", "lonely", "friends", "dab", "tag-discussion", "deep-breathing", "jerk-off-gesture", "gratitude", "cat-girls", "plexstorm", "hentai-game", "cute-pussy", "origin", "moaning", "twerking", "dancing", "shaking", "strip-tease", "anime-discussion", "video-game-discussion", "ass", "pasties", "high-heels", "harness", "thong", "leggings", "technical-difficulties", "panic-attack", "meditation", "just-chatting", "masturbation", "nipples"],
+ "date": "2020-02-07T23:21:48.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1225922638687752192"
+}, {
+ "tags": null,
+ "date": "2020-10-16T23:32:50.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1317247159478136832"
+}, {
+ "tags": ["bad-audio", "new-outfit", "anniversary", "bunny-outfit", "3d", "sexmachine", "raul", "recovery", "bunny-suit", "sit-on-face", "naked", "jacket", "mel-noises", "rickroll", "frickenator", "standing-cum", "legwarmers", "bunny-ears", "ass", "leg-shaking", "glitch", "doggy-style", "breeding", "dirty-talk", "cum-drunk", "trouble-walking", "slut", "food", "masturbation", "dick-sucking", "t1m", "lovense-lush", "pool", "flooring"],
+ "date": "2023-02-12T23:07:09.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1624907994671489026"
+}, {
+ "tags": ["mel-noises", "crying", "good-audio", "live2d", "moaning", "dildo", "masturbation", "glass-dildo", "teaser", "sex-stories", "horny", "script-writing", "joi", "topless", "pasties", "naked", "asmr", "just-chatting", "self-care", "deep-breathing", "guided-meditation", "tantric-sex", "slut", "orgasm", "hentai-game", "caring"],
+ "date": "2023-02-09T00:25:47.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1623478232036122624"
+}, {
+ "tags": ["just-chatting", "community", "anxiety", "dork", "live2d", "nut-between-worlds", "pro-social-behavior", "topless", "pasties", "harness", "boobs", "moaning", "blowjob"],
+ "date": "2023-02-13T03:07:00.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1624907994671489026"
+}, {
+ "tags": null,
+ "date": "2020-03-01T01:14:02.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1233923415964340225"
+}, {
+ "tags": null,
+ "date": "2020-03-28T01:42:21.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1243715015829585925"
+}, {
+ "tags": null,
+ "date": "2020-04-01T00:13:26.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1245142190952796167"
+}, {
+ "tags": null,
+ "date": "2020-05-02T22:01:33.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1256705414663725058"
+}, {
+ "tags": null,
+ "date": "2020-06-10T18:58:26.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1270792457941368832"
+}, {
+ "tags": null,
+ "date": "2020-06-28T00:10:07.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1277031489205678083"
+}, {
+ "tags": null,
+ "date": "2020-02-25T21:31:41.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1232417908678168576"
+}, {
+ "tags": null,
+ "date": "2020-03-10T22:00:51.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1237498680690855939"
+}, {
+ "tags": null,
+ "date": "2020-03-20T15:41:36.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1241027117284044801"
+}, {
+ "tags": null,
+ "date": "2020-08-28T23:03:16.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1299482712869306368"
+}, {
+ "tags": null,
+ "date": "2020-09-24T23:25:58.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1309272896456527872"
+}, {
+ "tags": null,
+ "date": "2020-10-13T23:03:14.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1316152545732157448"
+}, {
+ "tags": null,
+ "date": "2020-10-23T18:55:31.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1319714083462107139"
+}, {
+ "tags": ["just-chatting", "lovense-lush", "mel-noises", "pro-social-behavior", "topless", "g-string", "thong", "high-heels", "selfie-camera", "ass", "porn-discussion", "panties", "no-nut-november", "moaning", "feet", "feet-licking", "vtuber-discussion", "gamer-chair", "naked", "stretching", "flexibility", "orgasm", "masturbation"],
+ "date": "2020-11-09T00:55:59.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1325603004695842816"
+}, {
+ "tags": null,
+ "date": "2020-12-14T21:46:27.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1338601272354758656"
+}, {
+ "tags": null,
+ "date": "2020-12-24T23:02:13.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1342244216731275265"
+}, {
+ "tags": null,
+ "date": "2020-08-11T23:01:22.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1293321639728492544"
+}, {
+ "tags": null,
+ "date": "2020-10-11T22:05:30.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1315413239556190211"
+}, {
+ "tags": null,
+ "date": "2021-03-03T23:03:48.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1367249376675041285"
+}, {
+ "tags": null,
+ "date": "2021-04-18T00:30:03.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1383578535340634120"
+}, {
+ "tags": null,
+ "date": "2021-04-23T23:01:52.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1385730672661303296"
+}, {
+ "tags": null,
+ "date": "2021-06-06T20:55:39.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1401643974922838019"
+}, {
+ "tags": null,
+ "date": "2021-06-15T22:57:44.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1404936189946236930"
+}, {
+ "tags": null,
+ "date": "2021-07-27T23:04:15.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1420158120370872320"
+}, {
+ "tags": null,
+ "date": "2021-08-30T23:08:30.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1432480377302552587"
+}, {
+ "tags": null,
+ "date": "2021-09-03T21:59:09.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1433912474542264321"
+}, {
+ "tags": null,
+ "date": "2021-02-05T22:57:21.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1357825669024120841"
+}, {
+ "tags": null,
+ "date": "2021-10-04T22:20:50.000Z",
+ "announceUrl": "http://twitter.com/ProjektMelody/status/1445151953764458501"
+}, {
+ "tags": null,
+ "date": "2021-11-16T23:07:06.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1460746277717782528"
+}, {
+ "tags": null,
+ "date": "2021-12-22T23:58:43.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1473805228537438209"
+}, {
+ "tags": null,
+ "date": "2022-01-15T20:53:35.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1482455948459450369"
+}, {
+ "tags": null,
+ "date": "2022-01-28T22:13:21.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1487187063048921093"
+}, {
+ "tags": null,
+ "date": "2022-02-13T21:17:23.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1492971187047374849"
+}, {
+ "tags": null,
+ "date": "2022-04-13T20:10:50.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1514335322527649798"
+}, {
+ "tags": null,
+ "date": "2022-05-14T23:02:18.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1525612497935507457"
+}, {
+ "tags": null,
+ "date": "2022-05-26T18:31:28.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1529892992818876417"
+}, {
+ "tags": null,
+ "date": "2022-08-01T19:28:31.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1554187338804338696"
+}, {
+ "tags": null,
+ "date": "2022-09-02T20:06:16.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1565793017960828931"
+}, {
+ "tags": null,
+ "date": "2022-09-23T23:38:18.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1573456755236954114"
+}, {
+ "tags": ["memes", "anime", "bdsm", "orgasm", "moaning", "laughing", "cum-drunk", "lovense-lush"],
+ "date": "2022-10-27T23:20:05.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1585773359379677184"
+}, {
+ "tags": ["lovense-hyphy", "lovense-lush", "whispering", "asmr", "sportscar", "pee", "sick", "coughing", "shaking", "cum", "orgasm", "brainfrog", "oral", "sucking", "sex-toy", "cum-drunk", "moaning", "twitching", "thrusting", "grinding", "objectification", "flooring", "keyboard-clicking", "mocap-failure", "muted", "charades", "posing", "riding", "dry-humping", "ass", "high-heels", "legs", "hip-sway", "plug-suit", "chest-harness", "naked", "womb-tattoo", "sexy-dance", "slav-squat", "tail", "pole-dance", "clipping", "licking", "glowing", "dab"],
+ "date": "2022-11-12T00:13:40.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1591222662487236609"
+}, {
+ "tags": ["eroge", "video-game", "orc", "moaning", "cyber", "cum-drunk", "orgasm", "towel", "petting", "massage", "accupressure", "lingerie", "ass", "thong", "pasties", "adhesive-bandage", "monster-girls", "texting", "lovense-lush", "lovense-hyphy", "broken-toy", "tail", "live2d", "food-porn", "self-care", "aromatherapy", "monster-dick", "hot-sluts", "monster", "fantasy", "cock-sleeve", "feet", "footjob", "fingering", "elf", "cum-whore", "panties", "cum"],
+ "date": "2022-11-19T22:35:57.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1594097172689166337"
+}, {
+ "tags": ["ass", "tail", "lovense-lush", "conversation", "grinding", "flooring", "going-away", "humping", "laughing", "eating", "harness", "boobs", "toes", "cum-drunk", "aftershocks", "dancing", "pole-dancing", "moaning", "feet", "stepping", "cock-abuse", "extreme-closeup", "butthole", "panties", "shaking", "pussy-licking", "singing", "hentai", "carnival", "fingering", "wedgie", "fetishwear", "watch-along", "pasties", "creampie", "rude-sex", "cumming", "g-string", "idol", "voyeurism", "condom", "gay", "spitting", "pervert", "edging", "mutual-masturbation", "sniffing"],
+ "date": "2022-11-22T23:04:43.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1595191577068044289"
+}, {
+ "tags": ["hentai", "eroge", "dohna-dohna", "orgasm-denial", "chastity", "video-game", "live2d", "ovulation", "feet", "horny", "dream", "vampire", "just-chatting", "numi", "game-of-thrones", "recovery", "bad-audio", "yandere", "storytime", "spontaneous-song", "crushes"],
+ "date": "2023-01-01T22:03:49.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1609671764514164737"
+}, {
+ "tags": null,
+ "date": "2021-09-07T22:01:24.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1435362590893527040"
+}, {
+ "tags": null,
+ "date": "2021-09-16T20:00:39.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1438593697445302274"
+}, {
+ "tags": null,
+ "date": "2022-02-07T23:27:14.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1490829536316985348"
+}, {
+ "tags": ["lawnmower", "motorbunny", "bad-audio", "3d", "lovense-lush", "pussy-to-mouth", "screaming", "swimming-pool", "moaning", "deep-breathing", "cock-riding", "mel-noises", "mind-break", "technical-difficulties", "yelling", "echo", "reverse-cowgirl", "muffled-screams", "orgasm", "no-face-tracking", "swearing", "chaturbate-compliance", "spit", "messy", "cum-drinking", "clit-milking-device", "multiple-orgasms", "4-cum", "squirting", "loud-orgasm", "cum-chalice", "schlorp", "sksksksk"],
+ "date": "2023-01-25T00:19:39.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1618040869587947521"
+}, {
+ "tags": ["lovense-lush", "lovense-hush", "tail", "butt-plug", "double-penetration", "moaning", "blushing", "manual-masturbation", "embarrasment", "orgasm", "just-chatting", "shorts", "stripping", "jiggle-physics", "3d", "boobs", "pasties", "dancing", "swearing", "vtuber-discussion", "t-pose", "ass", "anime-discussion", "selfie-camera", "edging", "jojo-posing", "anal-fingering", "fingering"],
+ "date": "2020-11-18T01:59:20.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1328880436551049217"
+}, {
+ "tags": null,
+ "date": "2021-01-03T23:01:53.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1345868009483735042"
+}, {
+ "tags": null,
+ "date": "2021-01-10T19:57:37.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1348358353676873729"
+}, {
+ "tags": null,
+ "date": "2021-02-07T23:04:03.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1358552132295798787"
+}, {
+ "tags": ["boobs", "porn-game", "video-game", "bondage", "mobile-game", "android", "moaning", "bikini", "blowjob", "doggy-style", "3d", "sponsored"],
+ "date": "2022-11-18T01:03:45.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1593409592477638656"
+}, {
+ "tags": ["lovense-lush", "spanking", "ass", "stripping", "bottom-bitch", "permission", "cum-slut", "blowjob", "grinding", "yoga", "cyber", "kegel", "conversation", "bend-over", "squirming", "horny", "dildo-choking", "deep-throating", "finger-stimulation", "begging", "hummer", "orgasm", "cum-drunk", "laughing", "gratitude", "teasing", "crying", "bullying", "moaning", "feet-licking", "womb-tattoo", "harness", "boobs", "vagina", "drugs", "interpretive-dance", "sexy-dancing", "pole-dancing", "flooring", "jig", "silly-dancing", "tail"],
+ "date": "2022-11-22T01:15:55.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1594862203546501121"
+}, {
+ "tags": ["love-drunk", "noises", "x-mas", "technical-difficulties", "horny", "chat-analytics", "chat-roast", "lovense-lush", "moaning", "self-deprecation-humor", "edging", "just-chatting", "orgasm", "2-cum", "cum-drunk", "multiple-orgasms", "hands-free-cum", "handcuffs", "butt-plug", "anal", "chastity-device", "bdsm", "ball-gag", "collar", "heavy-breathing", "big-o", "snacking", "fat-bastard", "airplane", "mile-high-club", "dirty-talk", "video-game", "malady", "hime-hajime", "big-bang-studios", "a-nut-between-worlds"],
+ "date": "2022-12-17T22:14:20.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1604238592389238784"
+}, {
+ "tags": ["video-game", "recovery", "bad-audio", "technical-difficulties", "just-chatting", "purino-party", "zooted", "medication", null],
+ "date": "2023-01-05T02:07:18.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1610820355895037955"
+}, {
+ "tags": ["cum-ban", "soaking", "semantics", "lovense-lush", "dildo", "pussy-noises", "relaxation", "meditation", "games", "meltys-quest", "wet", "asmr", "messy", "moaning", "horny", "blowjob", "doctor-defiance", "cum-brain", "mind-break", "giggles", "mel-noises", "hentai-game", "prank", "ear-rape", "live2d", "voice-acting", "goblin-sex", "drake__selfsuck"],
+ "date": "2023-01-09T23:07:18.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1612586844298018817"
+}, {
+ "tags": ["bondage", "digital-art", "lovense-lush", "mel-noises", "moaning", "hucow", "pussy-milking", "browser-wars", "edging", "daddy-play", "orgasm", "feet", "live2d", "rapping", "singing", "vibrator", "good-audio", "vibrator-asmr", "spreader-bars", "precum", "puddle", "bdsm", "restraint", "slut", "cum-drunk", "loud-orgasm", "multiple-orgasms", "screaming", "begging", "cum-inside", "mind-break", "aftershocks", "labia-spreader"],
+ "date": "2023-01-29T22:06:21.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1619819262125944832"
+}, {
+ "tags": ["pasties", "topless", "live2d", "lovense-lush", "lovense-osci", "orgasm", "cum-drunk", "mind-break", "moaning", "mel-noises", "multiple-orgasms", "hentai-watch-along", "dirty-talk", "blowjob", "horny", "tentacles", "double-penetration", "fantasy"],
+ "date": "2023-02-01T01:38:32.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1620597436988411907"
+}, {
+ "tags": ["cooking", "onigiri", "seiso", "irl", "bad-audio", "rickroll", "dirty-slut", "crepe", "jokes", "just-chatting", "sex-toy-discussion", "booli", "femdom", "topless", "apron", "boobs", "nipples", "bacon", "innuendo", "dirty-talk", "parenting", "stories"],
+ "date": "2023-02-24T00:17:38.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1628911998787362817"
+}, {
+ "tags": ["3d", "lovense-lush", "lovense-sex-machine", "pool", "dancing", "sway", "ass", "shorts", "leggings", "middrift", "mel-noises", "pig-latin", "moaning", "topless", "bra", "bottomless", "good-audio", "kneeling", "legs-spread", "t1m", "pussy", "grinding", "shaking", "missionary-style", "first-time", "lovense-hyphy", "cum", "orgasm", "multiple-orgasms", "begging", "prone-bone", "daddy", "dirty-talk", "shibari", "closeup", "pov", "6-cums"],
+ "date": "2023-03-04T02:28:14.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1631843966843863040"
+}, {
+ "tags": ["anime-girl", "horny", "baka", "lovense-lush", "boobs", "harness", "pasties", "cum", "orgasm", "edging", "gunrun", "hormones", "subathon", "fantasy", "sake", "ntrpg", "game-night", "toilet", "ntr", "elderly", "fatherboard", "sneeze", "dream-daddy", "futa-fix-dick-dine-and-dash", "futanari", "asmr", "lovense-hush", "anal", "begging"],
+ "date": "2023-03-03T02:04:05.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1631475499753979908"
+}, {
+ "tags": ["lovense-partnership", "big-bang-a-nut-between-worlds", "selfcest", "cuck", "video-game", "sponsored-stream", "finger-blasting", "blowjob", "handjob"],
+ "date": "2023-03-24T21:13:29.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1639374902246404102"
+}, {
+ "tags": ["bikini", "womb-tattoo", "pool", "lovense-lush", "japan", "adhd", "edging", "permission", "cum-slut", "mel-noises", "moaning", "begging", "yelling", "mindbreak", "cum-drunk", "dirty-talk", "bbc", "dildo", "death", "lovense-sex-machine", "bakery", "orgasms", "multiple-orgasms", "ejaculate", "blowjob", "just-chatting", "choking", "joi", "slave", "master", "deepthroat", "sloppy", "3d", "goblin", "anal-breeding", "rapping", "dj", "dancing", "hime-hajime", "bad-audio", "voice-acting", "alto"],
+ "date": "2023-03-23T21:13:04.000Z",
+ "announceUrl": "https://twitter.com/ProjektMelody/status/1639012409175072769"
+}]
\ No newline at end of file
diff --git a/packages/strapi/favicon.png b/packages/strapi/favicon.png
new file mode 100644
index 0000000..df668a8
Binary files /dev/null and b/packages/strapi/favicon.png differ
diff --git a/packages/strapi/misc/2023-05-26-export-og-tags.js b/packages/strapi/misc/2023-05-26-export-og-tags.js
new file mode 100644
index 0000000..522e3e8
--- /dev/null
+++ b/packages/strapi/misc/2023-05-26-export-og-tags.js
@@ -0,0 +1,202 @@
+require('dotenv').config()
+
+const { Client } = require('pg')
+const fetch = require('node-fetch')
+const _ = require('lodash');
+
+
+
+// module.exports = {
+// async up(knex) {
+
+// // Get all VODs from the database
+// const vods = await knex.select('*').from('vods');
+
+// // sanity check every B2 URL
+// for (const vod of vods) {
+// await checkUrl(vod.video_src)
+// }
+
+// console.log(`there are ${problemUrls.length} the problem urls`)
+// console.log(problemUrls)
+
+// process.exit(5923423)
+// },
+// };
+
+// const slugify = require('slugify')
+
+
+// function slugifyString (str) {
+// return slugify(str, {
+// replacement: '-', // replace spaces with replacement character, defaults to `-`
+// remove: undefined, // remove characters that match regex, defaults to `undefined`
+// lower: true, // convert to lower case, defaults to `false`
+// strict: true, // strip special characters except replacement, defaults to `false`
+// locale: 'en', // language code of the locale to use
+// trim: true // trim leading and trailing replacement chars, defaults to `true`
+// })
+// }
+
+
+async function associateTagWithVodsInStrapi (tagId, vodsIds) {
+ const res = await fetch(`${process.env.STRAPI_URL}/api/tags/${tagId}`, {
+ method: 'PUT',
+ headers: {
+ 'authorization': `Bearer ${process.env.STRAPI_API_KEY}`
+ },
+ data: {
+ vods: [vodsIds]
+ }
+ })
+ const json = await res.json()
+
+
+ if (!res.ok) throw new Error(JSON.stringify(json))
+}
+
+
+
+async function associateVodWithTagsInStrapi (vodId, tagsIds) {
+ const res = await fetch(`${process.env.STRAPI_URL}/api/vods/${vodId}?populate=*`, {
+ method: 'PUT',
+ headers: {
+ 'authorization': `Bearer ${process.env.STRAPI_API_KEY}`,
+ 'Content-Type': 'application/json'
+ },
+ body: JSON.stringify({
+ data: {
+ tags: tagsIds
+ }
+ })
+ })
+ const json = await res.json()
+
+
+ if (!res.ok) throw new Error(JSON.stringify(json))
+}
+
+async function getStrapiVodByAnnounceUrl (announceUrl) {
+ const res = await fetch(`${process.env.STRAPI_URL}/api/vods?filters[announceUrl][$eqi]=${announceUrl}`, {
+ method: 'GET',
+ headers: {
+ 'authorization': `Bearer ${process.env.STRAPI_API_KEY}`
+ }
+ })
+ const json = await res.json()
+ return json.data[0]
+}
+
+
+// async function getStrapiVodByDate (date) {
+
+// // const r = await fetch(`${process.env.STRAPI_URL}/api/vods/200`, {
+// // method: 'GET',
+// // headers: {
+// // 'authorization': `Bearer ${process.env.STRAPI_API_KEY}`
+// // }
+// // })
+// // const j = await r.json()
+
+// const res = await fetch(`${process.env.STRAPI_URL}/api/vods?filters[date][$eqi]=${date}`, {
+// method: 'GET',
+// headers: {
+// 'authorization': `Bearer ${process.env.STRAPI_API_KEY}`
+// }
+// })
+// const json = await res.json()
+// process.exit(3)
+// if (!res.ok) throw new Error(JSON.stringify(json));
+// return json.id
+// }
+
+
+async function getStrapiTagByName (tag) {
+ const res = await fetch(`${process.env.STRAPI_URL}/api/tags?filters[name][$eqi]=${tag}`, {
+ method: 'GET',
+ headers: {
+ 'authorization': `Bearer ${process.env.STRAPI_API_KEY}`
+ }
+ })
+ const json = await res.json()
+ return json.data[0]
+}
+
+async function main () {
+ const client = new Client()
+ await client.connect()
+
+
+ // get list of vods from our source db
+ const vodsResponse = await client.query('SELECT tags, date, "announceUrl" FROM vod')
+
+ console.log(JSON.stringify(vodsResponse.rows))
+ process.exit(5)
+
+ for (const vod of vodsResponse.rows) {
+
+
+
+ // get matching vod in strapi
+ const strapiVod = await getStrapiVodByAnnounceUrl(vod.announceUrl)
+
+ if (strapiVod) {
+ // we've got a matching vod
+
+ if (vod.tags) {
+ console.log(`source vod has tags: ${vod.tags}`)
+
+ let strapiTagsIds = []
+
+ // for each tag, get the matching strapi tag ID
+ for (const tag of vod.tags) {
+ // lookup the strapi tag id
+ const strapiTag = await getStrapiTagByName(tag)
+ strapiTagsIds.push(strapiTag.id)
+ }
+
+ console.log(`we are adding the following strapiTagsIds to vod ID ${strapiVod.id}: ${strapiTagsIds}`)
+
+ // create relations between matching vod and the tags
+ await associateVodWithTagsInStrapi(strapiVod.id, strapiTagsIds)
+
+ }
+ }
+ }
+
+ // const groupedCollection = _.groupBy(related.rows, 'vod_id');
+ // for (const vodId in groupedCollection) {
+ // const tagsIds = groupedCollection[vodId].map((t)=>t.tag_id)
+ // const tagsIdsAltered = tagsIds.map((t)=>(t === 114) ? 520 : t)
+ // await associateVodWithTagsInStrapi(vodId, tagsIdsAltered)
+ // }
+
+ // const res = await client.query('SELECT id, name FROM tags')
+ // for (const tag of res.rows) {
+ // // for (const link of related.rows) {
+ // // await new Promise((resolve) => setTimeout(resolve, 1000))
+ // // await associateTagWithVodsInStrapi(link.tag_id, link.vod_id)
+ // // }
+ // }
+
+ await client.end()
+}
+
+
+
+
+
+// const res = await client.query('SELECT * FROM public.tags_vod_links')
+
+
+main()
+// restore tags from db backup
+// make associations between vods <--> tags in strapi
+
+
+// we iterate through the local, non-strapi backup db first.
+// get list of all tags
+// for each tag
+// * get list of related vods
+// * create relation in Strapi.
+
diff --git a/packages/strapi/misc/generateCuid.js b/packages/strapi/misc/generateCuid.js
new file mode 100644
index 0000000..c049924
--- /dev/null
+++ b/packages/strapi/misc/generateCuid.js
@@ -0,0 +1,7 @@
+const { init } = require('@paralleldrive/cuid2');
+
+module.exports = function() {
+ const length = 10;
+ const genCuid = init({ length });
+ return genCuid();
+}
\ No newline at end of file
diff --git a/packages/strapi/package.json b/packages/strapi/package.json
new file mode 100644
index 0000000..764c23f
--- /dev/null
+++ b/packages/strapi/package.json
@@ -0,0 +1,90 @@
+{
+ "name": "futureporn-strapi",
+ "private": true,
+ "version": "0.1.0",
+ "description": "A Strapi application",
+ "scripts": {
+ "dev:c": "concurrently \"npm:tunnel\" \"npm:dev:strapi\"",
+ "tunnel": "ngrok start futureporn-strapi",
+ "chisel": "bash ./chisel.sh",
+ "db": "bash ./database/devDb.sh",
+ "start": "strapi start",
+ "build": "strapi build",
+ "develop": "NODE_ENV=development strapi develop",
+ "strapi": "strapi",
+ "preinstall": "npx only-allow yarn"
+ },
+ "dependencies": {
+ "@11ty/eleventy-fetch": "^4.0.0",
+ "@aws-sdk/client-s3": "^3.485.0",
+ "@esm2cjs/execa": "6.1.1-cjs.1",
+ "@mux/mux-node": "^7.3.3",
+ "@paralleldrive/cuid2": "^2.2.2",
+ "@radix-ui/react-use-callback-ref": "^1.0.1",
+ "@strapi/plugin-i18n": "4.17.0",
+ "@strapi/plugin-users-permissions": "4.17.0",
+ "@strapi/provider-email-sendgrid": "4.17.0",
+ "@strapi/provider-upload-cloudinary": "4.17.0",
+ "@strapi/strapi": "4.17.0",
+ "@strapi/utils": "4.17.0",
+ "@testing-library/dom": "8.19.0",
+ "@testing-library/react": "12.1.4",
+ "@testing-library/react-hooks": "8.0.1",
+ "@testing-library/user-event": "14.4.3",
+ "aws-sdk": "^2.1539.0",
+ "bcryptjs": "2.4.3",
+ "better-sqlite3": "8.0.1",
+ "canvas": "^2.11.2",
+ "codemirror": "^6.0.1",
+ "css-loader": "^6.8.1",
+ "cuid": "^3.0.0",
+ "date-fns": "^3.1.0",
+ "formik": "2.2.9",
+ "fuzzy-search": "^3.2.1",
+ "grant-koa": "5.4.8",
+ "history": "^4.10.1",
+ "immer": "9.0.19",
+ "jsonwebtoken": "9.0.0",
+ "jwk-to-pem": "2.0.5",
+ "koa": "^2.15.0",
+ "koa2-ratelimit": "^1.1.3",
+ "lodash": "4.17.21",
+ "match-sorter": "^4.2.1",
+ "msw": "1.0.1",
+ "node-abort-controller": "^3.1.1",
+ "object-assign": "^4.1.1",
+ "pg": "^8.11.3",
+ "prop-types": "^15.8.1",
+ "purest": "4.0.2",
+ "react": "^18.2.0",
+ "react-dom": "^18.2.0",
+ "react-intl": "6.3.2",
+ "react-query": "3.24.3",
+ "react-redux": "8.0.5",
+ "react-router-dom": "5.3.4",
+ "react-test-renderer": "^17.0.2",
+ "semver": "^7.5.4",
+ "sharp": "^0.32.6",
+ "strapi-plugin-fuzzy-search": "^2.2.0",
+ "styled-components": "5.3.3",
+ "typescript": "^5.3.3",
+ "url-join": "4.0.1",
+ "yallist": "^4.0.0",
+ "yup": "^0.32.11"
+ },
+ "devDependencies": {
+ "concurrently": "^8.2.2"
+ },
+ "author": {
+ "name": "CJ_Clippy"
+ },
+ "strapi": {
+ "uuid": false
+ },
+ "engines": {
+ "node": ">=14.19.1 <=18.x.x",
+ "npm": ">=6.0.0"
+ },
+ "license": "MIT",
+ "packageManager": "yarn@1.22.19"
+}
diff --git a/packages/strapi/public/robots.txt b/packages/strapi/public/robots.txt
new file mode 100644
index 0000000..ff5d316
--- /dev/null
+++ b/packages/strapi/public/robots.txt
@@ -0,0 +1,3 @@
+# To prevent search engines from seeing the site altogether, uncomment the next two lines:
+# User-Agent: *
+# Disallow: /
diff --git a/packages/strapi/public/uploads/.gitkeep b/packages/strapi/public/uploads/.gitkeep
new file mode 100644
index 0000000..e69de29
diff --git a/packages/strapi/src/admin/app.example.js b/packages/strapi/src/admin/app.example.js
new file mode 100644
index 0000000..45cad61
--- /dev/null
+++ b/packages/strapi/src/admin/app.example.js
@@ -0,0 +1,39 @@
+const config = {
+ locales: [
+ // 'ar',
+ // 'fr',
+ // 'cs',
+ // 'de',
+ // 'dk',
+ // 'es',
+ // 'he',
+ // 'id',
+ // 'it',
+ // 'ja',
+ // 'ko',
+ // 'ms',
+ // 'nl',
+ // 'no',
+ // 'pl',
+ // 'pt-BR',
+ // 'pt',
+ // 'ru',
+ // 'sk',
+ // 'sv',
+ // 'th',
+ // 'tr',
+ // 'uk',
+ // 'vi',
+ // 'zh-Hans',
+ // 'zh',
+ ],
+};
+
+const bootstrap = (app) => {
+ console.log(app);
+};
+
+export default {
+ config,
+ bootstrap,
+};
diff --git a/packages/strapi/src/admin/webpack.config.example.js b/packages/strapi/src/admin/webpack.config.example.js
new file mode 100644
index 0000000..1ca45c2
--- /dev/null
+++ b/packages/strapi/src/admin/webpack.config.example.js
@@ -0,0 +1,9 @@
+'use strict';
+
+/* eslint-disable no-unused-vars */
+module.exports = (config, webpack) => {
+ // Note: we provide webpack above so you should not `require` it
+ // Perform customizations to webpack config
+ // Important: return the modified config
+ return config;
+};
diff --git a/packages/strapi/src/api/.gitkeep b/packages/strapi/src/api/.gitkeep
new file mode 100644
index 0000000..e69de29
diff --git a/packages/strapi/src/api/b2-file/content-types/b2-file/schema.json b/packages/strapi/src/api/b2-file/content-types/b2-file/schema.json
new file mode 100644
index 0000000..6992f65
--- /dev/null
+++ b/packages/strapi/src/api/b2-file/content-types/b2-file/schema.json
@@ -0,0 +1,36 @@
+{
+ "kind": "collectionType",
+ "collectionName": "b2_files",
+ "info": {
+ "singularName": "b2-file",
+ "pluralName": "b2-files",
+ "displayName": "B2 File",
+ "description": ""
+ },
+ "options": {
+ "draftAndPublish": false
+ },
+ "pluginOptions": {},
+ "attributes": {
+ "url": {
+ "type": "string",
+ "required": true,
+ "unique": true
+ },
+ "key": {
+ "type": "string",
+ "unique": true,
+ "required": true
+ },
+ "uploadId": {
+ "type": "string",
+ "unique": true,
+ "required": true
+ },
+ "cdnUrl": {
+ "type": "string",
+ "unique": true,
+ "required": true
+ }
+ }
+}
diff --git a/packages/strapi/src/api/b2-file/controllers/b2-file.js b/packages/strapi/src/api/b2-file/controllers/b2-file.js
new file mode 100644
index 0000000..65f936a
--- /dev/null
+++ b/packages/strapi/src/api/b2-file/controllers/b2-file.js
@@ -0,0 +1,9 @@
+'use strict';
+
+/**
+ * b2-file controller
+ */
+
+const { createCoreController } = require('@strapi/strapi').factories;
+
+module.exports = createCoreController('api::b2-file.b2-file');
diff --git a/packages/strapi/src/api/b2-file/routes/b2-file.js b/packages/strapi/src/api/b2-file/routes/b2-file.js
new file mode 100644
index 0000000..a74a8d9
--- /dev/null
+++ b/packages/strapi/src/api/b2-file/routes/b2-file.js
@@ -0,0 +1,9 @@
+'use strict';
+
+/**
+ * b2-file router
+ */
+
+const { createCoreRouter } = require('@strapi/strapi').factories;
+
+module.exports = createCoreRouter('api::b2-file.b2-file');
diff --git a/packages/strapi/src/api/b2-file/services/b2-file.js b/packages/strapi/src/api/b2-file/services/b2-file.js
new file mode 100644
index 0000000..03e2bdf
--- /dev/null
+++ b/packages/strapi/src/api/b2-file/services/b2-file.js
@@ -0,0 +1,9 @@
+'use strict';
+
+/**
+ * b2-file service
+ */
+
+const { createCoreService } = require('@strapi/strapi').factories;
+
+module.exports = createCoreService('api::b2-file.b2-file');
diff --git a/packages/strapi/src/api/contributor/content-types/contributor/schema.json b/packages/strapi/src/api/contributor/content-types/contributor/schema.json
new file mode 100644
index 0000000..3cc046c
--- /dev/null
+++ b/packages/strapi/src/api/contributor/content-types/contributor/schema.json
@@ -0,0 +1,30 @@
+{
+ "kind": "collectionType",
+ "collectionName": "contributors",
+ "info": {
+ "singularName": "contributor",
+ "pluralName": "contributors",
+ "displayName": "Contributor",
+ "description": ""
+ },
+ "options": {
+ "draftAndPublish": false
+ },
+ "pluginOptions": {},
+ "attributes": {
+ "name": {
+ "type": "string",
+ "required": true
+ },
+ "url": {
+ "type": "string"
+ },
+ "isFinancialDonor": {
+ "type": "boolean",
+ "default": false
+ },
+ "isVodProvider": {
+ "type": "boolean"
+ }
+ }
+}
diff --git a/packages/strapi/src/api/contributor/controllers/contributor.js b/packages/strapi/src/api/contributor/controllers/contributor.js
new file mode 100644
index 0000000..22b9cf6
--- /dev/null
+++ b/packages/strapi/src/api/contributor/controllers/contributor.js
@@ -0,0 +1,9 @@
+'use strict';
+
+/**
+ * contributor controller
+ */
+
+const { createCoreController } = require('@strapi/strapi').factories;
+
+module.exports = createCoreController('api::contributor.contributor');
diff --git a/packages/strapi/src/api/contributor/routes/contributor.js b/packages/strapi/src/api/contributor/routes/contributor.js
new file mode 100644
index 0000000..cf61a59
--- /dev/null
+++ b/packages/strapi/src/api/contributor/routes/contributor.js
@@ -0,0 +1,9 @@
+'use strict';
+
+/**
+ * contributor router
+ */
+
+const { createCoreRouter } = require('@strapi/strapi').factories;
+
+module.exports = createCoreRouter('api::contributor.contributor');
diff --git a/packages/strapi/src/api/contributor/services/contributor.js b/packages/strapi/src/api/contributor/services/contributor.js
new file mode 100644
index 0000000..ca75442
--- /dev/null
+++ b/packages/strapi/src/api/contributor/services/contributor.js
@@ -0,0 +1,9 @@
+'use strict';
+
+/**
+ * contributor service
+ */
+
+const { createCoreService } = require('@strapi/strapi').factories;
+
+module.exports = createCoreService('api::contributor.contributor');
diff --git a/packages/strapi/src/api/goal/content-types/goal/schema.json b/packages/strapi/src/api/goal/content-types/goal/schema.json
new file mode 100644
index 0000000..0580c6f
--- /dev/null
+++ b/packages/strapi/src/api/goal/content-types/goal/schema.json
@@ -0,0 +1,30 @@
+{
+ "kind": "collectionType",
+ "collectionName": "goals",
+ "info": {
+ "singularName": "goal",
+ "pluralName": "goals",
+ "displayName": "Goal",
+ "description": ""
+ },
+ "options": {
+ "draftAndPublish": false
+ },
+ "pluginOptions": {},
+ "attributes": {
+ "amountCents": {
+ "type": "string",
+ "required": true,
+ "unique": true
+ },
+ "description": {
+ "type": "string",
+ "required": true,
+ "unique": true
+ },
+ "name": {
+ "type": "string",
+ "unique": true
+ }
+ }
+}
diff --git a/packages/strapi/src/api/goal/controllers/goal.js b/packages/strapi/src/api/goal/controllers/goal.js
new file mode 100644
index 0000000..2b8e3a3
--- /dev/null
+++ b/packages/strapi/src/api/goal/controllers/goal.js
@@ -0,0 +1,9 @@
+'use strict';
+
+/**
+ * goal controller
+ */
+
+const { createCoreController } = require('@strapi/strapi').factories;
+
+module.exports = createCoreController('api::goal.goal');
diff --git a/packages/strapi/src/api/goal/routes/goal.js b/packages/strapi/src/api/goal/routes/goal.js
new file mode 100644
index 0000000..e836728
--- /dev/null
+++ b/packages/strapi/src/api/goal/routes/goal.js
@@ -0,0 +1,9 @@
+'use strict';
+
+/**
+ * goal router
+ */
+
+const { createCoreRouter } = require('@strapi/strapi').factories;
+
+module.exports = createCoreRouter('api::goal.goal');
diff --git a/packages/strapi/src/api/goal/services/goal.js b/packages/strapi/src/api/goal/services/goal.js
new file mode 100644
index 0000000..6c047ac
--- /dev/null
+++ b/packages/strapi/src/api/goal/services/goal.js
@@ -0,0 +1,11 @@
+'use strict';
+
+/**
+ * goal service
+ */
+
+const { createCoreService } = require('@strapi/strapi').factories;
+
+module.exports = createCoreService('api::goal.goal');
+
+
diff --git a/packages/strapi/src/api/gogs/content-types/gogs/schema.json b/packages/strapi/src/api/gogs/content-types/gogs/schema.json
new file mode 100644
index 0000000..d933d5d
--- /dev/null
+++ b/packages/strapi/src/api/gogs/content-types/gogs/schema.json
@@ -0,0 +1,24 @@
+{
+ "kind": "singleType",
+ "collectionName": "gogss",
+ "info": {
+ "singularName": "gogs",
+ "pluralName": "gogss",
+ "displayName": "Gogs"
+ },
+ "options": {
+ "draftAndPublish": false
+ },
+ "pluginOptions": {},
+ "attributes": {
+ "apiKey": {
+ "type": "string",
+ "required": true
+ },
+ "url": {
+ "type": "string",
+ "required": true,
+ "default": "https://git.futureporn.net"
+ }
+ }
+}
diff --git a/packages/strapi/src/api/gogs/controllers/gogs.js b/packages/strapi/src/api/gogs/controllers/gogs.js
new file mode 100644
index 0000000..5d83874
--- /dev/null
+++ b/packages/strapi/src/api/gogs/controllers/gogs.js
@@ -0,0 +1,29 @@
+'use strict';
+
+/**
+ * gogs controller
+ */
+
+const { createCoreController } = require('@strapi/strapi').factories;
+
+module.exports = createCoreController('api::gogs.gogs', ({ strapi }) => ({
+ issues: async (ctx) => {
+ try {
+ // Fetch the 'gogs' single type from Strapi
+ const gogsConfig = await strapi.query('api::gogs.gogs').findOne();
+
+ if (!gogsConfig) {
+ return ctx.badRequest('Gogs configuration not found');
+ }
+
+ const { url, apiKey } = gogsConfig;
+ const openIssues = await strapi.service('api::gogs.gogs').fetchAllPagesFromGogsAPI(`${url}/api/v1/repos/futureporn/pm/issues?state=open`, apiKey)
+ const closedIssues = await strapi.service('api::gogs.gogs').fetchAllPagesFromGogsAPI(`${url}/api/v1/repos/futureporn/pm/issues?state=closed`, apiKey)
+
+ return { openIssues, closedIssues }
+ } catch (error) {
+ console.error('Error fetching Gogs issues:', error);
+ return ctx.badRequest('Failed to fetch issues from Gogs');
+ }
+ }
+}));
\ No newline at end of file
diff --git a/packages/strapi/src/api/gogs/routes/gogs.js b/packages/strapi/src/api/gogs/routes/gogs.js
new file mode 100644
index 0000000..50c6544
--- /dev/null
+++ b/packages/strapi/src/api/gogs/routes/gogs.js
@@ -0,0 +1,34 @@
+'use strict';
+
+/**
+ * gogs router
+ */
+
+const { createCoreRouter } = require('@strapi/strapi').factories;
+
+const defaultRouter = createCoreRouter('api::gogs.gogs');
+
+// greets https://forum.strapi.io/t/how-to-add-custom-routes-to-core-routes-in-strapi-4/14070/7
+const customRouter = (innerRouter, extraRoutes = []) => {
+ let routes;
+ return {
+ get prefix() {
+ return innerRouter.prefix;
+ },
+ get routes() {
+ if (!routes) routes = extraRoutes.concat(innerRouter.routes)
+ return routes;
+ },
+ };
+};
+
+const myExtraRoutes = [
+ {
+ method: "GET",
+ path: "/gogs/issues",
+ handler: "api::gogs.gogs.issues"
+ }
+];
+
+module.exports = customRouter(defaultRouter, myExtraRoutes);
+
diff --git a/packages/strapi/src/api/gogs/services/gogs.js b/packages/strapi/src/api/gogs/services/gogs.js
new file mode 100644
index 0000000..13afb2f
--- /dev/null
+++ b/packages/strapi/src/api/gogs/services/gogs.js
@@ -0,0 +1,42 @@
+'use strict';
+
+/**
+ * gogs service
+ */
+
+const { createCoreService } = require('@strapi/strapi').factories;
+
+
+
+module.exports = createCoreService('api::gogs.gogs', ({ strapi }) => ({
+
+ async fetchAllPagesFromGogsAPI(url, apiKey) {
+
+ // Fetch the first page
+ const response = await fetch(url, {
+ headers: {
+ 'Authorization': `token ${apiKey}`
+ }
+ });
+
+ if (!response.ok) {
+ throw new Error(`Request failed with status: ${response.status}`);
+ }
+
+ const data = await response.json();
+
+ // Check if there are more pages available
+ if (response.headers.has('link')) {
+ const linkHeader = response.headers.get('link');
+ const nextPageMatch = /<([^>]+)>;\s*rel="next"/.exec(linkHeader);
+
+ if (nextPageMatch) {
+ const nextPageUrl = nextPageMatch[1];
+ const nextPageData = await this.fetchAllPagesFromGogsAPI(nextPageUrl, apiKey);
+ return [...data, ...nextPageData];
+ }
+ }
+
+ return data;
+ }
+}))
\ No newline at end of file
diff --git a/packages/strapi/src/api/issue/content-types/issue/schema.json b/packages/strapi/src/api/issue/content-types/issue/schema.json
new file mode 100644
index 0000000..b8c6768
--- /dev/null
+++ b/packages/strapi/src/api/issue/content-types/issue/schema.json
@@ -0,0 +1,36 @@
+{
+ "kind": "collectionType",
+ "collectionName": "issues",
+ "info": {
+ "singularName": "issue",
+ "pluralName": "issues",
+ "displayName": "issue",
+ "description": ""
+ },
+ "options": {
+ "draftAndPublish": false
+ },
+ "pluginOptions": {},
+ "attributes": {
+ "url": {
+ "type": "string",
+ "required": true
+ },
+ "sla": {
+ "type": "enumeration",
+ "enum": [
+ "public",
+ "patron",
+ "authenticated"
+ ],
+ "default": "public",
+ "required": true
+ },
+ "type": {
+ "type": "enumeration",
+ "enum": [
+ "stall"
+ ]
+ }
+ }
+}
diff --git a/packages/strapi/src/api/issue/controllers/issue.js b/packages/strapi/src/api/issue/controllers/issue.js
new file mode 100644
index 0000000..a9c83e3
--- /dev/null
+++ b/packages/strapi/src/api/issue/controllers/issue.js
@@ -0,0 +1,9 @@
+'use strict';
+
+/**
+ * issue controller
+ */
+
+const { createCoreController } = require('@strapi/strapi').factories;
+
+module.exports = createCoreController('api::issue.issue');
diff --git a/packages/strapi/src/api/issue/routes/issue.js b/packages/strapi/src/api/issue/routes/issue.js
new file mode 100644
index 0000000..146d9fe
--- /dev/null
+++ b/packages/strapi/src/api/issue/routes/issue.js
@@ -0,0 +1,9 @@
+'use strict';
+
+/**
+ * issue router
+ */
+
+const { createCoreRouter } = require('@strapi/strapi').factories;
+
+module.exports = createCoreRouter('api::issue.issue');
diff --git a/packages/strapi/src/api/issue/services/issue.js b/packages/strapi/src/api/issue/services/issue.js
new file mode 100644
index 0000000..9782a38
--- /dev/null
+++ b/packages/strapi/src/api/issue/services/issue.js
@@ -0,0 +1,9 @@
+'use strict';
+
+/**
+ * issue service
+ */
+
+const { createCoreService } = require('@strapi/strapi').factories;
+
+module.exports = createCoreService('api::issue.issue');
diff --git a/packages/strapi/src/api/mux-asset/content-types/mux-asset/schema.json b/packages/strapi/src/api/mux-asset/content-types/mux-asset/schema.json
new file mode 100644
index 0000000..736ba34
--- /dev/null
+++ b/packages/strapi/src/api/mux-asset/content-types/mux-asset/schema.json
@@ -0,0 +1,28 @@
+{
+ "kind": "collectionType",
+ "collectionName": "mux_assets",
+ "info": {
+ "singularName": "mux-asset",
+ "pluralName": "mux-assets",
+ "displayName": "Mux Asset",
+ "description": ""
+ },
+ "options": {
+ "draftAndPublish": false
+ },
+ "pluginOptions": {},
+ "attributes": {
+ "playbackId": {
+ "type": "string",
+ "required": false,
+ "unique": true
+ },
+ "assetId": {
+ "type": "string",
+ "unique": true
+ },
+ "deletionQueuedAt": {
+ "type": "datetime"
+ }
+ }
+}
diff --git a/packages/strapi/src/api/mux-asset/controllers/mux-asset.js b/packages/strapi/src/api/mux-asset/controllers/mux-asset.js
new file mode 100644
index 0000000..e02adbc
--- /dev/null
+++ b/packages/strapi/src/api/mux-asset/controllers/mux-asset.js
@@ -0,0 +1,56 @@
+'use strict';
+
+const { JWT } = require('@mux/mux-node');
+
+const MUX_SIGNING_KEY_ID = process.env.MUX_SIGNING_KEY_ID;
+const MUX_SIGNING_KEY_PRIVATE_KEY = process.env.MUX_SIGNING_KEY_PRIVATE_KEY;
+const MUX_PLAYBACK_RESTRICTION_ID = process.env.MUX_PLAYBACK_RESTRICTION_ID
+
+if (!MUX_SIGNING_KEY_PRIVATE_KEY) throw new Error('MUX_SIGNING_KEY_PRIVATE_KEY must be defined in env');
+if (!MUX_SIGNING_KEY_ID) throw new Error('MUX_SIGNING_KEY_ID must be defined in env');
+if (!MUX_PLAYBACK_RESTRICTION_ID) throw new Error('MUX_PLAYBACK_RESTRICTION_ID must be defined in env');
+
+
+/**
+ * mux-asset controller
+ */
+
+const { createCoreController } = require('@strapi/strapi').factories;
+
+module.exports = createCoreController('api::mux-asset.mux-asset', ({ strapi }) => ({
+
+ async secure (ctx, next) {
+
+ if (ctx?.query?.id === undefined) {
+ ctx.throw(400, 'id query param was missing!')
+ return
+ }
+
+ const tokens = {}
+
+ tokens.playbackToken = JWT.signPlaybackId(ctx.query.id, {
+ keyId: MUX_SIGNING_KEY_ID,
+ keySecret: MUX_SIGNING_KEY_PRIVATE_KEY,
+ params: {
+ playback_restriction_id: MUX_PLAYBACK_RESTRICTION_ID
+ },
+ })
+
+
+ tokens.storyboardToken = JWT.signPlaybackId(ctx.query.id, {
+ keyId: MUX_SIGNING_KEY_ID,
+ keySecret: MUX_SIGNING_KEY_PRIVATE_KEY,
+ type: 'storyboard'
+ })
+
+ tokens.thumbnailToken = JWT.signPlaybackId(ctx.query.id, {
+ keyId: MUX_SIGNING_KEY_ID,
+ keySecret: MUX_SIGNING_KEY_PRIVATE_KEY,
+ type: 'thumbnail'
+ })
+
+
+ ctx.body = tokens
+ }
+}))
+
diff --git a/packages/strapi/src/api/mux-asset/routes/mux-asset.js b/packages/strapi/src/api/mux-asset/routes/mux-asset.js
new file mode 100644
index 0000000..2dc38eb
--- /dev/null
+++ b/packages/strapi/src/api/mux-asset/routes/mux-asset.js
@@ -0,0 +1,33 @@
+'use strict';
+
+/**
+ * mux-asset router
+ */
+
+const { createCoreRouter } = require('@strapi/strapi').factories;
+
+const defaultRouter = createCoreRouter('api::mux-asset.mux-asset');
+
+// greets https://forum.strapi.io/t/how-to-add-custom-routes-to-core-routes-in-strapi-4/14070/7
+const customRouter = (innerRouter, extraRoutes = []) => {
+ let routes;
+ return {
+ get prefix() {
+ return innerRouter.prefix;
+ },
+ get routes() {
+ if (!routes) routes = extraRoutes.concat(innerRouter.routes)
+ return routes;
+ },
+ };
+};
+
+const myExtraRoutes = [
+ {
+ method: "GET",
+ path: "/mux-asset/secure",
+ handler: "mux-asset.secure"
+ }
+];
+
+module.exports = customRouter(defaultRouter, myExtraRoutes);
\ No newline at end of file
diff --git a/packages/strapi/src/api/mux-asset/services/mux-asset.js b/packages/strapi/src/api/mux-asset/services/mux-asset.js
new file mode 100644
index 0000000..a4cbcb5
--- /dev/null
+++ b/packages/strapi/src/api/mux-asset/services/mux-asset.js
@@ -0,0 +1,78 @@
+'use strict';
+
+const { JWT } = require('@mux/mux-node');
+const { createCoreService } = require('@strapi/strapi').factories;
+
+/**
+ * mux-asset service
+ */
+
+
+module.exports = createCoreService('api::mux-asset.mux-asset', ({strapi}) => ({
+
+
+ /**
+ * reference: https://docs.mux.com/guides/video/secure-video-playback#4-generate-a-json-web-token-jwt
+ * reference: https://docs.mux.com/guides/video/secure-video-playback#5-sign-the-json-web-token-jwt
+ *
+ * @param {String} playbackId - signed playback ID
+ * @param {String} keyId - signing key ID
+ * @param {String} keySecret - base64 encoded private key
+ * @param {String} playbackRestructionId - https://docs.mux.com/guides/video/secure-video-playback#create-a-playback-restriction
+ * @returns {Object} jwt -
+ * @returns {String} jwt.token -
+ * @returns {String} jwt.gifToken -
+ * @returns {String} jwt.thumbnailToken -
+ */
+ async signJwt (playbackId, keyId, keySecret, playbackRestrictionId) {
+ // Set some base options we can use for a few different signing types
+ // Type can be either video, thumbnail, gif, or storyboard
+ let baseOptions = {
+ keyId: keyId, // Enter your signing key id here
+ keySecret: keySecret, // Enter your base64 encoded private key here
+ expiration: '7d' // E.g 60, "2 days", "10h", "7d", numeric value interpreted as seconds
+ };
+
+ const playbackToken = JWT.signPlaybackId(playbackId, {
+ ...baseOptions ,
+ type: 'video',
+ params: { playback_restriction_id: playbackRestrictionId }
+ });
+
+ // Now the signed playback url should look like this:
+ // https://stream.mux.com/${playbackId}.m3u8?token=${token}
+
+ // If you wanted to pass in params for something like a gif, use the
+ // params key in the options object
+ // const gifToken = JWT.signPlaybackId(playbackId, {
+ // ...baseOptions,
+ // type: 'gif',
+ // params: { time: 10 },
+ // })
+
+ const thumbnailToken = JWT.signPlaybackId(playbackId, {
+ type: 'thumbnail',
+ params: { playback_restriction_id: playbackRestrictionId },
+ })
+
+ // Then, use this token in a URL like this:
+ // https://image.mux.com/${playbackId}/animated.gif?token=${gifToken}
+
+ // A final example, if you wanted to sign a thumbnail url with a playback restriction
+ const storyboardToken = JWT.sign(playbackId, {
+ ...baseOptions,
+ type: 'storyboard',
+ params: { playback_restriction_id: playbackRestrictionId },
+ })
+
+ // When used in a URL, it should look like this:
+ // https://image.mux.com/${playbackId}/thumbnail.png?token=${thumbnailToken}
+
+ return {
+ playbackToken,
+ storyboardToken,
+ thumbnailToken
+ }
+ },
+
+}));
\ No newline at end of file
diff --git a/packages/strapi/src/api/patreon/content-types/patreon/schema.json b/packages/strapi/src/api/patreon/content-types/patreon/schema.json
new file mode 100644
index 0000000..a76213c
--- /dev/null
+++ b/packages/strapi/src/api/patreon/content-types/patreon/schema.json
@@ -0,0 +1,39 @@
+{
+ "kind": "singleType",
+ "collectionName": "patreons",
+ "info": {
+ "singularName": "patreon",
+ "pluralName": "patreons",
+ "displayName": "Patreon",
+ "description": ""
+ },
+ "options": {
+ "draftAndPublish": false
+ },
+ "pluginOptions": {},
+ "attributes": {
+ "benefitId": {
+ "type": "string",
+ "required": true,
+ "default": "4760169"
+ },
+ "accessToken": {
+ "type": "string"
+ },
+ "refreshToken": {
+ "type": "string"
+ },
+ "campaignId": {
+ "type": "string",
+ "required": true
+ },
+ "muxAllocationCostCents": {
+ "type": "integer",
+ "default": 50,
+ "required": true
+ },
+ "membershipId": {
+ "type": "string"
+ }
+ }
+}
diff --git a/packages/strapi/src/api/patreon/controllers/patreon.js b/packages/strapi/src/api/patreon/controllers/patreon.js
new file mode 100644
index 0000000..c06944a
--- /dev/null
+++ b/packages/strapi/src/api/patreon/controllers/patreon.js
@@ -0,0 +1,37 @@
+'use strict';
+
+/**
+ * patreon controller
+ */
+
+const { createCoreController } = require('@strapi/strapi').factories;
+
+module.exports = createCoreController('api::patreon.patreon', ({ strapi }) => ({
+ async getPublicPatrons(ctx) {
+ const patrons = await strapi.entityService.findMany('plugin::users-permissions.user', {
+ fields: ['username', 'vanityLink', 'isNamePublic', 'isLinkPublic', 'patreonBenefits'],
+ })
+
+ let publicPatrons = []
+ for (const patron of patrons) {
+ let publicPatron = {}
+ let benefits = (!!patron?.patreonBenefits) ? patron.patreonBenefits.split(',') : []
+ if (patron.isNamePublic) publicPatron.username = patron.username;
+
+ // if patron has "Your URL displayed on Futureporn.net" benefit,
+ // publically share their link if they want it shared
+ if (benefits.includes('10663202')) {
+ if (patron.isLinkPublic) publicPatron.vanityLink = patron.vanityLink;
+ }
+
+ if (!!publicPatron.username || !!publicPatron.vanityLink) publicPatrons.push(publicPatron);
+ }
+
+ return publicPatrons
+ },
+ async muxAllocationCount(ctx) {
+ const count = await strapi.service('api::patreon.patreon').getMuxAllocationCount()
+ return count
+ }
+}));
+
diff --git a/packages/strapi/src/api/patreon/routes/patreon.js b/packages/strapi/src/api/patreon/routes/patreon.js
new file mode 100644
index 0000000..52af951
--- /dev/null
+++ b/packages/strapi/src/api/patreon/routes/patreon.js
@@ -0,0 +1,37 @@
+'use strict';
+
+/**
+ * patreon router
+ */
+
+const { createCoreRouter } = require('@strapi/strapi').factories;
+
+const defaultRouter = createCoreRouter('api::patreon.patreon');
+
+// greets https://forum.strapi.io/t/how-to-add-custom-routes-to-core-routes-in-strapi-4/14070/7
+const customRouter = (innerRouter, extraRoutes = []) => {
+ let routes;
+ return {
+ get prefix() {
+ return innerRouter.prefix;
+ },
+ get routes() {
+ if (!routes) routes = extraRoutes.concat(innerRouter.routes)
+ return routes;
+ },
+ };
+};
+
+const myExtraRoutes = [
+ {
+ method: "GET",
+ path: "/patreon/patrons",
+ handler: "api::patreon.patreon.getPublicPatrons"
+ }, {
+ method: 'GET',
+ path: '/patreon/muxAllocationCount',
+ handler: 'api::patreon.patreon.muxAllocationCount'
+ }
+];
+
+module.exports = customRouter(defaultRouter, myExtraRoutes);
\ No newline at end of file
diff --git a/packages/strapi/src/api/patreon/services/patreon.js b/packages/strapi/src/api/patreon/services/patreon.js
new file mode 100644
index 0000000..147d2a4
--- /dev/null
+++ b/packages/strapi/src/api/patreon/services/patreon.js
@@ -0,0 +1,45 @@
+'use strict';
+
+/**
+ * patreon service
+ */
+
+const EleventyFetch = require("@11ty/eleventy-fetch");
+const { createCoreService } = require('@strapi/strapi').factories;
+
+
+
+module.exports = createCoreService('api::patreon.patreon', ({strapi}) => ({
+
+
+ async getPatreonCampaign() {
+ return EleventyFetch('https://www.patreon.com/api/campaigns/8012692', {
+ duration: "12h",
+ type: "json",
+ })
+ },
+
+
+ async getPatreonCampaignPledgeSum() {
+ const campaign = await this.getPatreonCampaign()
+ return campaign.data.attributes.pledge_sum
+ },
+
+
+ /**
+ * Calculate how many mux allocations the site should have, based on the dollar amount of pledges from patreon
+ *
+ * @param {Number} pledgeSum - USD cents
+ */
+ async getMuxAllocationCount() {
+ const patreonData = await strapi.entityService.findMany('api::patreon.patreon', {
+ fields: ['muxAllocationCostCents']
+ })
+ if (!patreonData) throw new Error('patreonData in Strapi was missing');
+ const muxAllocationCostCents = patreonData.muxAllocationCostCents
+ const pledgeSum = await this.getPatreonCampaignPledgeSum()
+ const muxAllocationCount = Math.floor(pledgeSum / muxAllocationCostCents); // calculate the number of mux allocations required
+ return muxAllocationCount;
+ }
+}));
+
diff --git a/packages/strapi/src/api/profile/controllers/profile.js b/packages/strapi/src/api/profile/controllers/profile.js
new file mode 100644
index 0000000..610a88d
--- /dev/null
+++ b/packages/strapi/src/api/profile/controllers/profile.js
@@ -0,0 +1,21 @@
+'use strict';
+
+
+
+module.exports = {
+ update: async (ctx, next) => {
+ const update = strapi.plugin('users-permissions').controllers.user.update
+ await update(ctx);
+ },
+ me: async (ctx) => {
+ const userId = ctx?.state?.user?.id;
+ if (!userId) return ctx.badRequest("There was no user id in the request!");
+ const user = await strapi.entityService.findOne('plugin::users-permissions.user', userId, {
+ populate: 'role'
+ });
+ return user
+ },
+ test: async (ctx) => {
+ return 'blah'
+ }
+};
diff --git a/packages/strapi/src/api/profile/routes/profile.js b/packages/strapi/src/api/profile/routes/profile.js
new file mode 100644
index 0000000..7a33f1c
--- /dev/null
+++ b/packages/strapi/src/api/profile/routes/profile.js
@@ -0,0 +1,23 @@
+module.exports = {
+ routes: [
+ {
+ method: 'PUT',
+ path: '/profile/:id',
+ handler: 'profile.update',
+ config: {
+ prefix: '',
+ policies: ['global::updateOwnerOnly']
+ },
+ },
+ {
+ method: 'GET',
+ path: '/profile/me',
+ handler: 'profile.me'
+ },
+ {
+ method: 'GET',
+ path: '/profile/test',
+ handler: 'profile.test'
+ }
+ ],
+};
diff --git a/packages/strapi/src/api/profile/services/profile.js b/packages/strapi/src/api/profile/services/profile.js
new file mode 100644
index 0000000..56ac091
--- /dev/null
+++ b/packages/strapi/src/api/profile/services/profile.js
@@ -0,0 +1,7 @@
+'use strict';
+
+/**
+ * profile service
+ */
+
+module.exports = () => ({});
diff --git a/packages/strapi/src/api/stream/content-types/stream/lifecycles.js b/packages/strapi/src/api/stream/content-types/stream/lifecycles.js
new file mode 100644
index 0000000..661c14e
--- /dev/null
+++ b/packages/strapi/src/api/stream/content-types/stream/lifecycles.js
@@ -0,0 +1,61 @@
+const { init } = require('@paralleldrive/cuid2');
+
+
+
+module.exports = {
+ async beforeUpdate(event) {
+ const { data } = event.params;
+ if (!data.cuid) {
+ const length = 10; // 50% odds of collision after ~51,386,368 ids
+ const cuid = init({ length });
+ event.params.data.cuid = cuid();
+ }
+ },
+ async afterUpdate(event) {
+ console.log(`>>>>>>>>>>>>>> STREAM is afterUpdate !!!!!!!!!!!!`);
+
+ const { data, where, select, populate } = event.params;
+
+ console.log(data);
+
+ const id = where.id;
+
+ // greets https://forum.strapi.io/t/how-to-get-previous-component-data-in-lifecycle-hook/25892/4?u=ggr247
+ const existingData = await strapi.entityService.findOne("api::stream.stream", id, {
+ populate: ['vods', 'tweet']
+ })
+
+ // Initialize archiveStatus to a default value
+ let archiveStatus = 'missing';
+
+ // Iterate through all vods to determine archiveStatus
+ for (const vod of existingData.vods) {
+ if (!!vod.videoSrcHash) {
+ if (!!vod.note) {
+ // If a vod has both videoSrcHash and note, set archiveStatus to 'issue'
+ archiveStatus = 'issue';
+ break; // No need to check further
+ } else {
+ // If a vod has videoSrcHash but no note, set archiveStatus to 'good'
+ archiveStatus = 'good';
+ }
+ }
+ }
+
+ // we can't use query engine here, because that would trigger an infinite loop
+ // where this
+ // instead we access knex instance
+ await strapi.db.connection("streams").where({ id: id }).update({
+ archive_status: archiveStatus,
+ });
+
+ if (!!existingData.tweet) {
+ await strapi.db.connection("streams").where({ id: id }).update({
+ is_chaturbate_stream: existingData.tweet.isChaturbateInvite,
+ is_fansly_stream: existingData.tweet.isFanslyInvite
+ });
+ }
+
+
+ }
+};
\ No newline at end of file
diff --git a/packages/strapi/src/api/stream/content-types/stream/schema.json b/packages/strapi/src/api/stream/content-types/stream/schema.json
new file mode 100644
index 0000000..1506582
--- /dev/null
+++ b/packages/strapi/src/api/stream/content-types/stream/schema.json
@@ -0,0 +1,73 @@
+{
+ "kind": "collectionType",
+ "collectionName": "streams",
+ "info": {
+ "singularName": "stream",
+ "pluralName": "streams",
+ "displayName": "Stream",
+ "description": ""
+ },
+ "options": {
+ "draftAndPublish": false
+ },
+ "pluginOptions": {},
+ "attributes": {
+ "date_str": {
+ "type": "string",
+ "required": true,
+ "unique": true,
+ "regex": "\\d{4}-[01]\\d-[0-3]\\dT[0-2]\\d:[0-5]\\d:[0-5]\\d\\.\\d+([+-][0-2]\\d:[0-5]\\d|Z)"
+ },
+ "date2": {
+ "type": "string",
+ "required": true,
+ "unique": true,
+ "regex": "\\d{4}-[01]\\d-[0-3]\\dT[0-2]\\d:[0-5]\\d:[0-5]\\d\\.\\d+([+-][0-2]\\d:[0-5]\\d|Z)"
+ },
+ "vods": {
+ "type": "relation",
+ "relation": "oneToMany",
+ "target": "api::vod.vod",
+ "mappedBy": "stream"
+ },
+ "vtuber": {
+ "type": "relation",
+ "relation": "manyToOne",
+ "target": "api::vtuber.vtuber",
+ "inversedBy": "streams"
+ },
+ "tweet": {
+ "type": "relation",
+ "relation": "oneToOne",
+ "target": "api::tweet.tweet"
+ },
+ "date": {
+ "type": "datetime",
+ "required": true,
+ "unique": true
+ },
+ "archiveStatus": {
+ "type": "enumeration",
+ "enum": [
+ "missing",
+ "issue",
+ "good"
+ ],
+ "required": true,
+ "default": "missing"
+ },
+ "cuid": {
+ "type": "string",
+ "unique": true,
+ "required": false
+ },
+ "isChaturbateStream": {
+ "type": "boolean",
+ "default": false
+ },
+ "isFanslyStream": {
+ "type": "boolean",
+ "default": false
+ }
+ }
+}
diff --git a/packages/strapi/src/api/stream/controllers/stream.js b/packages/strapi/src/api/stream/controllers/stream.js
new file mode 100644
index 0000000..aaee46e
--- /dev/null
+++ b/packages/strapi/src/api/stream/controllers/stream.js
@@ -0,0 +1,9 @@
+'use strict';
+
+/**
+ * stream controller
+ */
+
+const { createCoreController } = require('@strapi/strapi').factories;
+
+module.exports = createCoreController('api::stream.stream');
diff --git a/packages/strapi/src/api/stream/routes/stream.js b/packages/strapi/src/api/stream/routes/stream.js
new file mode 100644
index 0000000..6af6923
--- /dev/null
+++ b/packages/strapi/src/api/stream/routes/stream.js
@@ -0,0 +1,9 @@
+'use strict';
+
+/**
+ * stream router
+ */
+
+const { createCoreRouter } = require('@strapi/strapi').factories;
+
+module.exports = createCoreRouter('api::stream.stream');
diff --git a/packages/strapi/src/api/stream/services/stream.js b/packages/strapi/src/api/stream/services/stream.js
new file mode 100644
index 0000000..b0311da
--- /dev/null
+++ b/packages/strapi/src/api/stream/services/stream.js
@@ -0,0 +1,9 @@
+'use strict';
+
+/**
+ * stream service
+ */
+
+const { createCoreService } = require('@strapi/strapi').factories;
+
+module.exports = createCoreService('api::stream.stream');
diff --git a/packages/strapi/src/api/tag-vod-relation/content-types/tag-vod-relation/schema.json b/packages/strapi/src/api/tag-vod-relation/content-types/tag-vod-relation/schema.json
new file mode 100644
index 0000000..129ef5a
--- /dev/null
+++ b/packages/strapi/src/api/tag-vod-relation/content-types/tag-vod-relation/schema.json
@@ -0,0 +1,39 @@
+{
+ "kind": "collectionType",
+ "collectionName": "tag_vod_relations",
+ "info": {
+ "singularName": "tag-vod-relation",
+ "pluralName": "tag-vod-relations",
+ "displayName": "Tag Vod Relation",
+ "description": ""
+ },
+ "options": {
+ "draftAndPublish": false
+ },
+ "pluginOptions": {},
+ "attributes": {
+ "votes": {
+ "type": "integer"
+ },
+ "creator": {
+ "type": "relation",
+ "relation": "oneToOne",
+ "target": "plugin::users-permissions.user"
+ },
+ "tag": {
+ "type": "relation",
+ "relation": "oneToOne",
+ "target": "api::tag.tag"
+ },
+ "creatorId": {
+ "type": "integer",
+ "required": true
+ },
+ "vod": {
+ "type": "relation",
+ "relation": "manyToOne",
+ "target": "api::vod.vod",
+ "inversedBy": "tagVodRelations"
+ }
+ }
+}
diff --git a/packages/strapi/src/api/tag-vod-relation/controllers/tag-vod-relation.js b/packages/strapi/src/api/tag-vod-relation/controllers/tag-vod-relation.js
new file mode 100644
index 0000000..8face45
--- /dev/null
+++ b/packages/strapi/src/api/tag-vod-relation/controllers/tag-vod-relation.js
@@ -0,0 +1,222 @@
+'use strict';
+
+/**
+ * tag-vod-relation controller
+ */
+
+const { createCoreController } = require('@strapi/strapi').factories;
+
+module.exports = createCoreController('api::tag-vod-relation.tag-vod-relation', ({ strapi }) => ({
+ async relate(ctx) {
+
+ const userId = ctx?.state?.user?.id;
+ if (!userId) return ctx.badRequest("There was no user id in the request!");
+ if (!ctx.request.body.data) return ctx.badRequest('data was missing from body');
+ if (!ctx.request.body.data.tag) return ctx.badRequest('tag was missing from data');
+ if (!ctx.request.body.data.vod) return ctx.badRequest('vod was missing from data');
+
+ const { tag: tagId, vod: vodId } = ctx.request.body.data;
+
+ const tagVodRelation = await strapi.entityService.create('api::tag-vod-relation.tag-vod-relation', {
+ data: {
+ vod: vodId,
+ tag: tagId,
+ creator: userId,
+ creatorId: userId,
+ publishedAt: new Date(),
+ votes: 2
+ }
+ })
+
+ return tagVodRelation
+ },
+ async vote(ctx) {
+ // @todo
+ },
+
+ // // greets https://docs.strapi.io/dev-docs/backend-customization/controllers#extending-core-controllers
+ // // greets https://docs.strapi.io/dev-docs/backend-customization/controllers#adding-a-new-controller
+ // // Method 2: Wrapping a core action (leaves core logic in place)
+ // async find(ctx) {
+ // // // some custom logic here
+ // // ctx.query = { ...ctx.query, local: 'en' }
+
+ // const userId = ctx?.state?.user?.id;
+ // if (!userId) return ctx.badRequest("There was no user id in the request!");
+
+
+
+ // // Calling the default core action
+ // const { data, meta } = await super.find(ctx);
+
+ // // add isCreator if the tvr was created by this user
+ // let dataWithCreator = data.map((d) => {
+ // if (d.data.attributes.)
+ // })
+
+ // // // some more custom logic
+ // // meta.date = Date.now()
+
+ // return { data, meta };
+ // },
+
+ // greets https://docs.strapi.io/dev-docs/backend-customization/controllers#extending-core-controllers
+ // greets https://docs.strapi.io/dev-docs/backend-customization/controllers#adding-a-new-controller
+ // Method 2: Wrapping a core action (leaves core logic in place)
+ async create(ctx) {
+ console.log('>> create a tag vod relation')
+ // only allow unique tag, vod combos
+
+ const { query } = ctx.request;
+
+ const userId = ctx?.state?.user?.id;
+ if (!userId) return ctx.badRequest("There was no user id in the request!");
+ if (!ctx.request.body.data) return ctx.badRequest('data was missing from body');
+ if (!ctx.request.body.data.tag) return ctx.badRequest('tag was missing from data');
+ if (!ctx.request.body.data.vod) return ctx.badRequest('vod was missing from data');
+
+ const { tag: tagId, vod: vodId } = ctx.request.body.data;
+
+ console.log(`lets make a combo entityService.findMany`)
+ const combo = await strapi.entityService.findMany('api::tag-vod-relation.tag-vod-relation', {
+ populate: ['tag', 'vod'],
+ filters: {
+ $and: [{
+ tag: {
+ id: {
+ $eq: ctx.request.body.data.tag
+ }
+ }
+ }, {
+ vod: {
+ id: {
+ $eq: ctx.request.body.data.vod
+ }
+ }
+ }]
+ }
+ })
+
+ if (combo.length > 0) {
+ return ctx.badRequest('this vod already has that tag');
+ }
+
+ // @todo add votes and creator
+ ctx.request.body.data.creator = userId
+ ctx.request.body.data.votes = 2
+
+ const parseBody = (ctx) => {
+ if (ctx.is('multipart')) {
+ return parseMultipartData(ctx);
+ }
+
+ const { data } = ctx.request.body || {};
+
+ return { data };
+ };
+
+
+ const sanitizedInputData = {
+ vod: vodId,
+ tag: tagId,
+ publishedAt: new Date(),
+ creator: userId,
+ creatorId: userId,
+ votes: 2
+ }
+
+
+
+
+
+ const entity = await strapi
+ .service('api::tag-vod-relation.tag-vod-relation')
+ .create({
+ ...query,
+ data: sanitizedInputData,
+ populate: { vod: true, tag: true }
+ });
+
+ const sanitizedEntity = await this.sanitizeOutput(entity, ctx);
+
+ return this.transformResponse({ ...sanitizedEntity });
+ },
+
+
+ async tagVod (ctx) {
+
+ // create tag if needed
+ const userId = ctx?.state?.user?.id;
+ if (!userId) return ctx.badRequest("There was no user id in the request!");
+ if (!ctx.request.body.data) return ctx.badRequest('data was missing from body');
+ if (!ctx.request.body.data.tagName) return ctx.badRequest('tagName was missing from data');
+ if (!ctx.request.body.data.vodId) return ctx.badRequest('vodId was missing from data');
+
+ const { tagName, vodId } = ctx.request.body.data;
+
+
+ const tag = await strapi.service('api::tag.tag').assertTag(tagName, userId);
+
+
+ try {
+ const tvr = await strapi.service('api::tag-vod-relation.tag-vod-relation').assertTvr(tag.id, vodId, userId);
+
+
+ const sanitizedEntity = await this.sanitizeOutput(tvr, ctx);
+ return this.transformResponse({ ...sanitizedEntity });
+ } catch (e) {
+ console.error(e)
+ ctx.badRequest('Vod Tag could not be created.')
+ }
+
+ },
+
+ async deleteMine (ctx) {
+ // // some custom logic here
+ // ctx.query = { ...ctx.query, local: 'en' }
+
+
+
+ const userId = ctx?.state?.user?.id;
+ if (!userId) return ctx.badRequest("There was no user id in the request!");
+ if (!ctx.request.params.id) return ctx.badRequest('id was missing from params');
+ const { id } = ctx.request.params;
+
+ // constraints
+ // only able to delete tagVodRelation if
+ // * creator
+ // * publishedAt isBefore(now-24h)
+
+
+ // get the tvr the user wants to delete
+ const tvrToDelete = await strapi.entityService.findOne('api::tag-vod-relation.tag-vod-relation', id, {
+ populate: {
+ tag: true,
+ vod: true,
+ creator: true,
+ }
+ })
+
+ if (!tvrToDelete) return ctx.badRequest('Tag to be deleted does not exist.');
+
+ if (tvrToDelete.creator.id !== userId)
+ ctx.forbidden('only the creator of the tag can delete it');
+
+ if ((new Date(tvrToDelete.createdAt).valueOf()+86400000) < new Date().valueOf())
+ ctx.forbidden('cannot delete tags older than 24 hours')
+
+ // Calling the default core action
+ const { data, meta } = await super.delete(ctx);
+
+ // delete the related tag if it has no other vod
+ // @todo?? or maybe this is handled by lifecycle hook?
+
+ // // some more custom logic
+ // meta.date = Date.now()
+
+ return { data, meta };
+ }
+
+
+}));
+
diff --git a/packages/strapi/src/api/tag-vod-relation/routes/tag-vod-relation.js b/packages/strapi/src/api/tag-vod-relation/routes/tag-vod-relation.js
new file mode 100644
index 0000000..2564f0f
--- /dev/null
+++ b/packages/strapi/src/api/tag-vod-relation/routes/tag-vod-relation.js
@@ -0,0 +1,51 @@
+'use strict';
+
+/**
+ * tag-vod-relation router
+ */
+
+const { createCoreRouter } = require('@strapi/strapi').factories;
+
+const defaultRouter = createCoreRouter('api::tag-vod-relation.tag-vod-relation');
+
+// greets https://forum.strapi.io/t/how-to-add-custom-routes-to-core-routes-in-strapi-4/14070/7
+const customRouter = (innerRouter, extraRoutes = []) => {
+ let routes;
+ return {
+ get prefix() {
+ return innerRouter.prefix;
+ },
+ get routes() {
+ if (!routes) routes = extraRoutes.concat(innerRouter.routes)
+ return routes;
+ },
+ };
+};
+
+const myExtraRoutes = [
+ {
+ method: "POST",
+ path: "/tag-vod-relations/relate",
+ handler: "api::tag-vod-relation.tag-vod-relation.relate"
+ },
+ // {
+ // method: 'GET',
+ // path: '/tag-vod-relations',
+ // handler: 'api::tag-vod-relation.tag-vod-relation.find'
+ // },
+ {
+ method: "PUT",
+ path: "/tag-vod-relations/vote",
+ handler: "api::tag-vod-relation.tag-vod-relation.vote"
+ }, {
+ method: 'POST',
+ path: '/tag-vod-relations/tag',
+ handler: 'api::tag-vod-relation.tag-vod-relation.tagVod'
+ }, {
+ method: 'DELETE',
+ path: '/tag-vod-relations/deleteMine/:id',
+ handler: 'api::tag-vod-relation.tag-vod-relation.deleteMine'
+ }
+];
+
+module.exports = customRouter(defaultRouter, myExtraRoutes);
\ No newline at end of file
diff --git a/packages/strapi/src/api/tag-vod-relation/services/tag-vod-relation.js b/packages/strapi/src/api/tag-vod-relation/services/tag-vod-relation.js
new file mode 100644
index 0000000..e958bbc
--- /dev/null
+++ b/packages/strapi/src/api/tag-vod-relation/services/tag-vod-relation.js
@@ -0,0 +1,69 @@
+'use strict';
+
+/**
+ * tag-vod-relation service
+ */
+
+const { createCoreService } = require('@strapi/strapi').factories;
+
+module.exports = createCoreService('api::tag-vod-relation.tag-vod-relation', ({ strapi }) => ({
+
+
+ async assertTvr(tagId, vodId, userId) {
+
+ if (!tagId) throw new Error('tagId was missing in request');
+ if (!vodId) throw new Error('vodId was missing in request');
+ if (!userId) throw new Error('userId was missing in request');
+
+
+
+ let existingTvr;
+ existingTvr = await strapi.entityService
+ .findMany('api::tag-vod-relation.tag-vod-relation', {
+ limit: 1,
+ filters: {
+ $and: [
+ {
+ tag: {
+ id: tagId,
+ },
+ },
+ {
+ vod: {
+ id: vodId
+ }
+ }
+ ]
+ },
+ populate: ['tag', 'vod']
+ })
+
+
+ if (existingTvr.length === 0) {
+ const newTvr = await strapi.entityService.create('api::tag-vod-relation.tag-vod-relation', {
+ data: {
+ tag: tagId,
+ vod: vodId,
+ creator: userId,
+ creatorId: userId,
+ },
+ populate: {
+ tag: true,
+ vod: true
+ }
+ })
+
+ // trigger data revalidation in next.js server
+ // fetch(`${nextJsServerUrl}/`)
+ return newTvr;
+ } else {
+
+ return existingTvr[0];
+ }
+
+
+ },
+
+}));
+
+
diff --git a/packages/strapi/src/api/tag/content-types/tag/schema.json b/packages/strapi/src/api/tag/content-types/tag/schema.json
new file mode 100644
index 0000000..2884619
--- /dev/null
+++ b/packages/strapi/src/api/tag/content-types/tag/schema.json
@@ -0,0 +1,38 @@
+{
+ "kind": "collectionType",
+ "collectionName": "tags",
+ "info": {
+ "singularName": "tag",
+ "pluralName": "tags",
+ "displayName": "Tag",
+ "description": ""
+ },
+ "options": {
+ "draftAndPublish": true
+ },
+ "pluginOptions": {},
+ "attributes": {
+ "name": {
+ "type": "string",
+ "unique": true,
+ "required": true
+ },
+ "toy": {
+ "type": "relation",
+ "relation": "manyToOne",
+ "target": "api::toy.toy",
+ "inversedBy": "tags"
+ },
+ "vods": {
+ "type": "relation",
+ "relation": "manyToMany",
+ "target": "api::vod.vod",
+ "inversedBy": "tags"
+ },
+ "creator": {
+ "type": "relation",
+ "relation": "oneToOne",
+ "target": "plugin::users-permissions.user"
+ }
+ }
+}
diff --git a/packages/strapi/src/api/tag/controllers/tag.js b/packages/strapi/src/api/tag/controllers/tag.js
new file mode 100644
index 0000000..51669a9
--- /dev/null
+++ b/packages/strapi/src/api/tag/controllers/tag.js
@@ -0,0 +1,87 @@
+'use strict';
+
+/**
+ * tag controller
+ */
+
+const { createCoreController } = require('@strapi/strapi').factories;
+const { sanitize } = require('@strapi/utils');
+
+
+module.exports = createCoreController('api::tag.tag', ({ strapi }) => ({
+
+ async random(ctx) {
+ const numberOfTags = 10; // Change this number to the desired number of random tags
+ const contentType = strapi.contentType('api::vod.vod');
+
+ // Fetch only the 'id' field of all tags
+ const tagIds = (await strapi.entityService.findMany(
+ "api::tag.tag",
+ {
+ fields: ['id'],
+ }
+ )).map(tag => tag.id);
+
+
+ const selectedTags = [];
+
+ // Randomly select the specified number of tag IDs
+ for (let i = 0; i < numberOfTags; i++) {
+ const randomIndex = Math.floor(Math.random() * tagIds.length);
+ const randomTagId = tagIds[randomIndex];
+
+
+ // Fetch the full details of the randomly selected tag using its ID
+ const rawTag = await strapi.entityService.findOne(
+ "api::tag.tag",
+ randomTagId, // Use the tag's ID
+ {
+ filter: {
+ publishedAt: {
+ $notNull: true,
+ },
+ },
+ fields: ['id', 'name']
+ }
+ );
+
+ selectedTags.push(await sanitize.contentAPI.output(rawTag, contentType, { auth: ctx.state.auth }));
+
+ // Remove the selected tag ID from the array to avoid duplicates
+ tagIds.splice(randomIndex, 1);
+ }
+
+ ctx.body = selectedTags;
+ },
+
+
+
+ async createTagRelation(ctx) {
+
+ // we have this controller which associates a tag with a vod
+ // this exists so users can indirectly update vod records which they dont have permissions to update
+ // first we need to get the user's request.
+ // they are telling us a vod ID and a tag ID
+ // our job is to get a reference to the vod, and add the tag relation.
+
+ if (!ctx.request.body.data) return ctx.badRequest('data was missing from body');
+ if (!ctx.request.body.data.tag) return ctx.badRequest('tag was missing from data');
+ if (!ctx.request.body.data.vod) return ctx.badRequest('vod was missing from data');
+
+ const { tag, vod: vodId } = ctx.request.body.data;
+
+
+
+ await strapi.entityService.update('api::vod.vod', vodId, {
+ data: {
+ tags: {
+ connect: [tag]
+ }
+ }
+ })
+
+ return 'OK'
+
+ },
+}));
+
diff --git a/packages/strapi/src/api/tag/routes/tag.js b/packages/strapi/src/api/tag/routes/tag.js
new file mode 100644
index 0000000..db82f8f
--- /dev/null
+++ b/packages/strapi/src/api/tag/routes/tag.js
@@ -0,0 +1,37 @@
+'use strict';
+
+/**
+ * tag router
+ */
+
+const { createCoreRouter } = require('@strapi/strapi').factories;
+const defaultRouter = createCoreRouter('api::tag.tag');
+
+// greets https://forum.strapi.io/t/how-to-add-custom-routes-to-core-routes-in-strapi-4/14070/7
+const customRouter = (innerRouter, extraRoutes = []) => {
+ let routes;
+ return {
+ get prefix() {
+ return innerRouter.prefix;
+ },
+ get routes() {
+ if (!routes) routes = extraRoutes.concat(innerRouter.routes)
+ return routes;
+ },
+ };
+};
+
+const myExtraRoutes = [
+ {
+ method: "POST",
+ path: "/tag/tagRelation",
+ handler: "api::tag.tag.createTagRelation"
+ },
+ {
+ method: 'GET',
+ path: '/tag/random',
+ handler: 'api::tag.tag.random'
+ }
+];
+
+module.exports = customRouter(defaultRouter, myExtraRoutes)
diff --git a/packages/strapi/src/api/tag/services/tag.js b/packages/strapi/src/api/tag/services/tag.js
new file mode 100644
index 0000000..538bebc
--- /dev/null
+++ b/packages/strapi/src/api/tag/services/tag.js
@@ -0,0 +1,46 @@
+'use strict';
+
+/**
+ * tag service
+ */
+
+const { createCoreService } = require('@strapi/strapi').factories;
+
+module.exports = createCoreService('api::tag.tag', ({ strapi }) => ({
+ async assertTag(tagName, userId) {
+
+ if (!tagName) throw new Error('tagName was missing from request');
+ if (!userId) throw new Error('userId was missing from request');
+
+ let tagEntry;
+
+ // does the named tag already exist?
+ // tagEntry = await strapi.db.query('api::tag.tag')
+ // .findOne({ where: { name: tagName } });
+ tagEntry = (await strapi.entityService.findMany('api::tag.tag', {
+ limit: 1,
+ filters: {
+ $and: [
+ {
+ publishedAt: { $notNull: true },
+ },
+ {
+ name: tagName
+ }
+ ]
+ }
+ }))[0]
+
+ if (!tagEntry) {
+ tagEntry = await strapi.entityService.create('api::tag.tag', {
+ data: {
+ name: tagName,
+ creator: userId,
+ publishedAt: new Date(),
+ }
+ })
+ }
+
+ return tagEntry;
+ },
+}));
diff --git a/packages/strapi/src/api/timestamp/content-types/timestamp/schema.json b/packages/strapi/src/api/timestamp/content-types/timestamp/schema.json
new file mode 100644
index 0000000..71b8ffb
--- /dev/null
+++ b/packages/strapi/src/api/timestamp/content-types/timestamp/schema.json
@@ -0,0 +1,47 @@
+{
+ "kind": "collectionType",
+ "collectionName": "timestamps",
+ "info": {
+ "singularName": "timestamp",
+ "pluralName": "timestamps",
+ "displayName": "Timestamp",
+ "description": ""
+ },
+ "options": {
+ "draftAndPublish": false,
+ "populateCreatorFields": true
+ },
+ "pluginOptions": {},
+ "attributes": {
+ "time": {
+ "type": "integer",
+ "required": true
+ },
+ "tag": {
+ "type": "relation",
+ "relation": "oneToOne",
+ "target": "api::tag.tag",
+ "required": true
+ },
+ "vod": {
+ "type": "relation",
+ "relation": "manyToOne",
+ "target": "api::vod.vod",
+ "inversedBy": "timestamps"
+ },
+ "creatorId": {
+ "type": "integer",
+ "required": true
+ },
+ "upvoters": {
+ "type": "relation",
+ "relation": "oneToMany",
+ "target": "plugin::users-permissions.user"
+ },
+ "downvoters": {
+ "type": "relation",
+ "relation": "oneToMany",
+ "target": "plugin::users-permissions.user"
+ }
+ }
+}
diff --git a/packages/strapi/src/api/timestamp/controllers/timestamp.js b/packages/strapi/src/api/timestamp/controllers/timestamp.js
new file mode 100644
index 0000000..a131f44
--- /dev/null
+++ b/packages/strapi/src/api/timestamp/controllers/timestamp.js
@@ -0,0 +1,166 @@
+'use strict';
+
+/**
+ * timestamp controller
+ */
+
+const { createCoreController } = require('@strapi/strapi').factories;
+
+module.exports = createCoreController('api::timestamp.timestamp', ({ strapi }) => ({
+
+
+ async find(ctx) {
+ const { data, meta } = await super.find(ctx);
+
+ // Iterate over each timestamp in the data array
+ const timestampsWithVotes = await Promise.all(data.map(async (timestamp) => {
+ // Retrieve the upvoters count for the current timestamp
+ // Retrieve the downvoters count for the current timestamp
+ const entry = await strapi.db
+ .query('api::timestamp.timestamp')
+ .findOne({
+ populate: ['upvoters', 'downvoters'],
+ where: {
+ id: timestamp.id
+ }
+ });
+
+ const upvotesCount = entry.upvoters.length
+ const downvotesCount = entry.downvoters.length
+
+ // Create new properties "upvotes" and "downvotes" on the timestamp object
+ timestamp.attributes.upvotes = upvotesCount;
+ timestamp.attributes.downvotes = downvotesCount;
+
+ return timestamp;
+ }));
+
+
+ return { data: timestampsWithVotes, meta };
+ },
+
+
+ async assert(ctx) {
+ const userId = ctx?.state?.user?.id;
+ if (!userId) return ctx.badRequest("There was no user id in the request!");
+ if (!ctx.request.body.data) return ctx.badRequest('data was missing from body');
+ if (!ctx.request.body.data.tagId) return ctx.badRequest('tagId was missing from data');
+ if (ctx.request.body.data.time === undefined || ctx.request.body.data.time === null || ctx.request.body.data.time < 0) return ctx.badRequest('time was missing from data');
+ if (!ctx.request.body.data.vodId) return ctx.badRequest('vodId was missing from data');
+ const { time, tagId, vodId } = ctx.request.body.data;
+ const timestamp = await strapi.service('api::timestamp.timestamp').assertTimestamp(userId, tagId, vodId, time);
+ return timestamp;
+ },
+
+
+ // greets https://docs.strapi.io/dev-docs/backend-customization/controllers#extending-core-controllers
+ // greets https://docs.strapi.io/dev-docs/backend-customization/controllers#adding-a-new-controller
+ // Method 2: Wrapping a core action (leaves core logic in place)
+ async create(ctx) {
+ // add creatorId to the record
+ const userId = ctx?.state?.user?.id;
+ if (!userId) return ctx.badRequest("There was no user id in the request!");
+ if (!ctx.request.body.data) return ctx.badRequest('data was missing from body');
+ if (!ctx.request.body.data.tag) return ctx.badRequest('tag was missing from data');
+ const { time, tag } = ctx.request.body.data;
+
+ ctx.request.body.data.creatorId = userId
+
+ // does the timestamp already exist with same combination of time+tag?
+ const duplicate = await strapi.db.query('api::timestamp.timestamp')
+ .findOne({ where: { time, tag }})
+
+ if (!!duplicate) return ctx.badRequest('A duplicate timestamp already exists!');
+
+ // Calling the default core action
+ const res = await super.create(ctx);
+
+ return res
+ },
+
+
+ async vote(ctx) {
+ const userId = ctx?.state?.user?.id;
+ const { direction } = ctx.request.body.data;
+ if (!ctx.request.params.id) return ctx.badRequest('id was missing from params');
+ const { id } = ctx.request.params;
+ // get the ts to be voted on
+ const ts = await strapi.entityService.findOne('api::timestamp.timestamp', id)
+ if (!ts) return ctx.badRequest('timestamp does not exist');
+ const res = await strapi.entityService.update('api::timestamp.timestamp', id, {
+ data: {
+ upvoters: direction === 1 ? { connect: [userId] } : { disconnect: [userId] },
+ downvoters: direction === 1 ? { disconnect: [userId] } : { connect: [userId] }
+ }
+ });
+ return res;
+ },
+
+
+
+ async delete(ctx) {
+ const userId = ctx?.state?.user?.id;
+ const { id } = ctx.request.params;
+
+ // get the ts to be deleted
+ const ts = await strapi.entityService.findOne('api::timestamp.timestamp', id)
+ if (!ts) return ctx.badRequest('Timestamp does not exist')
+
+
+ // Refuse to delete if not the tag creator
+ if (ts.creatorId !== userId) return ctx.forbidden('Only the timestamp creator can delete the timestamp.')
+
+
+ const res = await super.delete(ctx)
+ return res
+
+ },
+
+
+ async deleteMine (ctx) {
+ // // some custom logic here
+ // ctx.query = { ...ctx.query, local: 'en' }
+
+ const userId = ctx?.state?.user?.id;
+ if (!userId) return ctx.badRequest("There was no user id in the request!");
+ if (!ctx.request.params.id) return ctx.badRequest('id was missing from params');
+ const { id } = ctx.request.params;
+
+ // constraints
+ // only able to delete tagVodRelation if
+ // * creator
+ // * publishedAt isBefore(now-24h)
+
+
+ // get the tvr the user wants to delete
+ const timestampToDelete = await strapi.entityService.findOne('api::timestamp.timestamp', id, {
+ populate: {
+ tag: true,
+ vod: true
+ }
+ })
+
+ if (!timestampToDelete) return ctx.badRequest('Timestamp to be deleted does not exist.');
+
+
+ if (timestampToDelete.creatorId !== userId)
+ ctx.forbidden('only the creator of the timestamp can delete it');
+
+ if ((new Date(timestampToDelete.createdAt).valueOf()+86400000) < new Date().valueOf())
+ ctx.forbidden('cannot delete tags older than 24 hours')
+
+ // Calling the default core action
+ const { data, meta } = await super.delete(ctx);
+
+ // delete the related tag if it has no other vod
+ // @todo?? or maybe this is handled by lifecycle hook?
+
+ // // some more custom logic
+ // meta.date = Date.now()
+
+ return { data, meta };
+ }
+
+
+}))
+
diff --git a/packages/strapi/src/api/timestamp/routes/timestamp.js b/packages/strapi/src/api/timestamp/routes/timestamp.js
new file mode 100644
index 0000000..1c8e7c6
--- /dev/null
+++ b/packages/strapi/src/api/timestamp/routes/timestamp.js
@@ -0,0 +1,53 @@
+'use strict';
+
+/**
+ * timestamp router
+ */
+
+const { createCoreRouter } = require('@strapi/strapi').factories;
+
+
+const defaultRouter = createCoreRouter('api::timestamp.timestamp');
+
+// greets https://forum.strapi.io/t/how-to-add-custom-routes-to-core-routes-in-strapi-4/14070/7
+const customRouter = (innerRouter, extraRoutes = []) => {
+ let routes;
+ return {
+ get prefix() {
+ return innerRouter.prefix;
+ },
+ get routes() {
+ if (!routes) routes = extraRoutes.concat(innerRouter.routes)
+ return routes;
+ },
+ };
+};
+
+
+
+const myExtraRoutes = [
+ {
+ method: 'POST',
+ path: '/timestamps/assert',
+ handler: 'api::timestamp.timestamp.assert'
+ },
+ {
+ method: "PUT",
+ path: "/timestamps/:id/vote",
+ handler: "api::timestamp.timestamp.vote"
+ },
+ {
+ method: 'DELETE',
+ path: '/timestamps/:id',
+ handler: 'api::timestamp.timestamp.delete'
+ },
+ {
+ method: 'DELETE',
+ path: '/timestamps/deleteMine/:id',
+ handler: 'api::timestamp.timestamp.deleteMine'
+ }
+];
+
+module.exports = customRouter(defaultRouter, myExtraRoutes);
+
+
diff --git a/packages/strapi/src/api/timestamp/services/timestamp.js b/packages/strapi/src/api/timestamp/services/timestamp.js
new file mode 100644
index 0000000..bfa84c2
--- /dev/null
+++ b/packages/strapi/src/api/timestamp/services/timestamp.js
@@ -0,0 +1,44 @@
+'use strict';
+
+/**
+ * timestamp service
+ */
+
+const { createCoreService } = require('@strapi/strapi').factories;
+
+module.exports = createCoreService('api::timestamp.timestamp', ({ strapi }) => ({
+ async assertTimestamp(userId, tagId, vodId, time) {
+ const existingTimestamp = await strapi.entityService.findMany('api::timestamp.timestamp', {
+ populate: ['vod', 'tag'],
+ filters: {
+ $and: [
+ {
+ tag: {
+ id: tagId
+ }
+ },
+ {
+ vod: {
+ id: vodId
+ }
+ },
+ {
+ time: parseInt(time)
+ }
+ ]
+ },
+ limit: 1
+ })
+ if (existingTimestamp.length > 0) return existingTimestamp[0];
+ const newTimestamp = await strapi.entityService.create('api::timestamp.timestamp', {
+ data: {
+ tag: tagId,
+ vod: vodId,
+ creatorId: userId,
+ time: time,
+ }
+ });
+
+ return newTimestamp;
+ }
+}));
diff --git a/packages/strapi/src/api/toy/content-types/toy/schema.json b/packages/strapi/src/api/toy/content-types/toy/schema.json
new file mode 100644
index 0000000..4e2baba
--- /dev/null
+++ b/packages/strapi/src/api/toy/content-types/toy/schema.json
@@ -0,0 +1,51 @@
+{
+ "kind": "collectionType",
+ "collectionName": "toys",
+ "info": {
+ "singularName": "toy",
+ "pluralName": "toys",
+ "displayName": "Toy",
+ "description": ""
+ },
+ "options": {
+ "draftAndPublish": false
+ },
+ "pluginOptions": {},
+ "attributes": {
+ "tags": {
+ "type": "relation",
+ "relation": "oneToMany",
+ "target": "api::tag.tag",
+ "mappedBy": "toy"
+ },
+ "make": {
+ "type": "string",
+ "required": true
+ },
+ "model": {
+ "type": "string",
+ "required": true
+ },
+ "aspectRatio": {
+ "type": "string",
+ "default": "2:1",
+ "required": true
+ },
+ "image2": {
+ "type": "string",
+ "default": "https://futureporn-b2.b-cdn.net/default-thumbnail.webp",
+ "required": true
+ },
+ "linkTag": {
+ "type": "relation",
+ "relation": "oneToOne",
+ "target": "api::tag.tag"
+ },
+ "vtubers": {
+ "type": "relation",
+ "relation": "oneToMany",
+ "target": "api::vtuber.vtuber",
+ "mappedBy": "toy"
+ }
+ }
+}
diff --git a/packages/strapi/src/api/toy/controllers/toy.js b/packages/strapi/src/api/toy/controllers/toy.js
new file mode 100644
index 0000000..32bae69
--- /dev/null
+++ b/packages/strapi/src/api/toy/controllers/toy.js
@@ -0,0 +1,9 @@
+'use strict';
+
+/**
+ * toy controller
+ */
+
+const { createCoreController } = require('@strapi/strapi').factories;
+
+module.exports = createCoreController('api::toy.toy');
diff --git a/packages/strapi/src/api/toy/routes/toy.js b/packages/strapi/src/api/toy/routes/toy.js
new file mode 100644
index 0000000..21d9d6a
--- /dev/null
+++ b/packages/strapi/src/api/toy/routes/toy.js
@@ -0,0 +1,9 @@
+'use strict';
+
+/**
+ * toy router
+ */
+
+const { createCoreRouter } = require('@strapi/strapi').factories;
+
+module.exports = createCoreRouter('api::toy.toy');
diff --git a/packages/strapi/src/api/toy/services/toy.js b/packages/strapi/src/api/toy/services/toy.js
new file mode 100644
index 0000000..cd2dd6d
--- /dev/null
+++ b/packages/strapi/src/api/toy/services/toy.js
@@ -0,0 +1,9 @@
+'use strict';
+
+/**
+ * toy service
+ */
+
+const { createCoreService } = require('@strapi/strapi').factories;
+
+module.exports = createCoreService('api::toy.toy');
diff --git a/packages/strapi/src/api/tweet/content-types/tweet/lifecycles.js b/packages/strapi/src/api/tweet/content-types/tweet/lifecycles.js
new file mode 100644
index 0000000..b92154a
--- /dev/null
+++ b/packages/strapi/src/api/tweet/content-types/tweet/lifecycles.js
@@ -0,0 +1,136 @@
+const generateCuid = require('../../../../../misc/generateCuid.js');
+
+const cbUrlRegex = /chaturbate\.com/i;
+const fanslyUrlRegex = /https?:\/\/(?:www\.)?fans(?:\.ly|ly\.com)\/r\/[a-zA-Z0-9_]+/;
+
+const cbAlternativeUrls = [
+ 'shorturl.at/tNUVY' // used by ProjektMelody in the early days
+]
+
+
+/**
+ * Returns true if the tweet contains a chaturbate.com link
+ *
+ * @param {Object} tweet
+ * @returns {Boolean}
+ */
+const containsCBInviteLink = (tweet) => {
+ const containsCbUrl = (link) => {
+ if (!link?.url) return false;
+ const isCbUrl = cbUrlRegex.test(link.url);
+ const isAlternativeCbUrl = cbAlternativeUrls.some(alternativeUrl => link.url.includes(alternativeUrl));
+ return isCbUrl || isAlternativeCbUrl;
+ }
+ try {
+ if (!tweet?.links) return false;
+ return tweet.links.some(containsCbUrl)
+ } catch (e) {
+ logger.log({ level: 'error', message: 'ERROR ERROR ERROR ERROR ERROR ERROR ERROR ERROR ERROR ERROR ERROR ERROR ERROR ERROR ERROR ERROR ERROR ERROR' });
+ logger.log({ level: 'error', message: e });
+ return false;
+ }
+};
+
+const containsFanslyInviteLink = (tweet) => {
+ const containsFanslyUrl = (link) => {
+ if (!link?.url) return false;
+ return (fanslyUrlRegex.test(link?.url))
+ }
+ try {
+ if (!tweet?.links) return false;
+ return tweet.links.some(containsFanslyUrl)
+ } catch (e) {
+ logger.log({ level: 'error', message: 'ERROR ERROR ERROR ERROR ERROR ERROR ERROR ERROR ERROR ERROR ERROR ERROR ERROR ERROR ERROR ERROR ERROR ERROR' });
+ logger.log({ level: 'error', message: e });
+ return false;
+ }
+};
+
+
+const deriveTitle = (text) => {
+ // greetz https://www.urlregex.com/
+ const urlRegex = /((([A-Za-z]{3,9}:(?:\/\/)?)(?:[\-;:&=\+\$,\w]+@)?[A-Za-z0-9\.\-]+|(?:www\.|[\-;:&=\+\$,\w]+@)[A-Za-z0-9\.\-]+)((?:\/[\+~%\/\.\w\-_]*)?\??(?:[\-\+=&;%@\.\w_]*)#?(?:[\.\!\/\\\w]*))?)/g;
+ let title = text
+ .replace(urlRegex, '') // remove urls
+ .replace(/\n/g, ' ') // replace newlines with spaces
+ .replace(/>/g, '>') // gimme dem greater-than brackets
+ .replace(/</g, '<') // i want them less-thans too
+ .replace(/&/g, '&') // ampersands are sexy
+ .replace(/\s+$/, ''); // remove trailing whitespace
+ return title;
+};
+
+
+
+
+module.exports = {
+ async afterCreate(event) {
+ // * [ ] Create Stream
+ const id = event.result.id;
+ console.log(`>>> tweet afterCreate id=${id}`);
+ const { data } = event.params;
+
+ console.log(data);
+
+ // IF this tweet was a fansly or chaturbate invite, create & associate Stream
+ if (data.isChaturbateInvite || data.isFanslyInvite) {
+ const stream = await strapi.entityService.create('api::stream.stream', {
+ data: {
+ tweet: id,
+ vtuber: data.vtuber,
+ date: data.date,
+ date_str: data.date,
+ date2: data.date,
+ archiveStatus: 'missing',
+ cuid: generateCuid()
+ }
+ });
+
+ // console.log(data)
+ console.log(`stream.id=${stream.id}`);
+
+ // const existingData = await strapi.entityService.findOne("api::stream.stream", id, {
+ // populate: ['vods']
+ // })
+ }
+ },
+ async beforeCreate(event) {
+ // * [x] Set platform to CB or Fansly
+ // * [x] Set vtuber
+ // * [x] Set date
+ // * [x] Set id_str
+ // * [x] Set url
+
+ const { data, where, select, populate } = event.params;
+ console.log('>>> tweet beforeCreate!');
+
+ const tweet = JSON.parse(data.json);
+ // console.log(tweet);
+ console.log(`containsCBInviteLink=${containsCBInviteLink(tweet)}, containsFanslyInviteLink=${containsFanslyInviteLink(tweet)}`);
+
+
+ data.isChaturbateInvite = containsCBInviteLink(tweet);
+ data.isFanslyInvite = containsFanslyInviteLink(tweet);
+
+ const tweetDate = new Date(tweet.date).toISOString();
+ data.id_str = tweet.id_str;
+ data.date = tweetDate;
+ data.date2 = tweetDate;
+ data.url = tweet.url;
+
+ // Set VTuber
+ const twitterUsername = tweet.user.username;
+ const vtuberRecords = await strapi.entityService.findMany("api::vtuber.vtuber", {
+ fields: ['displayName', 'slug', 'id'],
+ filters: {
+ twitter: {
+ $endsWithi: twitterUsername
+ }
+ }
+ });
+ if (!!vtuberRecords[0]) data.vtuber = vtuberRecords[0].id;
+
+
+
+ }
+}
\ No newline at end of file
diff --git a/packages/strapi/src/api/tweet/content-types/tweet/schema.json b/packages/strapi/src/api/tweet/content-types/tweet/schema.json
new file mode 100644
index 0000000..3d94b7c
--- /dev/null
+++ b/packages/strapi/src/api/tweet/content-types/tweet/schema.json
@@ -0,0 +1,49 @@
+{
+ "kind": "collectionType",
+ "collectionName": "tweets",
+ "info": {
+ "singularName": "tweet",
+ "pluralName": "tweets",
+ "displayName": "Tweet",
+ "description": ""
+ },
+ "options": {
+ "draftAndPublish": false
+ },
+ "pluginOptions": {},
+ "attributes": {
+ "id_str": {
+ "type": "string",
+ "required": false,
+ "unique": true
+ },
+ "url": {
+ "type": "string",
+ "required": false
+ },
+ "date2": {
+ "type": "string",
+ "required": false,
+ "unique": true
+ },
+ "json": {
+ "type": "text",
+ "required": true
+ },
+ "vtuber": {
+ "type": "relation",
+ "relation": "oneToOne",
+ "target": "api::vtuber.vtuber"
+ },
+ "isChaturbateInvite": {
+ "type": "boolean"
+ },
+ "isFanslyInvite": {
+ "type": "boolean"
+ },
+ "date": {
+ "type": "datetime",
+ "unique": true
+ }
+ }
+}
diff --git a/packages/strapi/src/api/tweet/controllers/tweet.js b/packages/strapi/src/api/tweet/controllers/tweet.js
new file mode 100644
index 0000000..bbb1fed
--- /dev/null
+++ b/packages/strapi/src/api/tweet/controllers/tweet.js
@@ -0,0 +1,9 @@
+'use strict';
+
+/**
+ * tweet controller
+ */
+
+const { createCoreController } = require('@strapi/strapi').factories;
+
+module.exports = createCoreController('api::tweet.tweet');
diff --git a/packages/strapi/src/api/tweet/routes/tweet.js b/packages/strapi/src/api/tweet/routes/tweet.js
new file mode 100644
index 0000000..efce886
--- /dev/null
+++ b/packages/strapi/src/api/tweet/routes/tweet.js
@@ -0,0 +1,9 @@
+'use strict';
+
+/**
+ * tweet router
+ */
+
+const { createCoreRouter } = require('@strapi/strapi').factories;
+
+module.exports = createCoreRouter('api::tweet.tweet');
diff --git a/packages/strapi/src/api/tweet/services/tweet.js b/packages/strapi/src/api/tweet/services/tweet.js
new file mode 100644
index 0000000..9be1baf
--- /dev/null
+++ b/packages/strapi/src/api/tweet/services/tweet.js
@@ -0,0 +1,9 @@
+'use strict';
+
+/**
+ * tweet service
+ */
+
+const { createCoreService } = require('@strapi/strapi').factories;
+
+module.exports = createCoreService('api::tweet.tweet');
diff --git a/packages/strapi/src/api/user-submitted-content/content-types/user-submitted-content/lifecycles.js b/packages/strapi/src/api/user-submitted-content/content-types/user-submitted-content/lifecycles.js
new file mode 100644
index 0000000..b9bab96
--- /dev/null
+++ b/packages/strapi/src/api/user-submitted-content/content-types/user-submitted-content/lifecycles.js
@@ -0,0 +1,58 @@
+const { S3Client, DeleteObjectCommand } = require("@aws-sdk/client-s3");
+
+if (!process.env.S3_USC_BUCKET_NAME) throw new Error('S3_USC_BUCKET_NAME must be defined in env');
+if (!process.env.S3_USC_BUCKET_ENDPOINT) throw new Error('S3_USC_BUCKET_ENDPOINT must be defined in env');
+if (!process.env.S3_USC_BUCKET_REGION) throw new Error('S3_USC_BUCKET_REGION must be defined in env');
+if (!process.env.AWS_ACCESS_KEY_ID) throw new Error('AWS_ACCESS_KEY_ID must be defined in env');
+if (!process.env.AWS_SECRET_ACCESS_KEY) throw new Error('AWS_SECRET_ACCESS_KEY must be defined in env');
+
+// AWS.config.loadFromPath('./credentials-ehl.json');
+
+
+
+module.exports = {
+ async beforeCreate(event) {
+ console.log('>>> beforeCreate!');
+
+ },
+
+ // when strapi deletes a USC, we delete the related files in the S3 bucket.
+ async afterDelete(event) {
+
+ console.log('>>> afterDelete');
+ console.log(event);
+
+ const { result } = event;
+
+
+
+ // a client can be shared by different commands.
+ const client = new S3Client({
+ endpoint: process.env.S3_USC_BUCKET_ENDPOINT,
+ region: process.env.S3_USC_BUCKET_REGION
+ });
+ // https://fp-usc-dev.s3.us-west-000.backblazeb2.com/GEB7_QcaUAAQ29O.jpg
+
+ const res = await client.send(new DeleteObjectCommand({
+ Bucket: process.env.S3_USC_BUCKET_NAME,
+ Key: result.key
+ }));
+
+ console.log(res);
+
+
+
+ // var s3 = new S3();
+ // var params = { Bucket: process.env.S3_USC_BUCKET, Key: 'your object' };
+
+ // const res = await s3.deleteObject(params).promise();
+
+ // console.log('deletion complete.');
+ // console.log(res);
+
+ // , function(err, data) {
+ // if (err) console.log(err, err.stack); // error
+ // else console.log(); // deleted
+ // });
+ }
+}
\ No newline at end of file
diff --git a/packages/strapi/src/api/user-submitted-content/content-types/user-submitted-content/schema.json b/packages/strapi/src/api/user-submitted-content/content-types/user-submitted-content/schema.json
new file mode 100644
index 0000000..dc1eb4a
--- /dev/null
+++ b/packages/strapi/src/api/user-submitted-content/content-types/user-submitted-content/schema.json
@@ -0,0 +1,36 @@
+{
+ "kind": "collectionType",
+ "collectionName": "user_submitted_contents",
+ "info": {
+ "singularName": "user-submitted-content",
+ "pluralName": "user-submitted-contents",
+ "displayName": "User Submitted Content",
+ "description": ""
+ },
+ "options": {
+ "draftAndPublish": false
+ },
+ "pluginOptions": {},
+ "attributes": {
+ "uploader": {
+ "type": "relation",
+ "relation": "oneToOne",
+ "target": "plugin::users-permissions.user"
+ },
+ "attribution": {
+ "type": "boolean",
+ "default": false
+ },
+ "date": {
+ "type": "string",
+ "required": true
+ },
+ "notes": {
+ "type": "richtext"
+ },
+ "files": {
+ "type": "json",
+ "required": true
+ }
+ }
+}
diff --git a/packages/strapi/src/api/user-submitted-content/controllers/user-submitted-content.js b/packages/strapi/src/api/user-submitted-content/controllers/user-submitted-content.js
new file mode 100644
index 0000000..a94c328
--- /dev/null
+++ b/packages/strapi/src/api/user-submitted-content/controllers/user-submitted-content.js
@@ -0,0 +1,60 @@
+
+'use strict';
+
+
+if (!process.env.CDN_BUCKET_USC_URL) throw new Error('CDN_BUCKET_USC_URL environment variable is required!');
+
+/**
+ * user-submitted-content controller
+ */
+
+const { createCoreController } = require('@strapi/strapi').factories;
+
+// greets https://docs.strapi.io/dev-docs/backend-customization/controllers#adding-a-new-controller
+module.exports = createCoreController('api::user-submitted-content.user-submitted-content', ({ strapi }) => ({
+
+ async createFromUppy(ctx) {
+ try {
+ // Destructure data from the request body
+ const { data } = ctx.request.body;
+
+ console.log(data);
+
+ // Check for required fields in the data
+ const requiredFields = ['files', 'vtuber', 'date', 'notes', 'attribution'];
+ if (!data) {
+ return ctx.badRequest('ctx.request.body.data was missing.');
+ }
+ for (const field of requiredFields) {
+ console.log(`checking field=${field} data[field]=${data[field]}`);
+ if (data[field] === undefined || data[field] === null) {
+ return ctx.badRequest(`${field} was missing from request data.`);
+ }
+ }
+
+ // Extract relevant data
+ const { files, vtuber, date, notes, attribution } = data;
+ const uploader = ctx.state.user.id;
+
+ console.log('Creating user-submitted content');
+ const usc = await strapi.entityService.create('api::user-submitted-content.user-submitted-content', {
+ data: {
+ uploader,
+ files: files.map((f) => ({ ...f, cdnUrl: `${process.env.CDN_BUCKET_USC_URL}/${f.key}` })),
+ vtuber,
+ date,
+ notes,
+ attribution,
+ }
+ });
+
+ return usc;
+ } catch (error) {
+ // Handle unexpected errors
+ console.error(error);
+ return ctx.badRequest('An error occurred while processing the request');
+ }
+ }
+
+ }));
+
\ No newline at end of file
diff --git a/packages/strapi/src/api/user-submitted-content/routes/user-submitted-content.js b/packages/strapi/src/api/user-submitted-content/routes/user-submitted-content.js
new file mode 100644
index 0000000..ed91c49
--- /dev/null
+++ b/packages/strapi/src/api/user-submitted-content/routes/user-submitted-content.js
@@ -0,0 +1,33 @@
+'use strict';
+
+/**
+ * user-submitted-content router
+ */
+
+const { createCoreRouter } = require('@strapi/strapi').factories;
+
+const defaultRouter = createCoreRouter('api::user-submitted-content.user-submitted-content');
+
+// greets https://forum.strapi.io/t/how-to-add-custom-routes-to-core-routes-in-strapi-4/14070/7
+const customRouter = (innerRouter, extraRoutes = []) => {
+ let routes;
+ return {
+ get prefix() {
+ return innerRouter.prefix;
+ },
+ get routes() {
+ if (!routes) routes = extraRoutes.concat(innerRouter.routes)
+ return routes;
+ },
+ };
+};
+
+const myExtraRoutes = [
+ {
+ method: "POST",
+ path: "/user-submitted-contents/createFromUppy",
+ handler: "api::user-submitted-content.user-submitted-content.createFromUppy"
+ }
+];
+
+module.exports = customRouter(defaultRouter, myExtraRoutes);
\ No newline at end of file
diff --git a/packages/strapi/src/api/user-submitted-content/services/user-submitted-content.js b/packages/strapi/src/api/user-submitted-content/services/user-submitted-content.js
new file mode 100644
index 0000000..9c176aa
--- /dev/null
+++ b/packages/strapi/src/api/user-submitted-content/services/user-submitted-content.js
@@ -0,0 +1,9 @@
+'use strict';
+
+/**
+ * user-submitted-content service
+ */
+
+const { createCoreService } = require('@strapi/strapi').factories;
+
+module.exports = createCoreService('api::user-submitted-content.user-submitted-content');
diff --git a/packages/strapi/src/api/vod/content-types/lifecycles.js b/packages/strapi/src/api/vod/content-types/lifecycles.js
new file mode 100644
index 0000000..5090507
--- /dev/null
+++ b/packages/strapi/src/api/vod/content-types/lifecycles.js
@@ -0,0 +1,12 @@
+const { init } = require('@paralleldrive/cuid2');
+
+module.exports = {
+ async beforeUpdate(event) {
+ const { data } = event.params;
+ if (!data.cuid) {
+ const length = 10; // 50% odds of collision after ~51,386,368 ids
+ const cuid = init({ length });
+ event.params.data.cuid = cuid();
+ }
+ }
+}
\ No newline at end of file
diff --git a/packages/strapi/src/api/vod/content-types/vod/schema.json b/packages/strapi/src/api/vod/content-types/vod/schema.json
new file mode 100644
index 0000000..2446a76
--- /dev/null
+++ b/packages/strapi/src/api/vod/content-types/vod/schema.json
@@ -0,0 +1,142 @@
+{
+ "kind": "collectionType",
+ "collectionName": "vods",
+ "info": {
+ "singularName": "vod",
+ "pluralName": "vods",
+ "displayName": "VOD",
+ "description": ""
+ },
+ "options": {
+ "draftAndPublish": true
+ },
+ "pluginOptions": {},
+ "attributes": {
+ "videoSrcHash": {
+ "type": "string",
+ "regex": "Qm[1-9A-HJ-NP-Za-km-z]{44,}|b[A-Za-z2-7]{58,}|B[A-Z2-7]{58,}|z[1-9A-HJ-NP-Za-km-z]{48,}|F[0-9A-F]{50,}",
+ "required": false,
+ "unique": true
+ },
+ "video720Hash": {
+ "type": "string",
+ "unique": true,
+ "regex": "Qm[1-9A-HJ-NP-Za-km-z]{44,}|b[A-Za-z2-7]{58,}|B[A-Z2-7]{58,}|z[1-9A-HJ-NP-Za-km-z]{48,}|F[0-9A-F]{50,}"
+ },
+ "video480Hash": {
+ "type": "string",
+ "regex": "Qm[1-9A-HJ-NP-Za-km-z]{44,}|b[A-Za-z2-7]{58,}|B[A-Z2-7]{58,}|z[1-9A-HJ-NP-Za-km-z]{48,}|F[0-9A-F]{50,}",
+ "unique": true
+ },
+ "video360Hash": {
+ "type": "string",
+ "regex": "Qm[1-9A-HJ-NP-Za-km-z]{44,}|b[A-Za-z2-7]{58,}|B[A-Z2-7]{58,}|z[1-9A-HJ-NP-Za-km-z]{48,}|F[0-9A-F]{50,}",
+ "unique": true
+ },
+ "video240Hash": {
+ "type": "string",
+ "regex": "Qm[1-9A-HJ-NP-Za-km-z]{44,}|b[A-Za-z2-7]{58,}|B[A-Z2-7]{58,}|z[1-9A-HJ-NP-Za-km-z]{48,}|F[0-9A-F]{50,}",
+ "unique": true
+ },
+ "thinHash": {
+ "type": "string",
+ "regex": "Qm[1-9A-HJ-NP-Za-km-z]{44,}|b[A-Za-z2-7]{58,}|B[A-Z2-7]{58,}|z[1-9A-HJ-NP-Za-km-z]{48,}|F[0-9A-F]{50,}",
+ "unique": true
+ },
+ "thiccHash": {
+ "type": "string",
+ "regex": "Qm[1-9A-HJ-NP-Za-km-z]{44,}|b[A-Za-z2-7]{58,}|B[A-Z2-7]{58,}|z[1-9A-HJ-NP-Za-km-z]{48,}|F[0-9A-F]{50,}",
+ "unique": true
+ },
+ "announceTitle": {
+ "type": "string"
+ },
+ "announceUrl": {
+ "type": "string",
+ "unique": false
+ },
+ "note": {
+ "type": "text"
+ },
+ "date": {
+ "type": "datetime"
+ },
+ "date2": {
+ "type": "string",
+ "required": true
+ },
+ "spoilers": {
+ "type": "richtext"
+ },
+ "title": {
+ "type": "string"
+ },
+ "uploader": {
+ "type": "relation",
+ "relation": "oneToOne",
+ "target": "plugin::users-permissions.user"
+ },
+ "muxAsset": {
+ "type": "relation",
+ "relation": "oneToOne",
+ "target": "api::mux-asset.mux-asset"
+ },
+ "videoSrcB2": {
+ "type": "relation",
+ "relation": "oneToOne",
+ "target": "api::b2-file.b2-file"
+ },
+ "thumbnail": {
+ "type": "relation",
+ "relation": "oneToOne",
+ "target": "api::b2-file.b2-file"
+ },
+ "chatLog": {
+ "type": "richtext"
+ },
+ "tags": {
+ "type": "relation",
+ "relation": "manyToMany",
+ "target": "api::tag.tag",
+ "mappedBy": "vods"
+ },
+ "timestamps": {
+ "type": "relation",
+ "relation": "oneToMany",
+ "target": "api::timestamp.timestamp",
+ "mappedBy": "vod"
+ },
+ "tagVodRelations": {
+ "type": "relation",
+ "relation": "oneToMany",
+ "target": "api::tag-vod-relation.tag-vod-relation",
+ "mappedBy": "vod"
+ },
+ "vtuber": {
+ "type": "relation",
+ "relation": "manyToOne",
+ "target": "api::vtuber.vtuber",
+ "inversedBy": "vods"
+ },
+ "stream": {
+ "type": "relation",
+ "relation": "manyToOne",
+ "target": "api::stream.stream",
+ "inversedBy": "vods"
+ },
+ "archiveStatus": {
+ "type": "enumeration",
+ "enum": [
+ "missing",
+ "issue",
+ "good"
+ ],
+ "required": false,
+ "default": "issue"
+ },
+ "cuid": {
+ "type": "string",
+ "unique": true
+ }
+ }
+}
diff --git a/packages/strapi/src/api/vod/controllers/vod.js b/packages/strapi/src/api/vod/controllers/vod.js
new file mode 100644
index 0000000..9dc9ff2
--- /dev/null
+++ b/packages/strapi/src/api/vod/controllers/vod.js
@@ -0,0 +1,85 @@
+'use strict';
+
+
+const { sanitize } = require('@strapi/utils');
+
+if (!process.env.CDN_BUCKET_USC_URL) throw new Error('CDN_BUCKET_USC_URL environment variable is required!');
+
+/**
+ * vod controller
+ */
+
+const { createCoreController } = require('@strapi/strapi').factories;
+
+// greets https://docs.strapi.io/dev-docs/backend-customization/controllers#adding-a-new-controller
+module.exports = createCoreController('api::vod.vod', ({ strapi }) => ({
+
+ async createFromUppy(ctx) {
+
+ const uploaderId = ctx.state.user.id;
+
+ if (!ctx.request.body.data) return ctx.badRequest("data was missing in request body");
+ if (!ctx.request.body.data.date) return ctx.badRequest("date was missing");
+ if (!ctx.request.body.data.b2Key) return ctx.badRequest("b2Key was missing");
+ if (!ctx.request.body.data.b2UploadId) return ctx.badRequest("b2UploadId was missing");
+
+
+ const videoSrcB2 = await strapi.entityService.create('api::b2-file.b2-file', {
+ data: {
+ url: `https://f000.backblazeb2.com/b2api/v1/b2_download_file_by_id?fileId=${ctx.request.body.data.b2UploadId}`,
+ key: ctx.request.body.data.b2Key,
+ uploadId: ctx.request.body.data.b2UploadId,
+ cdnUrl: `${process.env.CDN_BUCKET_USC_URL}/${ctx.request.body.data.b2Key}`
+ }
+ });
+
+ const vod = await strapi.entityService.create('api::vod.vod', {
+ data: {
+ notes: ctx.request.body.data.notes,
+ date: ctx.request.body.data.date,
+ videoSrcB2: videoSrcB2.id,
+ publishedAt: null,
+ uploader: uploaderId,
+ }
+ });
+
+ return vod;
+ },
+
+ // greets https://stackoverflow.com/a/73929966/1004931
+ async random(ctx) {
+ const numberOfEntries = 1;
+ const contentType = strapi.contentType('api::vod.vod')
+
+ // Fetch only the 'id' field of all VODs
+ const entries = await strapi.entityService.findMany(
+ "api::vod.vod",
+ {
+ fields: ['id'],
+ filters: {
+ publishedAt: {
+ $notNull: true,
+ },
+ }
+ }
+ );
+
+ // Randomly select one entry
+ const randomEntry = entries[Math.floor(Math.random() * entries.length)];
+
+ // Fetch the full details of the randomly selected VOD
+ const rawVod = await strapi.entityService.findOne(
+ "api::vod.vod",
+ randomEntry.id,
+ {
+ populate: '*',
+ },
+ );
+
+ const sanitizedOutput = await sanitize.contentAPI.output(rawVod, contentType, { auth: ctx.state.auth });
+
+ ctx.body = sanitizedOutput;
+ }
+
+ })
+)
\ No newline at end of file
diff --git a/packages/strapi/src/api/vod/routes/vod.js b/packages/strapi/src/api/vod/routes/vod.js
new file mode 100644
index 0000000..132dacf
--- /dev/null
+++ b/packages/strapi/src/api/vod/routes/vod.js
@@ -0,0 +1,38 @@
+'use strict';
+
+/**
+ * vod router
+ */
+
+const { createCoreRouter } = require('@strapi/strapi').factories;
+
+const defaultRouter = createCoreRouter('api::vod.vod');
+
+// greets https://forum.strapi.io/t/how-to-add-custom-routes-to-core-routes-in-strapi-4/14070/7
+const customRouter = (innerRouter, extraRoutes = []) => {
+ let routes;
+ return {
+ get prefix() {
+ return innerRouter.prefix;
+ },
+ get routes() {
+ if (!routes) routes = extraRoutes.concat(innerRouter.routes)
+ return routes;
+ },
+ };
+};
+
+const myExtraRoutes = [
+ {
+ method: "POST",
+ path: "/vods/createFromUppy",
+ handler: "api::vod.vod.createFromUppy"
+ },
+ {
+ method: "GET",
+ path: "/vods/random",
+ handler: "api::vod.vod.random"
+ }
+];
+
+module.exports = customRouter(defaultRouter, myExtraRoutes);
\ No newline at end of file
diff --git a/packages/strapi/src/api/vod/services/vod.js b/packages/strapi/src/api/vod/services/vod.js
new file mode 100644
index 0000000..56fcec1
--- /dev/null
+++ b/packages/strapi/src/api/vod/services/vod.js
@@ -0,0 +1,9 @@
+'use strict';
+
+/**
+ * vod service
+ */
+
+const { createCoreService } = require('@strapi/strapi').factories;
+
+module.exports = createCoreService('api::vod.vod');
diff --git a/packages/strapi/src/api/vtuber/content-types/vtuber/lifecycles.js b/packages/strapi/src/api/vtuber/content-types/vtuber/lifecycles.js
new file mode 100644
index 0000000..2be365a
--- /dev/null
+++ b/packages/strapi/src/api/vtuber/content-types/vtuber/lifecycles.js
@@ -0,0 +1,23 @@
+const { createCanvas } = require('canvas');
+
+function hexColorToBase64Image(hexColor) {
+ const canvas = createCanvas(1, 1); // Create a canvas
+ const ctx = canvas.getContext('2d');
+ // Draw a rectangle filled with the hex color
+ ctx.fillStyle = hexColor;
+ ctx.fillRect(0, 0, canvas.width, canvas.height);
+ // Convert canvas content to base64 encoded image
+ const base64Image = canvas.toDataURL('image/png');
+ return base64Image;
+}
+
+
+
+module.exports = {
+ beforeUpdate(event) {
+ const { data, where, select, populate } = event.params;
+ const themeColor = event.params.data.themeColor;
+ const imageBlur = hexColorToBase64Image(themeColor);
+ event.params.data.imageBlur = imageBlur;
+ }
+};
\ No newline at end of file
diff --git a/packages/strapi/src/api/vtuber/content-types/vtuber/schema.json b/packages/strapi/src/api/vtuber/content-types/vtuber/schema.json
new file mode 100644
index 0000000..91568cc
--- /dev/null
+++ b/packages/strapi/src/api/vtuber/content-types/vtuber/schema.json
@@ -0,0 +1,118 @@
+{
+ "kind": "collectionType",
+ "collectionName": "vtubers",
+ "info": {
+ "singularName": "vtuber",
+ "pluralName": "vtubers",
+ "displayName": "Vtuber",
+ "description": ""
+ },
+ "options": {
+ "draftAndPublish": true
+ },
+ "pluginOptions": {},
+ "attributes": {
+ "displayName": {
+ "type": "string",
+ "required": true
+ },
+ "chaturbate": {
+ "type": "string"
+ },
+ "twitter": {
+ "type": "string"
+ },
+ "patreon": {
+ "type": "string"
+ },
+ "twitch": {
+ "type": "string"
+ },
+ "tiktok": {
+ "type": "string"
+ },
+ "onlyfans": {
+ "type": "string"
+ },
+ "youtube": {
+ "type": "string"
+ },
+ "linktree": {
+ "type": "string"
+ },
+ "carrd": {
+ "type": "string"
+ },
+ "fansly": {
+ "type": "string"
+ },
+ "pornhub": {
+ "type": "string"
+ },
+ "discord": {
+ "type": "string"
+ },
+ "reddit": {
+ "type": "string"
+ },
+ "throne": {
+ "type": "string"
+ },
+ "instagram": {
+ "type": "string"
+ },
+ "facebook": {
+ "type": "string"
+ },
+ "merch": {
+ "type": "string"
+ },
+ "slug": {
+ "type": "string",
+ "required": true
+ },
+ "vods": {
+ "type": "relation",
+ "relation": "oneToMany",
+ "target": "api::vod.vod",
+ "mappedBy": "vtuber"
+ },
+ "description1": {
+ "type": "text",
+ "required": true
+ },
+ "description2": {
+ "type": "text"
+ },
+ "image": {
+ "type": "string",
+ "required": true
+ },
+ "themeColor": {
+ "type": "string",
+ "default": "#353FFF",
+ "required": true
+ },
+ "imageBlur": {
+ "type": "string",
+ "default": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAABmJLR0QA/wD/AP+gvaeTAAAADUlEQVQImWMwtf//HwAEkwJzh0T9qwAAAABJRU5ErkJggg=="
+ },
+ "toys": {
+ "type": "relation",
+ "relation": "oneToMany",
+ "target": "api::toy.toy"
+ },
+ "toy": {
+ "type": "relation",
+ "relation": "manyToOne",
+ "target": "api::toy.toy",
+ "inversedBy": "vtubers"
+ },
+ "streams": {
+ "type": "relation",
+ "relation": "oneToMany",
+ "target": "api::stream.stream",
+ "mappedBy": "vtuber"
+ }
+ }
+}
diff --git a/packages/strapi/src/api/vtuber/controllers/vtuber.js b/packages/strapi/src/api/vtuber/controllers/vtuber.js
new file mode 100644
index 0000000..e13bb5e
--- /dev/null
+++ b/packages/strapi/src/api/vtuber/controllers/vtuber.js
@@ -0,0 +1,9 @@
+'use strict';
+
+/**
+ * vtuber controller
+ */
+
+const { createCoreController } = require('@strapi/strapi').factories;
+
+module.exports = createCoreController('api::vtuber.vtuber');
diff --git a/packages/strapi/src/api/vtuber/routes/vtuber.js b/packages/strapi/src/api/vtuber/routes/vtuber.js
new file mode 100644
index 0000000..8936096
--- /dev/null
+++ b/packages/strapi/src/api/vtuber/routes/vtuber.js
@@ -0,0 +1,9 @@
+'use strict';
+
+/**
+ * vtuber router
+ */
+
+const { createCoreRouter } = require('@strapi/strapi').factories;
+
+module.exports = createCoreRouter('api::vtuber.vtuber');
diff --git a/packages/strapi/src/api/vtuber/services/vtuber.js b/packages/strapi/src/api/vtuber/services/vtuber.js
new file mode 100644
index 0000000..c792042
--- /dev/null
+++ b/packages/strapi/src/api/vtuber/services/vtuber.js
@@ -0,0 +1,9 @@
+'use strict';
+
+/**
+ * vtuber service
+ */
+
+const { createCoreService } = require('@strapi/strapi').factories;
+
+module.exports = createCoreService('api::vtuber.vtuber');
diff --git a/packages/strapi/src/extensions/.gitkeep b/packages/strapi/src/extensions/.gitkeep
new file mode 100644
index 0000000..e69de29
diff --git a/packages/strapi/src/extensions/users-permissions/.eslintignore b/packages/strapi/src/extensions/users-permissions/.eslintignore
new file mode 100644
index 0000000..1723d82
--- /dev/null
+++ b/packages/strapi/src/extensions/users-permissions/.eslintignore
@@ -0,0 +1,2 @@
+node_modules/
+.eslintrc.js
diff --git a/packages/strapi/src/extensions/users-permissions/.eslintrc.js b/packages/strapi/src/extensions/users-permissions/.eslintrc.js
new file mode 100644
index 0000000..a6c2c1e
--- /dev/null
+++ b/packages/strapi/src/extensions/users-permissions/.eslintrc.js
@@ -0,0 +1,14 @@
+module.exports = {
+ root: true,
+ overrides: [
+ {
+ files: ['admin/**/*'],
+ extends: ['custom/front'],
+ },
+ {
+ files: ['**/*'],
+ excludedFiles: ['admin/**/*'],
+ extends: ['custom/back'],
+ },
+ ],
+};
diff --git a/packages/strapi/src/extensions/users-permissions/LICENSE b/packages/strapi/src/extensions/users-permissions/LICENSE
new file mode 100644
index 0000000..638baf8
--- /dev/null
+++ b/packages/strapi/src/extensions/users-permissions/LICENSE
@@ -0,0 +1,22 @@
+Copyright (c) 2015-present Strapi Solutions SAS
+
+Portions of the Strapi software are licensed as follows:
+
+* All software that resides under an "ee/" directory (the “EE Software”), if that directory exists, is licensed under the license defined in "ee/LICENSE".
+
+* All software outside of the above-mentioned directories or restrictions above is available under the "MIT Expat" license as set forth below.
+
+MIT Expat License
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
\ No newline at end of file
diff --git a/packages/strapi/src/extensions/users-permissions/README.md b/packages/strapi/src/extensions/users-permissions/README.md
new file mode 100644
index 0000000..af1f65a
--- /dev/null
+++ b/packages/strapi/src/extensions/users-permissions/README.md
@@ -0,0 +1 @@
+# Strapi plugin
diff --git a/packages/strapi/src/extensions/users-permissions/admin/src/components/BoundRoute/getMethodColor.js b/packages/strapi/src/extensions/users-permissions/admin/src/components/BoundRoute/getMethodColor.js
new file mode 100644
index 0000000..1ad903b
--- /dev/null
+++ b/packages/strapi/src/extensions/users-permissions/admin/src/components/BoundRoute/getMethodColor.js
@@ -0,0 +1,41 @@
+const getMethodColor = (verb) => {
+ switch (verb) {
+ case 'POST': {
+ return {
+ text: 'success600',
+ border: 'success200',
+ background: 'success100',
+ };
+ }
+ case 'GET': {
+ return {
+ text: 'secondary600',
+ border: 'secondary200',
+ background: 'secondary100',
+ };
+ }
+ case 'PUT': {
+ return {
+ text: 'warning600',
+ border: 'warning200',
+ background: 'warning100',
+ };
+ }
+ case 'DELETE': {
+ return {
+ text: 'danger600',
+ border: 'danger200',
+ background: 'danger100',
+ };
+ }
+ default: {
+ return {
+ text: 'neutral600',
+ border: 'neutral200',
+ background: 'neutral100',
+ };
+ }
+ }
+};
+
+export default getMethodColor;
diff --git a/packages/strapi/src/extensions/users-permissions/admin/src/components/BoundRoute/index.js b/packages/strapi/src/extensions/users-permissions/admin/src/components/BoundRoute/index.js
new file mode 100644
index 0000000..7680ff0
--- /dev/null
+++ b/packages/strapi/src/extensions/users-permissions/admin/src/components/BoundRoute/index.js
@@ -0,0 +1,72 @@
+import React from 'react';
+
+import { Box, Flex, Typography } from '@strapi/design-system';
+import map from 'lodash/map';
+import tail from 'lodash/tail';
+import PropTypes from 'prop-types';
+import { useIntl } from 'react-intl';
+import styled from 'styled-components';
+
+import getMethodColor from './getMethodColor';
+
+const MethodBox = styled(Box)`
+ margin: -1px;
+ border-radius: ${({ theme }) => theme.spaces[1]} 0 0 ${({ theme }) => theme.spaces[1]};
+`;
+
+function BoundRoute({ route }) {
+ const { formatMessage } = useIntl();
+
+ const { method, handler: title, path } = route;
+ const formattedRoute = path ? tail(path.split('/')) : [];
+ const [controller = '', action = ''] = title ? title.split('.') : [];
+ const colors = getMethodColor(route.method);
+
+ return (
+
+
+ {formatMessage({
+ id: 'users-permissions.BoundRoute.title',
+ defaultMessage: 'Bound route to',
+ })}
+
+ {controller}
+
+ .{action}
+
+
+
+
+
+ {method}
+
+
+
+ {map(formattedRoute, (value) => (
+
+ /{value}
+
+ ))}
+
+
+
+ );
+}
+
+BoundRoute.defaultProps = {
+ route: {
+ handler: 'Nocontroller.error',
+ method: 'GET',
+ path: '/there-is-no-path',
+ },
+};
+
+BoundRoute.propTypes = {
+ route: PropTypes.shape({
+ handler: PropTypes.string,
+ method: PropTypes.string,
+ path: PropTypes.string,
+ }),
+};
+
+export default BoundRoute;
diff --git a/packages/strapi/src/extensions/users-permissions/admin/src/components/FormModal/Input/index.js b/packages/strapi/src/extensions/users-permissions/admin/src/components/FormModal/Input/index.js
new file mode 100644
index 0000000..e5eaf94
--- /dev/null
+++ b/packages/strapi/src/extensions/users-permissions/admin/src/components/FormModal/Input/index.js
@@ -0,0 +1,123 @@
+/**
+ *
+ * Input
+ *
+ */
+
+import React from 'react';
+
+import { TextInput, ToggleInput } from '@strapi/design-system';
+import PropTypes from 'prop-types';
+import { useIntl } from 'react-intl';
+
+const Input = ({
+ description,
+ disabled,
+ intlLabel,
+ error,
+ name,
+ onChange,
+ placeholder,
+ providerToEditName,
+ type,
+ value,
+}) => {
+ const { formatMessage } = useIntl();
+ const inputValue =
+ name === 'noName'
+ ? `${window.strapi.backendURL}/api/connect/${providerToEditName}/callback`
+ : value;
+
+ const label = formatMessage(
+ { id: intlLabel.id, defaultMessage: intlLabel.defaultMessage },
+ { provider: providerToEditName, ...intlLabel.values }
+ );
+ const hint = description
+ ? formatMessage(
+ { id: description.id, defaultMessage: description.defaultMessage },
+ { provider: providerToEditName, ...description.values }
+ )
+ : '';
+
+ if (type === 'bool') {
+ return (
+ {
+ onChange({ target: { name, value: e.target.checked } });
+ }}
+ />
+ );
+ }
+
+ const formattedPlaceholder = placeholder
+ ? formatMessage(
+ { id: placeholder.id, defaultMessage: placeholder.defaultMessage },
+ { ...placeholder.values }
+ )
+ : '';
+
+ const errorMessage = error ? formatMessage({ id: error, defaultMessage: error }) : '';
+
+ return (
+
+ );
+};
+
+Input.defaultProps = {
+ description: null,
+ disabled: false,
+ error: '',
+ placeholder: null,
+ value: '',
+};
+
+Input.propTypes = {
+ description: PropTypes.shape({
+ id: PropTypes.string.isRequired,
+ defaultMessage: PropTypes.string.isRequired,
+ values: PropTypes.object,
+ }),
+ disabled: PropTypes.bool,
+ error: PropTypes.string,
+ intlLabel: PropTypes.shape({
+ id: PropTypes.string.isRequired,
+ defaultMessage: PropTypes.string.isRequired,
+ values: PropTypes.object,
+ }).isRequired,
+ name: PropTypes.string.isRequired,
+ onChange: PropTypes.func.isRequired,
+ placeholder: PropTypes.shape({
+ id: PropTypes.string.isRequired,
+ defaultMessage: PropTypes.string.isRequired,
+ values: PropTypes.object,
+ }),
+ providerToEditName: PropTypes.string.isRequired,
+ type: PropTypes.string.isRequired,
+ value: PropTypes.oneOfType([PropTypes.bool, PropTypes.string]),
+};
+
+export default Input;
diff --git a/packages/strapi/src/extensions/users-permissions/admin/src/components/FormModal/index.js b/packages/strapi/src/extensions/users-permissions/admin/src/components/FormModal/index.js
new file mode 100644
index 0000000..83c0592
--- /dev/null
+++ b/packages/strapi/src/extensions/users-permissions/admin/src/components/FormModal/index.js
@@ -0,0 +1,126 @@
+/**
+ *
+ * FormModal
+ *
+ */
+
+import React from 'react';
+
+import {
+ Button,
+ Flex,
+ Grid,
+ GridItem,
+ ModalBody,
+ ModalFooter,
+ ModalHeader,
+ ModalLayout,
+} from '@strapi/design-system';
+import { Breadcrumbs, Crumb } from '@strapi/design-system/v2';
+import { Form } from '@strapi/helper-plugin';
+import { Formik } from 'formik';
+import PropTypes from 'prop-types';
+import { useIntl } from 'react-intl';
+
+import Input from './Input';
+
+const FormModal = ({
+ headerBreadcrumbs,
+ initialData,
+ isSubmiting,
+ layout,
+ isOpen,
+ onSubmit,
+ onToggle,
+ providerToEditName,
+}) => {
+ const { formatMessage } = useIntl();
+
+ if (!isOpen) {
+ return null;
+ }
+
+ return (
+
+
+
+ {headerBreadcrumbs.map((crumb, index, arr) => (
+
+ {crumb}
+
+ ))}
+
+
+ onSubmit(values)}
+ initialValues={initialData}
+ validationSchema={layout.schema}
+ validateOnChange={false}
+ >
+ {({ errors, handleChange, values }) => {
+ return (
+
+
+
+
+ {layout.form.map((row) => {
+ return row.map((input) => {
+ return (
+
+
+
+ );
+ });
+ })}
+
+
+
+
+ {formatMessage({
+ id: 'app.components.Button.cancel',
+ defaultMessage: 'Cancel',
+ })}
+
+ }
+ endActions={
+
+ {formatMessage({ id: 'global.save', defaultMessage: 'Save' })}
+
+ }
+ />
+
+ );
+ }}
+
+
+ );
+};
+
+FormModal.defaultProps = {
+ initialData: null,
+ providerToEditName: null,
+};
+
+FormModal.propTypes = {
+ headerBreadcrumbs: PropTypes.arrayOf(PropTypes.string).isRequired,
+ initialData: PropTypes.object,
+ layout: PropTypes.shape({
+ form: PropTypes.arrayOf(PropTypes.array),
+ schema: PropTypes.object,
+ }).isRequired,
+ isOpen: PropTypes.bool.isRequired,
+ isSubmiting: PropTypes.bool.isRequired,
+ onSubmit: PropTypes.func.isRequired,
+ onToggle: PropTypes.func.isRequired,
+ providerToEditName: PropTypes.string,
+};
+
+export default FormModal;
diff --git a/packages/strapi/src/extensions/users-permissions/admin/src/components/Permissions/PermissionRow/CheckboxWrapper.js b/packages/strapi/src/extensions/users-permissions/admin/src/components/Permissions/PermissionRow/CheckboxWrapper.js
new file mode 100644
index 0000000..e3165e2
--- /dev/null
+++ b/packages/strapi/src/extensions/users-permissions/admin/src/components/Permissions/PermissionRow/CheckboxWrapper.js
@@ -0,0 +1,30 @@
+import { Box } from '@strapi/design-system';
+import styled, { css } from 'styled-components';
+
+const activeCheckboxWrapperStyles = css`
+ background: ${(props) => props.theme.colors.primary100};
+ svg {
+ opacity: 1;
+ }
+`;
+
+const CheckboxWrapper = styled(Box)`
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+
+ svg {
+ opacity: 0;
+ path {
+ fill: ${(props) => props.theme.colors.primary600};
+ }
+ }
+
+ /* Show active style both on hover and when the action is selected */
+ ${(props) => props.isActive && activeCheckboxWrapperStyles}
+ &:hover {
+ ${activeCheckboxWrapperStyles}
+ }
+`;
+
+export default CheckboxWrapper;
diff --git a/packages/strapi/src/extensions/users-permissions/admin/src/components/Permissions/PermissionRow/SubCategory.js b/packages/strapi/src/extensions/users-permissions/admin/src/components/Permissions/PermissionRow/SubCategory.js
new file mode 100644
index 0000000..a9a91bd
--- /dev/null
+++ b/packages/strapi/src/extensions/users-permissions/admin/src/components/Permissions/PermissionRow/SubCategory.js
@@ -0,0 +1,131 @@
+import React, { useCallback, useMemo } from 'react';
+
+import {
+ Box,
+ Checkbox,
+ Flex,
+ Typography,
+ Grid,
+ GridItem,
+ VisuallyHidden,
+} from '@strapi/design-system';
+import { Cog as CogIcon } from '@strapi/icons';
+import get from 'lodash/get';
+import PropTypes from 'prop-types';
+import { useIntl } from 'react-intl';
+import styled from 'styled-components';
+
+import { useUsersPermissions } from '../../../contexts/UsersPermissionsContext';
+
+import CheckboxWrapper from './CheckboxWrapper';
+
+const Border = styled.div`
+ flex: 1;
+ align-self: center;
+ border-top: 1px solid ${({ theme }) => theme.colors.neutral150};
+`;
+
+const SubCategory = ({ subCategory }) => {
+ const { formatMessage } = useIntl();
+ const { onChange, onChangeSelectAll, onSelectedAction, selectedAction, modifiedData } =
+ useUsersPermissions();
+
+ const currentScopedModifiedData = useMemo(() => {
+ return get(modifiedData, subCategory.name, {});
+ }, [modifiedData, subCategory]);
+
+ const hasAllActionsSelected = useMemo(() => {
+ return Object.values(currentScopedModifiedData).every((action) => action.enabled === true);
+ }, [currentScopedModifiedData]);
+
+ const hasSomeActionsSelected = useMemo(() => {
+ return (
+ Object.values(currentScopedModifiedData).some((action) => action.enabled === true) &&
+ !hasAllActionsSelected
+ );
+ }, [currentScopedModifiedData, hasAllActionsSelected]);
+
+ const handleChangeSelectAll = useCallback(
+ ({ target: { name } }) => {
+ onChangeSelectAll({ target: { name, value: !hasAllActionsSelected } });
+ },
+ [hasAllActionsSelected, onChangeSelectAll]
+ );
+
+ const isActionSelected = useCallback(
+ (actionName) => {
+ return selectedAction === actionName;
+ },
+ [selectedAction]
+ );
+
+ return (
+
+
+
+
+ {subCategory.label}
+
+
+
+
+
+ handleChangeSelectAll({ target: { name: subCategory.name, value } })
+ }
+ indeterminate={hasSomeActionsSelected}
+ >
+ {formatMessage({ id: 'app.utils.select-all', defaultMessage: 'Select all' })}
+
+
+
+
+
+ {subCategory.actions.map((action) => {
+ const name = `${action.name}.enabled`;
+
+ return (
+
+
+ onChange({ target: { name, value } })}
+ >
+ {action.label}
+
+ onSelectedAction(action.name)}
+ style={{ display: 'inline-flex', alignItems: 'center' }}
+ >
+
+ {formatMessage(
+ {
+ id: 'app.utils.show-bound-route',
+ defaultMessage: 'Show bound route for {route}',
+ },
+ {
+ route: action.name,
+ }
+ )}
+
+
+
+
+
+ );
+ })}
+
+
+
+ );
+};
+
+SubCategory.propTypes = {
+ subCategory: PropTypes.object.isRequired,
+};
+
+export default SubCategory;
diff --git a/packages/strapi/src/extensions/users-permissions/admin/src/components/Permissions/PermissionRow/index.js b/packages/strapi/src/extensions/users-permissions/admin/src/components/Permissions/PermissionRow/index.js
new file mode 100644
index 0000000..08ff3ff
--- /dev/null
+++ b/packages/strapi/src/extensions/users-permissions/admin/src/components/Permissions/PermissionRow/index.js
@@ -0,0 +1,55 @@
+import React, { useMemo } from 'react';
+
+import { Box } from '@strapi/design-system';
+import sortBy from 'lodash/sortBy';
+import PropTypes from 'prop-types';
+
+import SubCategory from './SubCategory';
+
+const PermissionRow = ({ name, permissions }) => {
+ const subCategories = useMemo(() => {
+ return sortBy(
+ Object.values(permissions.controllers).reduce((acc, curr, index) => {
+ const currentName = `${name}.controllers.${Object.keys(permissions.controllers)[index]}`;
+ const actions = sortBy(
+ Object.keys(curr).reduce((acc, current) => {
+ return [
+ ...acc,
+ {
+ ...curr[current],
+ label: current,
+ name: `${currentName}.${current}`,
+ },
+ ];
+ }, []),
+ 'label'
+ );
+
+ return [
+ ...acc,
+ {
+ actions,
+ label: Object.keys(permissions.controllers)[index],
+ name: currentName,
+ },
+ ];
+ }, []),
+ 'label'
+ );
+ }, [name, permissions]);
+
+ return (
+
+ {subCategories.map((subCategory) => (
+
+ ))}
+
+ );
+};
+
+PermissionRow.propTypes = {
+ name: PropTypes.string.isRequired,
+ permissions: PropTypes.object.isRequired,
+};
+
+export default PermissionRow;
diff --git a/packages/strapi/src/extensions/users-permissions/admin/src/components/Permissions/index.js b/packages/strapi/src/extensions/users-permissions/admin/src/components/Permissions/index.js
new file mode 100644
index 0000000..260ae00
--- /dev/null
+++ b/packages/strapi/src/extensions/users-permissions/admin/src/components/Permissions/index.js
@@ -0,0 +1,57 @@
+import React, { useReducer } from 'react';
+
+import { Accordion, AccordionContent, AccordionToggle, Box, Flex } from '@strapi/design-system';
+import { useIntl } from 'react-intl';
+
+import { useUsersPermissions } from '../../contexts/UsersPermissionsContext';
+import formatPluginName from '../../utils/formatPluginName';
+
+import init from './init';
+import PermissionRow from './PermissionRow';
+import { initialState, reducer } from './reducer';
+
+const Permissions = () => {
+ const { modifiedData } = useUsersPermissions();
+ const { formatMessage } = useIntl();
+ const [{ collapses }, dispatch] = useReducer(reducer, initialState, (state) =>
+ init(state, modifiedData)
+ );
+
+ const handleToggle = (index) =>
+ dispatch({
+ type: 'TOGGLE_COLLAPSE',
+ index,
+ });
+
+ return (
+
+ {collapses.map((collapse, index) => (
+ handleToggle(index)}
+ key={collapse.name}
+ variant={index % 2 === 0 ? 'secondary' : undefined}
+ >
+
+
+
+
+
+
+
+ ))}
+
+ );
+};
+
+export default Permissions;
diff --git a/packages/strapi/src/extensions/users-permissions/admin/src/components/Permissions/init.js b/packages/strapi/src/extensions/users-permissions/admin/src/components/Permissions/init.js
new file mode 100644
index 0000000..4125920
--- /dev/null
+++ b/packages/strapi/src/extensions/users-permissions/admin/src/components/Permissions/init.js
@@ -0,0 +1,9 @@
+const init = (initialState, permissions) => {
+ const collapses = Object.keys(permissions)
+ .sort()
+ .map((name) => ({ name, isOpen: false }));
+
+ return { ...initialState, collapses };
+};
+
+export default init;
diff --git a/packages/strapi/src/extensions/users-permissions/admin/src/components/Permissions/reducer.js b/packages/strapi/src/extensions/users-permissions/admin/src/components/Permissions/reducer.js
new file mode 100644
index 0000000..705e580
--- /dev/null
+++ b/packages/strapi/src/extensions/users-permissions/admin/src/components/Permissions/reducer.js
@@ -0,0 +1,27 @@
+import produce from 'immer';
+
+const initialState = {
+ collapses: [],
+};
+
+const reducer = (state, action) =>
+ // eslint-disable-next-line consistent-return
+ produce(state, (draftState) => {
+ switch (action.type) {
+ case 'TOGGLE_COLLAPSE': {
+ draftState.collapses = state.collapses.map((collapse, index) => {
+ if (index === action.index) {
+ return { ...collapse, isOpen: !collapse.isOpen };
+ }
+
+ return { ...collapse, isOpen: false };
+ });
+
+ break;
+ }
+ default:
+ return draftState;
+ }
+ });
+
+export { initialState, reducer };
diff --git a/packages/strapi/src/extensions/users-permissions/admin/src/components/Policies/index.js b/packages/strapi/src/extensions/users-permissions/admin/src/components/Policies/index.js
new file mode 100644
index 0000000..e9c53b3
--- /dev/null
+++ b/packages/strapi/src/extensions/users-permissions/admin/src/components/Policies/index.js
@@ -0,0 +1,62 @@
+import React from 'react';
+
+import { Flex, GridItem, Typography } from '@strapi/design-system';
+import get from 'lodash/get';
+import isEmpty from 'lodash/isEmpty';
+import without from 'lodash/without';
+import { useIntl } from 'react-intl';
+
+import { useUsersPermissions } from '../../contexts/UsersPermissionsContext';
+import BoundRoute from '../BoundRoute';
+
+const Policies = () => {
+ const { formatMessage } = useIntl();
+ const { selectedAction, routes } = useUsersPermissions();
+
+ const path = without(selectedAction.split('.'), 'controllers');
+ const controllerRoutes = get(routes, path[0]);
+ const pathResolved = path.slice(1).join('.');
+
+ const displayedRoutes = isEmpty(controllerRoutes)
+ ? []
+ : controllerRoutes.filter((o) => o.handler.endsWith(pathResolved));
+
+ return (
+
+ {selectedAction ? (
+
+ {displayedRoutes.map((route, key) => (
+ // eslint-disable-next-line react/no-array-index-key
+
+ ))}
+
+ ) : (
+
+
+ {formatMessage({
+ id: 'users-permissions.Policies.header.title',
+ defaultMessage: 'Advanced settings',
+ })}
+
+
+ {formatMessage({
+ id: 'users-permissions.Policies.header.hint',
+ defaultMessage:
+ "Select the application's actions or the plugin's actions and click on the cog icon to display the bound route",
+ })}
+
+
+ )}
+
+ );
+};
+
+export default Policies;
diff --git a/packages/strapi/src/extensions/users-permissions/admin/src/components/UsersPermissions/index.js b/packages/strapi/src/extensions/users-permissions/admin/src/components/UsersPermissions/index.js
new file mode 100644
index 0000000..6f40fa3
--- /dev/null
+++ b/packages/strapi/src/extensions/users-permissions/admin/src/components/UsersPermissions/index.js
@@ -0,0 +1,95 @@
+import React, { forwardRef, memo, useImperativeHandle, useReducer } from 'react';
+
+import { Flex, Grid, GridItem, Typography } from '@strapi/design-system';
+import PropTypes from 'prop-types';
+import { useIntl } from 'react-intl';
+
+import { UsersPermissionsProvider } from '../../contexts/UsersPermissionsContext';
+import getTrad from '../../utils/getTrad';
+import Permissions from '../Permissions';
+import Policies from '../Policies';
+
+import init from './init';
+import reducer, { initialState } from './reducer';
+
+const UsersPermissions = forwardRef(({ permissions, routes }, ref) => {
+ const { formatMessage } = useIntl();
+ const [state, dispatch] = useReducer(reducer, initialState, (state) =>
+ init(state, permissions, routes)
+ );
+
+ useImperativeHandle(ref, () => ({
+ getPermissions() {
+ return {
+ permissions: state.modifiedData,
+ };
+ },
+ resetForm() {
+ dispatch({ type: 'ON_RESET' });
+ },
+ setFormAfterSubmit() {
+ dispatch({ type: 'ON_SUBMIT_SUCCEEDED' });
+ },
+ }));
+
+ const handleChange = ({ target: { name, value } }) =>
+ dispatch({
+ type: 'ON_CHANGE',
+ keys: name.split('.'),
+ value: value === 'empty__string_value' ? '' : value,
+ });
+
+ const handleChangeSelectAll = ({ target: { name, value } }) =>
+ dispatch({
+ type: 'ON_CHANGE_SELECT_ALL',
+ keys: name.split('.'),
+ value,
+ });
+
+ const handleSelectedAction = (actionToSelect) =>
+ dispatch({
+ type: 'SELECT_ACTION',
+ actionToSelect,
+ });
+
+ const providerValue = {
+ ...state,
+ onChange: handleChange,
+ onChangeSelectAll: handleChangeSelectAll,
+ onSelectedAction: handleSelectedAction,
+ };
+
+ return (
+
+
+
+
+
+
+ {formatMessage({
+ id: getTrad('Plugins.header.title'),
+ defaultMessage: 'Permissions',
+ })}
+
+
+ {formatMessage({
+ id: getTrad('Plugins.header.description'),
+ defaultMessage: 'Only actions bound by a route are listed below.',
+ })}
+
+
+
+
+
+
+
+
+ );
+});
+
+UsersPermissions.propTypes = {
+ permissions: PropTypes.object.isRequired,
+ routes: PropTypes.object.isRequired,
+};
+
+export default memo(UsersPermissions);
diff --git a/packages/strapi/src/extensions/users-permissions/admin/src/components/UsersPermissions/init.js b/packages/strapi/src/extensions/users-permissions/admin/src/components/UsersPermissions/init.js
new file mode 100644
index 0000000..e124042
--- /dev/null
+++ b/packages/strapi/src/extensions/users-permissions/admin/src/components/UsersPermissions/init.js
@@ -0,0 +1,10 @@
+const init = (state, permissions, routes) => {
+ return {
+ ...state,
+ initialData: permissions,
+ modifiedData: permissions,
+ routes,
+ };
+};
+
+export default init;
diff --git a/packages/strapi/src/extensions/users-permissions/admin/src/components/UsersPermissions/reducer.js b/packages/strapi/src/extensions/users-permissions/admin/src/components/UsersPermissions/reducer.js
new file mode 100644
index 0000000..8a03a18
--- /dev/null
+++ b/packages/strapi/src/extensions/users-permissions/admin/src/components/UsersPermissions/reducer.js
@@ -0,0 +1,62 @@
+/* eslint-disable consistent-return */
+import produce from 'immer';
+import get from 'lodash/get';
+import set from 'lodash/set';
+import take from 'lodash/take';
+
+export const initialState = {
+ initialData: {},
+ modifiedData: {},
+ routes: {},
+ selectedAction: '',
+ policies: [],
+};
+
+const reducer = (state, action) =>
+ produce(state, (draftState) => {
+ switch (action.type) {
+ case 'ON_CHANGE': {
+ const keysLength = action.keys.length;
+ const isChangingCheckbox = action.keys[keysLength - 1] === 'enabled';
+
+ if (action.value && isChangingCheckbox) {
+ const selectedAction = take(action.keys, keysLength - 1).join('.');
+ draftState.selectedAction = selectedAction;
+ }
+
+ set(draftState, ['modifiedData', ...action.keys], action.value);
+ break;
+ }
+ case 'ON_CHANGE_SELECT_ALL': {
+ const pathToValue = ['modifiedData', ...action.keys];
+ const oldValues = get(state, pathToValue, {});
+ const updatedValues = Object.keys(oldValues).reduce((acc, current) => {
+ acc[current] = { ...oldValues[current], enabled: action.value };
+
+ return acc;
+ }, {});
+
+ set(draftState, pathToValue, updatedValues);
+
+ break;
+ }
+ case 'ON_RESET': {
+ draftState.modifiedData = state.initialData;
+ break;
+ }
+ case 'ON_SUBMIT_SUCCEEDED': {
+ draftState.initialData = state.modifiedData;
+ break;
+ }
+
+ case 'SELECT_ACTION': {
+ const { actionToSelect } = action;
+ draftState.selectedAction = actionToSelect === state.selectedAction ? '' : actionToSelect;
+ break;
+ }
+ default:
+ return draftState;
+ }
+ });
+
+export default reducer;
diff --git a/packages/strapi/src/extensions/users-permissions/admin/src/contexts/UsersPermissionsContext/index.js b/packages/strapi/src/extensions/users-permissions/admin/src/contexts/UsersPermissionsContext/index.js
new file mode 100644
index 0000000..ce66c34
--- /dev/null
+++ b/packages/strapi/src/extensions/users-permissions/admin/src/contexts/UsersPermissionsContext/index.js
@@ -0,0 +1,18 @@
+import React, { createContext, useContext } from 'react';
+
+import PropTypes from 'prop-types';
+
+const UsersPermissions = createContext({});
+
+const UsersPermissionsProvider = ({ children, value }) => {
+ return {children} ;
+};
+
+const useUsersPermissions = () => useContext(UsersPermissions);
+
+UsersPermissionsProvider.propTypes = {
+ children: PropTypes.node.isRequired,
+ value: PropTypes.object.isRequired,
+};
+
+export { UsersPermissions, UsersPermissionsProvider, useUsersPermissions };
diff --git a/packages/strapi/src/extensions/users-permissions/admin/src/hooks/index.js b/packages/strapi/src/extensions/users-permissions/admin/src/hooks/index.js
new file mode 100644
index 0000000..9988733
--- /dev/null
+++ b/packages/strapi/src/extensions/users-permissions/admin/src/hooks/index.js
@@ -0,0 +1,5 @@
+// eslint-disable-next-line import/prefer-default-export
+export { default as useForm } from './useForm';
+export { default as useRolesList } from './useRolesList';
+export * from './usePlugins';
+export { default as useFetchRole } from './useFetchRole';
diff --git a/packages/strapi/src/extensions/users-permissions/admin/src/hooks/useFetchRole/index.js b/packages/strapi/src/extensions/users-permissions/admin/src/hooks/useFetchRole/index.js
new file mode 100644
index 0000000..629e001
--- /dev/null
+++ b/packages/strapi/src/extensions/users-permissions/admin/src/hooks/useFetchRole/index.js
@@ -0,0 +1,67 @@
+import { useCallback, useEffect, useReducer, useRef } from 'react';
+
+import { useFetchClient, useNotification } from '@strapi/helper-plugin';
+
+import pluginId from '../../pluginId';
+
+import reducer, { initialState } from './reducer';
+
+const useFetchRole = (id) => {
+ const [state, dispatch] = useReducer(reducer, initialState);
+ const toggleNotification = useNotification();
+ const isMounted = useRef(null);
+ const { get } = useFetchClient();
+
+ useEffect(() => {
+ isMounted.current = true;
+
+ if (id) {
+ fetchRole(id);
+ } else {
+ dispatch({
+ type: 'GET_DATA_SUCCEEDED',
+ role: {},
+ });
+ }
+
+ return () => (isMounted.current = false);
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, [id]);
+
+ const fetchRole = async (roleId) => {
+ try {
+ const {
+ data: { role },
+ } = await get(`/${pluginId}/roles/${roleId}`);
+
+ // Prevent updating state on an unmounted component
+ if (isMounted.current) {
+ dispatch({
+ type: 'GET_DATA_SUCCEEDED',
+ role,
+ });
+ }
+ } catch (err) {
+ console.error(err);
+
+ dispatch({
+ type: 'GET_DATA_ERROR',
+ });
+ toggleNotification({
+ type: 'warning',
+ message: { id: 'notification.error' },
+ });
+ }
+ };
+
+ const handleSubmitSucceeded = useCallback((data) => {
+ dispatch({
+ type: 'ON_SUBMIT_SUCCEEDED',
+ ...data,
+ });
+ }, []);
+
+ return { ...state, onSubmitSucceeded: handleSubmitSucceeded };
+};
+
+export default useFetchRole;
diff --git a/packages/strapi/src/extensions/users-permissions/admin/src/hooks/useFetchRole/reducer.js b/packages/strapi/src/extensions/users-permissions/admin/src/hooks/useFetchRole/reducer.js
new file mode 100644
index 0000000..99dcf0d
--- /dev/null
+++ b/packages/strapi/src/extensions/users-permissions/admin/src/hooks/useFetchRole/reducer.js
@@ -0,0 +1,31 @@
+/* eslint-disable consistent-return */
+import produce from 'immer';
+
+export const initialState = {
+ role: {},
+ isLoading: true,
+};
+
+const reducer = (state, action) =>
+ produce(state, (draftState) => {
+ switch (action.type) {
+ case 'GET_DATA_SUCCEEDED': {
+ draftState.role = action.role;
+ draftState.isLoading = false;
+ break;
+ }
+ case 'GET_DATA_ERROR': {
+ draftState.isLoading = false;
+ break;
+ }
+ case 'ON_SUBMIT_SUCCEEDED': {
+ draftState.role.name = action.name;
+ draftState.role.description = action.description;
+ break;
+ }
+ default:
+ return draftState;
+ }
+ });
+
+export default reducer;
diff --git a/packages/strapi/src/extensions/users-permissions/admin/src/hooks/useForm/index.js b/packages/strapi/src/extensions/users-permissions/admin/src/hooks/useForm/index.js
new file mode 100644
index 0000000..0cf0ef6
--- /dev/null
+++ b/packages/strapi/src/extensions/users-permissions/admin/src/hooks/useForm/index.js
@@ -0,0 +1,70 @@
+import { useCallback, useEffect, useReducer, useRef } from 'react';
+
+import { useFetchClient, useNotification, useRBAC } from '@strapi/helper-plugin';
+
+import { getRequestURL } from '../../utils';
+
+import reducer, { initialState } from './reducer';
+
+const useUserForm = (endPoint, permissions) => {
+ const { isLoading: isLoadingForPermissions, allowedActions } = useRBAC(permissions);
+ const [{ isLoading, modifiedData }, dispatch] = useReducer(reducer, initialState);
+ const toggleNotification = useNotification();
+ const isMounted = useRef(true);
+
+ const { get } = useFetchClient();
+
+ useEffect(() => {
+ const getData = async () => {
+ try {
+ dispatch({
+ type: 'GET_DATA',
+ });
+
+ const { data } = await get(getRequestURL(endPoint));
+
+ dispatch({
+ type: 'GET_DATA_SUCCEEDED',
+ data,
+ });
+ } catch (err) {
+ // The user aborted the request
+ if (isMounted.current) {
+ dispatch({
+ type: 'GET_DATA_ERROR',
+ });
+ console.error(err);
+ toggleNotification({
+ type: 'warning',
+ message: { id: 'notification.error' },
+ });
+ }
+ }
+ };
+
+ if (!isLoadingForPermissions) {
+ getData();
+ }
+
+ return () => {
+ isMounted.current = false;
+ };
+ }, [isLoadingForPermissions, endPoint, get, toggleNotification]);
+
+ const dispatchSubmitSucceeded = useCallback((data) => {
+ dispatch({
+ type: 'ON_SUBMIT_SUCCEEDED',
+ data,
+ });
+ }, []);
+
+ return {
+ allowedActions,
+ dispatchSubmitSucceeded,
+ isLoading,
+ isLoadingForPermissions,
+ modifiedData,
+ };
+};
+
+export default useUserForm;
diff --git a/packages/strapi/src/extensions/users-permissions/admin/src/hooks/useForm/reducer.js b/packages/strapi/src/extensions/users-permissions/admin/src/hooks/useForm/reducer.js
new file mode 100644
index 0000000..1d05786
--- /dev/null
+++ b/packages/strapi/src/extensions/users-permissions/admin/src/hooks/useForm/reducer.js
@@ -0,0 +1,40 @@
+import produce from 'immer';
+
+const initialState = {
+ isLoading: true,
+ modifiedData: {},
+};
+
+const reducer = (state, action) =>
+ // eslint-disable-next-line consistent-return
+ produce(state, (draftState) => {
+ switch (action.type) {
+ case 'GET_DATA': {
+ draftState.isLoading = true;
+ draftState.modifiedData = {};
+
+ break;
+ }
+ case 'GET_DATA_SUCCEEDED': {
+ draftState.isLoading = false;
+ draftState.modifiedData = action.data;
+
+ break;
+ }
+ case 'GET_DATA_ERROR': {
+ draftState.isLoading = true;
+ break;
+ }
+ case 'ON_SUBMIT_SUCCEEDED': {
+ draftState.modifiedData = action.data;
+
+ break;
+ }
+ default: {
+ return draftState;
+ }
+ }
+ });
+
+export default reducer;
+export { initialState };
diff --git a/packages/strapi/src/extensions/users-permissions/admin/src/hooks/usePlugins.js b/packages/strapi/src/extensions/users-permissions/admin/src/hooks/usePlugins.js
new file mode 100644
index 0000000..ce1f0e8
--- /dev/null
+++ b/packages/strapi/src/extensions/users-permissions/admin/src/hooks/usePlugins.js
@@ -0,0 +1,71 @@
+import { useEffect } from 'react';
+
+import { useNotification, useFetchClient, useAPIErrorHandler } from '@strapi/helper-plugin';
+import { useQueries } from 'react-query';
+
+import pluginId from '../pluginId';
+import { cleanPermissions, getTrad } from '../utils';
+
+export const usePlugins = () => {
+ const toggleNotification = useNotification();
+ const { get } = useFetchClient();
+ const { formatAPIError } = useAPIErrorHandler(getTrad);
+
+ const [
+ {
+ data: permissions,
+ isLoading: isLoadingPermissions,
+ error: permissionsError,
+ refetch: refetchPermissions,
+ },
+ { data: routes, isLoading: isLoadingRoutes, error: routesError, refetch: refetchRoutes },
+ ] = useQueries([
+ {
+ queryKey: [pluginId, 'permissions'],
+ async queryFn() {
+ const res = await get(`/${pluginId}/permissions`);
+
+ return res.data.permissions;
+ },
+ },
+ {
+ queryKey: [pluginId, 'routes'],
+ async queryFn() {
+ const res = await get(`/${pluginId}/routes`);
+
+ return res.data.routes;
+ },
+ },
+ ]);
+
+ const refetchQueries = async () => {
+ await Promise.all([refetchPermissions(), refetchRoutes()]);
+ };
+
+ useEffect(() => {
+ if (permissionsError) {
+ toggleNotification({
+ type: 'warning',
+ message: formatAPIError(permissionsError),
+ });
+ }
+ }, [toggleNotification, permissionsError, formatAPIError]);
+
+ useEffect(() => {
+ if (routesError) {
+ toggleNotification({
+ type: 'warning',
+ message: formatAPIError(routesError),
+ });
+ }
+ }, [toggleNotification, routesError, formatAPIError]);
+
+ const isLoading = isLoadingPermissions || isLoadingRoutes;
+
+ return {
+ permissions: permissions ? cleanPermissions(permissions) : {},
+ routes: routes ?? {},
+ getData: refetchQueries,
+ isLoading,
+ };
+};
diff --git a/packages/strapi/src/extensions/users-permissions/admin/src/hooks/useRolesList/index.js b/packages/strapi/src/extensions/users-permissions/admin/src/hooks/useRolesList/index.js
new file mode 100644
index 0000000..aae9175
--- /dev/null
+++ b/packages/strapi/src/extensions/users-permissions/admin/src/hooks/useRolesList/index.js
@@ -0,0 +1,65 @@
+import { useCallback, useEffect, useReducer, useRef } from 'react';
+
+import { useFetchClient, useNotification } from '@strapi/helper-plugin';
+import get from 'lodash/get';
+
+import pluginId from '../../pluginId';
+
+import init from './init';
+import reducer, { initialState } from './reducer';
+
+const useRolesList = (shouldFetchData = true) => {
+ const [{ roles, isLoading }, dispatch] = useReducer(reducer, initialState, () =>
+ init(initialState, shouldFetchData)
+ );
+ const toggleNotification = useNotification();
+
+ const isMounted = useRef(true);
+ const fetchClient = useFetchClient();
+
+ const fetchRolesList = useCallback(async () => {
+ try {
+ dispatch({
+ type: 'GET_DATA',
+ });
+
+ const {
+ data: { roles },
+ } = await fetchClient.get(`/${pluginId}/roles`);
+
+ dispatch({
+ type: 'GET_DATA_SUCCEEDED',
+ data: roles,
+ });
+ } catch (err) {
+ const message = get(err, ['response', 'payload', 'message'], 'An error occured');
+
+ if (isMounted.current) {
+ dispatch({
+ type: 'GET_DATA_ERROR',
+ });
+
+ if (message !== 'Forbidden') {
+ toggleNotification({
+ type: 'warning',
+ message,
+ });
+ }
+ }
+ }
+ }, [fetchClient, toggleNotification]);
+
+ useEffect(() => {
+ if (shouldFetchData) {
+ fetchRolesList();
+ }
+
+ return () => {
+ isMounted.current = false;
+ };
+ }, [shouldFetchData, fetchRolesList]);
+
+ return { roles, isLoading, getData: fetchRolesList };
+};
+
+export default useRolesList;
diff --git a/packages/strapi/src/extensions/users-permissions/admin/src/hooks/useRolesList/init.js b/packages/strapi/src/extensions/users-permissions/admin/src/hooks/useRolesList/init.js
new file mode 100644
index 0000000..dfe71d9
--- /dev/null
+++ b/packages/strapi/src/extensions/users-permissions/admin/src/hooks/useRolesList/init.js
@@ -0,0 +1,5 @@
+const init = (initialState, shouldFetchData) => {
+ return { ...initialState, isLoading: shouldFetchData };
+};
+
+export default init;
diff --git a/packages/strapi/src/extensions/users-permissions/admin/src/hooks/useRolesList/reducer.js b/packages/strapi/src/extensions/users-permissions/admin/src/hooks/useRolesList/reducer.js
new file mode 100644
index 0000000..a6d347b
--- /dev/null
+++ b/packages/strapi/src/extensions/users-permissions/admin/src/hooks/useRolesList/reducer.js
@@ -0,0 +1,31 @@
+/* eslint-disable consistent-return */
+import produce from 'immer';
+
+export const initialState = {
+ roles: [],
+ isLoading: true,
+};
+
+const reducer = (state, action) =>
+ produce(state, (draftState) => {
+ switch (action.type) {
+ case 'GET_DATA': {
+ draftState.isLoading = true;
+ draftState.roles = [];
+ break;
+ }
+ case 'GET_DATA_SUCCEEDED': {
+ draftState.roles = action.data;
+ draftState.isLoading = false;
+ break;
+ }
+ case 'GET_DATA_ERROR': {
+ draftState.isLoading = false;
+ break;
+ }
+ default:
+ return draftState;
+ }
+ });
+
+export default reducer;
diff --git a/packages/strapi/src/extensions/users-permissions/admin/src/index.js b/packages/strapi/src/extensions/users-permissions/admin/src/index.js
new file mode 100644
index 0000000..ba721ed
--- /dev/null
+++ b/packages/strapi/src/extensions/users-permissions/admin/src/index.js
@@ -0,0 +1,125 @@
+// NOTE TO PLUGINS DEVELOPERS:
+// If you modify this file by adding new options to the plugin entry point
+// Here's the file: strapi/docs/3.0.0-beta.x/plugin-development/frontend-field-api.md
+// Here's the file: strapi/docs/3.0.0-beta.x/guides/registering-a-field-in-admin.md
+// Also the strapi-generate-plugins/files/admin/src/index.js needs to be updated
+// IF THE DOC IS NOT UPDATED THE PULL REQUEST WILL NOT BE MERGED
+import { prefixPluginTranslations } from '@strapi/helper-plugin';
+
+import pluginPkg from '../../package.json';
+
+import pluginPermissions from './permissions';
+import pluginId from './pluginId';
+import getTrad from './utils/getTrad';
+
+const name = pluginPkg.strapi.name;
+
+export default {
+ register(app) {
+ // Create the plugin's settings section
+ app.createSettingSection(
+ {
+ id: pluginId,
+ intlLabel: {
+ id: getTrad('Settings.section-label'),
+ defaultMessage: 'Users & Permissions plugin',
+ },
+ },
+ [
+ {
+ intlLabel: {
+ id: 'global.roles',
+ defaultMessage: 'Roles',
+ },
+ id: 'roles',
+ to: `/settings/${pluginId}/roles`,
+ async Component() {
+ const component = await import(
+ /* webpackChunkName: "users-roles-settings-page" */ './pages/Roles'
+ );
+
+ return component;
+ },
+ permissions: pluginPermissions.accessRoles,
+ },
+ {
+ intlLabel: {
+ id: getTrad('HeaderNav.link.providers'),
+ defaultMessage: 'Providers',
+ },
+ id: 'providers',
+ to: `/settings/${pluginId}/providers`,
+ async Component() {
+ const component = await import(
+ /* webpackChunkName: "users-providers-settings-page" */ './pages/Providers'
+ );
+
+ return component;
+ },
+ permissions: pluginPermissions.readProviders,
+ },
+ {
+ intlLabel: {
+ id: getTrad('HeaderNav.link.emailTemplates'),
+ defaultMessage: 'Email templates',
+ },
+ id: 'email-templates',
+ to: `/settings/${pluginId}/email-templates`,
+ async Component() {
+ const component = await import(
+ /* webpackChunkName: "users-email-settings-page" */ './pages/EmailTemplates'
+ );
+
+ return component;
+ },
+ permissions: pluginPermissions.readEmailTemplates,
+ },
+ {
+ intlLabel: {
+ id: getTrad('HeaderNav.link.advancedSettings'),
+ defaultMessage: 'Advanced Settings',
+ },
+ id: 'advanced-settings',
+ to: `/settings/${pluginId}/advanced-settings`,
+ async Component() {
+ const component = await import(
+ /* webpackChunkName: "users-advanced-settings-page" */ './pages/AdvancedSettings'
+ );
+
+ return component;
+ },
+ permissions: pluginPermissions.readAdvancedSettings,
+ },
+ ]
+ );
+
+ app.registerPlugin({
+ id: pluginId,
+ name,
+ });
+ },
+ bootstrap() {},
+ async registerTrads({ locales }) {
+ const importedTrads = await Promise.all(
+ locales.map((locale) => {
+ return import(
+ /* webpackChunkName: "users-permissions-translation-[request]" */ `./translations/${locale}.json`
+ )
+ .then(({ default: data }) => {
+ return {
+ data: prefixPluginTranslations(data, pluginId),
+ locale,
+ };
+ })
+ .catch(() => {
+ return {
+ data: {},
+ locale,
+ };
+ });
+ })
+ );
+
+ return Promise.resolve(importedTrads);
+ },
+};
diff --git a/packages/strapi/src/extensions/users-permissions/admin/src/pages/AdvancedSettings/index.js b/packages/strapi/src/extensions/users-permissions/admin/src/pages/AdvancedSettings/index.js
new file mode 100644
index 0000000..3f0726f
--- /dev/null
+++ b/packages/strapi/src/extensions/users-permissions/admin/src/pages/AdvancedSettings/index.js
@@ -0,0 +1,246 @@
+import React, { useMemo } from 'react';
+
+import {
+ Box,
+ Button,
+ ContentLayout,
+ Flex,
+ Grid,
+ GridItem,
+ HeaderLayout,
+ Main,
+ Option,
+ Select,
+ Typography,
+ useNotifyAT,
+} from '@strapi/design-system';
+import {
+ CheckPagePermissions,
+ Form,
+ GenericInput,
+ LoadingIndicatorPage,
+ SettingsPageTitle,
+ useFocusWhenNavigate,
+ useNotification,
+ useOverlayBlocker,
+ useRBAC,
+} from '@strapi/helper-plugin';
+import { Check } from '@strapi/icons';
+import { Formik } from 'formik';
+import { useIntl } from 'react-intl';
+import { useMutation, useQuery, useQueryClient } from 'react-query';
+
+import pluginPermissions from '../../permissions';
+import { getTrad } from '../../utils';
+
+import { fetchData, putAdvancedSettings } from './utils/api';
+import layout from './utils/layout';
+import schema from './utils/schema';
+
+const ProtectedAdvancedSettingsPage = () => (
+
+
+
+);
+
+const AdvancedSettingsPage = () => {
+ const { formatMessage } = useIntl();
+ const toggleNotification = useNotification();
+ const { lockApp, unlockApp } = useOverlayBlocker();
+ const { notifyStatus } = useNotifyAT();
+ const queryClient = useQueryClient();
+ useFocusWhenNavigate();
+
+ const updatePermissions = useMemo(
+ () => ({ update: pluginPermissions.updateAdvancedSettings }),
+ []
+ );
+ const {
+ isLoading: isLoadingForPermissions,
+ allowedActions: { canUpdate },
+ } = useRBAC(updatePermissions);
+
+ const { status: isLoadingData, data } = useQuery('advanced', () => fetchData(), {
+ onSuccess() {
+ notifyStatus(
+ formatMessage({
+ id: getTrad('Form.advancedSettings.data.loaded'),
+ defaultMessage: 'Advanced settings data has been loaded',
+ })
+ );
+ },
+ onError() {
+ toggleNotification({
+ type: 'warning',
+ message: { id: getTrad('notification.error'), defaultMessage: 'An error occured' },
+ });
+ },
+ });
+
+ const isLoading = isLoadingForPermissions || isLoadingData !== 'success';
+
+ const submitMutation = useMutation((body) => putAdvancedSettings(body), {
+ async onSuccess() {
+ await queryClient.invalidateQueries('advanced');
+ toggleNotification({
+ type: 'success',
+ message: { id: getTrad('notification.success.saved'), defaultMessage: 'Saved' },
+ });
+
+ unlockApp();
+ },
+ onError() {
+ toggleNotification({
+ type: 'warning',
+ message: { id: getTrad('notification.error'), defaultMessage: 'An error occured' },
+ });
+ unlockApp();
+ },
+ refetchActive: true,
+ });
+
+ const { isLoading: isSubmittingForm } = submitMutation;
+
+ const handleSubmit = async (body) => {
+ lockApp();
+
+ const urlConfirmation = body.email_confirmation ? body.email_confirmation_redirection : '';
+
+ await submitMutation.mutateAsync({ ...body, email_confirmation_redirection: urlConfirmation });
+ };
+
+ if (isLoading) {
+ return (
+
+
+
+
+
+
+
+ );
+ }
+
+ return (
+
+
+
+ {({ errors, values, handleChange, isSubmitting }) => {
+ return (
+
+ }
+ size="S"
+ >
+ {formatMessage({ id: 'global.save', defaultMessage: 'Save' })}
+
+ }
+ />
+
+
+
+
+ {formatMessage({
+ id: 'global.settings',
+ defaultMessage: 'Settings',
+ })}
+
+
+
+
+ handleChange({ target: { name: 'default_role', value: e } })
+ }
+ >
+ {data.roles.map((role) => {
+ return (
+
+ {role.name}
+
+ );
+ })}
+
+
+ {layout.map((input) => {
+ let value = values[input.name];
+
+ if (!value) {
+ value = input.type === 'bool' ? false : '';
+ }
+
+ return (
+
+
+
+ );
+ })}
+
+
+
+
+
+ );
+ }}
+
+
+ );
+};
+
+export default ProtectedAdvancedSettingsPage;
diff --git a/packages/strapi/src/extensions/users-permissions/admin/src/pages/AdvancedSettings/utils/api.js b/packages/strapi/src/extensions/users-permissions/admin/src/pages/AdvancedSettings/utils/api.js
new file mode 100644
index 0000000..238862a
--- /dev/null
+++ b/packages/strapi/src/extensions/users-permissions/admin/src/pages/AdvancedSettings/utils/api.js
@@ -0,0 +1,18 @@
+import { getFetchClient } from '@strapi/helper-plugin';
+
+import { getRequestURL } from '../../../utils';
+
+const fetchData = async () => {
+ const { get } = getFetchClient();
+ const { data } = await get(getRequestURL('advanced'));
+
+ return data;
+};
+
+const putAdvancedSettings = (body) => {
+ const { put } = getFetchClient();
+
+ return put(getRequestURL('advanced'), body);
+};
+
+export { fetchData, putAdvancedSettings };
diff --git a/packages/strapi/src/extensions/users-permissions/admin/src/pages/AdvancedSettings/utils/layout.js b/packages/strapi/src/extensions/users-permissions/admin/src/pages/AdvancedSettings/utils/layout.js
new file mode 100644
index 0000000..094e5a6
--- /dev/null
+++ b/packages/strapi/src/extensions/users-permissions/admin/src/pages/AdvancedSettings/utils/layout.js
@@ -0,0 +1,96 @@
+import { getTrad } from '../../../utils';
+
+const layout = [
+ {
+ intlLabel: {
+ id: getTrad('EditForm.inputToggle.label.email'),
+ defaultMessage: 'One account per email address',
+ },
+ description: {
+ id: getTrad('EditForm.inputToggle.description.email'),
+ defaultMessage:
+ 'Disallow the user to create multiple accounts using the same email address with different authentication providers.',
+ },
+ name: 'unique_email',
+ type: 'bool',
+ size: {
+ col: 12,
+ xs: 12,
+ },
+ },
+ {
+ intlLabel: {
+ id: getTrad('EditForm.inputToggle.label.sign-up'),
+ defaultMessage: 'Enable sign-ups',
+ },
+ description: {
+ id: getTrad('EditForm.inputToggle.description.sign-up'),
+ defaultMessage:
+ 'When disabled (OFF), the registration process is forbidden. No one can subscribe anymore no matter the used provider.',
+ },
+ name: 'allow_register',
+ type: 'bool',
+ size: {
+ col: 12,
+ xs: 12,
+ },
+ },
+ {
+ intlLabel: {
+ id: getTrad('EditForm.inputToggle.label.email-reset-password'),
+ defaultMessage: 'Reset password page',
+ },
+ description: {
+ id: getTrad('EditForm.inputToggle.description.email-reset-password'),
+ defaultMessage: "URL of your application's reset password page.",
+ },
+ placeholder: {
+ id: getTrad('EditForm.inputToggle.placeholder.email-reset-password'),
+ defaultMessage: 'ex: https://youtfrontend.com/reset-password',
+ },
+ name: 'email_reset_password',
+ type: 'text',
+ size: {
+ col: 6,
+ xs: 12,
+ },
+ },
+ {
+ intlLabel: {
+ id: getTrad('EditForm.inputToggle.label.email-confirmation'),
+ defaultMessage: 'Enable email confirmation',
+ },
+ description: {
+ id: getTrad('EditForm.inputToggle.description.email-confirmation'),
+ defaultMessage: 'When enabled (ON), new registered users receive a confirmation email.',
+ },
+ name: 'email_confirmation',
+ type: 'bool',
+ size: {
+ col: 12,
+ xs: 12,
+ },
+ },
+ {
+ intlLabel: {
+ id: getTrad('EditForm.inputToggle.label.email-confirmation-redirection'),
+ defaultMessage: 'Redirection url',
+ },
+ description: {
+ id: getTrad('EditForm.inputToggle.description.email-confirmation-redirection'),
+ defaultMessage: 'After you confirmed your email, choose where you will be redirected.',
+ },
+ placeholder: {
+ id: getTrad('EditForm.inputToggle.placeholder.email-confirmation-redirection'),
+ defaultMessage: 'ex: https://youtfrontend.com/email-confirmation',
+ },
+ name: 'email_confirmation_redirection',
+ type: 'text',
+ size: {
+ col: 6,
+ xs: 12,
+ },
+ },
+];
+
+export default layout;
diff --git a/packages/strapi/src/extensions/users-permissions/admin/src/pages/AdvancedSettings/utils/schema.js b/packages/strapi/src/extensions/users-permissions/admin/src/pages/AdvancedSettings/utils/schema.js
new file mode 100644
index 0000000..b8958a8
--- /dev/null
+++ b/packages/strapi/src/extensions/users-permissions/admin/src/pages/AdvancedSettings/utils/schema.js
@@ -0,0 +1,19 @@
+import { translatedErrors } from '@strapi/helper-plugin';
+import * as yup from 'yup';
+
+// eslint-disable-next-line prefer-regex-literals
+const URL_REGEX = new RegExp('(^$)|((.+:\\/\\/.*)(d*)\\/?(.*))');
+
+const schema = yup.object().shape({
+ email_confirmation_redirection: yup.mixed().when('email_confirmation', {
+ is: true,
+ then: yup.string().matches(URL_REGEX).required(),
+ otherwise: yup.string().nullable(),
+ }),
+ email_reset_password: yup
+ .string(translatedErrors.string)
+ .matches(URL_REGEX, translatedErrors.regex)
+ .nullable(),
+});
+
+export default schema;
diff --git a/packages/strapi/src/extensions/users-permissions/admin/src/pages/EmailTemplates/components/EmailForm.js b/packages/strapi/src/extensions/users-permissions/admin/src/pages/EmailTemplates/components/EmailForm.js
new file mode 100644
index 0000000..5d98122
--- /dev/null
+++ b/packages/strapi/src/extensions/users-permissions/admin/src/pages/EmailTemplates/components/EmailForm.js
@@ -0,0 +1,176 @@
+import React from 'react';
+
+import {
+ Button,
+ Grid,
+ GridItem,
+ ModalBody,
+ ModalFooter,
+ ModalHeader,
+ ModalLayout,
+ Textarea,
+} from '@strapi/design-system';
+import { Breadcrumbs, Crumb } from '@strapi/design-system/v2';
+import { Form, GenericInput } from '@strapi/helper-plugin';
+import { Formik } from 'formik';
+import PropTypes from 'prop-types';
+import { useIntl } from 'react-intl';
+
+import { getTrad } from '../../../utils';
+import schema from '../utils/schema';
+
+const EmailForm = ({ template, onToggle, onSubmit }) => {
+ const { formatMessage } = useIntl();
+
+ return (
+
+
+
+
+ {formatMessage({
+ id: getTrad('PopUpForm.header.edit.email-templates'),
+ defaultMessage: 'Edit email template',
+ })}
+
+
+ {formatMessage({ id: getTrad(template.display), defaultMessage: template.display })}
+
+
+
+
+ {({ errors, values, handleChange, isSubmitting }) => {
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Cancel
+
+ }
+ endActions={
+
+ Finish
+
+ }
+ />
+
+ );
+ }}
+
+
+ );
+};
+
+EmailForm.propTypes = {
+ template: PropTypes.shape({
+ display: PropTypes.string,
+ icon: PropTypes.string,
+ options: PropTypes.shape({
+ from: PropTypes.shape({
+ name: PropTypes.string,
+ email: PropTypes.string,
+ }),
+ message: PropTypes.string,
+ object: PropTypes.string,
+ response_email: PropTypes.string,
+ }),
+ }).isRequired,
+ onSubmit: PropTypes.func.isRequired,
+ onToggle: PropTypes.func.isRequired,
+};
+
+export default EmailForm;
diff --git a/packages/strapi/src/extensions/users-permissions/admin/src/pages/EmailTemplates/components/EmailTable.js b/packages/strapi/src/extensions/users-permissions/admin/src/pages/EmailTemplates/components/EmailTable.js
new file mode 100644
index 0000000..6562324
--- /dev/null
+++ b/packages/strapi/src/extensions/users-permissions/admin/src/pages/EmailTemplates/components/EmailTable.js
@@ -0,0 +1,128 @@
+import React from 'react';
+
+import {
+ Icon,
+ IconButton,
+ Table,
+ Tbody,
+ Td,
+ Th,
+ Thead,
+ Tr,
+ Typography,
+ VisuallyHidden,
+} from '@strapi/design-system';
+import { onRowClick, stopPropagation } from '@strapi/helper-plugin';
+import { Check, Pencil, Refresh } from '@strapi/icons';
+import PropTypes from 'prop-types';
+import { useIntl } from 'react-intl';
+
+import { getTrad } from '../../../utils';
+
+const EmailTable = ({ canUpdate, onEditClick }) => {
+ const { formatMessage } = useIntl();
+
+ return (
+
+
+
+
+
+ {formatMessage({
+ id: getTrad('Email.template.table.icon.label'),
+ defaultMessage: 'icon',
+ })}
+
+
+
+
+ {formatMessage({
+ id: getTrad('Email.template.table.name.label'),
+ defaultMessage: 'name',
+ })}
+
+
+
+
+ {formatMessage({
+ id: getTrad('Email.template.table.action.label'),
+ defaultMessage: 'action',
+ })}
+
+
+
+
+
+ onEditClick('reset_password') })}>
+
+
+
+
+
+
+
+ {formatMessage({
+ id: 'global.reset-password',
+ defaultMessage: 'Reset password',
+ })}
+
+
+
+ onEditClick('reset_password')}
+ label={formatMessage({
+ id: getTrad('Email.template.form.edit.label'),
+ defaultMessage: 'Edit a template',
+ })}
+ noBorder
+ icon={canUpdate && }
+ />
+
+
+ onEditClick('email_confirmation') })}>
+
+
+
+
+
+
+
+ {formatMessage({
+ id: getTrad('Email.template.email_confirmation'),
+ defaultMessage: 'Email address confirmation',
+ })}
+
+
+
+ onEditClick('email_confirmation')}
+ label={formatMessage({
+ id: getTrad('Email.template.form.edit.label'),
+ defaultMessage: 'Edit a template',
+ })}
+ noBorder
+ icon={canUpdate && }
+ />
+
+
+
+
+ );
+};
+
+EmailTable.propTypes = {
+ canUpdate: PropTypes.bool.isRequired,
+ onEditClick: PropTypes.func.isRequired,
+};
+
+export default EmailTable;
diff --git a/packages/strapi/src/extensions/users-permissions/admin/src/pages/EmailTemplates/index.js b/packages/strapi/src/extensions/users-permissions/admin/src/pages/EmailTemplates/index.js
new file mode 100644
index 0000000..3c3887c
--- /dev/null
+++ b/packages/strapi/src/extensions/users-permissions/admin/src/pages/EmailTemplates/index.js
@@ -0,0 +1,163 @@
+import React, { useMemo, useRef, useState } from 'react';
+
+import { ContentLayout, HeaderLayout, Main, useNotifyAT } from '@strapi/design-system';
+import {
+ CheckPagePermissions,
+ LoadingIndicatorPage,
+ SettingsPageTitle,
+ useFocusWhenNavigate,
+ useNotification,
+ useOverlayBlocker,
+ useRBAC,
+ useTracking,
+} from '@strapi/helper-plugin';
+import { useIntl } from 'react-intl';
+import { useMutation, useQuery, useQueryClient } from 'react-query';
+
+import pluginPermissions from '../../permissions';
+import { getTrad } from '../../utils';
+
+import EmailForm from './components/EmailForm';
+import EmailTable from './components/EmailTable';
+import { fetchData, putEmailTemplate } from './utils/api';
+
+const ProtectedEmailTemplatesPage = () => (
+
+
+
+);
+
+const EmailTemplatesPage = () => {
+ const { formatMessage } = useIntl();
+ const { trackUsage } = useTracking();
+ const { notifyStatus } = useNotifyAT();
+ const toggleNotification = useNotification();
+ const { lockApp, unlockApp } = useOverlayBlocker();
+ const trackUsageRef = useRef(trackUsage);
+ const queryClient = useQueryClient();
+ useFocusWhenNavigate();
+
+ const [isModalOpen, setIsModalOpen] = useState(false);
+ const [templateToEdit, setTemplateToEdit] = useState(null);
+
+ const updatePermissions = useMemo(() => {
+ return { update: pluginPermissions.updateEmailTemplates };
+ }, []);
+
+ const {
+ isLoading: isLoadingForPermissions,
+ allowedActions: { canUpdate },
+ } = useRBAC(updatePermissions);
+
+ const { status: isLoadingData, data } = useQuery('email-templates', () => fetchData(), {
+ onSuccess() {
+ notifyStatus(
+ formatMessage({
+ id: getTrad('Email.template.data.loaded'),
+ defaultMessage: 'Email templates has been loaded',
+ })
+ );
+ },
+ onError() {
+ toggleNotification({
+ type: 'warning',
+ message: { id: 'notification.error', defaultMessage: 'An error occured' },
+ });
+ },
+ });
+
+ const isLoading = isLoadingForPermissions || isLoadingData !== 'success';
+
+ const handleToggle = () => {
+ setIsModalOpen((prev) => !prev);
+ };
+
+ const handleEditClick = (template) => {
+ setTemplateToEdit(template);
+ handleToggle();
+ };
+
+ const submitMutation = useMutation((body) => putEmailTemplate({ 'email-templates': body }), {
+ async onSuccess() {
+ await queryClient.invalidateQueries('email-templates');
+
+ toggleNotification({
+ type: 'success',
+ message: { id: 'notification.success.saved', defaultMessage: 'Saved' },
+ });
+
+ trackUsageRef.current('didEditEmailTemplates');
+
+ unlockApp();
+ handleToggle();
+ },
+ onError() {
+ toggleNotification({
+ type: 'warning',
+ message: { id: 'notification.error', defaultMessage: 'An error occured' },
+ });
+ unlockApp();
+ },
+ refetchActive: true,
+ });
+ const { isLoading: isSubmittingForm } = submitMutation;
+
+ const handleSubmit = (body) => {
+ lockApp();
+ trackUsageRef.current('willEditEmailTemplates');
+
+ const editedTemplates = { ...data, [templateToEdit]: body };
+ submitMutation.mutate(editedTemplates);
+ };
+
+ if (isLoading) {
+ return (
+
+
+
+
+
+
+
+ );
+ }
+
+ return (
+
+
+
+
+
+ {isModalOpen && (
+
+ )}
+
+
+ );
+};
+
+export default ProtectedEmailTemplatesPage;
diff --git a/packages/strapi/src/extensions/users-permissions/admin/src/pages/EmailTemplates/utils/api.js b/packages/strapi/src/extensions/users-permissions/admin/src/pages/EmailTemplates/utils/api.js
new file mode 100644
index 0000000..46aef9f
--- /dev/null
+++ b/packages/strapi/src/extensions/users-permissions/admin/src/pages/EmailTemplates/utils/api.js
@@ -0,0 +1,18 @@
+import { getFetchClient } from '@strapi/helper-plugin';
+
+import { getRequestURL } from '../../../utils';
+
+const fetchData = async () => {
+ const { get } = getFetchClient();
+ const { data } = await get(getRequestURL('email-templates'));
+
+ return data;
+};
+
+const putEmailTemplate = (body) => {
+ const { put } = getFetchClient();
+
+ return put(getRequestURL('email-templates'), body);
+};
+
+export { fetchData, putEmailTemplate };
diff --git a/packages/strapi/src/extensions/users-permissions/admin/src/pages/EmailTemplates/utils/schema.js b/packages/strapi/src/extensions/users-permissions/admin/src/pages/EmailTemplates/utils/schema.js
new file mode 100644
index 0000000..33ca121
--- /dev/null
+++ b/packages/strapi/src/extensions/users-permissions/admin/src/pages/EmailTemplates/utils/schema.js
@@ -0,0 +1,22 @@
+import { translatedErrors } from '@strapi/helper-plugin';
+import * as yup from 'yup';
+
+const schema = yup.object().shape({
+ options: yup
+ .object()
+ .shape({
+ from: yup
+ .object()
+ .shape({
+ name: yup.string().required(translatedErrors.required),
+ email: yup.string().email(translatedErrors.email).required(translatedErrors.required),
+ })
+ .required(),
+ response_email: yup.string().email(translatedErrors.email),
+ object: yup.string().required(translatedErrors.required),
+ message: yup.string().required(translatedErrors.required),
+ })
+ .required(translatedErrors.required),
+});
+
+export default schema;
diff --git a/packages/strapi/src/extensions/users-permissions/admin/src/pages/Providers/index.js b/packages/strapi/src/extensions/users-permissions/admin/src/pages/Providers/index.js
new file mode 100644
index 0000000..c492f2d
--- /dev/null
+++ b/packages/strapi/src/extensions/users-permissions/admin/src/pages/Providers/index.js
@@ -0,0 +1,275 @@
+import React, { useMemo, useRef, useState } from 'react';
+
+import {
+ ContentLayout,
+ HeaderLayout,
+ IconButton,
+ Layout,
+ Main,
+ Table,
+ Tbody,
+ Td,
+ Th,
+ Thead,
+ Tr,
+ Typography,
+ useNotifyAT,
+ VisuallyHidden,
+} from '@strapi/design-system';
+import {
+ CheckPagePermissions,
+ LoadingIndicatorPage,
+ onRowClick,
+ SettingsPageTitle,
+ stopPropagation,
+ useFocusWhenNavigate,
+ useNotification,
+ useOverlayBlocker,
+ useRBAC,
+ useTracking,
+} from '@strapi/helper-plugin';
+import { Pencil } from '@strapi/icons';
+import has from 'lodash/has';
+import upperFirst from 'lodash/upperFirst';
+import { useIntl } from 'react-intl';
+import { useMutation, useQuery, useQueryClient } from 'react-query';
+
+import FormModal from '../../components/FormModal';
+import pluginPermissions from '../../permissions';
+import { getTrad } from '../../utils';
+
+import { fetchData, putProvider } from './utils/api';
+import createProvidersArray from './utils/createProvidersArray';
+import forms from './utils/forms';
+
+export const ProvidersPage = () => {
+ const { formatMessage } = useIntl();
+ useFocusWhenNavigate();
+ const { notifyStatus } = useNotifyAT();
+ const queryClient = useQueryClient();
+ const { trackUsage } = useTracking();
+ const trackUsageRef = useRef(trackUsage);
+ const [isOpen, setIsOpen] = useState(false);
+ const [isSubmiting, setIsSubmiting] = useState(false);
+ const [providerToEditName, setProviderToEditName] = useState(null);
+ const toggleNotification = useNotification();
+ const { lockApp, unlockApp } = useOverlayBlocker();
+
+ const updatePermissions = useMemo(() => {
+ return { update: pluginPermissions.updateProviders };
+ }, []);
+
+ const {
+ isLoading: isLoadingForPermissions,
+ allowedActions: { canUpdate },
+ } = useRBAC(updatePermissions);
+
+ const {
+ isLoading: isLoadingForData,
+ data: modifiedData,
+ isFetching,
+ } = useQuery('get-providers', () => fetchData(toggleNotification), {
+ onSuccess() {
+ notifyStatus(
+ formatMessage({
+ id: getTrad('Providers.data.loaded'),
+ defaultMessage: 'Providers have been loaded',
+ })
+ );
+ },
+ initialData: {},
+ });
+
+ const isLoading = isLoadingForData || isFetching;
+
+ const submitMutation = useMutation(putProvider, {
+ async onSuccess() {
+ await queryClient.invalidateQueries('get-providers');
+ toggleNotification({
+ type: 'info',
+ message: { id: getTrad('notification.success.submit') },
+ });
+
+ trackUsageRef.current('didEditAuthenticationProvider');
+ setIsSubmiting(false);
+ handleToggleModal();
+ unlockApp();
+ },
+ onError() {
+ toggleNotification({
+ type: 'warning',
+ message: { id: 'notification.error' },
+ });
+ unlockApp();
+ setIsSubmiting(false);
+ },
+ refetchActive: false,
+ });
+
+ const providers = useMemo(() => createProvidersArray(modifiedData), [modifiedData]);
+
+ const rowCount = providers.length;
+
+ const isProviderWithSubdomain = useMemo(() => {
+ if (!providerToEditName) {
+ return false;
+ }
+
+ const providerToEdit = providers.find((obj) => obj.name === providerToEditName);
+
+ return has(providerToEdit, 'subdomain');
+ }, [providers, providerToEditName]);
+
+ const pageTitle = formatMessage({
+ id: getTrad('HeaderNav.link.providers'),
+ defaultMessage: 'Providers',
+ });
+
+ const layoutToRender = useMemo(() => {
+ if (providerToEditName === 'email') {
+ return forms.email;
+ }
+
+ if (isProviderWithSubdomain) {
+ return forms.providersWithSubdomain;
+ }
+
+ return forms.providers;
+ }, [providerToEditName, isProviderWithSubdomain]);
+
+ const handleToggleModal = () => {
+ setIsOpen((prev) => !prev);
+ };
+
+ const handleClickEdit = (provider) => {
+ if (canUpdate) {
+ setProviderToEditName(provider.name);
+ handleToggleModal();
+ }
+ };
+
+ const handleSubmit = async (values) => {
+ setIsSubmiting(true);
+
+ lockApp();
+
+ trackUsageRef.current('willEditAuthenticationProvider');
+
+ const body = { ...modifiedData, [providerToEditName]: values };
+
+ submitMutation.mutate({ providers: body });
+ };
+
+ return (
+
+
+
+
+ {isLoading || isLoadingForPermissions ? (
+
+ ) : (
+
+
+
+
+
+
+ {formatMessage({ id: 'global.name', defaultMessage: 'Name' })}
+
+
+
+
+ {formatMessage({ id: getTrad('Providers.status'), defaultMessage: 'Status' })}
+
+
+
+
+
+ {formatMessage({
+ id: 'global.settings',
+ defaultMessage: 'Settings',
+ })}
+
+
+
+
+
+
+ {providers.map((provider) => (
+ handleClickEdit(provider),
+ condition: canUpdate,
+ })}
+ >
+
+
+ {provider.name}
+
+
+
+
+ {provider.enabled
+ ? formatMessage({
+ id: 'global.enabled',
+ defaultMessage: 'Enabled',
+ })
+ : formatMessage({
+ id: 'global.disabled',
+ defaultMessage: 'Disabled',
+ })}
+
+
+
+ {canUpdate && (
+ handleClickEdit(provider)}
+ noBorder
+ icon={ }
+ label="Edit"
+ />
+ )}
+
+
+ ))}
+
+
+
+ )}
+
+
+
+ );
+};
+
+const ProtectedProvidersPage = () => (
+
+
+
+);
+
+export default ProtectedProvidersPage;
diff --git a/packages/strapi/src/extensions/users-permissions/admin/src/pages/Providers/reducer.js b/packages/strapi/src/extensions/users-permissions/admin/src/pages/Providers/reducer.js
new file mode 100644
index 0000000..fe6f7d5
--- /dev/null
+++ b/packages/strapi/src/extensions/users-permissions/admin/src/pages/Providers/reducer.js
@@ -0,0 +1,54 @@
+import produce from 'immer';
+import set from 'lodash/set';
+
+const initialState = {
+ formErrors: {},
+ isLoading: true,
+ initialData: {},
+ modifiedData: {},
+};
+
+const reducer = (state, action) =>
+ // eslint-disable-next-line consistent-return
+ produce(state, (draftState) => {
+ switch (action.type) {
+ case 'GET_DATA': {
+ draftState.isLoading = true;
+ draftState.initialData = {};
+ draftState.modifiedData = {};
+
+ break;
+ }
+
+ case 'GET_DATA_SUCCEEDED': {
+ draftState.isLoading = false;
+ draftState.initialData = action.data;
+ draftState.modifiedData = action.data;
+
+ break;
+ }
+ case 'GET_DATA_ERROR': {
+ draftState.isLoading = true;
+ break;
+ }
+ case 'ON_CHANGE': {
+ set(draftState, ['modifiedData', ...action.keys.split('.')], action.value);
+ break;
+ }
+ case 'RESET_FORM': {
+ draftState.modifiedData = state.initialData;
+ draftState.formErrors = {};
+ break;
+ }
+ case 'SET_ERRORS': {
+ draftState.formErrors = action.errors;
+ break;
+ }
+ default: {
+ return draftState;
+ }
+ }
+ });
+
+export default reducer;
+export { initialState };
diff --git a/packages/strapi/src/extensions/users-permissions/admin/src/pages/Providers/utils/api.js b/packages/strapi/src/extensions/users-permissions/admin/src/pages/Providers/utils/api.js
new file mode 100644
index 0000000..0401426
--- /dev/null
+++ b/packages/strapi/src/extensions/users-permissions/admin/src/pages/Providers/utils/api.js
@@ -0,0 +1,26 @@
+import { getFetchClient } from '@strapi/helper-plugin';
+
+import { getRequestURL } from '../../../utils';
+
+// eslint-disable-next-line import/prefer-default-export
+export const fetchData = async (toggleNotification) => {
+ try {
+ const { get } = getFetchClient();
+ const { data } = await get(getRequestURL('providers'));
+
+ return data;
+ } catch (err) {
+ toggleNotification({
+ type: 'warning',
+ message: { id: 'notification.error' },
+ });
+
+ throw new Error('error');
+ }
+};
+
+export const putProvider = (body) => {
+ const { put } = getFetchClient();
+
+ return put(getRequestURL('providers'), body);
+};
diff --git a/packages/strapi/src/extensions/users-permissions/admin/src/pages/Providers/utils/createProvidersArray.js b/packages/strapi/src/extensions/users-permissions/admin/src/pages/Providers/utils/createProvidersArray.js
new file mode 100644
index 0000000..4e4be3d
--- /dev/null
+++ b/packages/strapi/src/extensions/users-permissions/admin/src/pages/Providers/utils/createProvidersArray.js
@@ -0,0 +1,21 @@
+import sortBy from 'lodash/sortBy';
+
+const createProvidersArray = (data) => {
+ return sortBy(
+ Object.keys(data).reduce((acc, current) => {
+ const { icon: iconName, enabled, subdomain } = data[current];
+ const icon = iconName === 'envelope' ? ['fas', 'envelope'] : ['fab', iconName];
+
+ if (subdomain !== undefined) {
+ acc.push({ name: current, icon, enabled, subdomain });
+ } else {
+ acc.push({ name: current, icon, enabled });
+ }
+
+ return acc;
+ }, []),
+ 'name'
+ );
+};
+
+export default createProvidersArray;
diff --git a/packages/strapi/src/extensions/users-permissions/admin/src/pages/Providers/utils/forms.js b/packages/strapi/src/extensions/users-permissions/admin/src/pages/Providers/utils/forms.js
new file mode 100644
index 0000000..08d2859
--- /dev/null
+++ b/packages/strapi/src/extensions/users-permissions/admin/src/pages/Providers/utils/forms.js
@@ -0,0 +1,259 @@
+import { translatedErrors } from '@strapi/helper-plugin';
+import * as yup from 'yup';
+
+import { getTrad } from '../../../utils';
+
+const callbackLabel = {
+ id: getTrad('PopUpForm.Providers.redirectURL.front-end.label'),
+ defaultMessage: 'The redirect URL to your front-end app',
+};
+const callbackPlaceholder = {
+ id: 'http://www.client-app.com',
+ defaultMessage: 'http://www.client-app.com',
+};
+const enabledDescription = {
+ id: getTrad('PopUpForm.Providers.enabled.description'),
+ defaultMessage: "If disabled, users won't be able to use this provider.",
+};
+const enabledLabel = {
+ id: getTrad('PopUpForm.Providers.enabled.label'),
+ defaultMessage: 'Enable',
+};
+const keyLabel = { id: getTrad('PopUpForm.Providers.key.label'), defaultMessage: 'Client ID' };
+const hintLabel = {
+ id: getTrad('PopUpForm.Providers.redirectURL.label'),
+ defaultMessage: 'The redirect URL to add in your {provider} application configurations',
+};
+const textPlaceholder = {
+ id: getTrad('PopUpForm.Providers.key.placeholder'),
+ defaultMessage: 'TEXT',
+};
+
+const secretLabel = {
+ id: getTrad('PopUpForm.Providers.secret.label'),
+ defaultMessage: 'Client Secret',
+};
+
+const forms = {
+ email: {
+ form: [
+ [
+ {
+ intlLabel: enabledLabel,
+ name: 'enabled',
+ type: 'bool',
+ description: enabledDescription,
+ size: 6,
+ // TODO check if still needed
+ // validations: {
+ // required: true,
+ // },
+ },
+ ],
+ ],
+ schema: yup.object().shape({
+ enabled: yup.bool().required(translatedErrors.required),
+ }),
+ },
+ providers: {
+ form: [
+ [
+ {
+ intlLabel: enabledLabel,
+ name: 'enabled',
+ type: 'bool',
+ description: enabledDescription,
+ size: 6,
+ validations: {
+ required: true,
+ },
+ },
+ ],
+ [
+ {
+ intlLabel: keyLabel,
+ name: 'key',
+ type: 'text',
+ placeholder: textPlaceholder,
+ size: 12,
+ validations: {
+ required: true,
+ },
+ },
+ ],
+ [
+ {
+ intlLabel: secretLabel,
+ name: 'secret',
+ type: 'text',
+ placeholder: textPlaceholder,
+ size: 12,
+ validations: {
+ required: true,
+ },
+ },
+ ],
+ [
+ {
+ intlLabel: callbackLabel,
+ placeholder: callbackPlaceholder,
+ name: 'callback',
+ type: 'text',
+ size: 12,
+ validations: {
+ required: true,
+ },
+ },
+ ],
+ [
+ {
+ intlLabel: hintLabel,
+ name: 'noName',
+ type: 'text',
+ validations: {},
+ size: 12,
+ disabled: true,
+ },
+ ],
+ ],
+ schema: yup.object().shape({
+ enabled: yup.bool().required(translatedErrors.required),
+ key: yup.string().when('enabled', {
+ is: true,
+ then: yup.string().required(translatedErrors.required),
+ otherwise: yup.string(),
+ }),
+ secret: yup.string().when('enabled', {
+ is: true,
+ then: yup.string().required(translatedErrors.required),
+ otherwise: yup.string(),
+ }),
+ callback: yup.string().when('enabled', {
+ is: true,
+ then: yup.string().required(translatedErrors.required),
+ otherwise: yup.string(),
+ }),
+ }),
+ },
+ providersWithSubdomain: {
+ form: [
+ [
+ {
+ intlLabel: enabledLabel,
+ name: 'enabled',
+ type: 'bool',
+ description: enabledDescription,
+ size: 6,
+ validations: {
+ required: true,
+ },
+ },
+ ],
+ [
+ {
+ intlLabel: keyLabel,
+ name: 'key',
+ type: 'text',
+ placeholder: textPlaceholder,
+ size: 12,
+ validations: {
+ required: true,
+ },
+ },
+ ],
+ [
+ {
+ intlLabel: secretLabel,
+ name: 'secret',
+ type: 'text',
+ placeholder: textPlaceholder,
+ size: 12,
+ validations: {
+ required: true,
+ },
+ },
+ ],
+ [
+ {
+ intlLabel: {
+ id: getTrad({ id: 'PopUpForm.Providers.jwksurl.label' }),
+ defaultMessage: 'JWKS URL',
+ },
+ name: 'jwksurl',
+ type: 'text',
+ placeholder: textPlaceholder,
+ size: 12,
+ validations: {
+ required: false,
+ },
+ },
+ ],
+
+ [
+ {
+ intlLabel: {
+ id: getTrad('PopUpForm.Providers.subdomain.label'),
+ defaultMessage: 'Host URI (Subdomain)',
+ },
+ name: 'subdomain',
+ type: 'text',
+ placeholder: {
+ id: getTrad('PopUpForm.Providers.subdomain.placeholder'),
+ defaultMessage: 'my.subdomain.com',
+ },
+ size: 12,
+ validations: {
+ required: true,
+ },
+ },
+ ],
+ [
+ {
+ intlLabel: callbackLabel,
+ placeholder: callbackPlaceholder,
+ name: 'callback',
+ type: 'text',
+ size: 12,
+ validations: {
+ required: true,
+ },
+ },
+ ],
+ [
+ {
+ intlLabel: hintLabel,
+ name: 'noName',
+ type: 'text',
+ validations: {},
+ size: 12,
+ disabled: true,
+ },
+ ],
+ ],
+ schema: yup.object().shape({
+ enabled: yup.bool().required(translatedErrors.required),
+ key: yup.string().when('enabled', {
+ is: true,
+ then: yup.string().required(translatedErrors.required),
+ otherwise: yup.string(),
+ }),
+ secret: yup.string().when('enabled', {
+ is: true,
+ then: yup.string().required(translatedErrors.required),
+ otherwise: yup.string(),
+ }),
+ subdomain: yup.string().when('enabled', {
+ is: true,
+ then: yup.string().required(translatedErrors.required),
+ otherwise: yup.string(),
+ }),
+ callback: yup.string().when('enabled', {
+ is: true,
+ then: yup.string().required(translatedErrors.required),
+ otherwise: yup.string(),
+ }),
+ }),
+ },
+};
+
+export default forms;
diff --git a/packages/strapi/src/extensions/users-permissions/admin/src/pages/Roles/CreatePage.js b/packages/strapi/src/extensions/users-permissions/admin/src/pages/Roles/CreatePage.js
new file mode 100644
index 0000000..15888f7
--- /dev/null
+++ b/packages/strapi/src/extensions/users-permissions/admin/src/pages/Roles/CreatePage.js
@@ -0,0 +1,185 @@
+import React, { useRef, useState } from 'react';
+
+import {
+ Box,
+ Button,
+ ContentLayout,
+ Flex,
+ Grid,
+ GridItem,
+ HeaderLayout,
+ Main,
+ Textarea,
+ TextInput,
+ Typography,
+} from '@strapi/design-system';
+import {
+ Form,
+ SettingsPageTitle,
+ useFetchClient,
+ useNotification,
+ useOverlayBlocker,
+ useTracking,
+} from '@strapi/helper-plugin';
+import { Check } from '@strapi/icons';
+import { Formik } from 'formik';
+import { useIntl } from 'react-intl';
+import { useHistory } from 'react-router-dom';
+
+import UsersPermissions from '../../components/UsersPermissions';
+import { usePlugins } from '../../hooks';
+import pluginId from '../../pluginId';
+import getTrad from '../../utils/getTrad';
+
+import { createRoleSchema } from './constants';
+
+const CreatePage = () => {
+ const { formatMessage } = useIntl();
+ const [isSubmitting, setIsSubmitting] = useState(false);
+ const toggleNotification = useNotification();
+ const { goBack } = useHistory();
+ const { lockApp, unlockApp } = useOverlayBlocker();
+ const { isLoading: isLoadingPlugins, permissions, routes } = usePlugins();
+ const { trackUsage } = useTracking();
+ const permissionsRef = useRef();
+ const { post } = useFetchClient();
+
+ const handleCreateRoleSubmit = async (data) => {
+ // Set loading state
+ lockApp();
+ setIsSubmitting(true);
+ try {
+ const permissions = permissionsRef.current.getPermissions();
+ // Update role in Strapi
+ await post(`/${pluginId}/roles`, { ...data, ...permissions, users: [] });
+ // Notify success
+ trackUsage('didCreateRole');
+ toggleNotification({
+ type: 'success',
+ message: {
+ id: getTrad('Settings.roles.created'),
+ defaultMessage: 'Role created',
+ },
+ });
+ // Forcing redirecting since we don't have the id in the response
+ goBack();
+ } catch (err) {
+ console.error(err);
+ toggleNotification({
+ type: 'warning',
+ message: {
+ id: 'notification.error',
+ defaultMessage: 'An error occurred',
+ },
+ });
+ }
+ // Unset loading state
+ setIsSubmitting(false);
+ unlockApp();
+ };
+
+ return (
+
+
+
+ {({ handleSubmit, values, handleChange, errors }) => (
+
+ }>
+ {formatMessage({
+ id: 'global.save',
+ defaultMessage: 'Save',
+ })}
+
+ )
+ }
+ title={formatMessage({
+ id: 'Settings.roles.create.title',
+ defaultMessage: 'Create a role',
+ })}
+ subtitle={formatMessage({
+ id: 'Settings.roles.create.description',
+ defaultMessage: 'Define the rights given to the role',
+ })}
+ />
+
+
+
+
+
+ {formatMessage({
+ id: getTrad('EditPage.form.roles'),
+ defaultMessage: 'Role details',
+ })}
+
+
+
+
+
+
+
+
+
+
+
+ {!isLoadingPlugins && (
+
+ )}
+
+
+
+ )}
+
+
+ );
+};
+
+export default CreatePage;
diff --git a/packages/strapi/src/extensions/users-permissions/admin/src/pages/Roles/EditPage.js b/packages/strapi/src/extensions/users-permissions/admin/src/pages/Roles/EditPage.js
new file mode 100644
index 0000000..9a88716
--- /dev/null
+++ b/packages/strapi/src/extensions/users-permissions/admin/src/pages/Roles/EditPage.js
@@ -0,0 +1,197 @@
+import React, { useRef, useState } from 'react';
+
+import {
+ ContentLayout,
+ HeaderLayout,
+ Main,
+ Button,
+ Flex,
+ Box,
+ TextInput,
+ Textarea,
+ Typography,
+ GridItem,
+ Grid,
+} from '@strapi/design-system';
+import {
+ useFetchClient,
+ useOverlayBlocker,
+ SettingsPageTitle,
+ LoadingIndicatorPage,
+ Form,
+ useNotification,
+ Link,
+} from '@strapi/helper-plugin';
+import { ArrowLeft, Check } from '@strapi/icons';
+import { Formik } from 'formik';
+import { useIntl } from 'react-intl';
+import { useRouteMatch } from 'react-router-dom';
+
+import UsersPermissions from '../../components/UsersPermissions';
+import { usePlugins, useFetchRole } from '../../hooks';
+import pluginId from '../../pluginId';
+import getTrad from '../../utils/getTrad';
+
+import { createRoleSchema } from './constants';
+
+const EditPage = () => {
+ const { formatMessage } = useIntl();
+ const [isSubmitting, setIsSubmitting] = useState(false);
+ const toggleNotification = useNotification();
+ const { lockApp, unlockApp } = useOverlayBlocker();
+ const {
+ params: { id },
+ } = useRouteMatch(`/settings/${pluginId}/roles/:id`);
+ const { isLoading: isLoadingPlugins, routes } = usePlugins();
+ const { role, onSubmitSucceeded, isLoading: isLoadingRole } = useFetchRole(id);
+ const permissionsRef = useRef();
+ const { put } = useFetchClient();
+
+ const handleEditRoleSubmit = async (data) => {
+ // Set loading state
+ lockApp();
+ setIsSubmitting(true);
+ try {
+ const permissions = permissionsRef.current.getPermissions();
+ // Update role in Strapi
+ await put(`/${pluginId}/roles/${id}`, { ...data, ...permissions, users: [] });
+ // Notify success
+ onSubmitSucceeded({ name: data.name, description: data.description });
+ toggleNotification({
+ type: 'success',
+ message: {
+ id: getTrad('Settings.roles.edited'),
+ defaultMessage: 'Role edited',
+ },
+ });
+ } catch (err) {
+ console.error(err);
+ toggleNotification({
+ type: 'warning',
+ message: {
+ id: 'notification.error',
+ defaultMessage: 'An error occurred',
+ },
+ });
+ }
+ // Unset loading state
+ setIsSubmitting(false);
+ unlockApp();
+ };
+
+ if (isLoadingRole) {
+ return ;
+ }
+
+ return (
+
+
+
+ {({ handleSubmit, values, handleChange, errors }) => (
+
+ }
+ >
+ {formatMessage({
+ id: 'global.save',
+ defaultMessage: 'Save',
+ })}
+
+ )
+ }
+ title={role.name}
+ subtitle={role.description}
+ navigationAction={
+ } to="/settings/users-permissions/roles">
+ {formatMessage({
+ id: 'global.back',
+ defaultMessage: 'Back',
+ })}
+
+ }
+ />
+
+
+
+
+
+ {formatMessage({
+ id: getTrad('EditPage.form.roles'),
+ defaultMessage: 'Role details',
+ })}
+
+
+
+
+
+
+
+
+
+
+
+ {!isLoadingPlugins && (
+
+ )}
+
+
+
+ )}
+
+
+ );
+};
+
+export default EditPage;
diff --git a/packages/strapi/src/extensions/users-permissions/admin/src/pages/Roles/ListPage/components/TableBody.js b/packages/strapi/src/extensions/users-permissions/admin/src/pages/Roles/ListPage/components/TableBody.js
new file mode 100644
index 0000000..a27b892
--- /dev/null
+++ b/packages/strapi/src/extensions/users-permissions/admin/src/pages/Roles/ListPage/components/TableBody.js
@@ -0,0 +1,93 @@
+import React from 'react';
+
+import { Flex, IconButton, Tbody, Td, Tr, Typography } from '@strapi/design-system';
+import { CheckPermissions, onRowClick, stopPropagation } from '@strapi/helper-plugin';
+import { Pencil, Trash } from '@strapi/icons';
+import PropTypes from 'prop-types';
+import { useIntl } from 'react-intl';
+import { useHistory } from 'react-router-dom';
+
+import pluginId from '../../../../pluginId';
+
+const TableBody = ({ sortedRoles, canDelete, permissions, setRoleToDelete, onDelete }) => {
+ const { formatMessage } = useIntl();
+ const { push } = useHistory();
+ const [showConfirmDelete, setShowConfirmDelete] = onDelete;
+
+ const checkCanDeleteRole = (role) =>
+ canDelete && !['public', 'authenticated'].includes(role.type);
+
+ const handleClickDelete = (id) => {
+ setRoleToDelete(id);
+ setShowConfirmDelete(!showConfirmDelete);
+ };
+
+ const handleClickEdit = (id) => {
+ push(`/settings/${pluginId}/roles/${id}`);
+ };
+
+ return (
+
+ {sortedRoles?.map((role) => (
+ handleClickEdit(role.id) })}>
+
+ {role.name}
+
+
+ {role.description}
+
+
+
+ {`${role.nb_users} ${formatMessage({
+ id: 'global.users',
+ defaultMessage: 'users',
+ }).toLowerCase()}`}
+
+
+
+
+
+ handleClickEdit(role.id)}
+ noBorder
+ icon={ }
+ label={formatMessage(
+ { id: 'app.component.table.edit', defaultMessage: 'Edit {target}' },
+ { target: `${role.name}` }
+ )}
+ />
+
+ {checkCanDeleteRole(role) && (
+
+ handleClickDelete(role.id)}
+ noBorder
+ icon={ }
+ label={formatMessage(
+ { id: 'global.delete-target', defaultMessage: 'Delete {target}' },
+ { target: `${role.name}` }
+ )}
+ />
+
+ )}
+
+
+
+ ))}
+
+ );
+};
+
+export default TableBody;
+
+TableBody.defaultProps = {
+ canDelete: false,
+};
+
+TableBody.propTypes = {
+ onDelete: PropTypes.array.isRequired,
+ permissions: PropTypes.object.isRequired,
+ setRoleToDelete: PropTypes.func.isRequired,
+ sortedRoles: PropTypes.array.isRequired,
+ canDelete: PropTypes.bool,
+};
diff --git a/packages/strapi/src/extensions/users-permissions/admin/src/pages/Roles/ListPage/index.js b/packages/strapi/src/extensions/users-permissions/admin/src/pages/Roles/ListPage/index.js
new file mode 100644
index 0000000..2326f2b
--- /dev/null
+++ b/packages/strapi/src/extensions/users-permissions/admin/src/pages/Roles/ListPage/index.js
@@ -0,0 +1,243 @@
+import React, { useMemo, useState } from 'react';
+
+import {
+ ActionLayout,
+ Button,
+ ContentLayout,
+ HeaderLayout,
+ Layout,
+ Main,
+ Table,
+ Th,
+ Thead,
+ Tr,
+ Typography,
+ useNotifyAT,
+ VisuallyHidden,
+} from '@strapi/design-system';
+import {
+ CheckPermissions,
+ ConfirmDialog,
+ EmptyStateLayout,
+ LoadingIndicatorPage,
+ NoPermissions,
+ SearchURLQuery,
+ SettingsPageTitle,
+ useCollator,
+ useFilter,
+ useFocusWhenNavigate,
+ useNotification,
+ useQueryParams,
+ useRBAC,
+ useTracking,
+} from '@strapi/helper-plugin';
+import { Plus } from '@strapi/icons';
+import { useIntl } from 'react-intl';
+import { useMutation, useQuery, useQueryClient } from 'react-query';
+import { useHistory } from 'react-router-dom';
+
+import permissions from '../../../permissions';
+import pluginId from '../../../pluginId';
+import { getTrad } from '../../../utils';
+
+import TableBody from './components/TableBody';
+import { deleteData, fetchData } from './utils/api';
+
+const RoleListPage = () => {
+ const { trackUsage } = useTracking();
+ const { formatMessage, locale } = useIntl();
+ const { push } = useHistory();
+ const toggleNotification = useNotification();
+ const { notifyStatus } = useNotifyAT();
+ const [{ query }] = useQueryParams();
+ const _q = query?._q || '';
+ const [showConfirmDelete, setShowConfirmDelete] = useState(false);
+ const [isConfirmButtonLoading, setIsConfirmButtonLoading] = useState(false);
+ const [roleToDelete, setRoleToDelete] = useState();
+ useFocusWhenNavigate();
+
+ const queryClient = useQueryClient();
+
+ const updatePermissions = useMemo(() => {
+ return {
+ create: permissions.createRole,
+ read: permissions.readRoles,
+ update: permissions.updateRole,
+ delete: permissions.deleteRole,
+ };
+ }, []);
+
+ const {
+ isLoading: isLoadingForPermissions,
+ allowedActions: { canRead, canDelete },
+ } = useRBAC(updatePermissions);
+
+ const {
+ isLoading: isLoadingForData,
+ data: { roles },
+ isFetching,
+ } = useQuery('get-roles', () => fetchData(toggleNotification, notifyStatus), {
+ initialData: {},
+ enabled: canRead,
+ });
+
+ const { includes } = useFilter(locale, {
+ sensitivity: 'base',
+ });
+
+ /**
+ * @type {Intl.Collator}
+ */
+ const formatter = useCollator(locale, {
+ sensitivity: 'base',
+ });
+
+ const isLoading = isLoadingForData || isFetching;
+
+ const handleNewRoleClick = () => {
+ trackUsage('willCreateRole');
+ push(`/settings/${pluginId}/roles/new`);
+ };
+
+ const handleShowConfirmDelete = () => {
+ setShowConfirmDelete(!showConfirmDelete);
+ };
+
+ const emptyLayout = {
+ roles: {
+ id: getTrad('Roles.empty'),
+ defaultMessage: "You don't have any roles yet.",
+ },
+ search: {
+ id: getTrad('Roles.empty.search'),
+ defaultMessage: 'No roles match the search.',
+ },
+ };
+
+ const pageTitle = formatMessage({
+ id: 'global.roles',
+ defaultMessage: 'Roles',
+ });
+
+ const deleteMutation = useMutation((id) => deleteData(id, toggleNotification), {
+ async onSuccess() {
+ await queryClient.invalidateQueries('get-roles');
+ },
+ });
+
+ const handleConfirmDelete = async () => {
+ setIsConfirmButtonLoading(true);
+ await deleteMutation.mutateAsync(roleToDelete);
+ setShowConfirmDelete(!showConfirmDelete);
+ setIsConfirmButtonLoading(false);
+ };
+
+ const sortedRoles = (roles || [])
+ .filter((role) => includes(role.name, _q) || includes(role.description, _q))
+ .sort(
+ (a, b) => formatter.compare(a.name, b.name) || formatter.compare(a.description, b.description)
+ );
+
+ const emptyContent = _q && !sortedRoles.length ? 'search' : 'roles';
+
+ const colCount = 4;
+ const rowCount = (roles?.length || 0) + 1;
+
+ return (
+
+
+
+
+ } size="S">
+ {formatMessage({
+ id: getTrad('List.button.roles'),
+ defaultMessage: 'Add new role',
+ })}
+
+
+ }
+ />
+
+
+ }
+ />
+
+
+ {!canRead && }
+ {(isLoading || isLoadingForPermissions) && }
+ {canRead && sortedRoles && sortedRoles?.length ? (
+
+
+
+
+
+ {formatMessage({ id: 'global.name', defaultMessage: 'Name' })}
+
+
+
+
+ {formatMessage({
+ id: 'global.description',
+ defaultMessage: 'Description',
+ })}
+
+
+
+
+ {formatMessage({
+ id: 'global.users',
+ defaultMessage: 'Users',
+ })}
+
+
+
+
+ {formatMessage({
+ id: 'global.actions',
+ defaultMessage: 'Actions',
+ })}
+
+
+
+
+
+
+ ) : (
+
+ )}
+
+
+
+
+ );
+};
+
+export default RoleListPage;
diff --git a/packages/strapi/src/extensions/users-permissions/admin/src/pages/Roles/ListPage/utils/api.js b/packages/strapi/src/extensions/users-permissions/admin/src/pages/Roles/ListPage/utils/api.js
new file mode 100644
index 0000000..67fb5e7
--- /dev/null
+++ b/packages/strapi/src/extensions/users-permissions/admin/src/pages/Roles/ListPage/utils/api.js
@@ -0,0 +1,32 @@
+import { getFetchClient } from '@strapi/helper-plugin';
+
+import { getRequestURL } from '../../../../utils';
+
+export const fetchData = async (toggleNotification, notifyStatus) => {
+ try {
+ const { get } = getFetchClient();
+ const { data } = await get(getRequestURL('roles'));
+ notifyStatus('The roles have loaded successfully');
+
+ return data;
+ } catch (err) {
+ toggleNotification({
+ type: 'warning',
+ message: { id: 'notification.error' },
+ });
+
+ throw new Error(err);
+ }
+};
+
+export const deleteData = async (id, toggleNotification) => {
+ try {
+ const { del } = getFetchClient();
+ await del(`${getRequestURL('roles')}/${id}`);
+ } catch (error) {
+ toggleNotification({
+ type: 'warning',
+ message: { id: 'notification.error', defaultMessage: 'An error occured' },
+ });
+ }
+};
diff --git a/packages/strapi/src/extensions/users-permissions/admin/src/pages/Roles/ProtectedCreatePage.js b/packages/strapi/src/extensions/users-permissions/admin/src/pages/Roles/ProtectedCreatePage.js
new file mode 100644
index 0000000..be2a0d1
--- /dev/null
+++ b/packages/strapi/src/extensions/users-permissions/admin/src/pages/Roles/ProtectedCreatePage.js
@@ -0,0 +1,15 @@
+import React from 'react';
+
+import { CheckPagePermissions } from '@strapi/helper-plugin';
+
+import pluginPermissions from '../../permissions';
+
+import RolesCreatePage from './CreatePage';
+
+const ProtectedRolesCreatePage = () => (
+
+
+
+);
+
+export default ProtectedRolesCreatePage;
diff --git a/packages/strapi/src/extensions/users-permissions/admin/src/pages/Roles/ProtectedEditPage.js b/packages/strapi/src/extensions/users-permissions/admin/src/pages/Roles/ProtectedEditPage.js
new file mode 100644
index 0000000..c3e0691
--- /dev/null
+++ b/packages/strapi/src/extensions/users-permissions/admin/src/pages/Roles/ProtectedEditPage.js
@@ -0,0 +1,15 @@
+import React from 'react';
+
+import { CheckPagePermissions } from '@strapi/helper-plugin';
+
+import pluginPermissions from '../../permissions';
+
+import RolesEditPage from './EditPage';
+
+const ProtectedRolesEditPage = () => (
+
+
+
+);
+
+export default ProtectedRolesEditPage;
diff --git a/packages/strapi/src/extensions/users-permissions/admin/src/pages/Roles/ProtectedListPage.js b/packages/strapi/src/extensions/users-permissions/admin/src/pages/Roles/ProtectedListPage.js
new file mode 100644
index 0000000..867a72b
--- /dev/null
+++ b/packages/strapi/src/extensions/users-permissions/admin/src/pages/Roles/ProtectedListPage.js
@@ -0,0 +1,17 @@
+import React from 'react';
+
+import { CheckPagePermissions } from '@strapi/helper-plugin';
+
+import pluginPermissions from '../../permissions';
+
+import RolesListPage from './ListPage';
+
+const ProtectedRolesListPage = () => {
+ return (
+
+
+
+ );
+};
+
+export default ProtectedRolesListPage;
diff --git a/packages/strapi/src/extensions/users-permissions/admin/src/pages/Roles/constants.js b/packages/strapi/src/extensions/users-permissions/admin/src/pages/Roles/constants.js
new file mode 100644
index 0000000..51bd2c3
--- /dev/null
+++ b/packages/strapi/src/extensions/users-permissions/admin/src/pages/Roles/constants.js
@@ -0,0 +1,7 @@
+import { translatedErrors } from '@strapi/helper-plugin';
+import * as yup from 'yup';
+
+export const createRoleSchema = yup.object().shape({
+ name: yup.string().required(translatedErrors.required),
+ description: yup.string().required(translatedErrors.required),
+});
diff --git a/packages/strapi/src/extensions/users-permissions/admin/src/pages/Roles/index.js b/packages/strapi/src/extensions/users-permissions/admin/src/pages/Roles/index.js
new file mode 100644
index 0000000..d23637b
--- /dev/null
+++ b/packages/strapi/src/extensions/users-permissions/admin/src/pages/Roles/index.js
@@ -0,0 +1,30 @@
+import React from 'react';
+
+import { AnErrorOccurred, CheckPagePermissions } from '@strapi/helper-plugin';
+import { Route, Switch } from 'react-router-dom';
+
+import pluginPermissions from '../../permissions';
+import pluginId from '../../pluginId';
+
+import ProtectedRolesCreatePage from './ProtectedCreatePage';
+import ProtectedRolesEditPage from './ProtectedEditPage';
+import ProtectedRolesListPage from './ProtectedListPage';
+
+const Roles = () => {
+ return (
+
+
+
+
+
+
+
+
+ );
+};
+
+export default Roles;
diff --git a/packages/strapi/src/extensions/users-permissions/admin/src/permissions.js b/packages/strapi/src/extensions/users-permissions/admin/src/permissions.js
new file mode 100644
index 0000000..4ab7e71
--- /dev/null
+++ b/packages/strapi/src/extensions/users-permissions/admin/src/permissions.js
@@ -0,0 +1,31 @@
+const pluginPermissions = {
+ // Roles
+ accessRoles: [
+ { action: 'plugin::users-permissions.roles.create', subject: null },
+ { action: 'plugin::users-permissions.roles.read', subject: null },
+ ],
+ createRole: [{ action: 'plugin::users-permissions.roles.create', subject: null }],
+ deleteRole: [{ action: 'plugin::users-permissions.roles.delete', subject: null }],
+ readRoles: [{ action: 'plugin::users-permissions.roles.read', subject: null }],
+ updateRole: [{ action: 'plugin::users-permissions.roles.update', subject: null }],
+
+ // AdvancedSettings
+ readAdvancedSettings: [
+ { action: 'plugin::users-permissions.advanced-settings.read', subject: null },
+ ],
+ updateAdvancedSettings: [
+ { action: 'plugin::users-permissions.advanced-settings.update', subject: null },
+ ],
+
+ // Emails
+ readEmailTemplates: [{ action: 'plugin::users-permissions.email-templates.read', subject: null }],
+ updateEmailTemplates: [
+ { action: 'plugin::users-permissions.email-templates.update', subject: null },
+ ],
+
+ // Providers
+ readProviders: [{ action: 'plugin::users-permissions.providers.read', subject: null }],
+ updateProviders: [{ action: 'plugin::users-permissions.providers.update', subject: null }],
+};
+
+export default pluginPermissions;
diff --git a/packages/strapi/src/extensions/users-permissions/admin/src/pluginId.js b/packages/strapi/src/extensions/users-permissions/admin/src/pluginId.js
new file mode 100644
index 0000000..791a679
--- /dev/null
+++ b/packages/strapi/src/extensions/users-permissions/admin/src/pluginId.js
@@ -0,0 +1,5 @@
+import pluginPkg from '../../package.json';
+
+const pluginId = pluginPkg.name.replace(/^@strapi\/plugin-/i, '');
+
+export default pluginId;
diff --git a/packages/strapi/src/extensions/users-permissions/admin/src/translations/ar.json b/packages/strapi/src/extensions/users-permissions/admin/src/translations/ar.json
new file mode 100644
index 0000000..d72ac92
--- /dev/null
+++ b/packages/strapi/src/extensions/users-permissions/admin/src/translations/ar.json
@@ -0,0 +1,40 @@
+{
+ "BoundRoute.title": "Bound route to",
+ "EditForm.inputSelect.description.role": "سيتم إرفاق المستخدم المصادق الجديد بالدور المحدد.",
+ "EditForm.inputSelect.label.role": "الدور الافتراضي للمستخدمين المصادقين",
+ "EditForm.inputToggle.description.email": "عدم السماح للمستخدم بإنشاء حسابات متعددة باستخدام نفس عنوان البريد الإلكتروني مع موفري مصادقة مختلفين.",
+ "EditForm.inputToggle.description.sign-up": "عند تعطيل (OFF) ، يتم حظر عملية التسجيل. لا أحد يستطيع الاشتراك بعد الآن بغض النظر عن المزود المستخدم.",
+ "EditForm.inputToggle.label.email": "حساب واحد لكل بريد الاكتروني",
+ "EditForm.inputToggle.label.sign-up": "تفعيل التسجيل",
+ "HeaderNav.link.advancedSettings": "إعدادات متقدمة",
+ "HeaderNav.link.emailTemplates": "قوالب الإيميل",
+ "HeaderNav.link.providers": "مزودين",
+ "Plugin.permissions.plugins.description": "حدد جميع الإجراءات المسموح بها للإضافة {name}.",
+ "Plugins.header.description": "يتم سرد الإجراءات المحددة المرتبطة بالمسار أدناه.",
+ "Plugins.header.title": "الصلاحيات",
+ "Policies.header.hint": "حدد إجراءات التطبيق أو إجراءات الإضافة وانقر على رمز الترس لعرض المسار المرتبط",
+ "Policies.header.title": "إعدادات متقدمة",
+ "PopUpForm.Email.email_templates.inputDescription": "إذا كنت غير متأكد من كيفية استخدام المتغيرات ، {link}",
+ "PopUpForm.Email.options.from.email.label": "البريد الإلكتروني للشاحن",
+ "PopUpForm.Email.options.from.email.placeholder": "kai@doe.com",
+ "PopUpForm.Email.options.from.name.label": "أسم المورد",
+ "PopUpForm.Email.options.from.name.placeholder": "Kai Doe",
+ "PopUpForm.Email.options.message.label": "الرسالة",
+ "PopUpForm.Email.options.object.label": "موضوع",
+ "PopUpForm.Email.options.response_email.label": "البريد الإلكتروني للاستجابة",
+ "PopUpForm.Email.options.response_email.placeholder": "kai@doe.com",
+ "PopUpForm.Providers.enabled.description": "في حالة التعطيل ، لن يتمكن المستخدمون من استخدام هذا الموفر.",
+ "PopUpForm.Providers.enabled.label": "مفعل",
+ "PopUpForm.Providers.key.label": "معرف العميل",
+ "PopUpForm.Providers.key.placeholder": "نص",
+ "PopUpForm.Providers.redirectURL.front-end.label": "عنوان URL لإعادة التوجيه إلى تطبيق الواجهة الأمامية (front-end)",
+ "PopUpForm.Providers.secret.label": "سر العميل (Client Secret)",
+ "PopUpForm.Providers.secret.placeholder": "نص",
+ "PopUpForm.Providers.subdomain.label": "Host URI (Subdomain)",
+ "PopUpForm.Providers.subdomain.placeholder": "my.subdomain.com",
+ "PopUpForm.header.edit.email-templates": "تحرير قوالب البريد الإلكتروني",
+ "notification.success.submit": "تم تحديث الإعدادات",
+ "plugin.description.long": "حماية الـAPI الخاص بك مع عملية مصادقة كاملة استناداً إلى JWT. يأتي هذا الملحق أيضًا مع إستراتيجية ACL التي تسمح لك بإدارة الأذونات بين مجموعات المستخدمين.",
+ "plugin.description.short": "حماية الـAPI الخاص بك مع عملية مصادقة كاملة استناداً إلى JWT",
+ "plugin.name": "الأدوار والصلاحية"
+}
diff --git a/packages/strapi/src/extensions/users-permissions/admin/src/translations/cs.json b/packages/strapi/src/extensions/users-permissions/admin/src/translations/cs.json
new file mode 100644
index 0000000..9edd07b
--- /dev/null
+++ b/packages/strapi/src/extensions/users-permissions/admin/src/translations/cs.json
@@ -0,0 +1,46 @@
+{
+ "BoundRoute.title": "Spojit adresu s",
+ "EditForm.inputSelect.description.role": "Připojí nově autentifikovaného uživatele ke svolené roli.",
+ "EditForm.inputSelect.label.role": "Výchozí role pro autentifikovaného uživatele",
+ "EditForm.inputToggle.description.email": "Zabránit uživateli vytvářet různé účty se stejným e-mailem a jinými poskytovateli autentifikace.",
+ "EditForm.inputToggle.description.email-confirmation": "Pokud je tato funkce povolena (ON), nově registrovaní uživatelé dostanou potvrzující e-mail.",
+ "EditForm.inputToggle.description.email-confirmation-redirection": "Po potvrzení e-mailu, zvolte kam budete přesměrováni.",
+ "EditForm.inputToggle.description.email-reset-password": "Adresa stránky obnovení hesla vaší aplikace",
+ "EditForm.inputToggle.description.sign-up": "Pokud je tato možnost zakázána (OFF), není možno projít registrací. Nikdo se již nemůže připojit, bez ohledu jakého použije poskytovatele.",
+ "EditForm.inputToggle.label.email": "Jeden účet na e-mail",
+ "EditForm.inputToggle.label.email-confirmation": "Povolit potvrzení z e-mailu",
+ "EditForm.inputToggle.label.email-confirmation-redirection": "Adresa pro přesměrování",
+ "EditForm.inputToggle.label.email-reset-password": "Stránka pro obnovení hesla",
+ "EditForm.inputToggle.label.sign-up": "Povolit registrace",
+ "HeaderNav.link.advancedSettings": "Pokročilá nastavení",
+ "HeaderNav.link.emailTemplates": "E-mailové šablony",
+ "HeaderNav.link.providers": "Poskytovatelé",
+ "Plugin.permissions.plugins.description": "Nastavit všechny akce pro zásuvný modul {name}.",
+ "Plugins.header.description": "Pouze akce spojené s adresou jsou vypsány níže.",
+ "Plugins.header.title": "Povolení",
+ "Policies.header.hint": "Vyberte akce aplikace, nebo akce zásuvného modulu a klikněte na ikonku ozubeného kolečka pro zobrazení adresy s nimi spojenou.",
+ "Policies.header.title": "Pokročilá nastavení",
+ "PopUpForm.Email.email_templates.inputDescription": "Pokud si nejste jisti jak používat proměnné, {link}",
+ "PopUpForm.Email.options.from.email.label": "Odesilatelův e-mail",
+ "PopUpForm.Email.options.from.email.placeholder": "jannovak@gmail.com",
+ "PopUpForm.Email.options.from.name.label": "Jméno odesilatele",
+ "PopUpForm.Email.options.from.name.placeholder": "Jan Novák",
+ "PopUpForm.Email.options.message.label": "Zpráva",
+ "PopUpForm.Email.options.object.label": "Předmět",
+ "PopUpForm.Email.options.response_email.label": "Response e-mail",
+ "PopUpForm.Email.options.response_email.placeholder": "jannovak@gmail.com",
+ "PopUpForm.Providers.enabled.description": "If disabled, users won't be able to use this provider.",
+ "PopUpForm.Providers.enabled.label": "Povolit",
+ "PopUpForm.Providers.key.label": "Client ID",
+ "PopUpForm.Providers.key.placeholder": "TEXT",
+ "PopUpForm.Providers.redirectURL.front-end.label": "Adresa pro přesměrování na vaši front-end aplikaci",
+ "PopUpForm.Providers.secret.label": "Client Secret",
+ "PopUpForm.Providers.secret.placeholder": "TEXT",
+ "PopUpForm.Providers.subdomain.label": "Host URI (Subdomain)",
+ "PopUpForm.Providers.subdomain.placeholder": "my.subdomain.com",
+ "PopUpForm.header.edit.email-templates": "Upravit e-mailové šablony",
+ "notification.success.submit": "Nastavení bylo aktualizování",
+ "plugin.description.long": "Chraňte své API pomocí kompletního autentifikačního procesu, založeného na JWT. Tento zásuvný modul obsahuje ACL strategii, která vám umožní spravovat oprávnění mezi skupinami uživatelů.",
+ "plugin.description.short": "Chraňte své API pomocí kompletního autentifikačního procesu, založeného na JWT",
+ "plugin.name": "Role a oprávnění"
+}
diff --git a/packages/strapi/src/extensions/users-permissions/admin/src/translations/de.json b/packages/strapi/src/extensions/users-permissions/admin/src/translations/de.json
new file mode 100644
index 0000000..be2f6d3
--- /dev/null
+++ b/packages/strapi/src/extensions/users-permissions/admin/src/translations/de.json
@@ -0,0 +1,58 @@
+{
+ "BoundRoute.title": "Pfad gebunden an",
+ "EditForm.inputSelect.description.role": "Die Rolle, die neu authentifizierten Benutzern automatisch zugewiesen wird.",
+ "EditForm.inputSelect.label.role": "Standardrolle für authentifizierte Benutzer",
+ "EditForm.inputToggle.description.email": "Verbiete das Anlegen verschiedener Accounts mit der gleichen E-Mail-Adresse bei unterschiedlichen Anmeldemethoden.",
+ "EditForm.inputToggle.description.email-confirmation": "Wenn aktiviert (ON) erhalten neu registrierte Benutzer eine Bestätigungs-E-Mail.",
+ "EditForm.inputToggle.description.email-confirmation-redirection": "Nachdem Sie die E-Mail bestätigt haben, wähle wohin sie weitergeleitet wird.",
+ "EditForm.inputToggle.description.email-reset-password": "URL deiner Passwort-Zurücksetzen-Seite deiner Anwendung",
+ "EditForm.inputToggle.description.sign-up": "Wenn deaktiviert (OFF), wird der Registrationsprozess unterbunden. Niemand kann sich mehr registrieren.",
+ "EditForm.inputToggle.label.email": "Ein Account pro E-Mail-Adresse",
+ "EditForm.inputToggle.label.email-confirmation": "Aktiviere E-Mail Benachrichtigungen",
+ "EditForm.inputToggle.label.email-confirmation-redirection": "Weiterleitungs-URL",
+ "EditForm.inputToggle.label.email-reset-password": "Passwort-Zurücksetzen-Seite",
+ "EditForm.inputToggle.label.sign-up": "Registration ermöglichen",
+ "Email.template.email_confirmation": "Bestätigung der E-Mail-Addresse",
+ "HeaderNav.link.advancedSettings": "Erweiterte Einstellungen",
+ "HeaderNav.link.emailTemplates": "E-Mail-Templates",
+ "HeaderNav.link.providers": "Methoden",
+ "Plugin.permissions.plugins.description": "Definiere die möglichen Aktionen des {name} Plugins.",
+ "Plugins.header.description": "Nur Aktionen, die an einen Pfad gebunden sind, werden hier gelistet.",
+ "Plugins.header.title": "Berechtigungen",
+ "Policies.header.hint": "Wähle eine Aktion aus und klicke auf das Zahnrad, um den an diese Aktion gebundenen Pfad anzuzeigen",
+ "Policies.header.title": "Fortgeschrittene Einstellungen",
+ "PopUpForm.Email.email_templates.inputDescription": "{link} für mehr Informationen",
+ "PopUpForm.Email.link.documentation": "Lies die Dokumentation",
+ "PopUpForm.Email.options.from.email.label": "E-Mail-Adresse des Absenders",
+ "PopUpForm.Email.options.from.email.placeholder": "kai@doe.com",
+ "PopUpForm.Email.options.from.name.label": "Name des Absenders",
+ "PopUpForm.Email.options.from.name.placeholder": "Kai Doe",
+ "PopUpForm.Email.options.message.label": "Nachricht",
+ "PopUpForm.Email.options.object.label": "Betreff",
+ "PopUpForm.Email.options.object.placeholder": "Bitte bestätige deine E-Mail-Adresse für %APP_NAME%",
+ "PopUpForm.Email.options.response_email.label": "Antwort E-Mail-Adresse",
+ "PopUpForm.Email.options.response_email.placeholder": "kai@doe.com",
+ "PopUpForm.Providers.enabled.description": "Wenn deaktiviert, kann diese Methode nicht verwendet werden.",
+ "PopUpForm.Providers.enabled.label": "Aktivieren",
+ "PopUpForm.Providers.key.label": "Client ID",
+ "PopUpForm.Providers.key.placeholder": "TEXT",
+ "PopUpForm.Providers.redirectURL.front-end.label": "Die URL zur Weiterleitung zu deiner Frontend-App",
+ "PopUpForm.Providers.redirectURL.label": "Die Weiterleitungs-URL für die App-Einstellungen von {provider}",
+ "PopUpForm.Providers.secret.label": "Client Secret",
+ "PopUpForm.Providers.secret.placeholder": "TEXT",
+ "PopUpForm.Providers.subdomain.label": "Host URI (Subdomain)",
+ "PopUpForm.Providers.subdomain.placeholder": "my.subdomain.com",
+ "PopUpForm.header.edit.email-templates": "E-Mail-Templates bearbeiten",
+ "PopUpForm.header.edit.providers": "Anbieter bearbeiten",
+ "Settings.roles.deleted": "Rolle gelöscht",
+ "Settings.roles.edited": "Rolle bearbeitet",
+ "Settings.section-label": "Nutzer- & Berechtigungen-Plugin",
+ "notification.success.submit": "Einstellungen aktualisiert",
+ "plugin.description.long": "Beschütze deine API mit einem vollständigen Authentifikationsprozess basierend auf JWT. Zudem bietet dieses Plugin eine ACL-Strategie, die erlaubt, die Berechtigungen für Benutzergruppen festzulegen.",
+ "plugin.description.short": "Beschütze deine API mit einem vollständigen Authentifikationsprozess basierend auf JWT.",
+ "plugin.name": "Nutzer- & Berechtigungen-Plugin",
+ "popUpWarning.button.cancel": "Abbrechen",
+ "popUpWarning.button.confirm": "Bestätigen",
+ "popUpWarning.title": "Bitte bestätigen",
+ "popUpWarning.warning.cancel": "Willst du wirklich alle deine Änderungen verwerfen?"
+}
diff --git a/packages/strapi/src/extensions/users-permissions/admin/src/translations/dk.json b/packages/strapi/src/extensions/users-permissions/admin/src/translations/dk.json
new file mode 100644
index 0000000..5465bd6
--- /dev/null
+++ b/packages/strapi/src/extensions/users-permissions/admin/src/translations/dk.json
@@ -0,0 +1,82 @@
+{
+ "BoundRoute.title": "Bundet rute til",
+ "EditForm.inputSelect.description.role": "Den vil tilknytte den nye godkendte bruger til den valgte rolle.",
+ "EditForm.inputSelect.label.role": "Standard rolle for godkendte brugere",
+ "EditForm.inputToggle.description.email": "Tillad IKKE brugere at oprette flere brugere med den samme e-mail-adresse med forskellige godkendelsesudbydere.",
+ "EditForm.inputToggle.description.email-confirmation": "Når aktiv (TIL), modtager nye registrerede brugere en bekræftelses e-mail.",
+ "EditForm.inputToggle.description.email-confirmation-redirection": "Efter bekræftet email, vælg hvor du vil omdirigeres til.",
+ "EditForm.inputToggle.description.email-reset-password": "URL til din apps nulstil kodeord side",
+ "EditForm.inputToggle.description.sign-up": "Når deaktiveret (FRA), er registrering forbudt. Ingen kan subscribe uanset udbyder.",
+ "EditForm.inputToggle.label.email": "En bruger pr. e-mail",
+ "EditForm.inputToggle.label.email-confirmation": "Aktivér e-mail bekræftelse",
+ "EditForm.inputToggle.label.email-confirmation-redirection": "Omdirigerings URL",
+ "EditForm.inputToggle.label.email-reset-password": "Nulstil kodeord side",
+ "EditForm.inputToggle.label.sign-up": "Aktivér oprettelser",
+ "EditForm.inputToggle.placeholder.email-confirmation-redirection": "f.eks. https://hjemmeside.dk/nulstil-kodeord",
+ "EditForm.inputToggle.placeholder.email-reset-password": "f.eks. https://hjemmeside.dk/nulstil-kodeord",
+ "EditPage.form.roles": "Rolle detaljer",
+ "Email.template.data.loaded": "E-mail skabeloner er hentet",
+ "Email.template.email_confirmation": "E-mail adresse bekræftelse",
+ "Email.template.form.edit.label": "Redigér en skabelon",
+ "Email.template.table.action.label": "handling",
+ "Email.template.table.icon.label": "ikon",
+ "Email.template.table.name.label": "navn",
+ "Form.advancedSettings.data.loaded": "Avancerede indstillinger hentet",
+ "HeaderNav.link.advancedSettings": "Advancerede indstillinger",
+ "HeaderNav.link.emailTemplates": "E-mail skabeloner",
+ "HeaderNav.link.providers": "Udbydere",
+ "Plugin.permissions.plugins.description": "Definér alle tilladte handlinger for {name} plugin.",
+ "Plugins.header.description": "Kunne handlinger tilknyttet en rute er vist nedenfor.",
+ "Plugins.header.title": "Rettigheder",
+ "Policies.header.hint": "Vælg applikationens handlinger eller plugin handlinger og klik på tandhjulet for at vise den bunde rute",
+ "Policies.header.title": "Advancerede indstillinger",
+ "PopUpForm.Email.email_templates.inputDescription": "Hvis du er usikker på brugen af variabler, {link}",
+ "PopUpForm.Email.link.documentation": "tjek vores dokumentation.",
+ "PopUpForm.Email.options.from.email.label": "Afsender e-mail",
+ "PopUpForm.Email.options.from.email.placeholder": "johndoe@gmail.com",
+ "PopUpForm.Email.options.from.name.label": "Afsender name",
+ "PopUpForm.Email.options.from.name.placeholder": "John Doe",
+ "PopUpForm.Email.options.message.label": "Besked",
+ "PopUpForm.Email.options.object.label": "Emne",
+ "PopUpForm.Email.options.object.placeholder": "Bekræft venligst din e-mail adresse for %APP_NAME%",
+ "PopUpForm.Email.options.response_email.label": "Svar e-mail",
+ "PopUpForm.Email.options.response_email.placeholder": "johndoe@gmail.com",
+ "PopUpForm.Providers.enabled.description": "Hvis deaktiveret, kan brugere ikke bruge denne udbyder.",
+ "PopUpForm.Providers.enabled.label": "Aktivér",
+ "PopUpForm.Providers.key.label": "Klient ID",
+ "PopUpForm.Providers.key.placeholder": "TEKST",
+ "PopUpForm.Providers.redirectURL.front-end.label": "Omstillings URL til din font-end app",
+ "PopUpForm.Providers.redirectURL.label": "Omstillings URL som tilføjes til din {provider} applikation konfigurationer",
+ "PopUpForm.Providers.secret.label": "Klient hemmelighed",
+ "PopUpForm.Providers.secret.placeholder": "TEKST",
+ "PopUpForm.Providers.subdomain.label": "Host URI (Subdomain)",
+ "PopUpForm.Providers.subdomain.placeholder": "mit.subdomain.dk",
+ "PopUpForm.header.edit.email-templates": "Redigér e-mail skabeloner",
+ "PopUpForm.header.edit.providers": "Redigér udbydere",
+ "Providers.data.loaded": "Providers hentet",
+ "Providers.status": "Status",
+ "Roles.empty": "Du har endnu ingen roller.",
+ "Roles.empty.search": "Ingen roller matcher søgningen.",
+ "Settings.roles.deleted": "Rolle slettet",
+ "Settings.roles.edited": "Rolle redigeret",
+ "Settings.section-label": "Brugere & Tilladelser plugin",
+ "components.Input.error.validation.email": "Dette er en ugyldig e.mail",
+ "components.Input.error.validation.json": "Dette stemmer ikke med JSON formatet",
+ "components.Input.error.validation.max": "Værdien er for høj.",
+ "components.Input.error.validation.maxLength": "Værdien er for lang.",
+ "components.Input.error.validation.min": "Værdien er for lav.",
+ "components.Input.error.validation.minLength": "Værdien er for kort.",
+ "components.Input.error.validation.minSupMax": "Kan ikke være overlegen",
+ "components.Input.error.validation.regex": "Værdien stemmer ikke overens med regex.",
+ "components.Input.error.validation.required": "Værdien er påkrævet.",
+ "components.Input.error.validation.unique": "Værdien er allerede brugt.",
+ "notification.success.submit": "Indstillingerne er blevet opdateret",
+ "page.title": "Indstillinger - Roller",
+ "plugin.description.long": "Beskyt din API med fuld godkendelse med JWT. Dette plugin kommer også med en ACL strategi som tillader dig at håndtere rettigeheder mellem grupper af brugere.",
+ "plugin.description.short": "Beskyt din API med fuld godkendelse med JWT",
+ "plugin.name": "Roller & rettigheder",
+ "popUpWarning.button.cancel": "Annuller",
+ "popUpWarning.button.confirm": "Bekræft",
+ "popUpWarning.title": "Bekræft venligst",
+ "popUpWarning.warning.cancel": "Er du sikker på at du vil annullere dine ændringer?"
+}
diff --git a/packages/strapi/src/extensions/users-permissions/admin/src/translations/en.json b/packages/strapi/src/extensions/users-permissions/admin/src/translations/en.json
new file mode 100644
index 0000000..62f0438
--- /dev/null
+++ b/packages/strapi/src/extensions/users-permissions/admin/src/translations/en.json
@@ -0,0 +1,82 @@
+{
+ "BoundRoute.title": "Bound route to",
+ "EditForm.inputSelect.description.role": "It will attach the new authenticated user to the selected role.",
+ "EditForm.inputSelect.label.role": "Default role for authenticated users",
+ "EditForm.inputToggle.description.email": "Disallow the user to create multiple accounts using the same email address with different authentication providers.",
+ "EditForm.inputToggle.description.email-confirmation": "When enabled (ON), new registered users receive a confirmation email.",
+ "EditForm.inputToggle.description.email-confirmation-redirection": "After you confirmed your email, choose where you will be redirected.",
+ "EditForm.inputToggle.description.email-reset-password": "URL of your application's reset password page",
+ "EditForm.inputToggle.description.sign-up": "When disabled (OFF), the registration process is forbidden. No one can subscribe anymore no matter the used provider.",
+ "EditForm.inputToggle.label.email": "One account per email address",
+ "EditForm.inputToggle.label.email-confirmation": "Enable email confirmation",
+ "EditForm.inputToggle.label.email-confirmation-redirection": "Redirection url",
+ "EditForm.inputToggle.label.email-reset-password": "Reset password page",
+ "EditForm.inputToggle.label.sign-up": "Enable sign-ups",
+ "EditForm.inputToggle.placeholder.email-confirmation-redirection": "ex: https://yourfrontend.com/email-confirmation-redirection",
+ "EditForm.inputToggle.placeholder.email-reset-password": "ex: https://yourfrontend.com/reset-password",
+ "EditPage.form.roles": "Role details",
+ "Email.template.data.loaded": "Email templates has been loaded",
+ "Email.template.email_confirmation": "Email address confirmation",
+ "Email.template.form.edit.label": "Edit a template",
+ "Email.template.table.action.label": "action",
+ "Email.template.table.icon.label": "icon",
+ "Email.template.table.name.label": "name",
+ "Form.advancedSettings.data.loaded": "Advanced settings data has been loaded",
+ "HeaderNav.link.advancedSettings": "Advanced settings",
+ "HeaderNav.link.emailTemplates": "Email templates",
+ "HeaderNav.link.providers": "Providers",
+ "Plugin.permissions.plugins.description": "Define all allowed actions for the {name} plugin.",
+ "Plugins.header.description": "Only actions bound by a route are listed below.",
+ "Plugins.header.title": "Permissions",
+ "Policies.header.hint": "Select the application's actions or the plugin's actions and click on the cog icon to display the bound route",
+ "Policies.header.title": "Advanced settings",
+ "PopUpForm.Email.email_templates.inputDescription": "If you're unsure how to use variables, {link}",
+ "PopUpForm.Email.link.documentation": "check out our documentation.",
+ "PopUpForm.Email.options.from.email.label": "Shipper email",
+ "PopUpForm.Email.options.from.email.placeholder": "kai@doe.com",
+ "PopUpForm.Email.options.from.name.label": "Shipper name",
+ "PopUpForm.Email.options.from.name.placeholder": "Kai Doe",
+ "PopUpForm.Email.options.message.label": "Message",
+ "PopUpForm.Email.options.object.label": "Subject",
+ "PopUpForm.Email.options.object.placeholder": "Please confirm your email address for %APP_NAME%",
+ "PopUpForm.Email.options.response_email.label": "Response email",
+ "PopUpForm.Email.options.response_email.placeholder": "kai@doe.com",
+ "PopUpForm.Providers.enabled.description": "If disabled, users won't be able to use this provider.",
+ "PopUpForm.Providers.enabled.label": "Enable",
+ "PopUpForm.Providers.key.label": "Client ID",
+ "PopUpForm.Providers.key.placeholder": "TEXT",
+ "PopUpForm.Providers.redirectURL.front-end.label": "The redirect URL to your front-end app",
+ "PopUpForm.Providers.redirectURL.label": "The redirect URL to add in your {provider} application configurations",
+ "PopUpForm.Providers.secret.label": "Client Secret",
+ "PopUpForm.Providers.secret.placeholder": "TEXT",
+ "PopUpForm.Providers.subdomain.label": "Host URI (Subdomain)",
+ "PopUpForm.Providers.subdomain.placeholder": "my.subdomain.com",
+ "PopUpForm.header.edit.email-templates": "Edit email template",
+ "PopUpForm.header.edit.providers": "Edit Provider",
+ "Providers.data.loaded": "Providers have been loaded",
+ "Providers.status": "Status",
+ "Roles.empty": "You don't have any roles yet.",
+ "Roles.empty.search": "No roles match the search.",
+ "Settings.roles.deleted": "Role deleted",
+ "Settings.roles.edited": "Role edited",
+ "Settings.section-label": "Users & Permissions plugin",
+ "components.Input.error.validation.email": "This is an invalid email",
+ "components.Input.error.validation.json": "This doesn't match the JSON format",
+ "components.Input.error.validation.max": "The value is too high.",
+ "components.Input.error.validation.maxLength": "The value is too long.",
+ "components.Input.error.validation.min": "The value is too low.",
+ "components.Input.error.validation.minLength": "The value is too short.",
+ "components.Input.error.validation.minSupMax": "Can't be superior",
+ "components.Input.error.validation.regex": "The value does not match the regex.",
+ "components.Input.error.validation.required": "This value is required.",
+ "components.Input.error.validation.unique": "This value is already used.",
+ "notification.success.submit": "Settings have been updated",
+ "page.title": "Settings - Roles",
+ "plugin.description.long": "Protect your API with a full authentication process based on JWT. This plugin comes also with an ACL strategy that allows you to manage the permissions between the groups of users.",
+ "plugin.description.short": "Protect your API with a full authentication process based on JWT.",
+ "plugin.name": "Users & Permissions Plugin",
+ "popUpWarning.button.cancel": "Cancel",
+ "popUpWarning.button.confirm": "Confirm",
+ "popUpWarning.title": "Please confirm",
+ "popUpWarning.warning.cancel": "Are you sure you want to cancel your modifications?"
+}
diff --git a/packages/strapi/src/extensions/users-permissions/admin/src/translations/es.json b/packages/strapi/src/extensions/users-permissions/admin/src/translations/es.json
new file mode 100644
index 0000000..d709dea
--- /dev/null
+++ b/packages/strapi/src/extensions/users-permissions/admin/src/translations/es.json
@@ -0,0 +1,82 @@
+{
+ "BoundRoute.title": "Ruta enlazada a",
+ "EditForm.inputSelect.description.role": "Adjuntará el nuevo usuario autenticado al rol seleccionado.",
+ "EditForm.inputSelect.label.role": "Rol predeterminado para usuarios autenticados",
+ "EditForm.inputToggle.description.email": "No permita que el usuario cree varias cuentas utilizando la misma dirección de correo electrónico con distintos proveedores de autenticación.",
+ "EditForm.inputToggle.description.email-confirmation": "Estando habilitado (ON), nuevos usuarios registrados reciben un correo de confirmación.",
+ "EditForm.inputToggle.description.email-confirmation-redirection": "After confirmed your email, chose where you will be redirected.",
+ "EditForm.inputToggle.description.email-reset-password": "URL de la página de restablecimiento de contraseña de su aplicación",
+ "EditForm.inputToggle.description.sign-up": "Cuando está desactivado (OFF), el proceso de registro está prohibido. Nadie puede suscribirse sin importar el proveedor utilizado.",
+ "EditForm.inputToggle.label.email": "Una cuenta por dirección de correo electrónico",
+ "EditForm.inputToggle.label.email-confirmation": "Habilitar confirmación de correo",
+ "EditForm.inputToggle.label.email-confirmation-redirection": "URL de redirección",
+ "EditForm.inputToggle.label.email-reset-password": "Página de reestablecer la contraseña",
+ "EditForm.inputToggle.label.sign-up": "Habilitar inscripciones",
+ "EditForm.inputToggle.placeholder.email-confirmation-redirection": "ej: https://tufrontend.com/restablecer-contrasena",
+ "EditForm.inputToggle.placeholder.email-reset-password": "ej: https://tufrontend.com/restablecer-contrasena",
+ "EditPage.form.roles": "Detalles del rol",
+ "Email.template.data.loaded": "Se han cargado las plantillas de correo electrónico",
+ "Email.template.email_confirmation": "Confirmación de dirección de correo electrónico",
+ "Email.template.form.edit.label": "Editar una plantilla",
+ "Email.template.table.action.label": "acción",
+ "Email.template.table.icon.label": "icono",
+ "Email.template.table.name.label": "nombre",
+ "Form.advancedSettings.data.loaded": "Se han cargado los datos de configuración avanzada",
+ "HeaderNav.link.advancedSettings": "Ajustes avanzados",
+ "HeaderNav.link.emailTemplates": "Plantillas de email",
+ "HeaderNav.link.providers": "Proveedores",
+ "Plugin.permissions.plugins.description": "Defina todas las acciones permitidas para el plugin {name}.",
+ "Plugins.header.description": "Sólo las acciones vinculadas a una ruta se enumeran a continuación.",
+ "Plugins.header.title": "Permisos",
+ "Policies.header.hint": "Seleccione las acciones de la aplicación o las acciones del plugin y haga clic en el icono del engranaje para ver la ruta vinculada",
+ "Policies.header.title": "Ajustes avanzados",
+ "PopUpForm.Email.email_templates.inputDescription": "Si no estás seguro de cómo usar las variables, {link}",
+ "PopUpForm.Email.link.documentation": "consulte nuestra documentación.",
+ "PopUpForm.Email.options.from.email.label": "Email del remitente",
+ "PopUpForm.Email.options.from.email.placeholder": "kai@doe.com",
+ "PopUpForm.Email.options.from.name.label": "Nombre del remitente",
+ "PopUpForm.Email.options.from.name.placeholder": "Kai Doe",
+ "PopUpForm.Email.options.message.label": "Mensaje",
+ "PopUpForm.Email.options.object.label": "Tema",
+ "PopUpForm.Email.options.object.placeholder": "Confirma tu dirección de correo electrónico para %APP_NAME%",
+ "PopUpForm.Email.options.response_email.label": "Email de respuesta",
+ "PopUpForm.Email.options.response_email.placeholder": "kai@doe.com",
+ "PopUpForm.Providers.enabled.description": "Si está desactivado, los usuarios no podrán utilizar este proveedor.",
+ "PopUpForm.Providers.enabled.label": "Habilitar",
+ "PopUpForm.Providers.key.label": "ID de cliente",
+ "PopUpForm.Providers.key.placeholder": "TEXTO",
+ "PopUpForm.Providers.redirectURL.front-end.label": "La URL de redireccionamiento a su aplicación front-end",
+ "PopUpForm.Providers.redirectURL.label": "La URL de redireccionamiento para agregar en las configuraciones de su aplicación de {proveedor}",
+ "PopUpForm.Providers.secret.label": "Secreto Cliente",
+ "PopUpForm.Providers.secret.placeholder": "TEXTO",
+ "PopUpForm.Providers.subdomain.label": "URI de host (subdominio)",
+ "PopUpForm.Providers.subdomain.placeholder": "mi.subdominio.com",
+ "PopUpForm.header.edit.email-templates": "Editar Plantillas de Email",
+ "PopUpForm.header.edit.providers": "Editar proveedor",
+ "Providers.data.loaded": "Los proveedores se han cargado",
+ "Providers.status": "Estado",
+ "Roles.empty": "Aún no tienes ningún rol.",
+ "Roles.empty.search": "Ningún rol coincide con la búsqueda.",
+ "Settings.roles.deleted": "Rol eliminado",
+ "Settings.roles.edited": "Rol editado",
+ "Settings.section-label": "Plugin de Usuarios y Permisos",
+ "components.Input.error.validation.email": "El correo electrónico inválido",
+ "components.Input.error.validation.json": "No coincide con el formato JSON",
+ "components.Input.error.validation.max": "El valor es demasiado alto.",
+ "components.Input.error.validation.maxLength": "El valor es demasiado largo.",
+ "components.Input.error.validation.min": "El valor es demasiado bajo.",
+ "components.Input.error.validation.minLength": "El valor es demasiado corto.",
+ "components.Input.error.validation.minSupMax": "No puede ser superior",
+ "components.Input.error.validation.regex": "El valor no coincide con la expresión regular.",
+ "components.Input.error.validation.required": "Este valor es obligatorio.",
+ "components.Input.error.validation.unique": "Este valor ya se utiliza.",
+ "notification.success.submit": "Los ajustes se han actualizado",
+ "page.title": "Configuración - Roles",
+ "plugin.description.long": "Proteja su API con un proceso de autenticación completo basado en JWT. Este plugin viene también con una estrategia ACL que le permite administrar los permisos entre los grupos de usuarios.",
+ "plugin.description.short": "Proteja su API con un proceso de autenticación completo basado en JWT",
+ "plugin.name": "Roles y Permisos",
+ "popUpWarning.button.cancel": "Cancelar",
+ "popUpWarning.button.confirm": "Confirmar",
+ "popUpWarning.title": "Por favor confirme",
+ "popUpWarning.warning.cancel": "¿Está seguro de que desea cancelar sus modificaciones?"
+}
diff --git a/packages/strapi/src/extensions/users-permissions/admin/src/translations/fr.json b/packages/strapi/src/extensions/users-permissions/admin/src/translations/fr.json
new file mode 100644
index 0000000..4234a5d
--- /dev/null
+++ b/packages/strapi/src/extensions/users-permissions/admin/src/translations/fr.json
@@ -0,0 +1,46 @@
+{
+ "BoundRoute.title": "Route associée à",
+ "EditForm.inputSelect.description.role": "Choisissez le rôle qui sera lié aux utilisateurs lors de leur enregistrement.",
+ "EditForm.inputSelect.label.role": "Rôle par defaut pour les nouveaux utilisateurs",
+ "EditForm.inputToggle.description.email": "Interdire l'utilisateur de créer de multiple comptes avec la même adresse e-mail avec des providers différents",
+ "EditForm.inputToggle.description.email-confirmation": "Quand cette option est activée (ON), les nouveaux utilisateurs enregistrés reçoivent un e-mail de confirmation.",
+ "EditForm.inputToggle.description.email-confirmation-redirection": "Après confirmation de votre e-mail, choisissez où vous allez être redirigé.",
+ "EditForm.inputToggle.description.email-reset-password": "URL de la page de réinitialisation de mot de passe.",
+ "EditForm.inputToggle.description.sign-up": "Quand l'inscription est désactivée (OFF), aucun utilisateur ne peut s'inscrire qu'importe le provider",
+ "EditForm.inputToggle.label.email": "Un compte par adresse e-mail",
+ "EditForm.inputToggle.label.email-confirmation": "Activer l'e-mail de confirmation",
+ "EditForm.inputToggle.label.email-confirmation-redirection": "Redirection de l'URL",
+ "EditForm.inputToggle.label.email-reset-password": "Page de réinitialisation de mot de passe",
+ "EditForm.inputToggle.label.sign-up": "Activer l'inscription",
+ "HeaderNav.link.advancedSettings": "Paramètres avancés",
+ "HeaderNav.link.emailTemplates": "Templates d'e-mail",
+ "HeaderNav.link.providers": "Fournisseurs",
+ "Plugin.permissions.plugins.description": "Définissez les actions autorisées dans le {name} plugin.",
+ "Plugins.header.description": "Sont listés uniquement les actions associées à une route.",
+ "Plugins.header.title": "Permissions",
+ "Policies.header.hint": "Sélectionnez les actions de l'application ou d'un plugin et cliquer sur l'icon de paramètres pour voir les routes associées à cette action",
+ "Policies.header.title": "Paramètres avancés",
+ "PopUpForm.Email.email_templates.inputDescription": "Regardez la documentation des variables, {link}",
+ "PopUpForm.Email.options.from.email.label": "E-mail de l'envoyeur",
+ "PopUpForm.Email.options.from.email.placeholder": "arthurdupont@gmail.com",
+ "PopUpForm.Email.options.from.name.label": "Nom de l'envoyeur",
+ "PopUpForm.Email.options.from.name.placeholder": "Arthur Dupont",
+ "PopUpForm.Email.options.message.label": "Message",
+ "PopUpForm.Email.options.object.label": "Objet",
+ "PopUpForm.Email.options.response_email.label": "E-mail de réponse",
+ "PopUpForm.Email.options.response_email.placeholder": "arthurdupont@gmail.com",
+ "PopUpForm.Providers.enabled.description": "S'il est désactivé les utilisateurs ne pourront pas utiliser ce provider.",
+ "PopUpForm.Providers.enabled.label": "Activer",
+ "PopUpForm.Providers.key.label": "Client ID",
+ "PopUpForm.Providers.key.placeholder": "TEXT",
+ "PopUpForm.Providers.redirectURL.front-end.label": "L'URL de redirection de votre app front-end",
+ "PopUpForm.Providers.secret.label": "Client Secret",
+ "PopUpForm.Providers.secret.placeholder": "TEXT",
+ "PopUpForm.Providers.subdomain.label": "Host URI (Subdomain)",
+ "PopUpForm.Providers.subdomain.placeholder": "my.subdomain.com",
+ "PopUpForm.header.edit.email-templates": "Editer E-mail Templates",
+ "notification.success.submit": "Les configurations ont bien été sauvegardés",
+ "plugin.description.long": "Protégez votre API avec un système d'authentification complet basé sur JWT (JSON Web Token). Ce plugin ajoute aussi une stratégie ACL (Access Control Layer) qui vous permet de gérer les permissions entre les groupes d'utilisateurs.",
+ "plugin.description.short": "Protégez votre API avec un système d'authentification complet basé sur JWT.",
+ "plugin.name": "Rôles et autorisations"
+}
diff --git a/packages/strapi/src/extensions/users-permissions/admin/src/translations/id.json b/packages/strapi/src/extensions/users-permissions/admin/src/translations/id.json
new file mode 100644
index 0000000..6119c97
--- /dev/null
+++ b/packages/strapi/src/extensions/users-permissions/admin/src/translations/id.json
@@ -0,0 +1,58 @@
+{
+ "BoundRoute.title": "Rute terikat ke",
+ "EditForm.inputSelect.description.role": "Ini akan melampirkan pengguna baru yang diautentikasi ke peran yang dipilih.",
+ "EditForm.inputSelect.label.role": "Peran default untuk pengguna yang diautentikasi",
+ "EditForm.inputToggle.description.email": "Larang pengguna membuat beberapa akun menggunakan alamat email yang sama dengan penyedia otentikasi yang berbeda.",
+ "EditForm.inputToggle.description.email-confirmation": "Saat diaktifkan (ON), pengguna baru yang terdaftar menerima email konfirmasi.",
+ "EditForm.inputToggle.description.email-confirmation-redirection": "Setelah Anda mengkonfirmasi email Anda, pilih ke mana Anda akan diarahkan.",
+ "EditForm.inputToggle.description.email-reset-password": "URL halaman setel ulang sandi aplikasi Anda",
+ "EditForm.inputToggle.description.sign-up": "Saat dinonaktifkan (OFF), proses pendaftaran dilarang. Tidak ada yang bisa berlangganan lagi tidak peduli penyedia yang digunakan.",
+ "EditForm.inputToggle.label.email": "Satu akun per alamat email",
+ "EditForm.inputToggle.label.email-confirmation": "Aktifkan konfirmasi email",
+ "EditForm.inputToggle.label.email-confirmation-redirection": "URL pengalihan",
+ "EditForm.inputToggle.label.email-reset-password": "Atur ulang halaman kata sandi",
+ "EditForm.inputToggle.label.sign-up": "Aktifkan pendaftaran",
+ "Email.template.email_confirmation": "Konfirmasi alamat email",
+ "HeaderNav.link.advancedSettings": "Pengaturan lanjutan",
+ "HeaderNav.link.emailTemplates": "Template email",
+ "HeaderNav.link.providers": "Penyedia",
+ "Plugin.permissions.plugins.description": "Tentukan semua tindakan yang diizinkan untuk plugin {name}.",
+ "Plugins.header.description": "Hanya tindakan yang terikat oleh rute yang dicantumkan di bawah.",
+ "Plugins.header.title": "Izin",
+ "Policies.header.hint": "Pilih tindakan aplikasi atau tindakan plugin dan klik ikon roda gigi untuk menampilkan rute terikat",
+ "Policies.header.title": "Pengaturan lanjutan",
+ "PopUpForm.Email.email_templates.inputDescription": "Jika Anda tidak yakin bagaimana menggunakan variabel, {link}",
+ "PopUpForm.Email.link.documentation": "lihat dokumentasi kami.",
+ "PopUpForm.Email.options.from.email.label": "Email pengirim",
+ "PopUpForm.Email.options.from.email.placeholder": "kai@doe.com",
+ "PopUpForm.Email.options.from.name.label": "Nama pengirim",
+ "PopUpForm.Email.options.from.name.placeholder": "Kai Doe",
+ "PopUpForm.Email.options.message.label": "Pesan",
+ "PopUpForm.Email.options.object.label": "Subyek",
+ "PopUpForm.Email.options.object.placeholder": "Harap konfirmasi alamat email Anda untuk% APP_NAME%",
+ "PopUpForm.Email.options.response_email.label": "Email tanggapan",
+ "PopUpForm.Email.options.response_email.placeholder": "kai@doe.com",
+ "PopUpForm.Providers.enabled.description": "Jika dinonaktifkan, pengguna tidak akan dapat menggunakan penyedia ini.",
+ "PopUpForm.Providers.enabled.label": "Memungkinkan",
+ "PopUpForm.Providers.key.label": "ID Klien",
+ "PopUpForm.Providers.key.placeholder": "TEKS",
+ "PopUpForm.Providers.redirectURL.front-end.label": "URL pengalihan ke aplikasi front-end Anda",
+ "PopUpForm.Providers.redirectURL.label": "URL pengalihan yang akan ditambahkan dalam konfigurasi aplikasi {provider} Anda",
+ "PopUpForm.Providers.secret.label": "Client Secret",
+ "PopUpForm.Providers.secret.placeholder": "TEKS",
+ "PopUpForm.Providers.subdomain.label": "URI Host (Subdomain)",
+ "PopUpForm.Providers.subdomain.placeholder": "saya.subdomain.com",
+ "PopUpForm.header.edit.email-templates": "Edit Template Email",
+ "PopUpForm.header.edit.providers": "Edit Penyedia",
+ "Settings.roles.deleted": "Peran dihapus",
+ "Settings.roles.edited": "Peran diedit",
+ "Settings.section-label": "Plugin Pengguna & Izin",
+ "notification.success.submit": "Pengaturan telah diperbarui",
+ "plugin.description.long": "Lindungi API Anda dengan proses otentikasi penuh berdasarkan JWT. Plugin ini juga dilengkapi dengan strategi ACL yang memungkinkan Anda untuk mengelola izin di antara grup pengguna.",
+ "plugin.description.short": "Lindungi API Anda dengan proses otentikasi penuh berdasarkan JWT",
+ "plugin.name": "Plugin Pengguna & Izin",
+ "popUpWarning.button.cancel": "Batalkan",
+ "popUpWarning.button.confirm": "Konfirmasi",
+ "popUpWarning.title": "Harap konfirmasi",
+ "popUpWarning.warning.cancel": "Anda yakin ingin membatalkan modifikasi Anda?"
+}
diff --git a/packages/strapi/src/extensions/users-permissions/admin/src/translations/it.json b/packages/strapi/src/extensions/users-permissions/admin/src/translations/it.json
new file mode 100644
index 0000000..83100f2
--- /dev/null
+++ b/packages/strapi/src/extensions/users-permissions/admin/src/translations/it.json
@@ -0,0 +1,58 @@
+{
+ "BoundRoute.title": "Vincola route a",
+ "EditForm.inputSelect.description.role": "Questa operazione assocerà i nuovi utenti autenticati al ruolo selezionato.",
+ "EditForm.inputSelect.label.role": "Ruolo di default per gli utenti registrati",
+ "EditForm.inputToggle.description.email": "Non consentire all'utente di creare account multipli usando lo stesso indirizzo email con provider di autenticazione diversi.",
+ "EditForm.inputToggle.description.email-confirmation": "Quando abilitato (ON), i nuovi utenti registrati riceveranno una richiesta di conferma via email.",
+ "EditForm.inputToggle.description.email-confirmation-redirection": "Scegli dove redirigere gli utenti che completano la conferma dell'indirizzo email.",
+ "EditForm.inputToggle.description.email-reset-password": "URL della pagina per il reset della password della tua applicazione",
+ "EditForm.inputToggle.description.sign-up": "Quando disabilitata (OFF), il processo di registrazione è proibito. Nessuno può iscriversi indipendentemente dal provider utilizzato.",
+ "EditForm.inputToggle.label.email": "Un solo account per indirizzo email",
+ "EditForm.inputToggle.label.email-confirmation": "Abilita conferma email",
+ "EditForm.inputToggle.label.email-confirmation-redirection": "URL di reindirizzamento",
+ "EditForm.inputToggle.label.email-reset-password": "Pagina reset password",
+ "EditForm.inputToggle.label.sign-up": "Abilita registrazione",
+ "Email.template.email_confirmation": "Conferma dell'indirizzo Email",
+ "HeaderNav.link.advancedSettings": "Impostazioni avanzate",
+ "HeaderNav.link.emailTemplates": "Template delle Email",
+ "HeaderNav.link.providers": "Provider",
+ "Plugin.permissions.plugins.description": "Definisce tutte le azioni consentite per il plugin {name}.",
+ "Plugins.header.description": "Di seguito sono elencate solo le azioni vincolate da una route.",
+ "Plugins.header.title": "Permessi",
+ "Policies.header.hint": "Seleziona le azioni dell'applicazione o del plugin e clicca sull'ingranaggio per mostrare il percorso corrispondente",
+ "Policies.header.title": "Impostazioni avanzate",
+ "PopUpForm.Email.email_templates.inputDescription": "Se non sai bene come usare le variabili, {link}",
+ "PopUpForm.Email.link.documentation": "controlla la nostra documentazione.",
+ "PopUpForm.Email.options.from.email.label": "Email del mittente",
+ "PopUpForm.Email.options.from.email.placeholder": "kai@doe.com",
+ "PopUpForm.Email.options.from.name.label": "Nome del mittente",
+ "PopUpForm.Email.options.from.name.placeholder": "Kai Doe",
+ "PopUpForm.Email.options.message.label": "Messaggio",
+ "PopUpForm.Email.options.object.label": "Oggetto",
+ "PopUpForm.Email.options.object.placeholder": "Conferma il tuo indirizzo email per %APP_NAME%",
+ "PopUpForm.Email.options.response_email.label": "Email di risposta",
+ "PopUpForm.Email.options.response_email.placeholder": "kai@doe.com",
+ "PopUpForm.Providers.enabled.description": "Se disabilitato, gli utenti non potranno usare questo provider.",
+ "PopUpForm.Providers.enabled.label": "Abilita",
+ "PopUpForm.Providers.key.label": "Client ID",
+ "PopUpForm.Providers.key.placeholder": "TEXT",
+ "PopUpForm.Providers.redirectURL.front-end.label": "L'URL di reindirizzamento per la tua app di front-end",
+ "PopUpForm.Providers.redirectURL.label": "L'URL di reindirizzamento da aggiungere nelle impostazioni dell'applicazione di {provider}",
+ "PopUpForm.Providers.secret.label": "Client Secret",
+ "PopUpForm.Providers.secret.placeholder": "TEXT",
+ "PopUpForm.Providers.subdomain.label": "Host URI (Sottodominio)",
+ "PopUpForm.Providers.subdomain.placeholder": "my.subdomain.com",
+ "PopUpForm.header.edit.email-templates": "Modifica i Template Email",
+ "PopUpForm.header.edit.providers": "Modifica Provider",
+ "Settings.roles.deleted": "Ruolo eliminato",
+ "Settings.roles.edited": "Ruolo modificato",
+ "Settings.section-label": "Plugin Utenti & Permessi",
+ "notification.success.submit": "Impostazioni aggiornate",
+ "plugin.description.long": "Proteggi le tue API con un processo di autenticazione completo basato su JWT. Questo plugin è implementato con una strategia ACL che ti consente di gestire i permessi tra i gruppi di utenti.",
+ "plugin.description.short": "Proteggi le tue API con un processo di autenticazione completo basato su JWT",
+ "plugin.name": "Plugin Utenti & Permessi",
+ "popUpWarning.button.cancel": "Annulla",
+ "popUpWarning.button.confirm": "Conferma",
+ "popUpWarning.title": "Si prega di confermare",
+ "popUpWarning.warning.cancel": "Sei sicuro di voler annullare le tue modifiche?"
+}
diff --git a/packages/strapi/src/extensions/users-permissions/admin/src/translations/ja.json b/packages/strapi/src/extensions/users-permissions/admin/src/translations/ja.json
new file mode 100644
index 0000000..e84a39d
--- /dev/null
+++ b/packages/strapi/src/extensions/users-permissions/admin/src/translations/ja.json
@@ -0,0 +1,44 @@
+{
+ "BoundRoute.title": "Bound route to",
+ "EditForm.inputSelect.description.role": "新しい認証されたユーザーが選択された役割にアタッチされます。",
+ "EditForm.inputSelect.label.role": "認証されたユーザーのデフォルトの役割",
+ "EditForm.inputToggle.description.email": "ユーザーが異なる認証プロバイダで同じ電子メールアドレスを使用して複数のアカウントを作成できないようにします。",
+ "EditForm.inputToggle.description.email-confirmation": "有効(ON)にすると、新しい登録ユーザーに確認メールが送信されます。",
+ "EditForm.inputToggle.description.email-confirmation-redirection": "あなたのEメールを確認したら、リダイレクト先を選択してください。",
+ "EditForm.inputToggle.description.sign-up": "あなたの電子メールを確認した後、リダイレクト先を選択しました。",
+ "EditForm.inputToggle.label.email": "メールアドレスごとに1つのアカウント",
+ "EditForm.inputToggle.label.email-confirmation": "Eメールの確認を有効にする",
+ "EditForm.inputToggle.label.email-confirmation-redirection": "リダイレクトURL",
+ "EditForm.inputToggle.label.sign-up": "申し込みを有効にする",
+ "HeaderNav.link.advancedSettings": "高度な設定",
+ "HeaderNav.link.emailTemplates": "メールテンプレート",
+ "HeaderNav.link.providers": "プロバイダー",
+ "Plugin.permissions.plugins.description": "{name} 個のプラグインに対して許可されたすべてのアクションを定義する",
+ "Plugins.header.description": "ルートにバインドされたアクションのみが以下にリストされています",
+ "Plugins.header.title": "権限",
+ "Policies.header.hint": "アプリケーションのアクションまたはプラグインのアクションを選択し、コグアイコンをクリックしてバインドされたルートを表示します",
+ "Policies.header.title": "高度な設定",
+ "PopUpForm.Email.email_templates.inputDescription": "変数の使用方法がわからない場合は、{link}",
+ "PopUpForm.Email.options.from.email.label": "送信者Eメール",
+ "PopUpForm.Email.options.from.email.placeholder": "kai@doe.com",
+ "PopUpForm.Email.options.from.name.label": "送信者名",
+ "PopUpForm.Email.options.from.name.placeholder": "Kai Doe",
+ "PopUpForm.Email.options.message.label": "メッセージ",
+ "PopUpForm.Email.options.object.label": "件名",
+ "PopUpForm.Email.options.response_email.label": "応答メール",
+ "PopUpForm.Email.options.response_email.placeholder": "kai@doe.com",
+ "PopUpForm.Providers.enabled.description": "無効にすると、ユーザーはこのプロバイダを使用できなくなります。",
+ "PopUpForm.Providers.enabled.label": "有効にする",
+ "PopUpForm.Providers.key.label": "クライアントID",
+ "PopUpForm.Providers.key.placeholder": "TEXT",
+ "PopUpForm.Providers.redirectURL.front-end.label": "フロントエンドアプリへのリダイレクトURL",
+ "PopUpForm.Providers.secret.label": "クライアントの秘密",
+ "PopUpForm.Providers.secret.placeholder": "TEXT",
+ "PopUpForm.Providers.subdomain.label": "Host URI (Subdomain)",
+ "PopUpForm.Providers.subdomain.placeholder": "my.subdomain.com",
+ "PopUpForm.header.edit.email-templates": "メールテンプレートの編集",
+ "notification.success.submit": "設定が更新されました",
+ "plugin.description.long": "JWTに基づいた完全な認証プロセスでAPIを保護します。このプラグインには、ユーザーのグループ間で権限を管理できるACL戦略もあります。",
+ "plugin.description.short": "JWTに基づく完全な認証プロセスでAPIを保護する",
+ "plugin.name": "ロールと権限"
+}
diff --git a/packages/strapi/src/extensions/users-permissions/admin/src/translations/ko.json b/packages/strapi/src/extensions/users-permissions/admin/src/translations/ko.json
new file mode 100644
index 0000000..fb18847
--- /dev/null
+++ b/packages/strapi/src/extensions/users-permissions/admin/src/translations/ko.json
@@ -0,0 +1,82 @@
+{
+ "BoundRoute.title": "라우트(bound route)",
+ "EditForm.inputSelect.description.role": "인증된 사용자에 선택한 역할(role)을 부여합니다.",
+ "EditForm.inputSelect.label.role": "인증된 사용자의 기본 역할(role)",
+ "EditForm.inputToggle.description.email": "사용자가 동일한 이메일 주소를 사용해 여러 계정을 만들지 못하게 합니다.",
+ "EditForm.inputToggle.description.email-confirmation": "(ON)이 활성화되면, 새로 가입하는 사용자는 인증 메일을 받게됩니다.",
+ "EditForm.inputToggle.description.email-confirmation-redirection": "이메일 인증완료 후 리다이렉트 될 주소",
+ "EditForm.inputToggle.description.email-reset-password": "애플리케이션의 비밀번호 재설정 URL 페이지",
+ "EditForm.inputToggle.description.sign-up": "비활성(OFF)일 경우, 등록 프로세스를 금지합니다. 사용하는 프로바이더(provider)에 관계 없이 누구도 가입할 수 없습니다.",
+ "EditForm.inputToggle.label.email": "이메일 주소 당 하나의 계정",
+ "EditForm.inputToggle.label.email-confirmation": "이메일 인증 활성화",
+ "EditForm.inputToggle.label.email-confirmation-redirection": "리다이렉션 url",
+ "EditForm.inputToggle.label.email-reset-password": "패스워드 재설정 페이지",
+ "EditForm.inputToggle.label.sign-up": "사용자 등록",
+ "EditForm.inputToggle.placeholder.email-confirmation-redirection": "예: https://yourfrontend.com/reset-password",
+ "EditForm.inputToggle.placeholder.email-reset-password": "예: https://yourfrontend.com/reset-password",
+ "EditPage.form.roles": "역할 상세정보",
+ "Email.template.data.loaded": "이메일 템플릿을 불러왔습니다.",
+ "Email.template.email_confirmation": "이메일 주소 확인",
+ "Email.template.form.edit.label": "템플릿 수정",
+ "Email.template.table.action.label": "action",
+ "Email.template.table.icon.label": "icon",
+ "Email.template.table.name.label": "name",
+ "Form.advancedSettings.data.loaded": "고급 설정 정보를 불러왔습니다.",
+ "HeaderNav.link.advancedSettings": "고급 설정",
+ "HeaderNav.link.emailTemplates": "이메일 템플릿",
+ "HeaderNav.link.providers": "프로바이더(Providers)",
+ "Plugin.permissions.plugins.description": "{name} 플러그인에서 허용할 액션을 설정합니다.",
+ "Plugins.header.description": "라우트(route)에 연결된 액션만 표시됩니다.",
+ "Plugins.header.title": "권한(Permissions)",
+ "Policies.header.hint": "애플리케이션 또는 플러그인을 선택하고 항목을 클릭하면 바인딩 된 경로를 표시할 수 있습니다.",
+ "Policies.header.title": "고급 설정",
+ "PopUpForm.Email.email_templates.inputDescription": "이메일 템플릿 문법은 이 {link}를 확인하세요.",
+ "PopUpForm.Email.link.documentation": "check out our documentation.",
+ "PopUpForm.Email.options.from.email.label": "보내는 이메일",
+ "PopUpForm.Email.options.from.email.placeholder": "kai@doe.com",
+ "PopUpForm.Email.options.from.name.label": "보내는 사람",
+ "PopUpForm.Email.options.from.name.placeholder": "Kai Doe",
+ "PopUpForm.Email.options.message.label": "내용",
+ "PopUpForm.Email.options.object.label": "제목",
+ "PopUpForm.Email.options.object.placeholder": "Please confirm your email address for %APP_NAME%",
+ "PopUpForm.Email.options.response_email.label": "응답받을 이메일",
+ "PopUpForm.Email.options.response_email.placeholder": "kai@doe.com",
+ "PopUpForm.Providers.enabled.description": "사용하지 않을 경우 이 프로바이더(provider) 기능을 이용할 수 없습니다.",
+ "PopUpForm.Providers.enabled.label": "사용",
+ "PopUpForm.Providers.key.label": "클라이언트 ID(Client ID)",
+ "PopUpForm.Providers.key.placeholder": "텍스트",
+ "PopUpForm.Providers.redirectURL.front-end.label": "프론트엔드 애플리케이션 리다이렉트 URL",
+ "PopUpForm.Providers.redirectURL.label": "{provider} 애플리케이션 구성에 추가할 리디렉션 URL",
+ "PopUpForm.Providers.secret.label": "클라이언트 시크릿(Client Secret)",
+ "PopUpForm.Providers.secret.placeholder": "텍스트",
+ "PopUpForm.Providers.subdomain.label": "Host URI (Subdomain)",
+ "PopUpForm.Providers.subdomain.placeholder": "my.subdomain.com",
+ "PopUpForm.header.edit.email-templates": "이메일 템플릿 수정",
+ "PopUpForm.header.edit.providers": "프로바이더 수정",
+ "Providers.data.loaded": "프로바이더를 불러왔습니다.",
+ "Providers.status": "상태",
+ "Roles.empty": "아직 역할이 없습니다.",
+ "Roles.empty.search": "검색과 일치하는 역할이 없습니다.",
+ "Settings.roles.deleted": "Role deleted",
+ "Settings.roles.edited": "Role edited",
+ "Settings.section-label": "사용자 & 권한 플러그인",
+ "components.Input.error.validation.email": "유효하지 않은 이메일입니다.",
+ "components.Input.error.validation.json": "JSON 형식과 일치하지 않습니다.",
+ "components.Input.error.validation.max": "값이 너무 큽니다.",
+ "components.Input.error.validation.maxLength": "값이 너무 깁니다.",
+ "components.Input.error.validation.min": "값이 너무 작습니다.",
+ "components.Input.error.validation.minLength": "값이 너무 짧습니다.",
+ "components.Input.error.validation.minSupMax": "이보다 클 수 없습니다.",
+ "components.Input.error.validation.regex": "값이 정규식과 일치하지 않습니다.",
+ "components.Input.error.validation.required": "필수 항목입니다.",
+ "components.Input.error.validation.unique": "이 값은 이미 사용되고 있습니다.",
+ "notification.success.submit": "설정을 업데이트했습니다.",
+ "page.title": "설정 - 역할",
+ "plugin.description.long": "JWT 기반의 인증 프로세스로 API를 보호하세요. 이 플러그인에서 사용자 그룹간 권한을 관리할 수 있는 ACL 전략도 설정할 수 있습니다.",
+ "plugin.description.short": "JWT 기반의 인증 프로세스로 API를 보호하세요.",
+ "plugin.name": "역할(roles) & 권한(permissions)",
+ "popUpWarning.button.cancel": "취소",
+ "popUpWarning.button.confirm": "확인",
+ "popUpWarning.title": "Please confirm",
+ "popUpWarning.warning.cancel": "수정 사항을 취소하시겠습니까?"
+}
diff --git a/packages/strapi/src/extensions/users-permissions/admin/src/translations/ms.json b/packages/strapi/src/extensions/users-permissions/admin/src/translations/ms.json
new file mode 100644
index 0000000..b596fdb
--- /dev/null
+++ b/packages/strapi/src/extensions/users-permissions/admin/src/translations/ms.json
@@ -0,0 +1,45 @@
+{
+ "BoundRoute.title": "Ikat laluan ke",
+ "EditForm.inputSelect.description.role": "Ini akan meletakkan peranan yang dipilih pada pengguna baru.",
+ "EditForm.inputSelect.label.role": "Peranan asal untuk pengguna yang disahkan",
+ "EditForm.inputToggle.description.email": "Tidak membenarkan pengguna membuat beberapa akaun menggunakan alamat e-mel yang sama dengan pembekal pengesahan yang berbeza.",
+ "EditForm.inputToggle.description.email-confirmation": "Apabila diaktifkan (ON), pengguna berdaftar baru akan menerima e-mel pengesahan.",
+ "EditForm.inputToggle.description.email-confirmation-redirection": "Setelah mengesahkan e-mel anda, pilih di mana anda akan di redirect kan.",
+ "EditForm.inputToggle.description.email-reset-password": "URL halaman kata laluan tetapan semula untuk aplikasi anda",
+ "EditForm.inputToggle.description.sign-up": "Apabila dinyahaktifkan (MATI), proses pendaftaran tidak dibenarkan. Tidak ada yang boleh melanggan lagi tidak kira pembekal telah dipakai.",
+ "EditForm.inputToggle.label.email": "Satu akaun setiap alamat e-mel",
+ "EditForm.inputToggle.label.email-confirmation": "Aktifkan pengesahan e-mel",
+ "EditForm.inputToggle.label.email-confirmation-redirection": "Redirection url",
+ "EditForm.inputToggle.label.email-reset-password": "Halaman tetapan semula kata laluan",
+ "EditForm.inputToggle.label.sign-up": "Aktifkan pendaftaran",
+ "HeaderNav.link.advancedSettings": "Tetapan lanjut",
+ "HeaderNav.link.emailTemplates": "Templat e-mel",
+ "HeaderNav.link.providers": "Pembekal",
+ "Plugin.permissions.plugins.description": "Pilih arahan yang dibenarkan untuk plugin {name}.",
+ "Plugins.header.description": "Hanya arahan yang terpasang dengan laluan sahaja yang tersenarai di bawah.",
+ "Plugins.header.title": "Keizinan",
+ "Policies.header.hint": "Pilih tindakan aplikasi atau plugin dan klik pada ikon gear untuk melihat laluan yang terpasang",
+ "Policies.header.title": "Tetapan lanjut",
+ "PopUpForm.Email.email_templates.inputDescription": "Sekiranya anda tidak pasti cara menggunakan pemboleh ubah, {link} ",
+ "PopUpForm.Email.options.from.email.label": "E-mel penghantar",
+ "PopUpForm.Email.options.from.email.placeholder": "kai@doe.com",
+ "PopUpForm.Email.options.from.name.label": "Nama pengirim",
+ "PopUpForm.Email.options.from.name.placeholder": "Kai Doe",
+ "PopUpForm.Email.options.message.label": "Mesej",
+ "PopUpForm.Email.options.object.label": "Subjek",
+ "PopUpForm.Email.options.response_email.label": "E-mel jawapan",
+ "PopUpForm.Email.options.response_email.placeholder": "kai@doe.com",
+ "PopUpForm.Providers.enabled.description": "Sekiranya dinyahaktifkan, pengguna tidak akan dapat menggunakan pembekal ini.",
+ "PopUpForm.Providers.enabled.label": "Aktifkan",
+ "PopUpForm.Providers.key.label": "ID Pelanggan",
+ "PopUpForm.Providers.key.placeholder": "TEKS",
+ "PopUpForm.Providers.redirectURL.front-end.label": "URL pengubah hala ke aplikasi 'front-end' anda",
+ "PopUpForm.Providers.secret.label": "Client Secret",
+ "PopUpForm.Providers.secret.placeholder": "TEKS",
+ "PopUpForm.Providers.subdomain.label": "Host URI (Subdomain)",
+ "PopUpForm.Providers.subdomain.placeholder": "my.subdomain.com",
+ "PopUpForm.header.edit.email-templates": "Edit Templat E-mel",
+ "notification.success.submit": "Tetapan telah dikemas kini",
+ "plugin.description.long": "Lindungi API anda dengan proses pengesahan penuh berdasarkan JWT. Plugin ini juga dilengkapi dengan strategi ACL yang membolehkan anda mengurus pengizinan antara kumpulan pengguna.",
+ "plugin.description.short": "Lindungi API anda dengan proses pengesahan penuh berdasarkan JWT"
+}
diff --git a/packages/strapi/src/extensions/users-permissions/admin/src/translations/nl.json b/packages/strapi/src/extensions/users-permissions/admin/src/translations/nl.json
new file mode 100644
index 0000000..784c262
--- /dev/null
+++ b/packages/strapi/src/extensions/users-permissions/admin/src/translations/nl.json
@@ -0,0 +1,44 @@
+{
+ "BoundRoute.title": "Gebonden route naar",
+ "EditForm.inputSelect.description.role": "Het zal de nieuwe geautoriseerde gebruiker aan de geselecteerde rol verbinden.",
+ "EditForm.inputSelect.label.role": "Standaard rol voor geautoriseerde gebruikers",
+ "EditForm.inputToggle.description.email": "Zorg ervoor dat de gebruiker niet meerdere accounts kan maken met hetzelfde e-mailadres maar met verschillende leveranciers.",
+ "EditForm.inputToggle.description.email-confirmation": "Wanneer ingeschakeld (ON), ontvangen nieuw geregistreerde gebruikers een bevestigingsmail.",
+ "EditForm.inputToggle.description.email-confirmation-redirection": "Na het bevestigen van je e-mail, kies naar waar je doorgestuurd zal worden.",
+ "EditForm.inputToggle.description.sign-up": "Wanneer uitgeschakeld (OFF), is registratie verboden. Niemand kan abonneren ongeacht de leverancier",
+ "EditForm.inputToggle.label.email": "Één account per e-mailadres.",
+ "EditForm.inputToggle.label.email-confirmation": "Schakel emailbevestiging in",
+ "EditForm.inputToggle.label.email-confirmation-redirection": "Doorstuur URL",
+ "EditForm.inputToggle.label.sign-up": "Registratie inschakelen",
+ "HeaderNav.link.advancedSettings": "Geavanceerde instellingen",
+ "HeaderNav.link.emailTemplates": "E-mail sjabloon",
+ "HeaderNav.link.providers": "Leveranciers",
+ "Plugin.permissions.plugins.description": "Voer alle toegestane acties in voor extensie {name}.",
+ "Plugins.header.description": "Alleen acties gekoppeld aan een route worden hieronder weergegeven.",
+ "Plugins.header.title": "Permissies",
+ "Policies.header.hint": "Selecteer de actie van de applicatie of de acties van de extensie en klik op het tandwiel icoontje om de gekoppelde route weer te geven",
+ "Policies.header.title": "Geavanceerde instellingen",
+ "PopUpForm.Email.email_templates.inputDescription": "Als je niet zeker weet hoe je variabelen moet gebruiken, {link}",
+ "PopUpForm.Email.options.from.email.label": "Afzender e-mail",
+ "PopUpForm.Email.options.from.email.placeholder": "kai@doe.com",
+ "PopUpForm.Email.options.from.name.label": "Afzender naam",
+ "PopUpForm.Email.options.from.name.placeholder": "Kai Doe",
+ "PopUpForm.Email.options.message.label": "Bericht",
+ "PopUpForm.Email.options.object.label": "Onderwerp",
+ "PopUpForm.Email.options.response_email.label": "Antwoord e-mail",
+ "PopUpForm.Email.options.response_email.placeholder": "kai@doe.com",
+ "PopUpForm.Providers.enabled.description": "Als deze uitgeschakeld is kunnen gebruikers geen gebruik maken van deze leverancier.",
+ "PopUpForm.Providers.enabled.label": "Inschakelen",
+ "PopUpForm.Providers.key.label": "Client ID",
+ "PopUpForm.Providers.key.placeholder": "TEXT",
+ "PopUpForm.Providers.redirectURL.front-end.label": "De doorstuur URL voor jouw front-end app",
+ "PopUpForm.Providers.secret.label": "Client Secret",
+ "PopUpForm.Providers.secret.placeholder": "TEXT",
+ "PopUpForm.Providers.subdomain.label": "Host URI (Subdomain)",
+ "PopUpForm.Providers.subdomain.placeholder": "my.subdomain.com",
+ "PopUpForm.header.edit.email-templates": "E-mail sjablonen aanpassen",
+ "notification.success.submit": "Instellingen zijn geüpdatet",
+ "plugin.description.long": "Beveilig je API met een volledig authenticatie proces op JWT. Deze extensie komt ook met een ACL strategie welke ervoor zorgt dat je de permissies tussen groepen van gebruikers kan beheren.",
+ "plugin.description.short": "Beveilig je API met een volledig authenticatie proces op JWT",
+ "plugin.name": "Rollen & Permissies"
+}
diff --git a/packages/strapi/src/extensions/users-permissions/admin/src/translations/pl.json b/packages/strapi/src/extensions/users-permissions/admin/src/translations/pl.json
new file mode 100644
index 0000000..945d494
--- /dev/null
+++ b/packages/strapi/src/extensions/users-permissions/admin/src/translations/pl.json
@@ -0,0 +1,82 @@
+{
+ "BoundRoute.title": "Wywoływanie",
+ "EditForm.inputSelect.description.role": "Połączy nowego uwierzytelnionego użytkownika z wybraną rolą.",
+ "EditForm.inputSelect.label.role": "Domyślna rola dla uwierzytelnionych użytkowników",
+ "EditForm.inputToggle.description.email": "Nie zezwalaj użytkownikowi na tworzenie wielu kont za pomocą tego samego adresu e-mail u różnych dostawców uwierzytelniania.",
+ "EditForm.inputToggle.description.email-confirmation": "Gdy włączone (ON), nowo zarejestrowani uzytkownicy otrzymają wiadomość potwierdzającą.",
+ "EditForm.inputToggle.description.email-confirmation-redirection": "Po potwierdzeniu adresu email, wybierz gdzie zostaniesz przekierowany.",
+ "EditForm.inputToggle.description.email-reset-password": "Adres URL strony resetowania hasła aplikacji",
+ "EditForm.inputToggle.description.sign-up": "Po wyłączeniu (OFF) proces rejestracji jest zabroniony. Nikt nie może już dołączyć bez względu na używanego dostawcę.",
+ "EditForm.inputToggle.label.email": "Jedno konto na adres email",
+ "EditForm.inputToggle.label.email-confirmation": "Zezwól na potwierdzenie adresu email",
+ "EditForm.inputToggle.label.email-confirmation-redirection": "Url przekierowania",
+ "EditForm.inputToggle.label.email-reset-password": "Strona resetowania hasła",
+ "EditForm.inputToggle.label.sign-up": "Włącz możliwość rejestracji",
+ "EditForm.inputToggle.placeholder.email-confirmation-redirection": "ex: https://yourfrontend.com/confirmation-redirection",
+ "EditForm.inputToggle.placeholder.email-reset-password": "ex: https://yourfrontend.com/reset-password",
+ "EditPage.form.roles": "Szczegóły roli",
+ "Email.template.data.loaded": "Szablon email został załadowany",
+ "Email.template.email_confirmation": "Potwierdzenie adresu email",
+ "Email.template.form.edit.label": "Edytuj szablon",
+ "Email.template.table.action.label": "akcja",
+ "Email.template.table.icon.label": "ikonka",
+ "Email.template.table.name.label": "nazwa",
+ "Form.advancedSettings.data.loaded": "Ustawienia zaawansowane zostały załadowane",
+ "HeaderNav.link.advancedSettings": "Zaawansowane",
+ "HeaderNav.link.emailTemplates": "Szablony e-mail",
+ "HeaderNav.link.providers": "Dostawcy",
+ "Plugin.permissions.plugins.description": "Określ dozwolone działania dla pluginu {name}.",
+ "Plugins.header.description": "Jedynie akcje związane z wywoływaniami są wymienione poniżej.",
+ "Plugins.header.title": "Uprawnienia",
+ "Policies.header.hint": "Wybierz działania aplikacji lub działania pluginu i kliknij ikonę koła zębatego, aby wyświetlić wywoływania",
+ "Policies.header.title": "Zaawansowane",
+ "PopUpForm.Email.email_templates.inputDescription": "Nie wiesz jak skonfigurować zmienne? {link}",
+ "PopUpForm.Email.link.documentation": "sprawdź dokumentację.",
+ "PopUpForm.Email.options.from.email.label": "Email nadawcy",
+ "PopUpForm.Email.options.from.email.placeholder": "jannowak@gmail.com",
+ "PopUpForm.Email.options.from.name.label": "Nazwa nadawcy",
+ "PopUpForm.Email.options.from.name.placeholder": "Jan Nowak",
+ "PopUpForm.Email.options.message.label": "Wiadomość",
+ "PopUpForm.Email.options.object.label": "Temat",
+ "PopUpForm.Email.options.object.placeholder": "Proszę potwierdź adres email dla %APP_NAME%",
+ "PopUpForm.Email.options.response_email.label": "Email zwrotny",
+ "PopUpForm.Email.options.response_email.placeholder": "jannowak@gmail.com",
+ "PopUpForm.Providers.enabled.description": "W przypadku wyłączenia, użytkownicy nie będą mogli skorzystać z tego dostawcy.",
+ "PopUpForm.Providers.enabled.label": "Włączony",
+ "PopUpForm.Providers.key.label": "ID klienta",
+ "PopUpForm.Providers.key.placeholder": "TEKST",
+ "PopUpForm.Providers.redirectURL.front-end.label": "Adres przekierowania do własnej aplikacji",
+ "PopUpForm.Providers.redirectURL.label": "Adres przekierowania do dodania w twoich ustawieniach aplikacji: {provider}",
+ "PopUpForm.Providers.secret.label": "Klucz sekretny klienta",
+ "PopUpForm.Providers.secret.placeholder": "TEKST",
+ "PopUpForm.Providers.subdomain.label": "Host URI (Subdomain)",
+ "PopUpForm.Providers.subdomain.placeholder": "my.subdomain.com",
+ "PopUpForm.header.edit.email-templates": "Zmień szablony e-mail",
+ "PopUpForm.header.edit.providers": "Edytuj dostawcę",
+ "Providers.data.loaded": "Dostawcy zostali załadowani",
+ "Providers.status": "Status",
+ "Roles.empty": "Nie masz jeszcze żadnych ról.",
+ "Roles.empty.search": "Żadne role nie pasują do wyszukiwania.",
+ "Settings.roles.deleted": "Rola usunięta",
+ "Settings.roles.edited": "Rola edytowana",
+ "Settings.section-label": "Użytkownicy i Uprawnienia",
+ "components.Input.error.validation.email": "Ten email jest niepoprawny",
+ "components.Input.error.validation.json": "Nie pasuje do formatu JSON",
+ "components.Input.error.validation.max": "Wartość zbyt duża.",
+ "components.Input.error.validation.maxLength": "Wartość zbyt długa.",
+ "components.Input.error.validation.min": "Wartość zbyt mała.",
+ "components.Input.error.validation.minLength": "Wartość zbyt krótka.",
+ "components.Input.error.validation.minSupMax": "Nie może być wyższy",
+ "components.Input.error.validation.regex": "Wartość nie pasuje do regexa.",
+ "components.Input.error.validation.required": "Wartość wymagana.",
+ "components.Input.error.validation.unique": "Wartość już używana.",
+ "notification.success.submit": "Ustawienia zostały zaktualizowane",
+ "page.title": "Ustawienia - Role",
+ "plugin.description.long": "Chroń API za pomocą procesu pełnego uwierzytelniania opartego na JWT. Ten plugin zawiera również strategię ACL, która pozwala zarządzać uprawnieniami między grupami użytkowników.",
+ "plugin.description.short": "Chroń API za pomocą procesu pełnego uwierzytelniania opartego na JWT",
+ "plugin.name": "Role i Uprawnienia",
+ "popUpWarning.button.cancel": "Anuluj",
+ "popUpWarning.button.confirm": "Potwierdź",
+ "popUpWarning.title": "Proszę potwierdź",
+ "popUpWarning.warning.cancel": "Czy jesteś pewny, że chcesz anulować zmiany?"
+}
diff --git a/packages/strapi/src/extensions/users-permissions/admin/src/translations/pt-BR.json b/packages/strapi/src/extensions/users-permissions/admin/src/translations/pt-BR.json
new file mode 100644
index 0000000..b6ee10f
--- /dev/null
+++ b/packages/strapi/src/extensions/users-permissions/admin/src/translations/pt-BR.json
@@ -0,0 +1,40 @@
+{
+ "BoundRoute.title": "Rota definida para",
+ "EditForm.inputSelect.description.role": "Ele anexará o novo usuário autenticado ao nível selecionado.",
+ "EditForm.inputSelect.label.role": "Nível padrão para usuários autenticados",
+ "EditForm.inputToggle.description.email": "Não permitir que o usuário crie várias contas usando o mesmo endereço de e-mail com diferentes provedores de autenticação.",
+ "EditForm.inputToggle.description.sign-up": "Quando desativado (OFF), o processo de registro é proibido. Nenhum novo usuário poderá se registrar, não importa o provedor usado.",
+ "EditForm.inputToggle.label.email": "Limitar 1 conta por endereço de email",
+ "EditForm.inputToggle.label.sign-up": "Ativar registro de usuários",
+ "HeaderNav.link.advancedSettings": "Configurações avançadas",
+ "HeaderNav.link.emailTemplates": "Modelos de email",
+ "HeaderNav.link.providers": "Provedores",
+ "Plugin.permissions.plugins.description": "Defina todas as ações permitidas para o plugin {name}.",
+ "Plugins.header.description": "Somente ações vinculadas por uma rota estão listadas abaixo.",
+ "Plugins.header.title": "Permissões",
+ "Policies.header.hint": "Selecione as ações do aplicativo ou as ações do plugin e clique no ícone do cog para exibir a rota",
+ "Policies.header.title": "Configurações avançadas",
+ "PopUpForm.Email.email_templates.inputDescription": "Se não tiver certeza de como usar variáveis, {link}",
+ "PopUpForm.Email.options.from.email.label": "Email do remetente",
+ "PopUpForm.Email.options.from.email.placeholder": "kai@doe.com",
+ "PopUpForm.Email.options.from.name.label": "Nome do remetente",
+ "PopUpForm.Email.options.from.name.placeholder": "Kai Doe",
+ "PopUpForm.Email.options.message.label": "Mensagem",
+ "PopUpForm.Email.options.object.label": "Assunto",
+ "PopUpForm.Email.options.response_email.label": "Email de resposta",
+ "PopUpForm.Email.options.response_email.placeholder": "kai@doe.com",
+ "PopUpForm.Providers.enabled.description": "Se desativado, os usuários não poderão usar este provedor",
+ "PopUpForm.Providers.enabled.label": "Ativar",
+ "PopUpForm.Providers.key.label": "ID do cliente",
+ "PopUpForm.Providers.key.placeholder": "TEXT",
+ "PopUpForm.Providers.redirectURL.front-end.label": "O URL de redirecionamento para seu aplicativo front-end",
+ "PopUpForm.Providers.secret.label": "Segredo do Cliente",
+ "PopUpForm.Providers.secret.placeholder": "TEXT",
+ "PopUpForm.Providers.subdomain.label": "Host URI (Subdomain)",
+ "PopUpForm.Providers.subdomain.placeholder": "my.subdomain.com",
+ "PopUpForm.header.edit.email-templates": "Editar modelos de email",
+ "notification.success.submit": "As configurações foram atualizadas",
+ "plugin.description.long": "Proteja sua API com um processo de autenticação completo baseado no JWT. Esse plugin também vem com uma estratégia de ACL que permite gerenciar as permissões entre os grupos de usuários.",
+ "plugin.description.short": "Proteja sua API com um processo de autenticação completo baseado no JWT",
+ "plugin.name": "Papéis e permissões"
+}
diff --git a/packages/strapi/src/extensions/users-permissions/admin/src/translations/pt.json b/packages/strapi/src/extensions/users-permissions/admin/src/translations/pt.json
new file mode 100644
index 0000000..a2d2d4b
--- /dev/null
+++ b/packages/strapi/src/extensions/users-permissions/admin/src/translations/pt.json
@@ -0,0 +1,44 @@
+{
+ "BoundRoute.title": "Ligar rota a",
+ "EditForm.inputSelect.description.role": "Vai atribuir o grupo selecionado ao novo utilizador autenticado.",
+ "EditForm.inputSelect.label.role": "Grupo por defeito para utilizadores autenticados",
+ "EditForm.inputToggle.description.email": "Proibir a criação de múltiplas contas com o mesmo email por serviços de autenticação diferentes.",
+ "EditForm.inputToggle.description.email-confirmation": "Quando ativado (ON), os novos utilizadores recebem um email de confirmação.",
+ "EditForm.inputToggle.description.email-confirmation-redirection": "Após confirmar o seu email, escolha para onde vai ser redirecionado.",
+ "EditForm.inputToggle.description.sign-up": "Quando desativado (OFF), o processo de registo está proibido. Ninguém se consegue registar mais, independentemente do serviço de authenticação.",
+ "EditForm.inputToggle.label.email": "Uma conta por endereço de email",
+ "EditForm.inputToggle.label.email-confirmation": "Ativar email de confirmação",
+ "EditForm.inputToggle.label.email-confirmation-redirection": "Endereço de redirecionamento (URL)",
+ "EditForm.inputToggle.label.sign-up": "Ativar registos",
+ "HeaderNav.link.advancedSettings": "Configurações avançadas",
+ "HeaderNav.link.emailTemplates": "Modelos de email",
+ "HeaderNav.link.providers": "Serviços de autenticação",
+ "Plugin.permissions.plugins.description": "Defina todas as ações permitidas para o plugin {name}.",
+ "Plugins.header.description": "Todas as ações associadas a uma rota estão listadas abaixo.",
+ "Plugins.header.title": "Permissões",
+ "Policies.header.hint": "Selecione as ações da aplicação ou dos plugins e clique no ícone para mostrar as rotas associadas",
+ "Policies.header.title": "Configurações avançadas",
+ "PopUpForm.Email.email_templates.inputDescription": "Se não tem a certeza de como usar as variáveis, {link}",
+ "PopUpForm.Email.options.from.email.label": "Shipper email",
+ "PopUpForm.Email.options.from.email.placeholder": "kai@doe.com",
+ "PopUpForm.Email.options.from.name.label": "Shipper name",
+ "PopUpForm.Email.options.from.name.placeholder": "Kai Doe",
+ "PopUpForm.Email.options.message.label": "Mensagem",
+ "PopUpForm.Email.options.object.label": "Assunto",
+ "PopUpForm.Email.options.response_email.label": "Email de resposta",
+ "PopUpForm.Email.options.response_email.placeholder": "kai@doe.com",
+ "PopUpForm.Providers.enabled.description": "Se desativado, os utilizadores não conseguirão utilizar este serviço de autenticação.",
+ "PopUpForm.Providers.enabled.label": "Ativar",
+ "PopUpForm.Providers.key.label": "ID de Client",
+ "PopUpForm.Providers.key.placeholder": "TEXTO",
+ "PopUpForm.Providers.redirectURL.front-end.label": "Endereço de redirecionamento para a sua aplicação de front-end",
+ "PopUpForm.Providers.secret.label": "Segredo de cliente",
+ "PopUpForm.Providers.secret.placeholder": "TEXTO",
+ "PopUpForm.Providers.subdomain.label": "Host URI (Subdomain)",
+ "PopUpForm.Providers.subdomain.placeholder": "my.subdomain.com",
+ "PopUpForm.header.edit.email-templates": "Editar Modelos de Email",
+ "notification.success.submit": "As configurações foram atualizadas",
+ "plugin.description.long": "Proteja a sua API com um processo completo de autenticação baseado em JWT. Este plugin também vem com estratégia de ACL que permite gerir permissões entre grupos de utilizadores.",
+ "plugin.description.short": "Proteja a sua API com um processo completo de autenticação baseado em JWT",
+ "plugin.name": "Grupos & Permissões"
+}
diff --git a/packages/strapi/src/extensions/users-permissions/admin/src/translations/ru.json b/packages/strapi/src/extensions/users-permissions/admin/src/translations/ru.json
new file mode 100644
index 0000000..b0e5787
--- /dev/null
+++ b/packages/strapi/src/extensions/users-permissions/admin/src/translations/ru.json
@@ -0,0 +1,82 @@
+{
+ "BoundRoute.title": "Связать путь с",
+ "EditForm.inputSelect.description.role": "При регистрации пользователи будут иметь выбранную роль.",
+ "EditForm.inputSelect.label.role": "Роль по умолчанию для новых пользователей",
+ "EditForm.inputToggle.description.email": "Запретить пользователю создавать несколько учётных записей, используя один и тот же адрес электронной почты, у разных поставщиков аутентификации.",
+ "EditForm.inputToggle.description.email-confirmation": "Если включено (ON), при регистрации пользователи будут получать письмо для подтверждения адреса электронной почты.",
+ "EditForm.inputToggle.description.email-confirmation-redirection": "Укажите URL-адрес для перенаправления пользователей после подтверждения адреса электронной почты.",
+ "EditForm.inputToggle.description.email-reset-password": "URL-адрес страницы для сброса пароля учётной записи пользователя",
+ "EditForm.inputToggle.description.sign-up": "Если выключено (OFF), процесс регистрации пользователей запрещен. Никто не может зарегистрироваться, независимо от провайдера.",
+ "EditForm.inputToggle.label.email": "Одна учётная запись на один адрес электронной почты",
+ "EditForm.inputToggle.label.email-confirmation": "Включить подтверждение по электронной почте",
+ "EditForm.inputToggle.label.email-confirmation-redirection": "URL-адрес для перенаправления",
+ "EditForm.inputToggle.label.email-reset-password": "Страница сброса пароля",
+ "EditForm.inputToggle.label.sign-up": "Включить регистрации",
+ "EditForm.inputToggle.placeholder.email-confirmation-redirection": "например: https://yourfrontend.com/email-confirmation-redirection",
+ "EditForm.inputToggle.placeholder.email-reset-password": "например: https://yourfrontend.com/reset-password",
+ "EditPage.form.roles": "Сведения о роли",
+ "Email.template.data.loaded": "Шаблоны автоматических писем для электронной почты были загружены",
+ "Email.template.email_confirmation": "Адреса электронной почты с письмом о подтверждении",
+ "Email.template.form.edit.label": "Редактировать шаблон",
+ "Email.template.table.action.label": "действие",
+ "Email.template.table.icon.label": "иконка",
+ "Email.template.table.name.label": "название",
+ "Form.advancedSettings.data.loaded": "Данные расширенных настроек были загружены",
+ "HeaderNav.link.advancedSettings": "Расширенные настройки",
+ "HeaderNav.link.emailTemplates": "Шаблоны писем",
+ "HeaderNav.link.providers": "Провайдеры",
+ "Plugin.permissions.plugins.description": "Определите все разрешенные действия для плагина {name}.",
+ "Plugins.header.description": "Ниже перечислены только действия, связанные с путём.",
+ "Plugins.header.title": "Разрешения",
+ "Policies.header.hint": "Выберите действия приложения или плагина и нажмите на значок шестерёнки, чтобы отобразить связанный путь",
+ "Policies.header.title": "Расширенные настройки",
+ "PopUpForm.Email.email_templates.inputDescription": "Если вы не уверены, как использовать переменные — {link}",
+ "PopUpForm.Email.link.documentation": "ознакомьтесь с нашей документацией.",
+ "PopUpForm.Email.options.from.email.label": "Электронная почта отправителя",
+ "PopUpForm.Email.options.from.email.placeholder": "kai@doe.com",
+ "PopUpForm.Email.options.from.name.label": "Имя отправителя",
+ "PopUpForm.Email.options.from.name.placeholder": "Kai Doe",
+ "PopUpForm.Email.options.message.label": "Сообщение",
+ "PopUpForm.Email.options.object.label": "Тема",
+ "PopUpForm.Email.options.object.placeholder": "Пожалуйста, подтвердите свой адрес электронной почты для %APP_NAME%",
+ "PopUpForm.Email.options.response_email.label": "Электронная почта для ответов",
+ "PopUpForm.Email.options.response_email.placeholder": "paul@example.com",
+ "PopUpForm.Providers.enabled.description": "Если этот параметр отключен, пользователи не смогут использовать этого поставщика.",
+ "PopUpForm.Providers.enabled.label": "Включено",
+ "PopUpForm.Providers.key.label": "ID клиента",
+ "PopUpForm.Providers.key.placeholder": "TEXT",
+ "PopUpForm.Providers.redirectURL.front-end.label": "URL-адрес перенаправления на ваше приложение",
+ "PopUpForm.Providers.redirectURL.label": "URL-адрес перенаправления, который нужно добавить в {provider} конфигурации приложения",
+ "PopUpForm.Providers.secret.label": "Client Secret",
+ "PopUpForm.Providers.secret.placeholder": "TEXT",
+ "PopUpForm.Providers.subdomain.label": "Хост URI (Поддомен)",
+ "PopUpForm.Providers.subdomain.placeholder": "my.subdomain.com",
+ "PopUpForm.header.edit.email-templates": "Редактировать шаблон письма",
+ "PopUpForm.header.edit.providers": "Редактировать провайдера",
+ "Providers.data.loaded": "Провайдеры были загружены",
+ "Providers.status": "Статус",
+ "Roles.empty": "У вас пока нет никаких ролей.",
+ "Roles.empty.search": "Ни одна роль не соответствует поисковому запросу.",
+ "Settings.roles.deleted": "Роль удалена",
+ "Settings.roles.edited": "Роль отредактирована",
+ "Settings.section-label": "Плагин «Пользователи и Разрешения»",
+ "components.Input.error.validation.email": "Неверный адрес электронной почты",
+ "components.Input.error.validation.json": "Это не соответствует формату JSON",
+ "components.Input.error.validation.max": "Значение слишком велико.",
+ "components.Input.error.validation.maxLength": "Значение слишком длинное.",
+ "components.Input.error.validation.min": "Значение слишком мало.",
+ "components.Input.error.validation.minLength": "Значение слишком короткое.",
+ "components.Input.error.validation.minSupMax": "Не может быть выше",
+ "components.Input.error.validation.regex": "Значение не соответствует регулярному выражению.",
+ "components.Input.error.validation.required": "Это значение является обязательным.",
+ "components.Input.error.validation.unique": "Это значение уже используется.",
+ "notification.success.submit": "Настройки были обновлены",
+ "page.title": "Настройки — Роли",
+ "plugin.description.long": "Защитите свой API с помощью полноценного процесса аутентификации, основанного на JWT. Этот плагин также имеет настройки стратегии ACL, которые позволяют вам управлять разрешениями между группами пользователей.",
+ "plugin.description.short": "Защитите свой API с помощью полноценного процесса аутентификации, основанного на JWT.",
+ "plugin.name": "Пользователи и Разрешения",
+ "popUpWarning.button.cancel": "Отменить",
+ "popUpWarning.button.confirm": "Подтвердить",
+ "popUpWarning.title": "Пожалуйста подтвердите",
+ "popUpWarning.warning.cancel": "Вы уверены, что хотите отменить свои изменения?"
+}
diff --git a/packages/strapi/src/extensions/users-permissions/admin/src/translations/sk.json b/packages/strapi/src/extensions/users-permissions/admin/src/translations/sk.json
new file mode 100644
index 0000000..ca70fe4
--- /dev/null
+++ b/packages/strapi/src/extensions/users-permissions/admin/src/translations/sk.json
@@ -0,0 +1,46 @@
+{
+ "BoundRoute.title": "URL endpoint naviazaný k",
+ "EditForm.inputSelect.description.role": "Pridá rolu k používateľovi.",
+ "EditForm.inputSelect.label.role": "Predvolená rola pre autorizovaných používateľov",
+ "EditForm.inputToggle.description.email": "Zakázať používateľovi vytvoriť viac účtov s rovnakou e-mailovou adresou pre rôznych poskytovateľov.",
+ "EditForm.inputToggle.description.email-confirmation": "Ak je povolené (ON), registrovaní používatelia dostanú potvrdzovací e-mail.",
+ "EditForm.inputToggle.description.email-confirmation-redirection": "URL na ktorú bude používateľ presmerovaný po potvrdení e-mailu.",
+ "EditForm.inputToggle.description.email-reset-password": "URL pre nastavenie nového hesla",
+ "EditForm.inputToggle.description.sign-up": "Ak je zakázané (OFF), registrácie nebudú povolené. Nikto sa nebude môcť registrovať bez ohľadu na zvoleného poskytovateľa.",
+ "EditForm.inputToggle.label.email": "Iba jedno konto pre jednu e-mailovú adresu",
+ "EditForm.inputToggle.label.email-confirmation": "Povoliť potvrdzovanie e-mailových adries",
+ "EditForm.inputToggle.label.email-confirmation-redirection": "URL pre potvrdenie e-mailovej adresy",
+ "EditForm.inputToggle.label.email-reset-password": "URL pre obnovu hesla",
+ "EditForm.inputToggle.label.sign-up": "Povoliť registrácie",
+ "HeaderNav.link.advancedSettings": "Pokročilé nastavenia",
+ "HeaderNav.link.emailTemplates": "Šablóny emailov",
+ "HeaderNav.link.providers": "Poskytovatelia",
+ "Plugin.permissions.plugins.description": "Zvoľte akcie, ktoré majú byť povolené pre plugin {name}.",
+ "Plugins.header.description": "Zobrazujú sa iba akcie naviazané na URL endpoint.",
+ "Plugins.header.title": "Oprávnenia",
+ "Policies.header.hint": "Vyberte akciu a kliknite na ikonku nastavení pre zobrazenie naviazanej URL",
+ "Policies.header.title": "Pokročilé nastavenia",
+ "PopUpForm.Email.email_templates.inputDescription": "Ak si nie ste istý ako používať premenné, {link}",
+ "PopUpForm.Email.options.from.email.label": "E-mail odosielateľa",
+ "PopUpForm.Email.options.from.email.placeholder": "janko.hrasko@gmail.com",
+ "PopUpForm.Email.options.from.name.label": "Meno odosielateľa",
+ "PopUpForm.Email.options.from.name.placeholder": "Janko Hraško",
+ "PopUpForm.Email.options.message.label": "Obsah e-mailu",
+ "PopUpForm.Email.options.object.label": "Predmet",
+ "PopUpForm.Email.options.response_email.label": "Odpovedať na e-mail",
+ "PopUpForm.Email.options.response_email.placeholder": "janko.hrasko@gmail.com",
+ "PopUpForm.Providers.enabled.description": "Ak je zakázané, používatelia nebudú môcť použiť tohto poskytovateľa.",
+ "PopUpForm.Providers.enabled.label": "Povoliť",
+ "PopUpForm.Providers.key.label": "Client ID",
+ "PopUpForm.Providers.key.placeholder": "TEXT",
+ "PopUpForm.Providers.redirectURL.front-end.label": "URL presmerovania do vašej aplikácie",
+ "PopUpForm.Providers.secret.label": "Client Secret",
+ "PopUpForm.Providers.secret.placeholder": "TEXT",
+ "PopUpForm.Providers.subdomain.label": "Host URI (Subdomain)",
+ "PopUpForm.Providers.subdomain.placeholder": "my.subdomain.com",
+ "PopUpForm.header.edit.email-templates": "Upraviť šablóny e-mailov",
+ "notification.success.submit": "Nastavenia boli uložené",
+ "plugin.description.long": "Zabezpečte vaše API pomocou JWT tokenov. Tento plugin taktiež podporuje ACL záznamy, ktoré umožňujú spravovať oprávnenia v rámci skupín používateľov.",
+ "plugin.description.short": "Zabezpečte vaše API pomocou JWT tokenov",
+ "plugin.name": "Roly a oprávnenia"
+}
diff --git a/packages/strapi/src/extensions/users-permissions/admin/src/translations/sv.json b/packages/strapi/src/extensions/users-permissions/admin/src/translations/sv.json
new file mode 100644
index 0000000..285c935
--- /dev/null
+++ b/packages/strapi/src/extensions/users-permissions/admin/src/translations/sv.json
@@ -0,0 +1,82 @@
+{
+ "BoundRoute.title": "Bind rutt till",
+ "EditForm.inputSelect.description.role": "Den bifogar den nya autentiserade användaren till den valda rollen.",
+ "EditForm.inputSelect.label.role": "Standardroll för autentiserade användare",
+ "EditForm.inputToggle.description.email": "Tillåt ej användaren att skapa flera konton med samma e-postadress med olika autentiseringstjänster.",
+ "EditForm.inputToggle.description.email-confirmation": "När aktiverat (PÅ) får nya registrerade användare ett bekräftelsemeddelande.",
+ "EditForm.inputToggle.description.email-confirmation-redirection": "När du har bekräftat din e-post väljer du var du ska omdirigeras.",
+ "EditForm.inputToggle.description.email-reset-password": "URL:en till din applikations sida för återställning av lösenord",
+ "EditForm.inputToggle.description.sign-up": "När inaktiverad (AV) är registreringsprocessen förbjuden. Ingen kan prenumerera längre oavsett vilken autentiseringstjänst som används.",
+ "EditForm.inputToggle.label.email": "Ett konto per e-postadress",
+ "EditForm.inputToggle.label.email-confirmation": "Aktivera e-postbekräftelse",
+ "EditForm.inputToggle.label.email-confirmation-redirection": "Omdirigerings-url",
+ "EditForm.inputToggle.label.email-reset-password": "Återställ lösenordssidan",
+ "EditForm.inputToggle.label.sign-up": "Tillåt registreringar",
+ "EditForm.inputToggle.placeholder.email-confirmation-redirection": "t.ex: https://yourfrontend.com/email-confirmation-redirection",
+ "EditForm.inputToggle.placeholder.email-reset-password": "t.ex: https://yourfrontend.com/reset-password",
+ "EditPage.form.roles": "Rolldetaljer",
+ "Email.template.data.loaded": "E-postmallar har laddats",
+ "Email.template.email_confirmation": "Bekräftelse av e-postadress",
+ "Email.template.form.edit.label": "Redigera en mall",
+ "Email.template.table.action.label": "händelse",
+ "Email.template.table.icon.label": "ikon",
+ "Email.template.table.name.label": "namn",
+ "Form.advancedSettings.data.loaded": "Data för avancerade inställningar har laddats",
+ "HeaderNav.link.advancedSettings": "Avancerade inställningar",
+ "HeaderNav.link.emailTemplates": "E-postmall",
+ "HeaderNav.link.providers": "Autentiseringstjänster",
+ "Plugin.permissions.plugins.description": "Definiera alla tillåtna åtgärder för {name} plugin.",
+ "Plugins.header.description": "Endast åtgärder som är bundna av en rutt listas nedan.",
+ "Plugins.header.title": "Behörigheter",
+ "Policies.header.hint": "Välj programmets åtgärder eller plugins åtgärder och klicka på kugghjulsikonen för att visa den bundna rutten",
+ "Policies.header.title": "Avancerade inställningar",
+ "PopUpForm.Email.email_templates.inputDescription": "Om du är osäker på hur du använder variabler, {link}",
+ "PopUpForm.Email.link.documentation": "Kolla in vår dokumentation.",
+ "PopUpForm.Email.options.from.email.label": "Avsändarens e-postadress",
+ "PopUpForm.Email.options.from.email.placeholder": "kai@doe.com",
+ "PopUpForm.Email.options.from.name.label": "Avsändarens namn",
+ "PopUpForm.Email.options.from.name.placeholder": "Kai Doe",
+ "PopUpForm.Email.options.message.label": "Meddelande",
+ "PopUpForm.Email.options.object.label": "Ämne",
+ "PopUpForm.Email.options.object.placeholder": "Bekräfta din e-postadress för %APP_NAME%",
+ "PopUpForm.Email.options.response_email.label": "Svarsmail",
+ "PopUpForm.Email.options.response_email.placeholder": "kai@doe.com",
+ "PopUpForm.Providers.enabled.description": "Om inaktiverat kan användarna inte använda den här tjänsten.",
+ "PopUpForm.Providers.enabled.label": "Tillåt",
+ "PopUpForm.Providers.key.label": "Klient ID",
+ "PopUpForm.Providers.key.placeholder": "TEXT",
+ "PopUpForm.Providers.redirectURL.front-end.label": "Omdirigerings-URL: en till din front-end-app",
+ "PopUpForm.Providers.redirectURL.label": "Webbadressen för omdirigering som ska läggas till i {Provider} applikationskonfigurationer",
+ "PopUpForm.Providers.secret.label": "Klient hemlighet",
+ "PopUpForm.Providers.secret.placeholder": "TEXT",
+ "PopUpForm.Providers.subdomain.label": "Host URI (Subdomän)",
+ "PopUpForm.Providers.subdomain.placeholder": "min.subdoman.com",
+ "PopUpForm.header.edit.email-templates": "Redigera e-postmallar",
+ "PopUpForm.header.edit.providers": "Redigera tjänst",
+ "Providers.data.loaded": "Tjänster har laddats in",
+ "Providers.status": "Status",
+ "Roles.empty": "Du har inga roller än.",
+ "Roles.empty.search": "Inga roller matchar sökningen.",
+ "Settings.roles.deleted": "Roll borttagen",
+ "Settings.roles.edited": "Roll redigerad",
+ "Settings.section-label": "Roller och behörigheter",
+ "components.Input.error.validation.email": "E-postadressen är ogiltig",
+ "components.Input.error.validation.json": "Detta är inte giltig JSON",
+ "components.Input.error.validation.max": "Värdet är för högt.",
+ "components.Input.error.validation.maxLength": "Värdet är för långt.",
+ "components.Input.error.validation.min": "Värdet är för lågt.",
+ "components.Input.error.validation.minLength": "Värdet är för kort.",
+ "components.Input.error.validation.minSupMax": "Minsta värdet är större än maximalt värde.",
+ "components.Input.error.validation.regex": "Värdet matchar inte regex-mönstret.",
+ "components.Input.error.validation.required": "Värdet är obligatoriskt.",
+ "components.Input.error.validation.unique": "Detta värdet är redan använt.",
+ "notification.success.submit": "Inställningar har uppdaterats",
+ "page.title": "Inställningar - Roller",
+ "plugin.description.long": "Skydda ditt API med en fullständig autentiseringsprocess baserad på JWT. Detta plugin har också en ACL-strategi som låter dig hantera behörigheterna mellan användargrupperna.",
+ "plugin.description.short": "Skydda ditt API med en fullständig autentiseringsprocess baserad på JWT",
+ "plugin.name": "Roller och behörigheter",
+ "popUpWarning.button.cancel": "Avbryt",
+ "popUpWarning.button.confirm": "Bekräfta",
+ "popUpWarning.title": "Var god bekräfta",
+ "popUpWarning.warning.cancel": "Är du säker att du vill avbryta dina ändringar?"
+}
diff --git a/packages/strapi/src/extensions/users-permissions/admin/src/translations/th.json b/packages/strapi/src/extensions/users-permissions/admin/src/translations/th.json
new file mode 100644
index 0000000..f457d86
--- /dev/null
+++ b/packages/strapi/src/extensions/users-permissions/admin/src/translations/th.json
@@ -0,0 +1,56 @@
+{
+ "BoundRoute.title": "กำหนดเส้นทางไปยัง",
+ "EditForm.inputSelect.description.role": "แนบผู้ใช้ที่พิสูจน์ตัวตนใหม่ไปยังบทบาทที่เลือก",
+ "EditForm.inputSelect.label.role": "บทบาทพื้นฐานสำหรับผู้ใช้ที่พิสูจน์ตัวตน",
+ "EditForm.inputToggle.description.email": "ไม่อนุญาตให้ผู้ใช้สร้างหลายแอคเคาต์ โดยใช้อีเมลเดียวกันกับผู้ให้บริการการพิสูจน์ตัวตนที่ต่างกัน",
+ "EditForm.inputToggle.description.email-confirmation": "เมื่อเปิดใช้งาน (เปิด) ผู้ใช้สีแดงที่ลงทะเบียนใหม่จะได้รับอีเมลยืนยัน",
+ "EditForm.inputToggle.description.email-confirmation-redirection": "หลังจากยืนยันอีเมลของคุณแล้ว, ให้เลือกตำแหน่งที่คุณจะเปลี่ยนทิศทาง",
+ "EditForm.inputToggle.description.email-reset-password": "URL ของเพจรีเซ็ตรหัสผ่านแอปพลิเคชันของคุณ",
+ "EditForm.inputToggle.description.sign-up": "เมื่อปิดใช้งาน (OFF) กระบวนการลงทะเบียนจะถูกห้าม ไม่มีใครสามารถสมัครสมาชิกได้อีกต่อไปไม่ว่าจะเป็นผู้ให้บริการที่ใช้",
+ "EditForm.inputToggle.label.email": "หนึ่งแอคเคาต์ต่ออีเมลแอดเดรส",
+ "EditForm.inputToggle.label.email-confirmation": "เปิดใช้งานการยืนยันอีเมล",
+ "EditForm.inputToggle.label.email-confirmation-redirection": "Url การเปลี่ยนทิศทาง",
+ "EditForm.inputToggle.label.email-reset-password": "หน้ารีเซ็ตรหัสผ่าน",
+ "EditForm.inputToggle.label.sign-up": "เปิดใช้งานการลงทะเบียน",
+ "Email.template.email_confirmation": "ยืนยันอีเมลแอดเดรส",
+ "HeaderNav.link.advancedSettings": "การตั้งค่าขั้นสูง",
+ "HeaderNav.link.emailTemplates": "เท็มเพลตอีเมล",
+ "HeaderNav.link.providers": "ผู้ให้บริการ",
+ "Plugin.permissions.plugins.description": "กำหนดการดำเนินการที่อนุญาตทั้งหมดสำหรับปลั๊กอิน {name}",
+ "Plugins.header.description": "เฉพาะการดำเนินการที่โยงโดยเราต์จะถูกแสดงด้านล่าง",
+ "Plugins.header.title": "สิทธิการใช้งาน",
+ "Policies.header.hint": "เลือกแอ็คชันของแอปพลิเคชันหรือแอ็คชันของปลั๊กอินและคลิกบนไอคอนฟันเฟือง เพื่อแสดงเส้นทางที่โยงไว้",
+ "Policies.header.title": "การตั้งค่าขั้นสูง",
+ "PopUpForm.Email.email_templates.inputDescription": "ถ้าคุณไม่แน่ใจว่าจะใช้ตัวแปรอย่างไร {link}",
+ "PopUpForm.Email.link.documentation": "ดูเอกสารของเราสิ",
+ "PopUpForm.Email.options.from.email.label": "อีเมล Shipper",
+ "PopUpForm.Email.options.from.email.placeholder": "kai@doe.com",
+ "PopUpForm.Email.options.from.name.label": "ชื่อ Shipper",
+ "PopUpForm.Email.options.from.name.placeholder": "Kai Doe",
+ "PopUpForm.Email.options.message.label": "ข้อความ",
+ "PopUpForm.Email.options.object.label": "เรื่อง",
+ "PopUpForm.Email.options.object.placeholder": "โปรดยืนยันอีเมลแอดเดรสของคุณสำหรับ % APP _ NAME %",
+ "PopUpForm.Email.options.response_email.label": "อีเมลตอบกลับ",
+ "PopUpForm.Email.options.response_email.placeholder": "kai@doe.com",
+ "PopUpForm.Providers.enabled.description": "ถ้าปิดใช้งาน, ผู้ใช้จะไม่สามารถใช้ผู้ให้บริการนี้ได้",
+ "PopUpForm.Providers.enabled.label": "เปิดใช้งาน",
+ "PopUpForm.Providers.key.label": "ID ไคลเอ็นต์",
+ "PopUpForm.Providers.key.placeholder": "ข้อความ",
+ "PopUpForm.Providers.redirectURL.front-end.label": "เปลี่ยนทิศทาง URL ไปยังแอป front-end ของคุณ",
+ "PopUpForm.Providers.redirectURL.label": "เปลี่ยนทิศทาง URL เพื่อเพิ่มในตั้งค่าแอปพลิเคชัน {provider} ของคุณ",
+ "PopUpForm.Providers.secret.label": "Secret ไคลเอ็นต์",
+ "PopUpForm.Providers.secret.placeholder": "ข้อความ",
+ "PopUpForm.header.edit.email-templates": "แก้ไขเทมเพลตอีเมล",
+ "PopUpForm.header.edit.providers": "แก้ไขผู้ให้บริการ",
+ "Settings.roles.deleted": "ลบบทบาทแล้ว",
+ "Settings.roles.edited": "บทบาทที่แก้ไข",
+ "Settings.section-label": "ปลั๊กอินผู้ใช้ & สิทธิ",
+ "notification.success.submit": "อัปเดตการตั้งค่าแล้ว",
+ "plugin.description.long": "ป้องกัน API ของคุณด้วยกระบวนการพิสูจน์ตัวตนแบบสมบูรณ์โดยอิงจาก JWT ปลั๊กอินนี้มาพร้อมกับกลยุทธ์ ACL ที่อนุญาตให้คุณจัดการกับสิทธิระหว่างกลุ่มของผู้ใช้ได้ด้วย",
+ "plugin.description.short": "ปกป้อง API ของคุณที่มีกระบวนการพิสูจน์ตัวตนแบบสมบูรณ์โดยอิงจาก JWT",
+ "plugin.name": "ปลั๊กอิน ผู้ใช้ & การอนุญาต",
+ "popUpWarning.button.cancel": "ยกเลิก",
+ "popUpWarning.button.confirm": "ยืนยัน",
+ "popUpWarning.title": "โปรดยืนยัน",
+ "popUpWarning.warning.cancel": "คุณแน่ใจว่าต้องการยกเลิกการแก้ไขของคุณหรือไม่?"
+}
diff --git a/packages/strapi/src/extensions/users-permissions/admin/src/translations/tr.json b/packages/strapi/src/extensions/users-permissions/admin/src/translations/tr.json
new file mode 100644
index 0000000..76a2331
--- /dev/null
+++ b/packages/strapi/src/extensions/users-permissions/admin/src/translations/tr.json
@@ -0,0 +1,81 @@
+{
+ "BoundRoute.title": "Bağlı rota",
+ "EditForm.inputSelect.description.role": "Yeni kimliği doğrulanmış kullanıcıyı seçilen rolü ekler.",
+ "EditForm.inputSelect.label.role": "Kimliği doğrulanmış kullanıcılar için varsayılan rol",
+ "EditForm.inputToggle.description.email": "Kullanıcıyı, farklı kimlik doğrulama sağlayıcılarıyla aynı e-posta adresini kullanarak birden fazla hesap oluşturmasına izin vermeyin.",
+ "EditForm.inputToggle.description.email-confirmation": "Etkinleştirildiğinde yeni kayıtlı kullanıcılar bir onay e-postası alır.",
+ "EditForm.inputToggle.description.email-confirmation-redirection": "E-postanızı onayladıktan sonra, yönlendirileceğiniz yeri seçin.",
+ "EditForm.inputToggle.description.sign-up": "Devre dışı bırakıldığında (KAPALI), kayıt işlemi yasaktır. Artık kullanılan sağlayıcı ne olursa olsun hiç kimse abone olamaz.",
+ "EditForm.inputToggle.label.email": "E-posta adresi başına bir hesap",
+ "EditForm.inputToggle.label.email-confirmation": "E-posta onayını etkinleştir",
+ "EditForm.inputToggle.label.email-confirmation-redirection": "Yönlendirme URL'si",
+ "EditForm.inputToggle.label.sign-up": "Kayıtları etkinleştir",
+ "EditForm.inputToggle.placeholder.email-confirmation-redirection": "ör: https://yourfrontend.com/email-confirmation-redirection",
+ "EditForm.inputToggle.placeholder.email-reset-password": "ör: https://yourfrontend.com/reset-password",
+ "EditPage.form.roles": "Rol detayları",
+ "Email.template.data.loaded": "E-posta şablonları yüklendi",
+ "Email.template.email_confirmation": "E-posta adresi doğrulaması",
+ "Email.template.form.edit.label": "Şablonu düzenle",
+ "Email.template.table.action.label": "eylem",
+ "Email.template.table.icon.label": "ikon",
+ "Email.template.table.name.label": "ad",
+ "Form.advancedSettings.data.loaded": "Gelişmiş ayarlar verisi yüklendi",
+ "HeaderNav.link.advancedSettings": "Gelişmiş Ayarlar",
+ "HeaderNav.link.emailTemplates": "E-posta Şablonları",
+ "HeaderNav.link.providers": "Sağlayıcıları",
+ "Plugin.permissions.plugins.description": "{name} eklentisi için izin verilen tüm eylemleri tanımlayın.",
+ "Plugins.header.description": "Yalnızca bir güzergahla sınırlandırılan işlemler aşağıda listelenmiştir.",
+ "Plugins.header.title": "İzinler",
+ "Policies.header.hint": "Uygulamanın eylemlerini veya eklentinin eylemlerini seçin ve bağlı rotayı görüntülemek için dişli çark simgesini tıklayın",
+ "Policies.header.title": "Gelişmiş Ayarlar",
+ "PopUpForm.Email.email_templates.inputDescription": "Değişkenleri nasıl kullanacağınızdan emin değilseniz, {link}",
+ "PopUpForm.Email.link.documentation": "dokümantasyonu kontrol et.",
+ "PopUpForm.Email.options.from.email.label": "Gönderenin E-posta",
+ "PopUpForm.Email.options.from.email.placeholder": "kai@doe.com",
+ "PopUpForm.Email.options.from.name.label": "Gönderenin adı",
+ "PopUpForm.Email.options.from.name.placeholder": "Kai Doe",
+ "PopUpForm.Email.options.message.label": "Mesaj",
+ "PopUpForm.Email.options.object.label": "Konu",
+ "PopUpForm.Email.options.object.placeholder": "%APP_NAME% için e-posta adresini doğrula",
+ "PopUpForm.Email.options.response_email.label": "Yanıt e-postası",
+ "PopUpForm.Email.options.response_email.placeholder": "kai@doe.com",
+ "PopUpForm.Providers.enabled.description": "Devre dışı bırakıldıysa kullanıcılar bu sağlayıcıyı kullanamaz.",
+ "PopUpForm.Providers.enabled.label": "Etkinleştirme",
+ "PopUpForm.Providers.key.label": "Web istemcisi ID",
+ "PopUpForm.Providers.key.placeholder": "METİN",
+ "PopUpForm.Providers.redirectURL.front-end.label": "Arayüz uygulamanızın yönlendirme URL'si",
+ "PopUpForm.Providers.redirectURL.label": "{provider} uygulama ayarlarına ekleyeceğin yönlendirme URLi",
+ "PopUpForm.Providers.secret.label": "Web istemcisi Secret",
+ "PopUpForm.Providers.secret.placeholder": "METİN",
+ "PopUpForm.Providers.subdomain.label": "Host URI (Subdomain)",
+ "PopUpForm.Providers.subdomain.placeholder": "my.subdomain.com",
+ "PopUpForm.header.edit.email-templates": "E-posta Şablonlarını Düzenle",
+ "PopUpForm.header.edit.providers": "Sağlayıcıyı Düzenle",
+ "Providers.data.loaded": "Sağlayıcılar yüklendi",
+ "Providers.image": "Görsel",
+ "Providers.status": "Durum",
+ "Roles.empty": "Henüz hiç rolün yok.",
+ "Roles.empty.search": "Aramaya uygun rol bulunmadı.",
+ "Settings.roles.deleted": "Rol silindi",
+ "Settings.roles.edited": "Rol düzenlendi",
+ "Settings.section-label": "Kullanıcılar ve İzinler eklentisi",
+ "components.Input.error.validation.email": "Bu geçersiz bir e-posta",
+ "components.Input.error.validation.json": "Bu JSON biçimine uymuyor",
+ "components.Input.error.validation.max": "Değer çok yüksek.",
+ "components.Input.error.validation.maxLength": "Değer çok uzun.",
+ "components.Input.error.validation.min": "Değer çok düşük.",
+ "components.Input.error.validation.minLength": "Değer çok kısa.",
+ "components.Input.error.validation.minSupMax": "Üst olamaz",
+ "components.Input.error.validation.regex": "Değer RegExp'e uymuyor.",
+ "components.Input.error.validation.required": "Değer gerekli.",
+ "components.Input.error.validation.unique": "Değer zaten kullanılıyor.",
+ "notification.success.submit": "Ayarlar güncellendi",
+ "page.title": "Ayarlar - Roller",
+ "plugin.description.long": "Servisinizi JWT'ye dayalı tam bir kimlik doğrulama işlemi ile koruyun. Bu eklenti, kullanıcı grupları arasındaki izinleri yönetmenize izin veren bir ACL stratejisiyle de gelir.",
+ "plugin.description.short": "Servisinizi JWT'ye dayalı tam bir kimlik doğrulama işlemi ile koruyun",
+ "plugin.name": "Roller ve İzinler",
+ "popUpWarning.button.cancel": "İptal Et",
+ "popUpWarning.button.confirm": "Onayla",
+ "popUpWarning.title": "Lütfen onayla",
+ "popUpWarning.warning.cancel": "Değişiklikleri iptal etmek istediğinden emin misin?"
+}
diff --git a/packages/strapi/src/extensions/users-permissions/admin/src/translations/uk.json b/packages/strapi/src/extensions/users-permissions/admin/src/translations/uk.json
new file mode 100644
index 0000000..8896d5e
--- /dev/null
+++ b/packages/strapi/src/extensions/users-permissions/admin/src/translations/uk.json
@@ -0,0 +1,45 @@
+{
+ "BoundRoute.title": "Пов'язано з",
+ "EditForm.inputSelect.description.role": "Підключає нового автентифікованого користувача до вибраної ролі.",
+ "EditForm.inputSelect.label.role": "Роль за замовчуванням для автентифікованих користувачів",
+ "EditForm.inputToggle.description.email": "Не дозволяти користувачам створювати кілька аккаунтів з тим самим email, але різним провайдером автентифікації.",
+ "EditForm.inputToggle.description.email-confirmation": "Якщо увімкнено (ON), щойно зареєстровані користувачі отримують листа для підтверждення.",
+ "EditForm.inputToggle.description.email-confirmation-redirection": "Куди ви будете перенаправлені після підтвердження свого email.",
+ "EditForm.inputToggle.description.email-reset-password": "URL-адреса сторінки скидання пароля вашого додатку",
+ "EditForm.inputToggle.description.sign-up": "Якщо вимкнено (OFF), реєстрація заборонена. Незалежно від використовуваного провайдера більше ніхто не зможе приєднатись.",
+ "EditForm.inputToggle.label.email": "Один аккаунт на email",
+ "EditForm.inputToggle.label.email-confirmation": "Увімкнути підтверження email",
+ "EditForm.inputToggle.label.email-confirmation-redirection": "URL для перенаправлення",
+ "EditForm.inputToggle.label.email-reset-password": "Сторінка скидання пароля",
+ "EditForm.inputToggle.label.sign-up": "Увімкнути реєстрацію",
+ "HeaderNav.link.advancedSettings": "Розширені налаштування",
+ "HeaderNav.link.emailTemplates": "Шаблони листів",
+ "HeaderNav.link.providers": "Провайдери",
+ "Plugin.permissions.plugins.description": "Встановіть всі дозволені дії у плаґіні {name}.",
+ "Plugins.header.description": "Нижче перераховано лише дії, пов'язані з маршрутом.",
+ "Plugins.header.title": "Дозволи",
+ "Policies.header.hint": "Виберіть дії вашого додатку або дії плаґіну та натисніть на значок шестірні, щоб відобразити пов'язаний маршрут",
+ "Policies.header.title": "Розширені налашрування",
+ "PopUpForm.Email.email_templates.inputDescription": "Якщо ви не впевнені, як використовувати змінні, {link}",
+ "PopUpForm.Email.options.from.email.label": "Email відправника",
+ "PopUpForm.Email.options.from.email.placeholder": "kai@doe.com",
+ "PopUpForm.Email.options.from.name.label": "Ім'я відправника",
+ "PopUpForm.Email.options.from.name.placeholder": "Kai Doe",
+ "PopUpForm.Email.options.message.label": "Повідомлення",
+ "PopUpForm.Email.options.object.label": "Тема",
+ "PopUpForm.Email.options.response_email.label": "Email для відповіді",
+ "PopUpForm.Email.options.response_email.placeholder": "kai@doe.com",
+ "PopUpForm.Providers.enabled.description": "Якщо вимкнуто, користувачі не зможуть вікористати цей провайдер.",
+ "PopUpForm.Providers.enabled.label": "Увімкнути",
+ "PopUpForm.Providers.key.label": "Client ID",
+ "PopUpForm.Providers.key.placeholder": "TEXT",
+ "PopUpForm.Providers.redirectURL.front-end.label": "URL переадресації для вашего front-end додатку",
+ "PopUpForm.Providers.secret.label": "Client Secret",
+ "PopUpForm.Providers.secret.placeholder": "TEXT",
+ "PopUpForm.Providers.subdomain.label": "Host URI (Subdomain)",
+ "PopUpForm.Providers.subdomain.placeholder": "my.subdomain.com",
+ "PopUpForm.header.edit.email-templates": "Редагування шаблони листів",
+ "notification.success.submit": "Налаштування оновлено",
+ "plugin.description.long": "Захистіть API за допомогою процесу аутентифікації на основі JWT. Цей плагін також включає можливості ACL, які дозволяють керувати дозволами між групами користувачів.",
+ "plugin.description.short": "Захистіть API за допомогою процесу аутентифікації на основі JWT"
+}
diff --git a/packages/strapi/src/extensions/users-permissions/admin/src/translations/vi.json b/packages/strapi/src/extensions/users-permissions/admin/src/translations/vi.json
new file mode 100644
index 0000000..6673b05
--- /dev/null
+++ b/packages/strapi/src/extensions/users-permissions/admin/src/translations/vi.json
@@ -0,0 +1,46 @@
+{
+ "BoundRoute.title": "Đến tới",
+ "EditForm.inputSelect.description.role": "Đính kèm người dùng mới đã được xác thực vào quyền được chọn.",
+ "EditForm.inputSelect.label.role": "Quyền mặc định cho các người dùng đã được chứng thực",
+ "EditForm.inputToggle.description.email": "Không cho phép người dùng tạo nhiều tài khoản có cùng địa chỉ email với nhiều nhà cung cấp chứng thực.",
+ "EditForm.inputToggle.description.email-confirmation": "Khi được kích hoạt (ON), người dùng đăng ký mới nhận được một email xác nhận.",
+ "EditForm.inputToggle.description.email-confirmation-redirection": "Sau khi xác nhận email của bạn, chọn nơi bạn sẽ được đưa về.",
+ "EditForm.inputToggle.description.email-reset-password": "URL của trang lấy lại mật khẩu của ứng dụng của bạn",
+ "EditForm.inputToggle.description.sign-up": "Khi không kích hoạt (OFF), quá trình đăng ký bị cấm. Không ai có thể đăng ký thêm dù dùng bất kỳ nhà cung cấp nào.",
+ "EditForm.inputToggle.label.email": "Một tài khoản trên một địa chỉ email",
+ "EditForm.inputToggle.label.email-confirmation": "Kích hoạt email xác nhận",
+ "EditForm.inputToggle.label.email-confirmation-redirection": "URL đưa về",
+ "EditForm.inputToggle.label.email-reset-password": "Trang lấy lại mật khẩu",
+ "EditForm.inputToggle.label.sign-up": "Kích hoạt đăng ký",
+ "HeaderNav.link.advancedSettings": "Cài đặt nâng cao",
+ "HeaderNav.link.emailTemplates": "Mẫu email",
+ "HeaderNav.link.providers": "Các nhà cung cấp",
+ "Plugin.permissions.plugins.description": "Định nghĩa tất cả hành động được phép cho {name} plugin.",
+ "Plugins.header.description": "Chỉ các hành động đến bởi một đường dẫn được liệt kê bên dưới.",
+ "Plugins.header.title": "Các Quyền",
+ "Policies.header.hint": "Chọn các hành động của ứng dựng hoặc hành động của plugin và nhấn vào biểu tượng bánh răng để hiển thị đường đến",
+ "Policies.header.title": "Các cài đặt nâng cao",
+ "PopUpForm.Email.email_templates.inputDescription": "Nếu bạn không chắc sử dụng các biến như thế nào, {link}",
+ "PopUpForm.Email.options.from.email.label": "Email người gửi",
+ "PopUpForm.Email.options.from.email.placeholder": "kai@doe.com",
+ "PopUpForm.Email.options.from.name.label": "Tên người gửi",
+ "PopUpForm.Email.options.from.name.placeholder": "Kai Doe",
+ "PopUpForm.Email.options.message.label": "Thông điệp",
+ "PopUpForm.Email.options.object.label": "Chủ đề",
+ "PopUpForm.Email.options.response_email.label": "Email phản hồi",
+ "PopUpForm.Email.options.response_email.placeholder": "kai@doe.com",
+ "PopUpForm.Providers.enabled.description": "Nếu không kích hoạt, người dùng sẽ không thể dùng nhà cung cấp này.",
+ "PopUpForm.Providers.enabled.label": "Kích hoạt",
+ "PopUpForm.Providers.key.label": "Client ID",
+ "PopUpForm.Providers.key.placeholder": "VĂN BẢN",
+ "PopUpForm.Providers.redirectURL.front-end.label": "URL chuyển tiếp đến ứng dụng bên ngoài của bạn",
+ "PopUpForm.Providers.secret.label": "Client Secret",
+ "PopUpForm.Providers.secret.placeholder": "VĂN BẢN",
+ "PopUpForm.Providers.subdomain.label": "Host URI (Subdomain)",
+ "PopUpForm.Providers.subdomain.placeholder": "my.subdomain.com",
+ "PopUpForm.header.edit.email-templates": "Sửa Các Mẫu Email",
+ "notification.success.submit": "Các cấu hình đã được cập nhật",
+ "plugin.description.long": "Bảo vệ API của bạn với quá trình chứng thực đầy đủ dựa trên JWT. Plugin này cũng kèm với chiến lược ACL cho phép bạn quản lý quyền giữa các nhóm người dùng.",
+ "plugin.description.short": "Bảo vệ API của bạn với quá trình chứng thực đầy đủ dựa trên JWT",
+ "plugin.name": "Vai trò và Quyền"
+}
diff --git a/packages/strapi/src/extensions/users-permissions/admin/src/translations/zh-Hans.json b/packages/strapi/src/extensions/users-permissions/admin/src/translations/zh-Hans.json
new file mode 100644
index 0000000..f1b5688
--- /dev/null
+++ b/packages/strapi/src/extensions/users-permissions/admin/src/translations/zh-Hans.json
@@ -0,0 +1,82 @@
+{
+ "BoundRoute.title": "绑定路由到",
+ "EditForm.inputSelect.description.role": "新验证身份的用户将被赋予所选角色。",
+ "EditForm.inputSelect.label.role": "认证用户的默认角色",
+ "EditForm.inputToggle.description.email": "不允许用户使用不同的认证提供者(绑定的相同的电子邮件地址)来创建多个帐户。",
+ "EditForm.inputToggle.description.email-confirmation": "启用(ON)后,新注册的用户会收到一封确认电子邮件。",
+ "EditForm.inputToggle.description.email-confirmation-redirection": "确认您的电子邮件后,选择将您重定向到的位置。",
+ "EditForm.inputToggle.description.email-reset-password": "应用程序的重置密码页面的 URL",
+ "EditForm.inputToggle.description.sign-up": "当禁用(OFF)时,注册过程将被禁止。任何人无论使用任何的供应商都不可以订阅。",
+ "EditForm.inputToggle.label.email": "每个电子邮件地址一个帐户",
+ "EditForm.inputToggle.label.email-confirmation": "启用电子邮件确认",
+ "EditForm.inputToggle.label.email-confirmation-redirection": "重定向 URL",
+ "EditForm.inputToggle.label.email-reset-password": "重置密码页面 URL",
+ "EditForm.inputToggle.label.sign-up": "启用注册",
+ "EditForm.inputToggle.placeholder.email-confirmation-redirection": "例如: https://yourfrontend.com/reset-password",
+ "EditForm.inputToggle.placeholder.email-reset-password": "例如: https://yourfrontend.com/reset-password",
+ "EditPage.form.roles": "角色详情",
+ "Email.template.data.loaded": "电子邮件模板已加载",
+ "Email.template.email_confirmation": "邮箱地址确认",
+ "Email.template.form.edit.label": "编辑模板",
+ "Email.template.table.action.label": "操作",
+ "Email.template.table.icon.label": "图标",
+ "Email.template.table.name.label": "名称",
+ "Form.advancedSettings.data.loaded": "高级设置数据已加载",
+ "HeaderNav.link.advancedSettings": "高级设置",
+ "HeaderNav.link.emailTemplates": "电子邮件模板",
+ "HeaderNav.link.providers": "提供者",
+ "Plugin.permissions.plugins.description": "定义 {name} 插件所有允许的操作。",
+ "Plugins.header.description": "下面只列出路由绑定的操作。",
+ "Plugins.header.title": "权限",
+ "Policies.header.hint": "选择应用程序或插件的操作,然后点击 COG 图标显示绑定的路由",
+ "Policies.header.title": "高级设置",
+ "PopUpForm.Email.email_templates.inputDescription": "如果你不确定如何使用变量, {link}",
+ "PopUpForm.Email.link.documentation": "查看我们的文档",
+ "PopUpForm.Email.options.from.email.label": "发件人地址",
+ "PopUpForm.Email.options.from.email.placeholder": "kai@doe.com",
+ "PopUpForm.Email.options.from.name.label": "发件人名称",
+ "PopUpForm.Email.options.from.name.placeholder": "Kai Doe",
+ "PopUpForm.Email.options.message.label": "消息",
+ "PopUpForm.Email.options.object.label": "主题",
+ "PopUpForm.Email.options.object.placeholder": "请为%APP_NAME%确认邮箱地址",
+ "PopUpForm.Email.options.response_email.label": "回复邮件",
+ "PopUpForm.Email.options.response_email.placeholder": "kai@doe.com",
+ "PopUpForm.Providers.enabled.description": "如果禁用,用户将无法使用此供应商。",
+ "PopUpForm.Providers.enabled.label": "启用",
+ "PopUpForm.Providers.key.label": "客户端 ID",
+ "PopUpForm.Providers.key.placeholder": "文本",
+ "PopUpForm.Providers.redirectURL.front-end.label": "重定向 URL",
+ "PopUpForm.Providers.redirectURL.label": "添加到{provider}应用配置的跳转URL",
+ "PopUpForm.Providers.secret.label": "客户端秘钥",
+ "PopUpForm.Providers.secret.placeholder": "文本",
+ "PopUpForm.Providers.subdomain.label": "主机URI(子域名)",
+ "PopUpForm.Providers.subdomain.placeholder": "my.subdomain.com",
+ "PopUpForm.header.edit.email-templates": "编辑电子邮件模版",
+ "PopUpForm.header.edit.providers": "编辑提供商",
+ "Providers.data.loaded": "提供商已加载",
+ "Providers.status": "状态",
+ "Roles.empty": "您还没有任何角色。",
+ "Roles.empty.search": "没有与搜索相匹配的角色。",
+ "Settings.roles.deleted": "角色已被删除",
+ "Settings.roles.edited": "角色编辑完成",
+ "Settings.section-label": "用户及权限插件",
+ "components.Input.error.validation.email": "这是一个无效的电子邮件",
+ "components.Input.error.validation.json": "这不符合JSON格式",
+ "components.Input.error.validation.max": "值过高。",
+ "components.Input.error.validation.maxLength": "值过长。",
+ "components.Input.error.validation.min": "值太低。",
+ "components.Input.error.validation.minLength": "值太短。",
+ "components.Input.error.validation.minSupMax": "不能超过上限",
+ "components.Input.error.validation.regex": "该值不符合正则表达式。",
+ "components.Input.error.validation.required": "该值为必填项。",
+ "components.Input.error.validation.unique": "该值已被使用。",
+ "notification.success.submit": "设置已被更新",
+ "page.title": "设置 - 角色",
+ "plugin.description.long": "使用基于 JWT 的完整身份验证过程来保护 API。这个插件还有一个 ACL 策略,允许你管理用户组之间的权限。",
+ "plugin.description.short": "使用基于 JWT 的完整身份验证过程保护 API",
+ "plugin.name": "角色及权限",
+ "popUpWarning.button.cancel": "取消",
+ "popUpWarning.button.confirm": "确认",
+ "popUpWarning.title": "请确认",
+ "popUpWarning.warning.cancel": "你确定你要取消你的修改?"
+}
diff --git a/packages/strapi/src/extensions/users-permissions/admin/src/translations/zh.json b/packages/strapi/src/extensions/users-permissions/admin/src/translations/zh.json
new file mode 100644
index 0000000..72d0624
--- /dev/null
+++ b/packages/strapi/src/extensions/users-permissions/admin/src/translations/zh.json
@@ -0,0 +1,82 @@
+{
+ "BoundRoute.title": "綁定路徑到",
+ "EditForm.inputSelect.description.role": "將新的驗證使用者加入此身份。",
+ "EditForm.inputSelect.label.role": "驗證使用者預設身份",
+ "EditForm.inputToggle.description.email": "禁止使用者使用同一個電子郵件地址 + 不同的驗證方式註冊多個帳號",
+ "EditForm.inputToggle.description.email-confirmation": "當啟用後,新註冊的使用者將會收到一封認證郵件。",
+ "EditForm.inputToggle.description.email-confirmation-redirection": "認證完後後,使用者被重新導向的網址。",
+ "EditForm.inputToggle.description.email-reset-password": "您的應用程式的重設密碼頁面的網址",
+ "EditForm.inputToggle.description.sign-up": "當停用後,不論使用任何驗證方式使用者將無法註冊。",
+ "EditForm.inputToggle.label.email": "電子郵件地址單一帳號限制",
+ "EditForm.inputToggle.label.email-confirmation": "啟用電子郵件地址驗證",
+ "EditForm.inputToggle.label.email-confirmation-redirection": "重新導向網址",
+ "EditForm.inputToggle.label.email-reset-password": "密碼重設頁面",
+ "EditForm.inputToggle.label.sign-up": "啟用註冊",
+ "EditForm.inputToggle.placeholder.email-confirmation-redirection": "例如:https://yourfrontend.com/email-confirmation-redirection",
+ "EditForm.inputToggle.placeholder.email-reset-password": "例如:https://yourfrontend.com/reset-password",
+ "EditPage.form.roles": "角色詳細資訊",
+ "Email.template.data.loaded": "已載入電子郵件範本",
+ "Email.template.email_confirmation": "電子郵件地址確認",
+ "Email.template.form.edit.label": "編輯範本",
+ "Email.template.table.action.label": "操作",
+ "Email.template.table.icon.label": "圖示",
+ "Email.template.table.name.label": "名稱",
+ "Form.advancedSettings.data.loaded": "已載入進階設定資料",
+ "HeaderNav.link.advancedSettings": "進階設定",
+ "HeaderNav.link.emailTemplates": "郵件範本",
+ "HeaderNav.link.providers": "驗證方式",
+ "Plugin.permissions.plugins.description": "為 {name} 擴充功能定義所有可用的操作",
+ "Plugins.header.description": "只有綁定路徑的操作會顯示在下方",
+ "Plugins.header.title": "權限",
+ "Policies.header.hint": "選取應用程式或擴充功能的操作然後點擊齒輪圖示以顯示綁定路徑",
+ "Policies.header.title": "進階設定",
+ "PopUpForm.Email.email_templates.inputDescription": "如果您不確定要怎麼使用變數,請 {link}",
+ "PopUpForm.Email.link.documentation": "查閱我們的說明文件。",
+ "PopUpForm.Email.options.from.email.label": "寄件人地址",
+ "PopUpForm.Email.options.from.email.placeholder": "kai@doe.com",
+ "PopUpForm.Email.options.from.name.label": "寄件人名稱",
+ "PopUpForm.Email.options.from.name.placeholder": "Kai Doe",
+ "PopUpForm.Email.options.message.label": "訊息",
+ "PopUpForm.Email.options.object.label": "主旨",
+ "PopUpForm.Email.options.object.placeholder": "請驗證 %APP_NAME% 的電子郵件地址",
+ "PopUpForm.Email.options.response_email.label": "回覆地址",
+ "PopUpForm.Email.options.response_email.placeholder": "kai@doe.com",
+ "PopUpForm.Providers.enabled.description": "如果停用,使用者將無法使用這個驗證方式",
+ "PopUpForm.Providers.enabled.label": "啟用",
+ "PopUpForm.Providers.key.label": "客戶端 ID",
+ "PopUpForm.Providers.key.placeholder": "TEXT",
+ "PopUpForm.Providers.redirectURL.front-end.label": "您應用程式的前端頁面網址",
+ "PopUpForm.Providers.redirectURL.label": "The redirect URL to add in your {provider} application configurations",
+ "PopUpForm.Providers.secret.label": "客戶端密鑰",
+ "PopUpForm.Providers.secret.placeholder": "TEXT",
+ "PopUpForm.Providers.subdomain.label": "Host URI (子網域)",
+ "PopUpForm.Providers.subdomain.placeholder": "my.subdomain.com",
+ "PopUpForm.header.edit.email-templates": "編輯郵件範本",
+ "PopUpForm.header.edit.providers": "編輯供應者",
+ "Providers.data.loaded": "已載入供應者",
+ "Providers.status": "狀態",
+ "Roles.empty": "您目前沒有任何角色。",
+ "Roles.empty.search": "沒有符合搜尋的角色。",
+ "Settings.roles.deleted": "已刪除角色",
+ "Settings.roles.edited": "已編輯角色",
+ "Settings.section-label": "使用者與權限外掛程式",
+ "components.Input.error.validation.email": "此電子郵件地址無效",
+ "components.Input.error.validation.json": "不符合 JSON 格式",
+ "components.Input.error.validation.max": "數值過高。",
+ "components.Input.error.validation.maxLength": "數值過長。",
+ "components.Input.error.validation.min": "數值過低。",
+ "components.Input.error.validation.minLength": "數值過短。",
+ "components.Input.error.validation.minSupMax": "Can't be superior",
+ "components.Input.error.validation.regex": "數值與 regex 不符。",
+ "components.Input.error.validation.required": "此數值為必填。",
+ "components.Input.error.validation.unique": "此值已被使用。",
+ "notification.success.submit": "設定已更新",
+ "page.title": "設定 - 角色",
+ "plugin.description.long": "使用 JWT 認證保護您的 API。這個擴充功能也使用 ACL 來讓你管理不同群組使用者的權限。",
+ "plugin.description.short": "使用 JWT 認證保護您的 API",
+ "plugin.name": "身份與權限",
+ "popUpWarning.button.cancel": "取消",
+ "popUpWarning.button.confirm": "確認",
+ "popUpWarning.title": "請確認",
+ "popUpWarning.warning.cancel": "您確定要取消變更嗎?"
+}
diff --git a/packages/strapi/src/extensions/users-permissions/admin/src/utils/cleanPermissions.js b/packages/strapi/src/extensions/users-permissions/admin/src/utils/cleanPermissions.js
new file mode 100644
index 0000000..b50159a
--- /dev/null
+++ b/packages/strapi/src/extensions/users-permissions/admin/src/utils/cleanPermissions.js
@@ -0,0 +1,25 @@
+import isEmpty from 'lodash/isEmpty';
+
+const cleanPermissions = (permissions) =>
+ Object.keys(permissions).reduce((acc, current) => {
+ const currentPermission = permissions[current].controllers;
+ const cleanedControllers = Object.keys(currentPermission).reduce((acc2, curr) => {
+ if (isEmpty(currentPermission[curr])) {
+ return acc2;
+ }
+
+ acc2[curr] = currentPermission[curr];
+
+ return acc2;
+ }, {});
+
+ if (isEmpty(cleanedControllers)) {
+ return acc;
+ }
+
+ acc[current] = { controllers: cleanedControllers };
+
+ return acc;
+ }, {});
+
+export default cleanPermissions;
diff --git a/packages/strapi/src/extensions/users-permissions/admin/src/utils/formatPluginName.js b/packages/strapi/src/extensions/users-permissions/admin/src/utils/formatPluginName.js
new file mode 100644
index 0000000..4dc7814
--- /dev/null
+++ b/packages/strapi/src/extensions/users-permissions/admin/src/utils/formatPluginName.js
@@ -0,0 +1,26 @@
+import upperFirst from 'lodash/upperFirst';
+
+function formatPluginName(pluginSlug) {
+ switch (pluginSlug) {
+ case 'application':
+ return 'Application';
+ case 'plugin::content-manager':
+ return 'Content manager';
+ case 'plugin::content-type-builder':
+ return 'Content types builder';
+ case 'plugin::documentation':
+ return 'Documentation';
+ case 'plugin::email':
+ return 'Email';
+ case 'plugin::i18n':
+ return 'i18n';
+ case 'plugin::upload':
+ return 'Upload';
+ case 'plugin::users-permissions':
+ return 'Users-permissions';
+ default:
+ return upperFirst(pluginSlug.replace('api::', '').replace('plugin::', ''));
+ }
+}
+
+export default formatPluginName;
diff --git a/packages/strapi/src/extensions/users-permissions/admin/src/utils/formatPolicies.js b/packages/strapi/src/extensions/users-permissions/admin/src/utils/formatPolicies.js
new file mode 100644
index 0000000..8511f6b
--- /dev/null
+++ b/packages/strapi/src/extensions/users-permissions/admin/src/utils/formatPolicies.js
@@ -0,0 +1,8 @@
+const formatPolicies = (policies) =>
+ policies.reduce((acc, current) => {
+ acc.push({ label: current, value: current });
+
+ return acc;
+ }, []);
+
+export default formatPolicies;
diff --git a/packages/strapi/src/extensions/users-permissions/admin/src/utils/getRequestURL.js b/packages/strapi/src/extensions/users-permissions/admin/src/utils/getRequestURL.js
new file mode 100644
index 0000000..226cfc2
--- /dev/null
+++ b/packages/strapi/src/extensions/users-permissions/admin/src/utils/getRequestURL.js
@@ -0,0 +1,5 @@
+import pluginId from '../pluginId';
+
+const getRequestURL = (endPoint) => `/${pluginId}/${endPoint}`;
+
+export default getRequestURL;
diff --git a/packages/strapi/src/extensions/users-permissions/admin/src/utils/getTrad.js b/packages/strapi/src/extensions/users-permissions/admin/src/utils/getTrad.js
new file mode 100644
index 0000000..d0a071b
--- /dev/null
+++ b/packages/strapi/src/extensions/users-permissions/admin/src/utils/getTrad.js
@@ -0,0 +1,5 @@
+import pluginId from '../pluginId';
+
+const getTrad = (id) => `${pluginId}.${id}`;
+
+export default getTrad;
diff --git a/packages/strapi/src/extensions/users-permissions/admin/src/utils/index.js b/packages/strapi/src/extensions/users-permissions/admin/src/utils/index.js
new file mode 100644
index 0000000..61137b9
--- /dev/null
+++ b/packages/strapi/src/extensions/users-permissions/admin/src/utils/index.js
@@ -0,0 +1,4 @@
+export { default as cleanPermissions } from './cleanPermissions';
+export { default as formatPolicies } from './formatPolicies';
+export { default as getRequestURL } from './getRequestURL';
+export { default as getTrad } from './getTrad';
diff --git a/packages/strapi/src/extensions/users-permissions/content-types/user/schema.json b/packages/strapi/src/extensions/users-permissions/content-types/user/schema.json
new file mode 100644
index 0000000..a156044
--- /dev/null
+++ b/packages/strapi/src/extensions/users-permissions/content-types/user/schema.json
@@ -0,0 +1,88 @@
+{
+ "kind": "collectionType",
+ "collectionName": "up_users",
+ "info": {
+ "name": "user",
+ "description": "",
+ "singularName": "user",
+ "pluralName": "users",
+ "displayName": "User"
+ },
+ "options": {
+ "draftAndPublish": false
+ },
+ "attributes": {
+ "username": {
+ "type": "string",
+ "minLength": 3,
+ "unique": true,
+ "configurable": false,
+ "required": true
+ },
+ "email": {
+ "type": "email",
+ "minLength": 6,
+ "configurable": false,
+ "required": true
+ },
+ "provider": {
+ "type": "string",
+ "configurable": false
+ },
+ "password": {
+ "type": "password",
+ "minLength": 6,
+ "configurable": false,
+ "private": true,
+ "searchable": false
+ },
+ "resetPasswordToken": {
+ "type": "string",
+ "configurable": false,
+ "private": true,
+ "searchable": false
+ },
+ "confirmationToken": {
+ "type": "string",
+ "configurable": false,
+ "private": true,
+ "searchable": false
+ },
+ "confirmed": {
+ "type": "boolean",
+ "default": false,
+ "configurable": false
+ },
+ "blocked": {
+ "type": "boolean",
+ "default": false,
+ "configurable": false
+ },
+ "role": {
+ "type": "relation",
+ "relation": "manyToOne",
+ "target": "plugin::users-permissions.role",
+ "inversedBy": "users",
+ "configurable": false
+ },
+ "isNamePublic": {
+ "type": "boolean",
+ "default": false
+ },
+ "avatar": {
+ "type": "string",
+ "default": "http://placekitten.com/32/32"
+ },
+ "isLinkPublic": {
+ "type": "boolean",
+ "default": false
+ },
+ "vanityLink": {
+ "type": "string",
+ "maxLength": 256
+ },
+ "patreonBenefits": {
+ "type": "text"
+ }
+ }
+}
diff --git a/packages/strapi/src/extensions/users-permissions/documentation/content-api.yaml b/packages/strapi/src/extensions/users-permissions/documentation/content-api.yaml
new file mode 100644
index 0000000..f00eb90
--- /dev/null
+++ b/packages/strapi/src/extensions/users-permissions/documentation/content-api.yaml
@@ -0,0 +1,878 @@
+tags:
+ - name: 'Users-Permissions - Auth'
+ description: 'Authentication endpoints'
+ externalDocs:
+ description: 'Find out more'
+ url: 'https://docs.strapi.io/developer-docs/latest/plugins/users-permissions.html'
+
+ - name: 'Users-Permissions - Users & Roles'
+ description: 'Users, roles, and permissions endpoints'
+ externalDocs:
+ description: 'Find out more'
+ url: 'https://docs.strapi.io/developer-docs/latest/plugins/users-permissions.html'
+
+paths:
+ /connect/{provider}:
+ get:
+ parameters:
+ - name: provider
+ in: path
+ required: true
+ description: Provider name
+ schema:
+ type: string
+ pattern: '.*'
+ tags:
+ - Users-Permissions - Auth
+ summary: Login with a provider
+ description: Redirects to provider login before being redirect to /auth/{provider}/callback
+ responses:
+ 301:
+ description: Redirect response
+ default:
+ description: Error
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ /auth/local:
+ post:
+ tags:
+ - Users-Permissions - Auth
+ summary: Local login
+ description: Returns a jwt token and user info
+ requestBody:
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ identifier:
+ type: string
+ password:
+ type: string
+ example:
+ identifier: foobar
+ password: Test1234
+ required: true
+ responses:
+ 200:
+ description: Connection
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Users-Permissions-UserRegistration'
+ default:
+ description: Error
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ /auth/local/register:
+ post:
+ tags:
+ - Users-Permissions - Auth
+ summary: Register a user
+ description: Returns a jwt token and user info
+ requestBody:
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ username:
+ type: string
+ email:
+ type: string
+ password:
+ type: string
+ example:
+ username: foobar
+ email: foo.bar@strapi.io
+ password: Test1234
+ required: true
+ responses:
+ 200:
+ description: Successfull registration
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Users-Permissions-UserRegistration'
+ default:
+ description: Error
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+
+ /auth/{provider}/callback:
+ get:
+ tags:
+ - Users-Permissions - Auth
+ summary: Default Callback from provider auth
+ parameters:
+ - name: provider
+ in: path
+ required: true
+ description: Provider name
+ schema:
+ type: string
+ responses:
+ 200:
+ description: Returns a jwt token and user info
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Users-Permissions-UserRegistration'
+ default:
+ description: Error
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+
+ /auth/forgot-password:
+ post:
+ tags:
+ - Users-Permissions - Auth
+ summary: Send rest password email
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ email:
+ type: string
+ example:
+ email: foo.bar@strapi.io
+ responses:
+ 200:
+ description: Returns ok
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ ok:
+ type: string
+ enum: [true]
+ default:
+ description: Error
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ /auth/reset-password:
+ post:
+ tags:
+ - Users-Permissions - Auth
+ summary: Rest user password
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ password:
+ type: string
+ passwordConfirmation:
+ type: string
+ code:
+ type: string
+ example:
+ password: Test1234
+ passwordConfirmation: Test1234
+ code: zertyoaizndoianzodianzdonaizdoinaozdnia
+ responses:
+ 200:
+ description: Returns a jwt token and user info
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Users-Permissions-UserRegistration'
+ default:
+ description: Error
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+
+ /auth/change-password:
+ post:
+ tags:
+ - Users-Permissions - Auth
+ summary: Update user's own password
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ type: object
+ required:
+ - password
+ - currentPassword
+ - passwordConfirmation
+ properties:
+ password:
+ type: string
+ currentPassword:
+ type: string
+ passwordConfirmation:
+ type: string
+ responses:
+ 200:
+ description: Returns a jwt token and user info
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Users-Permissions-UserRegistration'
+ default:
+ description: Error
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ /auth/email-confirmation:
+ get:
+ tags:
+ - Users-Permissions - Auth
+ summary: Confirm user email
+ parameters:
+ - in: query
+ name: confirmation
+ schema:
+ type: string
+ description: confirmation token received by email
+ responses:
+ 301:
+ description: Redirects to the configure email confirmation redirect url
+ default:
+ description: Error
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+
+ /auth/send-email-confirmation:
+ post:
+ tags:
+ - Users-Permissions - Auth
+ summary: Send confirmation email
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ email:
+ type: string
+ responses:
+ 200:
+ description: Returns email and boolean to confirm email was sent
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ email:
+ type: string
+ sent:
+ type: string
+ enum: [true]
+ default:
+ description: Error
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+
+ /users-permissions/permissions:
+ get:
+ tags:
+ - Users-Permissions - Users & Roles
+ summary: Get default generated permissions
+ responses:
+ 200:
+ description: Returns the permissions tree
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ permissions:
+ $ref: '#/components/schemas/Users-Permissions-PermissionsTree'
+ example:
+ permissions:
+ api::content-type.content-type:
+ controllers:
+ controllerA:
+ find:
+ enabled: false
+ policy: ''
+ findOne:
+ enabled: false
+ policy: ''
+ create:
+ enabled: false
+ policy: ''
+ controllerB:
+ find:
+ enabled: false
+ policy: ''
+ findOne:
+ enabled: false
+ policy: ''
+ create:
+ enabled: false
+ policy: ''
+ default:
+ description: Error
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ /users-permissions/roles:
+ get:
+ tags:
+ - Users-Permissions - Users & Roles
+ summary: List roles
+ responses:
+ 200:
+ description: Returns list of roles
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ roles:
+ type: array
+ items:
+ allOf:
+ - $ref: '#/components/schemas/Users-Permissions-Role'
+ - type: object
+ properties:
+ nb_users:
+ type: number
+ example:
+ roles:
+ - id: 1
+ name: Public
+ description: Default role given to unauthenticated user.
+ type: public
+ createdAt: 2022-05-19T17:35:35.097Z
+ updatedAt: 2022-05-31T16:05:36.603Z
+ nb_users: 0
+
+ default:
+ description: Error
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+
+ post:
+ tags:
+ - Users-Permissions - Users & Roles
+ summary: Create a role
+ requestBody:
+ $ref: '#/components/requestBodies/Users-Permissions-RoleRequest'
+ responses:
+ 200:
+ description: Returns ok if the role was create
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ ok:
+ type: string
+ enum: [true]
+ default:
+ description: Error
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+
+ /users-permissions/roles/{id}:
+ get:
+ tags:
+ - Users-Permissions - Users & Roles
+ summary: Get a role
+ parameters:
+ - in: path
+ name: id
+ required: true
+ schema:
+ type: string
+ description: role Id
+ responses:
+ 200:
+ description: Returns the role
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ role:
+ $ref: '#/components/schemas/Users-Permissions-Role'
+ example:
+ role:
+ id: 1
+ name: Public
+ description: Default role given to unauthenticated user.
+ type: public
+ createdAt: 2022-05-19T17:35:35.097Z
+ updatedAt: 2022-05-31T16:05:36.603Z
+ permissions:
+ api::content-type.content-type:
+ controllers:
+ controllerA:
+ find:
+ enabled: true
+ default:
+ description: Error
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+
+ /users-permissions/roles/{role}:
+ put:
+ tags:
+ - Users-Permissions - Users & Roles
+ summary: Update a role
+ parameters:
+ - in: path
+ name: role
+ required: true
+ schema:
+ type: string
+ description: role Id
+ requestBody:
+ $ref: '#/components/requestBodies/Users-Permissions-RoleRequest'
+ responses:
+ 200:
+ description: Returns ok if the role was udpated
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ ok:
+ type: string
+ enum: [true]
+ default:
+ description: Error
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+
+ delete:
+ tags:
+ - Users-Permissions - Users & Roles
+ summary: Delete a role
+ parameters:
+ - in: path
+ name: role
+ required: true
+ schema:
+ type: string
+ description: role Id
+ responses:
+ 200:
+ description: Returns ok if the role was delete
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ ok:
+ type: string
+ enum: [true]
+ default:
+ description: Error
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+
+ /users:
+ get:
+ tags:
+ - Users-Permissions - Users & Roles
+ summary: Get list of users
+ responses:
+ 200:
+ description: Returns an array of users
+ content:
+ application/json:
+ schema:
+ type: array
+ items:
+ $ref: '#/components/schemas/Users-Permissions-User'
+ example:
+ - id: 9
+ username: foao@strapi.io
+ email: foao@strapi.io
+ provider: local
+ confirmed: false
+ blocked: false
+ createdAt: 2022-06-01T18:32:35.211Z
+ updatedAt: 2022-06-01T18:32:35.217Z
+ default:
+ description: Error
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+
+ post:
+ tags:
+ - Users-Permissions - Users & Roles
+ summary: Create a user
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ type: object
+ required:
+ - username
+ - email
+ - password
+ properties:
+ email:
+ type: string
+ username:
+ type: string
+ password:
+ type: string
+ example:
+ username: foo
+ email: foo@strapi.io
+ password: foo-password
+ responses:
+ 201:
+ description: Returns created user info
+ content:
+ application/json:
+ schema:
+ allOf:
+ - $ref: '#/components/schemas/Users-Permissions-User'
+ - type: object
+ properties:
+ role:
+ $ref: '#/components/schemas/Users-Permissions-Role'
+ example:
+ id: 1
+ username: foo
+ email: foo@strapi.io
+ provider: local
+ confirmed: false
+ blocked: false
+ createdAt: 2022-05-19T17:35:35.096Z
+ updatedAt: 2022-05-19T17:35:35.096Z
+ role:
+ id: 1
+ name: X
+ description: Default role given to authenticated user.
+ type: authenticated
+ createdAt: 2022-05-19T17:35:35.096Z
+ updatedAt: 2022-06-04T07:11:59.551Z
+ default:
+ description: Error
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ /users/{id}:
+ get:
+ tags:
+ - Users-Permissions - Users & Roles
+ summary: Get a user
+ parameters:
+ - in: path
+ name: id
+ required: true
+ schema:
+ type: string
+ description: user Id
+ responses:
+ 200:
+ description: Returns a user
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Users-Permissions-User'
+ example:
+ id: 1
+ username: foo
+ email: foo@strapi.io
+ provider: local
+ confirmed: false
+ blocked: false
+ createdAt: 2022-05-19T17:35:35.096Z
+ updatedAt: 2022-05-19T17:35:35.096Z
+ default:
+ description: Error
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ put:
+ tags:
+ - Users-Permissions - Users & Roles
+ summary: Update a user
+ parameters:
+ - in: path
+ name: id
+ required: true
+ schema:
+ type: string
+ description: user Id
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ type: object
+ required:
+ - username
+ - email
+ - password
+ properties:
+ email:
+ type: string
+ username:
+ type: string
+ password:
+ type: string
+ example:
+ username: foo
+ email: foo@strapi.io
+ password: foo-password
+ responses:
+ 200:
+ description: Returns updated user info
+ content:
+ application/json:
+ schema:
+ allOf:
+ - $ref: '#/components/schemas/Users-Permissions-User'
+ - type: object
+ properties:
+ role:
+ $ref: '#/components/schemas/Users-Permissions-Role'
+ example:
+ id: 1
+ username: foo
+ email: foo@strapi.io
+ provider: local
+ confirmed: false
+ blocked: false
+ createdAt: 2022-05-19T17:35:35.096Z
+ updatedAt: 2022-05-19T17:35:35.096Z
+ role:
+ id: 1
+ name: X
+ description: Default role given to authenticated user.
+ type: authenticated
+ createdAt: 2022-05-19T17:35:35.096Z
+ updatedAt: 2022-06-04T07:11:59.551Z
+ default:
+ description: Error
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ delete:
+ tags:
+ - Users-Permissions - Users & Roles
+ summary: Delete a user
+ parameters:
+ - in: path
+ name: id
+ required: true
+ schema:
+ type: string
+ description: user Id
+ responses:
+ '200':
+ description: Returns deleted user info
+ content:
+ application/json:
+ schema:
+ allOf:
+ - $ref: '#/components/schemas/Users-Permissions-User'
+ example:
+ id: 1
+ username: foo
+ email: foo@strapi.io
+ provider: local
+ confirmed: false
+ blocked: false
+ createdAt: 2022-05-19T17:35:35.096Z
+ updatedAt: 2022-05-19T17:35:35.096Z
+ default:
+ description: Error
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ /users/me:
+ get:
+ tags:
+ - Users-Permissions - Users & Roles
+ summary: Get authenticated user info
+ responses:
+ 200:
+ description: Returns user info
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Users-Permissions-User'
+ example:
+ id: 1
+ username: foo
+ email: foo@strapi.io
+ provider: local
+ confirmed: false
+ blocked: false
+ createdAt: 2022-05-19T17:35:35.096Z
+ updatedAt: 2022-05-19T17:35:35.096Z
+ default:
+ description: Error
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+
+ /users/count:
+ get:
+ tags:
+ - Users-Permissions - Users & Roles
+ summary: Get user count
+ responses:
+ 200:
+ description: Returns a number
+ content:
+ application/json:
+ schema:
+ type: number
+ example: 1
+ default:
+ description: Error
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+
+components:
+ schemas:
+ Users-Permissions-Role:
+ type: object
+ properties:
+ id:
+ type: number
+ name:
+ type: string
+ description:
+ type: string
+ type:
+ type: string
+ createdAt:
+ type: string
+ format: date-time
+ updatedAt:
+ type: string
+ format: date-time
+
+ Users-Permissions-User:
+ type: object
+ properties:
+ id:
+ type: number
+ example: 1
+ username:
+ type: string
+ example: 'foo.bar'
+ email:
+ type: string
+ example: 'foo.bar@strapi.io'
+ provider:
+ type: string
+ example: 'local'
+ confirmed:
+ type: boolean
+ example: true
+ blocked:
+ type: boolean
+ example: false
+ createdAt:
+ type: string
+ format: date-time
+ example: '2022-06-02T08:32:06.258Z'
+ updatedAt:
+ type: string
+ format: date-time
+ example: '2022-06-02T08:32:06.267Z'
+
+ Users-Permissions-UserRegistration:
+ type: object
+ properties:
+ jwt:
+ type: string
+ example: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c'
+ user:
+ $ref: '#/components/schemas/Users-Permissions-User'
+
+ Users-Permissions-PermissionsTree:
+ type: object
+ additionalProperties:
+ type: object
+ description: every api
+ properties:
+ controllers:
+ description: every controller of the api
+ type: object
+ additionalProperties:
+ type: object
+ additionalProperties:
+ description: every action of every controller
+ type: object
+ properties:
+ enabled:
+ type: boolean
+ policy:
+ type: string
+ requestBodies:
+ Users-Permissions-RoleRequest:
+ required: true
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ name:
+ type: string
+ description:
+ type: string
+ type:
+ type: string
+ permissions:
+ $ref: '#/components/schemas/Users-Permissions-PermissionsTree'
+ example:
+ name: foo
+ description: role foo
+ permissions:
+ api::content-type.content-type:
+ controllers:
+ controllerA:
+ find:
+ enabled: true
diff --git a/packages/strapi/src/extensions/users-permissions/jest.config.front.js b/packages/strapi/src/extensions/users-permissions/jest.config.front.js
new file mode 100644
index 0000000..3e8054a
--- /dev/null
+++ b/packages/strapi/src/extensions/users-permissions/jest.config.front.js
@@ -0,0 +1,7 @@
+'use strict';
+
+module.exports = {
+ preset: '../../../jest-preset.front.js',
+ displayName: 'Users & Permissions plugin',
+ setupFilesAfterEnv: ['./tests/setup.js'],
+};
diff --git a/packages/strapi/src/extensions/users-permissions/package.json b/packages/strapi/src/extensions/users-permissions/package.json
new file mode 100644
index 0000000..5305e84
--- /dev/null
+++ b/packages/strapi/src/extensions/users-permissions/package.json
@@ -0,0 +1,81 @@
+{
+ "name": "@strapi/plugin-users-permissions",
+ "version": "4.11.2",
+ "description": "Protect your API with a full-authentication process based on JWT",
+ "repository": {
+ "type": "git",
+ "url": "git://github.com/strapi/strapi.git"
+ },
+ "license": "SEE LICENSE IN LICENSE",
+ "author": {
+ "name": "Strapi Solutions SAS",
+ "email": "hi@strapi.io",
+ "url": "https://strapi.io"
+ },
+ "maintainers": [
+ {
+ "name": "Strapi Solutions SAS",
+ "email": "hi@strapi.io",
+ "url": "https://strapi.io"
+ }
+ ],
+ "scripts": {
+ "test:unit": "run -T jest",
+ "test:unit:watch": "run -T jest --watch",
+ "test:front": "run -T cross-env IS_EE=true jest --config ./jest.config.front.js",
+ "test:front:watch": "run -T cross-env IS_EE=true jest --config ./jest.config.front.js --watchAll",
+ "test:front:ce": "run -T cross-env IS_EE=false jest --config ./jest.config.front.js",
+ "test:front:watch:ce": "run -T cross-env IS_EE=false jest --config ./jest.config.front.js --watchAll",
+ "lint": "run -T eslint ."
+ },
+ "dependencies": {
+ "@strapi/design-system": "1.8.0",
+ "@strapi/helper-plugin": "4.11.2",
+ "@strapi/icons": "1.8.0",
+ "@strapi/utils": "4.11.2",
+ "bcryptjs": "2.4.3",
+ "formik": "2.4.0",
+ "grant-koa": "5.4.8",
+ "immer": "9.0.19",
+ "jsonwebtoken": "9.0.0",
+ "jwk-to-pem": "2.0.5",
+ "koa": "^2.13.4",
+ "koa2-ratelimit": "^1.1.2",
+ "lodash": "4.17.21",
+ "prop-types": "^15.8.1",
+ "purest": "4.0.2",
+ "react-intl": "6.4.1",
+ "react-query": "3.39.3",
+ "react-redux": "8.0.5",
+ "url-join": "4.0.1",
+ "yup": "^0.32.9"
+ },
+ "devDependencies": {
+ "@testing-library/dom": "9.2.0",
+ "@testing-library/react": "14.0.0",
+ "@testing-library/user-event": "14.4.3",
+ "msw": "1.2.1",
+ "react": "^18.2.0",
+ "react-dom": "^18.2.0",
+ "react-router-dom": "5.3.4",
+ "styled-components": "5.3.3"
+ },
+ "peerDependencies": {
+ "react": "^17.0.0 || ^18.0.0",
+ "react-dom": "^17.0.0 || ^18.0.0",
+ "react-router-dom": "5.3.4",
+ "styled-components": "5.3.3"
+ },
+ "engines": {
+ "node": ">=14.19.1 <=18.x.x",
+ "npm": ">=6.0.0"
+ },
+ "strapi": {
+ "displayName": "Roles & Permissions",
+ "name": "users-permissions",
+ "description": "Protect your API with a full authentication process based on JWT. This plugin comes also with an ACL strategy that allows you to manage the permissions between the groups of users.",
+ "required": true,
+ "kind": "plugin"
+ },
+ "gitHead": "6f7c815c2bbe41dda7d77136eb8df736c028ff67"
+}
diff --git a/packages/strapi/src/extensions/users-permissions/server/bootstrap/grant-config.js b/packages/strapi/src/extensions/users-permissions/server/bootstrap/grant-config.js
new file mode 100644
index 0000000..31c612c
--- /dev/null
+++ b/packages/strapi/src/extensions/users-permissions/server/bootstrap/grant-config.js
@@ -0,0 +1,131 @@
+'use strict';
+
+module.exports = (baseURL) => ({
+ email: {
+ enabled: true,
+ icon: 'envelope',
+ },
+ discord: {
+ enabled: false,
+ icon: 'discord',
+ key: '',
+ secret: '',
+ callback: `${baseURL}/discord/callback`,
+ scope: ['identify', 'email'],
+ },
+ facebook: {
+ enabled: false,
+ icon: 'facebook-square',
+ key: '',
+ secret: '',
+ callback: `${baseURL}/facebook/callback`,
+ scope: ['email'],
+ },
+ google: {
+ enabled: false,
+ icon: 'google',
+ key: '',
+ secret: '',
+ callback: `${baseURL}/google/callback`,
+ scope: ['email'],
+ },
+ github: {
+ enabled: false,
+ icon: 'github',
+ key: '',
+ secret: '',
+ callback: `${baseURL}/github/callback`,
+ scope: ['user', 'user:email'],
+ },
+ microsoft: {
+ enabled: false,
+ icon: 'windows',
+ key: '',
+ secret: '',
+ callback: `${baseURL}/microsoft/callback`,
+ scope: ['user.read'],
+ },
+ twitter: {
+ enabled: false,
+ icon: 'twitter',
+ key: '',
+ secret: '',
+ callback: `${baseURL}/twitter/callback`,
+ },
+ instagram: {
+ enabled: false,
+ icon: 'instagram',
+ key: '',
+ secret: '',
+ callback: `${baseURL}/instagram/callback`,
+ scope: ['user_profile'],
+ },
+ vk: {
+ enabled: false,
+ icon: 'vk',
+ key: '',
+ secret: '',
+ callback: `${baseURL}/vk/callback`,
+ scope: ['email'],
+ },
+ twitch: {
+ enabled: false,
+ icon: 'twitch',
+ key: '',
+ secret: '',
+ callback: `${baseURL}/twitch/callback`,
+ scope: ['user:read:email'],
+ },
+ linkedin: {
+ enabled: false,
+ icon: 'linkedin',
+ key: '',
+ secret: '',
+ callback: `${baseURL}/linkedin/callback`,
+ scope: ['r_liteprofile', 'r_emailaddress'],
+ },
+ cognito: {
+ enabled: false,
+ icon: 'aws',
+ key: '',
+ secret: '',
+ subdomain: 'my.subdomain.com',
+ callback: `${baseURL}/cognito/callback`,
+ scope: ['email', 'openid', 'profile'],
+ },
+ reddit: {
+ enabled: false,
+ icon: 'reddit',
+ key: '',
+ secret: '',
+ state: true,
+ callback: `${baseURL}/reddit/callback`,
+ scope: ['identity'],
+ },
+ auth0: {
+ enabled: false,
+ icon: '',
+ key: '',
+ secret: '',
+ subdomain: 'my-tenant.eu',
+ callback: `${baseURL}/auth0/callback`,
+ scope: ['openid', 'email', 'profile'],
+ },
+ cas: {
+ enabled: false,
+ icon: 'book',
+ key: '',
+ secret: '',
+ callback: `${baseURL}/cas/callback`,
+ scope: ['openid email'], // scopes should be space delimited
+ subdomain: 'my.subdomain.com/cas',
+ },
+ patreon: {
+ enabled: false,
+ icon: '',
+ key: '',
+ secret: '',
+ callback: `${baseURL}/patreon/callback`,
+ scope: ['identity', 'identity[email]'],
+ },
+});
diff --git a/packages/strapi/src/extensions/users-permissions/server/bootstrap/index.js b/packages/strapi/src/extensions/users-permissions/server/bootstrap/index.js
new file mode 100644
index 0000000..8d3f020
--- /dev/null
+++ b/packages/strapi/src/extensions/users-permissions/server/bootstrap/index.js
@@ -0,0 +1,133 @@
+'use strict';
+
+/**
+ * An asynchronous bootstrap function that runs before
+ * your application gets started.
+ *
+ * This gives you an opportunity to set up your data model,
+ * run jobs, or perform some special logic.
+ */
+const crypto = require('crypto');
+const _ = require('lodash');
+const urljoin = require('url-join');
+const { getService } = require('../utils');
+const getGrantConfig = require('./grant-config');
+
+const usersPermissionsActions = require('./users-permissions-actions');
+
+const initGrant = async (pluginStore) => {
+ const apiPrefix = strapi.config.get('api.rest.prefix');
+ const baseURL = urljoin(strapi.config.server.url, apiPrefix, 'auth');
+
+ const grantConfig = getGrantConfig(baseURL);
+
+ const prevGrantConfig = (await pluginStore.get({ key: 'grant' })) || {};
+ // store grant auth config to db
+ // when plugin_users-permissions_grant is not existed in db
+ // or we have added/deleted provider here.
+ if (!prevGrantConfig || !_.isEqual(_.keys(prevGrantConfig), _.keys(grantConfig))) {
+ // merge with the previous provider config.
+ _.keys(grantConfig).forEach((key) => {
+ if (key in prevGrantConfig) {
+ grantConfig[key] = _.merge(grantConfig[key], prevGrantConfig[key]);
+ }
+ });
+ await pluginStore.set({ key: 'grant', value: grantConfig });
+ }
+};
+
+const initEmails = async (pluginStore) => {
+ if (!(await pluginStore.get({ key: 'email' }))) {
+ const value = {
+ reset_password: {
+ display: 'Email.template.reset_password',
+ icon: 'sync',
+ options: {
+ from: {
+ name: 'Administration Panel',
+ email: 'no-reply@strapi.io',
+ },
+ response_email: '',
+ object: 'Reset password',
+ message: `We heard that you lost your password. Sorry about that!
+
+But don’t worry! You can use the following link to reset your password:
+<%= URL %>?code=<%= TOKEN %>
+
+Thanks.
`,
+ },
+ },
+ email_confirmation: {
+ display: 'Email.template.email_confirmation',
+ icon: 'check-square',
+ options: {
+ from: {
+ name: 'Administration Panel',
+ email: 'no-reply@strapi.io',
+ },
+ response_email: '',
+ object: 'Account confirmation',
+ message: `Thank you for registering!
+
+You have to confirm your email address. Please click on the link below.
+
+<%= URL %>?confirmation=<%= CODE %>
+
+Thanks.
`,
+ },
+ },
+ };
+
+ await pluginStore.set({ key: 'email', value });
+ }
+};
+
+const initAdvancedOptions = async (pluginStore) => {
+ if (!(await pluginStore.get({ key: 'advanced' }))) {
+ const value = {
+ unique_email: true,
+ allow_register: true,
+ email_confirmation: false,
+ email_reset_password: null,
+ email_confirmation_redirection: null,
+ default_role: 'authenticated',
+ };
+
+ await pluginStore.set({ key: 'advanced', value });
+ }
+};
+
+module.exports = async ({ strapi }) => {
+ const pluginStore = strapi.store({ type: 'plugin', name: 'users-permissions' });
+
+ await initGrant(pluginStore);
+ await initEmails(pluginStore);
+ await initAdvancedOptions(pluginStore);
+
+ await strapi.admin.services.permission.actionProvider.registerMany(
+ usersPermissionsActions.actions
+ );
+
+ await getService('users-permissions').initialize();
+
+ if (!strapi.config.get('plugin.users-permissions.jwtSecret')) {
+ if (process.env.NODE_ENV !== 'development') {
+ throw new Error(
+ `Missing jwtSecret. Please, set configuration variable "jwtSecret" for the users-permissions plugin in config/plugins.js (ex: you can generate one using Node with \`crypto.randomBytes(16).toString('base64')\`).
+For security reasons, prefer storing the secret in an environment variable and read it in config/plugins.js. See https://docs.strapi.io/developer-docs/latest/setup-deployment-guides/configurations/optional/environment.html#configuration-using-environment-variables.`
+ );
+ }
+
+ const jwtSecret = crypto.randomBytes(16).toString('base64');
+
+ strapi.config.set('plugin.users-permissions.jwtSecret', jwtSecret);
+
+ if (!process.env.JWT_SECRET) {
+ const envPath = process.env.ENV_PATH || '.env';
+ strapi.fs.appendFile(envPath, `JWT_SECRET=${jwtSecret}\n`);
+ strapi.log.info(
+ `The Users & Permissions plugin automatically generated a jwt secret and stored it in ${envPath} under the name JWT_SECRET.`
+ );
+ }
+ }
+};
diff --git a/packages/strapi/src/extensions/users-permissions/server/bootstrap/users-permissions-actions.js b/packages/strapi/src/extensions/users-permissions/server/bootstrap/users-permissions-actions.js
new file mode 100644
index 0000000..f017103
--- /dev/null
+++ b/packages/strapi/src/extensions/users-permissions/server/bootstrap/users-permissions-actions.js
@@ -0,0 +1,80 @@
+'use strict';
+
+module.exports = {
+ actions: [
+ {
+ // Roles
+ section: 'plugins',
+ displayName: 'Create',
+ uid: 'roles.create',
+ subCategory: 'roles',
+ pluginName: 'users-permissions',
+ },
+ {
+ section: 'plugins',
+ displayName: 'Read',
+ uid: 'roles.read',
+ subCategory: 'roles',
+ pluginName: 'users-permissions',
+ },
+ {
+ section: 'plugins',
+ displayName: 'Update',
+ uid: 'roles.update',
+ subCategory: 'roles',
+ pluginName: 'users-permissions',
+ },
+ {
+ section: 'plugins',
+ displayName: 'Delete',
+ uid: 'roles.delete',
+ subCategory: 'roles',
+ pluginName: 'users-permissions',
+ },
+ {
+ // providers
+ section: 'plugins',
+ displayName: 'Read',
+ uid: 'providers.read',
+ subCategory: 'providers',
+ pluginName: 'users-permissions',
+ },
+ {
+ section: 'plugins',
+ displayName: 'Edit',
+ uid: 'providers.update',
+ subCategory: 'providers',
+ pluginName: 'users-permissions',
+ },
+ {
+ // emailTemplates
+ section: 'plugins',
+ displayName: 'Read',
+ uid: 'email-templates.read',
+ subCategory: 'emailTemplates',
+ pluginName: 'users-permissions',
+ },
+ {
+ section: 'plugins',
+ displayName: 'Edit',
+ uid: 'email-templates.update',
+ subCategory: 'emailTemplates',
+ pluginName: 'users-permissions',
+ },
+ {
+ // advancedSettings
+ section: 'plugins',
+ displayName: 'Read',
+ uid: 'advanced-settings.read',
+ subCategory: 'advancedSettings',
+ pluginName: 'users-permissions',
+ },
+ {
+ section: 'plugins',
+ displayName: 'Edit',
+ uid: 'advanced-settings.update',
+ subCategory: 'advancedSettings',
+ pluginName: 'users-permissions',
+ },
+ ],
+};
diff --git a/packages/strapi/src/extensions/users-permissions/server/config.js b/packages/strapi/src/extensions/users-permissions/server/config.js
new file mode 100644
index 0000000..05b16a8
--- /dev/null
+++ b/packages/strapi/src/extensions/users-permissions/server/config.js
@@ -0,0 +1,23 @@
+'use strict';
+
+module.exports = {
+ default: ({ env }) => ({
+ jwtSecret: env('JWT_SECRET'),
+ jwt: {
+ expiresIn: '30d',
+ },
+ ratelimit: {
+ interval: 60000,
+ max: 10,
+ },
+ layout: {
+ user: {
+ actions: {
+ create: 'contentManagerUser.create', // Use the User plugin's controller.
+ update: 'contentManagerUser.update',
+ },
+ },
+ },
+ }),
+ validator() {},
+};
diff --git a/packages/strapi/src/extensions/users-permissions/server/content-types/index.js b/packages/strapi/src/extensions/users-permissions/server/content-types/index.js
new file mode 100644
index 0000000..8476e7d
--- /dev/null
+++ b/packages/strapi/src/extensions/users-permissions/server/content-types/index.js
@@ -0,0 +1,11 @@
+'use strict';
+
+const permission = require('./permission');
+const role = require('./role');
+const user = require('./user');
+
+module.exports = {
+ permission: { schema: permission },
+ role: { schema: role },
+ user: { schema: user },
+};
diff --git a/packages/strapi/src/extensions/users-permissions/server/content-types/permission/index.js b/packages/strapi/src/extensions/users-permissions/server/content-types/permission/index.js
new file mode 100644
index 0000000..70648c8
--- /dev/null
+++ b/packages/strapi/src/extensions/users-permissions/server/content-types/permission/index.js
@@ -0,0 +1,34 @@
+'use strict';
+
+module.exports = {
+ collectionName: 'up_permissions',
+ info: {
+ name: 'permission',
+ description: '',
+ singularName: 'permission',
+ pluralName: 'permissions',
+ displayName: 'Permission',
+ },
+ pluginOptions: {
+ 'content-manager': {
+ visible: false,
+ },
+ 'content-type-builder': {
+ visible: false,
+ },
+ },
+ attributes: {
+ action: {
+ type: 'string',
+ required: true,
+ configurable: false,
+ },
+ role: {
+ type: 'relation',
+ relation: 'manyToOne',
+ target: 'plugin::users-permissions.role',
+ inversedBy: 'permissions',
+ configurable: false,
+ },
+ },
+};
diff --git a/packages/strapi/src/extensions/users-permissions/server/content-types/role/index.js b/packages/strapi/src/extensions/users-permissions/server/content-types/role/index.js
new file mode 100644
index 0000000..ceb45c6
--- /dev/null
+++ b/packages/strapi/src/extensions/users-permissions/server/content-types/role/index.js
@@ -0,0 +1,51 @@
+'use strict';
+
+module.exports = {
+ collectionName: 'up_roles',
+ info: {
+ name: 'role',
+ description: '',
+ singularName: 'role',
+ pluralName: 'roles',
+ displayName: 'Role',
+ },
+ pluginOptions: {
+ 'content-manager': {
+ visible: false,
+ },
+ 'content-type-builder': {
+ visible: false,
+ },
+ },
+ attributes: {
+ name: {
+ type: 'string',
+ minLength: 3,
+ required: true,
+ configurable: false,
+ },
+ description: {
+ type: 'string',
+ configurable: false,
+ },
+ type: {
+ type: 'string',
+ unique: true,
+ configurable: false,
+ },
+ permissions: {
+ type: 'relation',
+ relation: 'oneToMany',
+ target: 'plugin::users-permissions.permission',
+ mappedBy: 'role',
+ configurable: false,
+ },
+ users: {
+ type: 'relation',
+ relation: 'oneToMany',
+ target: 'plugin::users-permissions.user',
+ mappedBy: 'role',
+ configurable: false,
+ },
+ },
+};
diff --git a/packages/strapi/src/extensions/users-permissions/server/content-types/user/index.js b/packages/strapi/src/extensions/users-permissions/server/content-types/user/index.js
new file mode 100644
index 0000000..d999d98
--- /dev/null
+++ b/packages/strapi/src/extensions/users-permissions/server/content-types/user/index.js
@@ -0,0 +1,75 @@
+'use strict';
+
+const schemaConfig = require('./schema-config');
+
+module.exports = {
+ collectionName: 'up_users',
+ info: {
+ name: 'user',
+ description: '',
+ singularName: 'user',
+ pluralName: 'users',
+ displayName: 'User',
+ },
+ options: {
+ draftAndPublish: false,
+ timestamps: true,
+ },
+ attributes: {
+ username: {
+ type: 'string',
+ minLength: 3,
+ unique: true,
+ configurable: false,
+ required: true,
+ },
+ email: {
+ type: 'email',
+ minLength: 6,
+ configurable: false,
+ required: true,
+ },
+ provider: {
+ type: 'string',
+ configurable: false,
+ },
+ password: {
+ type: 'password',
+ minLength: 6,
+ configurable: false,
+ private: true,
+ searchable: false,
+ },
+ resetPasswordToken: {
+ type: 'string',
+ configurable: false,
+ private: true,
+ searchable: false,
+ },
+ confirmationToken: {
+ type: 'string',
+ configurable: false,
+ private: true,
+ searchable: false,
+ },
+ confirmed: {
+ type: 'boolean',
+ default: false,
+ configurable: false,
+ },
+ blocked: {
+ type: 'boolean',
+ default: false,
+ configurable: false,
+ },
+ role: {
+ type: 'relation',
+ relation: 'manyToOne',
+ target: 'plugin::users-permissions.role',
+ inversedBy: 'users',
+ configurable: false,
+ },
+ },
+
+ config: schemaConfig, // TODO: to move to content-manager options
+};
diff --git a/packages/strapi/src/extensions/users-permissions/server/content-types/user/schema-config.js b/packages/strapi/src/extensions/users-permissions/server/content-types/user/schema-config.js
new file mode 100644
index 0000000..7442cd1
--- /dev/null
+++ b/packages/strapi/src/extensions/users-permissions/server/content-types/user/schema-config.js
@@ -0,0 +1,15 @@
+'use strict';
+
+module.exports = {
+ attributes: {
+ resetPasswordToken: {
+ hidden: true,
+ },
+ confirmationToken: {
+ hidden: true,
+ },
+ provider: {
+ hidden: true,
+ },
+ },
+};
diff --git a/packages/strapi/src/extensions/users-permissions/server/controllers/auth.js b/packages/strapi/src/extensions/users-permissions/server/controllers/auth.js
new file mode 100644
index 0000000..02821f7
--- /dev/null
+++ b/packages/strapi/src/extensions/users-permissions/server/controllers/auth.js
@@ -0,0 +1,416 @@
+'use strict';
+
+/**
+ * Auth.js controller
+ *
+ * @description: A set of functions called "actions" for managing `Auth`.
+ */
+
+/* eslint-disable no-useless-escape */
+const crypto = require('crypto');
+const _ = require('lodash');
+const utils = require('@strapi/utils');
+const { getService } = require('../utils');
+const {
+ validateCallbackBody,
+ validateRegisterBody,
+ validateSendEmailConfirmationBody,
+ validateForgotPasswordBody,
+ validateResetPasswordBody,
+ validateEmailConfirmationBody,
+ validateChangePasswordBody,
+} = require('./validation/auth');
+
+const { getAbsoluteAdminUrl, getAbsoluteServerUrl, sanitize } = utils;
+const { ApplicationError, ValidationError } = utils.errors;
+
+const sanitizeUser = (user, ctx) => {
+ const { auth } = ctx.state;
+ const userSchema = strapi.getModel('plugin::users-permissions.user');
+
+ return sanitize.contentAPI.output(user, userSchema, { auth });
+};
+
+module.exports = {
+ async callback(ctx) {
+ const provider = ctx.params.provider || 'local';
+ const params = ctx.request.body;
+
+ const store = strapi.store({ type: 'plugin', name: 'users-permissions' });
+ const grantSettings = await store.get({ key: 'grant' });
+
+ const grantProvider = provider === 'local' ? 'email' : provider;
+
+ if (!_.get(grantSettings, [grantProvider, 'enabled'])) {
+ throw new ApplicationError('This provider is disabled');
+ }
+
+ if (provider === 'local') {
+ await validateCallbackBody(params);
+
+ const { identifier } = params;
+
+ // Check if the user exists.
+ const user = await strapi.query('plugin::users-permissions.user').findOne({
+ where: {
+ provider,
+ $or: [{ email: identifier.toLowerCase() }, { username: identifier }],
+ },
+ });
+
+ if (!user) {
+ throw new ValidationError('Invalid identifier or password');
+ }
+
+ if (!user.password) {
+ throw new ValidationError('Invalid identifier or password');
+ }
+
+ const validPassword = await getService('user').validatePassword(
+ params.password,
+ user.password
+ );
+
+ if (!validPassword) {
+ throw new ValidationError('Invalid identifier or password');
+ }
+
+ const advancedSettings = await store.get({ key: 'advanced' });
+ const requiresConfirmation = _.get(advancedSettings, 'email_confirmation');
+
+ if (requiresConfirmation && user.confirmed !== true) {
+ throw new ApplicationError('Your account email is not confirmed');
+ }
+
+ if (user.blocked === true) {
+ throw new ApplicationError('Your account has been blocked by an administrator');
+ }
+
+ return ctx.send({
+ jwt: getService('jwt').issue({ id: user.id }),
+ user: await sanitizeUser(user, ctx),
+ });
+ }
+
+ // Connect the user with the third-party provider.
+ try {
+ const user = await getService('providers').connect(provider, ctx.query);
+
+ return ctx.send({
+ jwt: getService('jwt').issue({ id: user.id }),
+ user: await sanitizeUser(user, ctx),
+ });
+ } catch (error) {
+ throw new ApplicationError(error.message);
+ }
+ },
+
+ async changePassword(ctx) {
+ if (!ctx.state.user) {
+ throw new ApplicationError('You must be authenticated to reset your password');
+ }
+
+ const { currentPassword, password } = await validateChangePasswordBody(ctx.request.body);
+
+ const user = await strapi.entityService.findOne(
+ 'plugin::users-permissions.user',
+ ctx.state.user.id
+ );
+
+ const validPassword = await getService('user').validatePassword(currentPassword, user.password);
+
+ if (!validPassword) {
+ throw new ValidationError('The provided current password is invalid');
+ }
+
+ if (currentPassword === password) {
+ throw new ValidationError('Your new password must be different than your current password');
+ }
+
+ await getService('user').edit(user.id, { password });
+
+ ctx.send({
+ jwt: getService('jwt').issue({ id: user.id }),
+ user: await sanitizeUser(user, ctx),
+ });
+ },
+
+ async resetPassword(ctx) {
+ const { password, passwordConfirmation, code } = await validateResetPasswordBody(
+ ctx.request.body
+ );
+
+ if (password !== passwordConfirmation) {
+ throw new ValidationError('Passwords do not match');
+ }
+
+ const user = await strapi
+ .query('plugin::users-permissions.user')
+ .findOne({ where: { resetPasswordToken: code } });
+
+ if (!user) {
+ throw new ValidationError('Incorrect code provided');
+ }
+
+ await getService('user').edit(user.id, {
+ resetPasswordToken: null,
+ password,
+ });
+
+ // Update the user.
+ ctx.send({
+ jwt: getService('jwt').issue({ id: user.id }),
+ user: await sanitizeUser(user, ctx),
+ });
+ },
+
+ async connect(ctx, next) {
+ const grant = require('grant-koa');
+
+ const providers = await strapi
+ .store({ type: 'plugin', name: 'users-permissions', key: 'grant' })
+ .get();
+
+ const apiPrefix = strapi.config.get('api.rest.prefix');
+ const grantConfig = {
+ defaults: {
+ prefix: `${apiPrefix}/connect`,
+ },
+ ...providers,
+ };
+
+ const [requestPath] = ctx.request.url.split('?');
+ const provider = requestPath.split('/connect/')[1].split('/')[0];
+
+ if (!_.get(grantConfig[provider], 'enabled')) {
+ throw new ApplicationError('This provider is disabled');
+ }
+
+ if (!strapi.config.server.url.startsWith('http')) {
+ strapi.log.warn(
+ 'You are using a third party provider for login. Make sure to set an absolute url in config/server.js. More info here: https://docs.strapi.io/developer-docs/latest/plugins/users-permissions.html#setting-up-the-server-url'
+ );
+ }
+
+ // Ability to pass OAuth callback dynamically
+ grantConfig[provider].callback =
+ _.get(ctx, 'query.callback') ||
+ _.get(ctx, 'session.grant.dynamic.callback') ||
+ grantConfig[provider].callback;
+ grantConfig[provider].redirect_uri = getService('providers').buildRedirectUri(provider);
+
+ return grant(grantConfig)(ctx, next);
+ },
+
+ async forgotPassword(ctx) {
+ const { email } = await validateForgotPasswordBody(ctx.request.body);
+
+ const pluginStore = await strapi.store({ type: 'plugin', name: 'users-permissions' });
+
+ const emailSettings = await pluginStore.get({ key: 'email' });
+ const advancedSettings = await pluginStore.get({ key: 'advanced' });
+
+ // Find the user by email.
+ const user = await strapi
+ .query('plugin::users-permissions.user')
+ .findOne({ where: { email: email.toLowerCase() } });
+
+ if (!user || user.blocked) {
+ return ctx.send({ ok: true });
+ }
+
+ // Generate random token.
+ const userInfo = await sanitizeUser(user, ctx);
+
+ const resetPasswordToken = crypto.randomBytes(64).toString('hex');
+
+ const resetPasswordSettings = _.get(emailSettings, 'reset_password.options', {});
+ const emailBody = await getService('users-permissions').template(
+ resetPasswordSettings.message,
+ {
+ URL: advancedSettings.email_reset_password,
+ SERVER_URL: getAbsoluteServerUrl(strapi.config),
+ ADMIN_URL: getAbsoluteAdminUrl(strapi.config),
+ USER: userInfo,
+ TOKEN: resetPasswordToken,
+ }
+ );
+
+ const emailObject = await getService('users-permissions').template(
+ resetPasswordSettings.object,
+ {
+ USER: userInfo,
+ }
+ );
+
+ const emailToSend = {
+ to: user.email,
+ from:
+ resetPasswordSettings.from.email || resetPasswordSettings.from.name
+ ? `${resetPasswordSettings.from.name} <${resetPasswordSettings.from.email}>`
+ : undefined,
+ replyTo: resetPasswordSettings.response_email,
+ subject: emailObject,
+ text: emailBody,
+ html: emailBody,
+ };
+
+ // NOTE: Update the user before sending the email so an Admin can generate the link if the email fails
+ await getService('user').edit(user.id, { resetPasswordToken });
+
+ // Send an email to the user.
+ await strapi.plugin('email').service('email').send(emailToSend);
+
+ ctx.send({ ok: true });
+ },
+
+ async register(ctx) {
+ const pluginStore = await strapi.store({ type: 'plugin', name: 'users-permissions' });
+
+ const settings = await pluginStore.get({ key: 'advanced' });
+
+ if (!settings.allow_register) {
+ throw new ApplicationError('Register action is currently disabled');
+ }
+
+ const params = {
+ ..._.omit(ctx.request.body, [
+ 'confirmed',
+ 'blocked',
+ 'confirmationToken',
+ 'resetPasswordToken',
+ 'provider',
+ 'id',
+ 'createdAt',
+ 'updatedAt',
+ 'createdBy',
+ 'updatedBy',
+ 'role',
+ ]),
+ provider: 'local',
+ };
+
+ await validateRegisterBody(params);
+
+ const role = await strapi
+ .query('plugin::users-permissions.role')
+ .findOne({ where: { type: settings.default_role } });
+
+ if (!role) {
+ throw new ApplicationError('Impossible to find the default role');
+ }
+
+ const { email, username, provider } = params;
+
+ const identifierFilter = {
+ $or: [
+ { email: email.toLowerCase() },
+ { username: email.toLowerCase() },
+ { username },
+ { email: username },
+ ],
+ };
+
+ const conflictingUserCount = await strapi.query('plugin::users-permissions.user').count({
+ where: { ...identifierFilter, provider },
+ });
+
+ if (conflictingUserCount > 0) {
+ throw new ApplicationError('Email or Username are already taken');
+ }
+
+ if (settings.unique_email) {
+ const conflictingUserCount = await strapi.query('plugin::users-permissions.user').count({
+ where: { ...identifierFilter },
+ });
+
+ if (conflictingUserCount > 0) {
+ throw new ApplicationError('Email or Username are already taken');
+ }
+ }
+
+ const newUser = {
+ ...params,
+ role: role.id,
+ email: email.toLowerCase(),
+ username,
+ confirmed: !settings.email_confirmation,
+ };
+
+ const user = await getService('user').add(newUser);
+
+ const sanitizedUser = await sanitizeUser(user, ctx);
+
+ if (settings.email_confirmation) {
+ try {
+ await getService('user').sendConfirmationEmail(sanitizedUser);
+ } catch (err) {
+ throw new ApplicationError(err.message);
+ }
+
+ return ctx.send({ user: sanitizedUser });
+ }
+
+ const jwt = getService('jwt').issue(_.pick(user, ['id']));
+
+ return ctx.send({
+ jwt,
+ user: sanitizedUser,
+ });
+ },
+
+ async emailConfirmation(ctx, next, returnUser) {
+ const { confirmation: confirmationToken } = await validateEmailConfirmationBody(ctx.query);
+
+ const userService = getService('user');
+ const jwtService = getService('jwt');
+
+ const [user] = await userService.fetchAll({ filters: { confirmationToken } });
+
+ if (!user) {
+ throw new ValidationError('Invalid token');
+ }
+
+ await userService.edit(user.id, { confirmed: true, confirmationToken: null });
+
+ if (returnUser) {
+ ctx.send({
+ jwt: jwtService.issue({ id: user.id }),
+ user: await sanitizeUser(user, ctx),
+ });
+ } else {
+ const settings = await strapi
+ .store({ type: 'plugin', name: 'users-permissions', key: 'advanced' })
+ .get();
+
+ ctx.redirect(settings.email_confirmation_redirection || '/');
+ }
+ },
+
+ async sendEmailConfirmation(ctx) {
+ const { email } = await validateSendEmailConfirmationBody(ctx.request.body);
+
+ const user = await strapi.query('plugin::users-permissions.user').findOne({
+ where: { email: email.toLowerCase() },
+ });
+
+ if (!user) {
+ return ctx.send({ email, sent: true });
+ }
+
+ if (user.confirmed) {
+ throw new ApplicationError('Already confirmed');
+ }
+
+ if (user.blocked) {
+ throw new ApplicationError('User blocked');
+ }
+
+ await getService('user').sendConfirmationEmail(user);
+
+ ctx.send({
+ email: user.email,
+ sent: true,
+ });
+ },
+};
diff --git a/packages/strapi/src/extensions/users-permissions/server/controllers/content-manager-user.js b/packages/strapi/src/extensions/users-permissions/server/controllers/content-manager-user.js
new file mode 100644
index 0000000..b6e10cd
--- /dev/null
+++ b/packages/strapi/src/extensions/users-permissions/server/controllers/content-manager-user.js
@@ -0,0 +1,175 @@
+'use strict';
+
+const _ = require('lodash');
+const { contentTypes: contentTypesUtils } = require('@strapi/utils');
+const { ApplicationError, ValidationError, NotFoundError, ForbiddenError } =
+ require('@strapi/utils').errors;
+const { validateCreateUserBody, validateUpdateUserBody } = require('./validation/user');
+
+const { UPDATED_BY_ATTRIBUTE, CREATED_BY_ATTRIBUTE } = contentTypesUtils.constants;
+
+const userModel = 'plugin::users-permissions.user';
+const ACTIONS = {
+ read: 'plugin::content-manager.explorer.read',
+ create: 'plugin::content-manager.explorer.create',
+ edit: 'plugin::content-manager.explorer.update',
+ delete: 'plugin::content-manager.explorer.delete',
+};
+
+const findEntityAndCheckPermissions = async (ability, action, model, id) => {
+ const entity = await strapi.query(userModel).findOne({
+ where: { id },
+ populate: [`${CREATED_BY_ATTRIBUTE}.roles`],
+ });
+
+ if (_.isNil(entity)) {
+ throw new NotFoundError();
+ }
+
+ const pm = strapi.admin.services.permission.createPermissionsManager({ ability, action, model });
+
+ if (pm.ability.cannot(pm.action, pm.toSubject(entity))) {
+ throw new ForbiddenError();
+ }
+
+ const entityWithoutCreatorRoles = _.omit(entity, `${CREATED_BY_ATTRIBUTE}.roles`);
+
+ return { pm, entity: entityWithoutCreatorRoles };
+};
+
+module.exports = {
+ /**
+ * Create a/an user record.
+ * @return {Object}
+ */
+ async create(ctx) {
+ const { body } = ctx.request;
+ const { user: admin, userAbility } = ctx.state;
+
+ const { email, username } = body;
+
+ const pm = strapi.admin.services.permission.createPermissionsManager({
+ ability: userAbility,
+ action: ACTIONS.create,
+ model: userModel,
+ });
+
+ if (!pm.isAllowed) {
+ return ctx.forbidden();
+ }
+
+ const sanitizedBody = await pm.pickPermittedFieldsOf(body, { subject: userModel });
+
+ const advanced = await strapi
+ .store({ type: 'plugin', name: 'users-permissions', key: 'advanced' })
+ .get();
+
+ await validateCreateUserBody(ctx.request.body);
+
+ const userWithSameUsername = await strapi
+ .query('plugin::users-permissions.user')
+ .findOne({ where: { username } });
+
+ if (userWithSameUsername) {
+ throw new ApplicationError('Username already taken');
+ }
+
+ if (advanced.unique_email) {
+ const userWithSameEmail = await strapi
+ .query('plugin::users-permissions.user')
+ .findOne({ where: { email: email.toLowerCase() } });
+
+ if (userWithSameEmail) {
+ throw new ApplicationError('Email already taken');
+ }
+ }
+
+ const user = {
+ ...sanitizedBody,
+ provider: 'local',
+ [CREATED_BY_ATTRIBUTE]: admin.id,
+ [UPDATED_BY_ATTRIBUTE]: admin.id,
+ };
+
+ user.email = _.toLower(user.email);
+
+ if (!user.role) {
+ const defaultRole = await strapi
+ .query('plugin::users-permissions.role')
+ .findOne({ where: { type: advanced.default_role } });
+
+ user.role = defaultRole.id;
+ }
+
+ try {
+ const data = await strapi
+ .service('plugin::content-manager.entity-manager')
+ .create(user, userModel);
+ const sanitizedData = await pm.sanitizeOutput(data, { action: ACTIONS.read });
+
+ ctx.created(sanitizedData);
+ } catch (error) {
+ throw new ApplicationError(error.message);
+ }
+ },
+ /**
+ * Update a/an user record.
+ * @return {Object}
+ */
+
+ async update(ctx) {
+ const { id } = ctx.params;
+ const { body } = ctx.request;
+ const { user: admin, userAbility } = ctx.state;
+
+ const advancedConfigs = await strapi
+ .store({ type: 'plugin', name: 'users-permissions', key: 'advanced' })
+ .get();
+
+ const { email, username, password } = body;
+
+ const { pm, entity } = await findEntityAndCheckPermissions(
+ userAbility,
+ ACTIONS.edit,
+ userModel,
+ id
+ );
+ const user = entity;
+
+ await validateUpdateUserBody(ctx.request.body);
+
+ if (_.has(body, 'password') && !password && user.provider === 'local') {
+ throw new ValidationError('password.notNull');
+ }
+
+ if (_.has(body, 'username')) {
+ const userWithSameUsername = await strapi
+ .query('plugin::users-permissions.user')
+ .findOne({ where: { username } });
+
+ if (userWithSameUsername && _.toString(userWithSameUsername.id) !== _.toString(id)) {
+ throw new ApplicationError('Username already taken');
+ }
+ }
+
+ if (_.has(body, 'email') && advancedConfigs.unique_email) {
+ const userWithSameEmail = await strapi
+ .query('plugin::users-permissions.user')
+ .findOne({ where: { email: _.toLower(email) } });
+
+ if (userWithSameEmail && _.toString(userWithSameEmail.id) !== _.toString(id)) {
+ throw new ApplicationError('Email already taken');
+ }
+ body.email = _.toLower(body.email);
+ }
+
+ const sanitizedData = await pm.pickPermittedFieldsOf(body, { subject: pm.toSubject(user) });
+ const updateData = _.omit({ ...sanitizedData, updatedBy: admin.id }, 'createdBy');
+
+ const data = await strapi
+ .service('plugin::content-manager.entity-manager')
+ .update({ id }, updateData, userModel);
+
+ ctx.body = await pm.sanitizeOutput(data, { action: ACTIONS.read });
+ },
+};
diff --git a/packages/strapi/src/extensions/users-permissions/server/controllers/index.js b/packages/strapi/src/extensions/users-permissions/server/controllers/index.js
new file mode 100644
index 0000000..8a02508
--- /dev/null
+++ b/packages/strapi/src/extensions/users-permissions/server/controllers/index.js
@@ -0,0 +1,17 @@
+'use strict';
+
+const auth = require('./auth');
+const user = require('./user');
+const role = require('./role');
+const permissions = require('./permissions');
+const settings = require('./settings');
+const contentmanageruser = require('./content-manager-user');
+
+module.exports = {
+ auth,
+ user,
+ role,
+ permissions,
+ settings,
+ contentmanageruser,
+};
diff --git a/packages/strapi/src/extensions/users-permissions/server/controllers/permissions.js b/packages/strapi/src/extensions/users-permissions/server/controllers/permissions.js
new file mode 100644
index 0000000..3213215
--- /dev/null
+++ b/packages/strapi/src/extensions/users-permissions/server/controllers/permissions.js
@@ -0,0 +1,26 @@
+'use strict';
+
+const _ = require('lodash');
+const { getService } = require('../utils');
+
+module.exports = {
+ async getPermissions(ctx) {
+ const permissions = await getService('users-permissions').getActions();
+
+ ctx.send({ permissions });
+ },
+
+ async getPolicies(ctx) {
+ const policies = _.keys(strapi.plugin('users-permissions').policies);
+
+ ctx.send({
+ policies: _.without(policies, 'permissions'),
+ });
+ },
+
+ async getRoutes(ctx) {
+ const routes = await getService('users-permissions').getRoutes();
+
+ ctx.send({ routes });
+ },
+};
diff --git a/packages/strapi/src/extensions/users-permissions/server/controllers/role.js b/packages/strapi/src/extensions/users-permissions/server/controllers/role.js
new file mode 100644
index 0000000..a31c86f
--- /dev/null
+++ b/packages/strapi/src/extensions/users-permissions/server/controllers/role.js
@@ -0,0 +1,77 @@
+'use strict';
+
+const _ = require('lodash');
+const { ApplicationError, ValidationError } = require('@strapi/utils').errors;
+const { getService } = require('../utils');
+const { validateDeleteRoleBody } = require('./validation/user');
+
+module.exports = {
+ /**
+ * Default action.
+ *
+ * @return {Object}
+ */
+ async createRole(ctx) {
+ if (_.isEmpty(ctx.request.body)) {
+ throw new ValidationError('Request body cannot be empty');
+ }
+
+ await getService('role').createRole(ctx.request.body);
+
+ ctx.send({ ok: true });
+ },
+
+ async findOne(ctx) {
+ const { id } = ctx.params;
+
+ const role = await getService('role').findOne(id);
+
+ if (!role) {
+ return ctx.notFound();
+ }
+
+ ctx.send({ role });
+ },
+
+ async find(ctx) {
+ const roles = await getService('role').find();
+
+ ctx.send({ roles });
+ },
+
+ async updateRole(ctx) {
+ const roleID = ctx.params.role;
+
+ if (_.isEmpty(ctx.request.body)) {
+ throw new ValidationError('Request body cannot be empty');
+ }
+
+ await getService('role').updateRole(roleID, ctx.request.body);
+
+ ctx.send({ ok: true });
+ },
+
+ async deleteRole(ctx) {
+ const roleID = ctx.params.role;
+
+ if (!roleID) {
+ await validateDeleteRoleBody(ctx.params);
+ }
+
+ // Fetch public role.
+ const publicRole = await strapi
+ .query('plugin::users-permissions.role')
+ .findOne({ where: { type: 'public' } });
+
+ const publicRoleID = publicRole.id;
+
+ // Prevent from removing the public role.
+ if (roleID.toString() === publicRoleID.toString()) {
+ throw new ApplicationError('Cannot delete public role');
+ }
+
+ await getService('role').deleteRole(roleID, publicRoleID);
+
+ ctx.send({ ok: true });
+ },
+};
diff --git a/packages/strapi/src/extensions/users-permissions/server/controllers/settings.js b/packages/strapi/src/extensions/users-permissions/server/controllers/settings.js
new file mode 100644
index 0000000..1ae8ab2
--- /dev/null
+++ b/packages/strapi/src/extensions/users-permissions/server/controllers/settings.js
@@ -0,0 +1,85 @@
+'use strict';
+
+const _ = require('lodash');
+const { ValidationError } = require('@strapi/utils').errors;
+const { getService } = require('../utils');
+const { isValidEmailTemplate } = require('./validation/email-template');
+
+module.exports = {
+ async getEmailTemplate(ctx) {
+ ctx.send(await strapi.store({ type: 'plugin', name: 'users-permissions', key: 'email' }).get());
+ },
+
+ async updateEmailTemplate(ctx) {
+ if (_.isEmpty(ctx.request.body)) {
+ throw new ValidationError('Request body cannot be empty');
+ }
+
+ const emailTemplates = ctx.request.body['email-templates'];
+
+ for (const key of Object.keys(emailTemplates)) {
+ const template = emailTemplates[key].options.message;
+
+ if (!isValidEmailTemplate(template)) {
+ throw new ValidationError('Invalid template');
+ }
+ }
+
+ await strapi
+ .store({ type: 'plugin', name: 'users-permissions', key: 'email' })
+ .set({ value: emailTemplates });
+
+ ctx.send({ ok: true });
+ },
+
+ async getAdvancedSettings(ctx) {
+ const settings = await strapi
+ .store({ type: 'plugin', name: 'users-permissions', key: 'advanced' })
+ .get();
+
+ const roles = await getService('role').find();
+
+ ctx.send({ settings, roles });
+ },
+
+ async updateAdvancedSettings(ctx) {
+ if (_.isEmpty(ctx.request.body)) {
+ throw new ValidationError('Request body cannot be empty');
+ }
+
+ await strapi
+ .store({ type: 'plugin', name: 'users-permissions', key: 'advanced' })
+ .set({ value: ctx.request.body });
+
+ ctx.send({ ok: true });
+ },
+
+ async getProviders(ctx) {
+ const providers = await strapi
+ .store({ type: 'plugin', name: 'users-permissions', key: 'grant' })
+ .get();
+
+ for (const provider in providers) {
+ if (provider !== 'email') {
+ providers[provider].redirectUri = strapi
+ .plugin('users-permissions')
+ .service('providers')
+ .buildRedirectUri(provider);
+ }
+ }
+
+ ctx.send(providers);
+ },
+
+ async updateProviders(ctx) {
+ if (_.isEmpty(ctx.request.body)) {
+ throw new ValidationError('Request body cannot be empty');
+ }
+
+ await strapi
+ .store({ type: 'plugin', name: 'users-permissions', key: 'grant' })
+ .set({ value: ctx.request.body.providers });
+
+ ctx.send({ ok: true });
+ },
+};
diff --git a/packages/strapi/src/extensions/users-permissions/server/controllers/user.js b/packages/strapi/src/extensions/users-permissions/server/controllers/user.js
new file mode 100644
index 0000000..1b45e05
--- /dev/null
+++ b/packages/strapi/src/extensions/users-permissions/server/controllers/user.js
@@ -0,0 +1,209 @@
+'use strict';
+
+/**
+ * User.js controller
+ *
+ * @description: A set of functions called "actions" for managing `User`.
+ */
+
+const _ = require('lodash');
+const utils = require('@strapi/utils');
+const { getService } = require('../utils');
+const { validateCreateUserBody, validateUpdateUserBody } = require('./validation/user');
+
+const { sanitize } = utils;
+const { ApplicationError, ValidationError, NotFoundError } = utils.errors;
+
+const sanitizeOutput = async (user, ctx) => {
+ const schema = strapi.getModel('plugin::users-permissions.user');
+ const { auth } = ctx.state;
+
+ return sanitize.contentAPI.output(user, schema, { auth });
+};
+
+const sanitizeQuery = async (query, ctx) => {
+ const schema = strapi.getModel('plugin::users-permissions.user');
+ const { auth } = ctx.state;
+
+ return sanitize.contentAPI.query(query, schema, { auth });
+};
+
+module.exports = {
+ /**
+ * Create a/an user record.
+ * @return {Object}
+ */
+ async create(ctx) {
+ const advanced = await strapi
+ .store({ type: 'plugin', name: 'users-permissions', key: 'advanced' })
+ .get();
+
+ await validateCreateUserBody(ctx.request.body);
+
+ const { email, username, role } = ctx.request.body;
+
+ const userWithSameUsername = await strapi
+ .query('plugin::users-permissions.user')
+ .findOne({ where: { username } });
+
+ if (userWithSameUsername) {
+ if (!email) throw new ApplicationError('Username already taken');
+ }
+
+ if (advanced.unique_email) {
+ const userWithSameEmail = await strapi
+ .query('plugin::users-permissions.user')
+ .findOne({ where: { email: email.toLowerCase() } });
+
+ if (userWithSameEmail) {
+ throw new ApplicationError('Email already taken');
+ }
+ }
+
+ const user = {
+ ...ctx.request.body,
+ email: email.toLowerCase(),
+ provider: 'local',
+ };
+
+ if (!role) {
+ const defaultRole = await strapi
+ .query('plugin::users-permissions.role')
+ .findOne({ where: { type: advanced.default_role } });
+
+ user.role = defaultRole.id;
+ }
+
+ try {
+ const data = await getService('user').add(user);
+ const sanitizedData = await sanitizeOutput(data, ctx);
+
+ ctx.created(sanitizedData);
+ } catch (error) {
+ throw new ApplicationError(error.message);
+ }
+ },
+
+ /**
+ * Update a/an user record.
+ * @return {Object}
+ */
+ async update(ctx) {
+ const advancedConfigs = await strapi
+ .store({ type: 'plugin', name: 'users-permissions', key: 'advanced' })
+ .get();
+
+ const { id } = ctx.params;
+ const { email, username, password } = ctx.request.body;
+
+ const user = await getService('user').fetch(id);
+ if (!user) {
+ throw new NotFoundError(`User not found`);
+ }
+
+ await validateUpdateUserBody(ctx.request.body);
+
+ if (user.provider === 'local' && _.has(ctx.request.body, 'password') && !password) {
+ throw new ValidationError('password.notNull');
+ }
+
+ if (_.has(ctx.request.body, 'username')) {
+ const userWithSameUsername = await strapi
+ .query('plugin::users-permissions.user')
+ .findOne({ where: { username } });
+
+ if (userWithSameUsername && _.toString(userWithSameUsername.id) !== _.toString(id)) {
+ throw new ApplicationError('Username already taken');
+ }
+ }
+
+ if (_.has(ctx.request.body, 'email') && advancedConfigs.unique_email) {
+ const userWithSameEmail = await strapi
+ .query('plugin::users-permissions.user')
+ .findOne({ where: { email: email.toLowerCase() } });
+
+ if (userWithSameEmail && _.toString(userWithSameEmail.id) !== _.toString(id)) {
+ throw new ApplicationError('Email already taken');
+ }
+ ctx.request.body.email = ctx.request.body.email.toLowerCase();
+ }
+
+ const updateData = {
+ ...ctx.request.body,
+ };
+
+ const data = await getService('user').edit(user.id, updateData);
+ const sanitizedData = await sanitizeOutput(data, ctx);
+
+ ctx.send(sanitizedData);
+ },
+
+ /**
+ * Retrieve user records.
+ * @return {Object|Array}
+ */
+ async find(ctx) {
+ const sanitizedQuery = await sanitizeQuery(ctx.query, ctx);
+ const users = await getService('user').fetchAll(sanitizedQuery);
+
+ ctx.body = await Promise.all(users.map((user) => sanitizeOutput(user, ctx)));
+ },
+
+ /**
+ * Retrieve a user record.
+ * @return {Object}
+ */
+ async findOne(ctx) {
+ const { id } = ctx.params;
+ const sanitizedQuery = await sanitizeQuery(ctx.query, ctx);
+
+ let data = await getService('user').fetch(id, sanitizedQuery);
+
+ if (data) {
+ data = await sanitizeOutput(data, ctx);
+ }
+
+ ctx.body = data;
+ },
+
+ /**
+ * Retrieve user count.
+ * @return {Number}
+ */
+ async count(ctx) {
+ const sanitizedQuery = await sanitizeQuery(ctx.query, ctx);
+
+ ctx.body = await getService('user').count(sanitizedQuery);
+ },
+
+ /**
+ * Destroy a/an user record.
+ * @return {Object}
+ */
+ async destroy(ctx) {
+ const { id } = ctx.params;
+
+ const data = await getService('user').remove({ id });
+ const sanitizedUser = await sanitizeOutput(data, ctx);
+
+ ctx.send(sanitizedUser);
+ },
+
+ /**
+ * Retrieve authenticated user.
+ * @return {Object|Array}
+ */
+ async me(ctx) {
+ const authUser = ctx.state.user;
+ const { query } = ctx;
+
+ if (!authUser) {
+ return ctx.unauthorized();
+ }
+
+ const sanitizedQuery = await sanitizeQuery(query, ctx);
+ const user = await getService('user').fetch(authUser.id, sanitizedQuery);
+
+ ctx.body = await sanitizeOutput(user, ctx);
+ },
+};
diff --git a/packages/strapi/src/extensions/users-permissions/server/controllers/validation/auth.js b/packages/strapi/src/extensions/users-permissions/server/controllers/validation/auth.js
new file mode 100644
index 0000000..fdb4ac0
--- /dev/null
+++ b/packages/strapi/src/extensions/users-permissions/server/controllers/validation/auth.js
@@ -0,0 +1,57 @@
+'use strict';
+
+const { yup, validateYupSchema } = require('@strapi/utils');
+
+const callbackSchema = yup.object({
+ identifier: yup.string().required(),
+ password: yup.string().required(),
+});
+
+const registerSchema = yup.object({
+ email: yup.string().email().required(),
+ username: yup.string().required(),
+ password: yup.string().required(),
+});
+
+const sendEmailConfirmationSchema = yup.object({
+ email: yup.string().email().required(),
+});
+
+const validateEmailConfirmationSchema = yup.object({
+ confirmation: yup.string().required(),
+});
+
+const forgotPasswordSchema = yup
+ .object({
+ email: yup.string().email().required(),
+ })
+ .noUnknown();
+
+const resetPasswordSchema = yup
+ .object({
+ password: yup.string().required(),
+ passwordConfirmation: yup.string().required(),
+ code: yup.string().required(),
+ })
+ .noUnknown();
+
+const changePasswordSchema = yup
+ .object({
+ password: yup.string().required(),
+ passwordConfirmation: yup
+ .string()
+ .required()
+ .oneOf([yup.ref('password')], 'Passwords do not match'),
+ currentPassword: yup.string().required(),
+ })
+ .noUnknown();
+
+module.exports = {
+ validateCallbackBody: validateYupSchema(callbackSchema),
+ validateRegisterBody: validateYupSchema(registerSchema),
+ validateSendEmailConfirmationBody: validateYupSchema(sendEmailConfirmationSchema),
+ validateEmailConfirmationBody: validateYupSchema(validateEmailConfirmationSchema),
+ validateForgotPasswordBody: validateYupSchema(forgotPasswordSchema),
+ validateResetPasswordBody: validateYupSchema(resetPasswordSchema),
+ validateChangePasswordBody: validateYupSchema(changePasswordSchema),
+};
diff --git a/packages/strapi/src/extensions/users-permissions/server/controllers/validation/email-template.js b/packages/strapi/src/extensions/users-permissions/server/controllers/validation/email-template.js
new file mode 100644
index 0000000..49b3f76
--- /dev/null
+++ b/packages/strapi/src/extensions/users-permissions/server/controllers/validation/email-template.js
@@ -0,0 +1,74 @@
+'use strict';
+
+const { trim } = require('lodash/fp');
+const {
+ template: { createLooseInterpolationRegExp, createStrictInterpolationRegExp },
+} = require('@strapi/utils');
+
+const invalidPatternsRegexes = [
+ // Ignore "evaluation" patterns: <% ... %>
+ /<%[^=]([\s\S]*?)%>/m,
+ // Ignore basic string interpolations
+ /\${([^{}]*)}/m,
+];
+
+const authorizedKeys = [
+ 'URL',
+ 'ADMIN_URL',
+ 'SERVER_URL',
+ 'CODE',
+ 'USER',
+ 'USER.email',
+ 'USER.username',
+ 'TOKEN',
+];
+
+const matchAll = (pattern, src) => {
+ const matches = [];
+ let match;
+
+ const regexPatternWithGlobal = RegExp(pattern, 'g');
+
+ // eslint-disable-next-line no-cond-assign
+ while ((match = regexPatternWithGlobal.exec(src))) {
+ const [, group] = match;
+
+ matches.push(trim(group));
+ }
+
+ return matches;
+};
+
+const isValidEmailTemplate = (template) => {
+ // Check for known invalid patterns
+ for (const reg of invalidPatternsRegexes) {
+ if (reg.test(template)) {
+ return false;
+ }
+ }
+
+ const interpolation = {
+ // Strict interpolation pattern to match only valid groups
+ strict: createStrictInterpolationRegExp(authorizedKeys),
+ // Weak interpolation pattern to match as many group as possible.
+ loose: createLooseInterpolationRegExp(),
+ };
+
+ // Compute both strict & loose matches
+ const strictMatches = matchAll(interpolation.strict, template);
+ const looseMatches = matchAll(interpolation.loose, template);
+
+ // If we have more matches with the loose RegExp than with the strict one,
+ // then it means that at least one of the interpolation group is invalid
+ // Note: In the future, if we wanted to give more details for error formatting
+ // purposes, we could return the difference between the two arrays
+ if (looseMatches.length > strictMatches.length) {
+ return false;
+ }
+
+ return true;
+};
+
+module.exports = {
+ isValidEmailTemplate,
+};
diff --git a/packages/strapi/src/extensions/users-permissions/server/controllers/validation/user.js b/packages/strapi/src/extensions/users-permissions/server/controllers/validation/user.js
new file mode 100644
index 0000000..d62f3f7
--- /dev/null
+++ b/packages/strapi/src/extensions/users-permissions/server/controllers/validation/user.js
@@ -0,0 +1,59 @@
+'use strict';
+
+const { yup, validateYupSchema } = require('@strapi/utils');
+
+const deleteRoleSchema = yup.object().shape({
+ role: yup.strapiID().required(),
+});
+
+const createUserBodySchema = yup.object().shape({
+ email: yup.string().email().required(),
+ username: yup.string().min(1).required(),
+ password: yup.string().min(1).required(),
+ role: yup.lazy((value) =>
+ typeof value === 'object'
+ ? yup
+ .object()
+ .shape({
+ connect: yup
+ .array()
+ .of(yup.object().shape({ id: yup.strapiID().required() }))
+ .min(1, 'Users must have a role')
+ .required(),
+ })
+ .required()
+ : yup.strapiID().required()
+ ),
+});
+
+const updateUserBodySchema = yup.object().shape({
+ email: yup.string().email().min(1),
+ username: yup.string().min(1),
+ password: yup.string().min(1),
+ role: yup.lazy((value) =>
+ typeof value === 'object'
+ ? yup.object().shape({
+ connect: yup
+ .array()
+ .of(yup.object().shape({ id: yup.strapiID().required() }))
+ .required(),
+ disconnect: yup
+ .array()
+ .test('CheckDisconnect', 'Cannot remove role', function test(disconnectValue) {
+ if (value.connect.length === 0 && disconnectValue.length > 0) {
+ return false;
+ }
+
+ return true;
+ })
+ .required(),
+ })
+ : yup.strapiID()
+ ),
+});
+
+module.exports = {
+ validateCreateUserBody: validateYupSchema(createUserBodySchema),
+ validateUpdateUserBody: validateYupSchema(updateUserBodySchema),
+ validateDeleteRoleBody: validateYupSchema(deleteRoleSchema),
+};
diff --git a/packages/strapi/src/extensions/users-permissions/server/graphql/index.js b/packages/strapi/src/extensions/users-permissions/server/graphql/index.js
new file mode 100644
index 0000000..4780f32
--- /dev/null
+++ b/packages/strapi/src/extensions/users-permissions/server/graphql/index.js
@@ -0,0 +1,44 @@
+'use strict';
+
+const getTypes = require('./types');
+const getQueries = require('./queries');
+const getMutations = require('./mutations');
+const getResolversConfig = require('./resolvers-configs');
+
+module.exports = ({ strapi }) => {
+ const { config: graphQLConfig } = strapi.plugin('graphql');
+ const extensionService = strapi.plugin('graphql').service('extension');
+
+ const isShadowCRUDEnabled = graphQLConfig('shadowCRUD', true);
+
+ if (!isShadowCRUDEnabled) {
+ return;
+ }
+
+ // Disable Permissions queries & mutations but allow the
+ // type to be used/selected in filters or nested resolvers
+ extensionService
+ .shadowCRUD('plugin::users-permissions.permission')
+ .disableQueries()
+ .disableMutations();
+
+ // Disable User & Role's Create/Update/Delete actions so they can be replaced
+ const actionsToDisable = ['create', 'update', 'delete'];
+
+ extensionService.shadowCRUD('plugin::users-permissions.user').disableActions(actionsToDisable);
+ extensionService.shadowCRUD('plugin::users-permissions.role').disableActions(actionsToDisable);
+
+ // Register new types & resolvers config
+ extensionService.use(({ nexus }) => {
+ const types = getTypes({ strapi, nexus });
+ const queries = getQueries({ strapi, nexus });
+ const mutations = getMutations({ strapi, nexus });
+ const resolversConfig = getResolversConfig({ strapi });
+
+ return {
+ types: [types, queries, mutations],
+
+ resolversConfig,
+ };
+ });
+};
diff --git a/packages/strapi/src/extensions/users-permissions/server/graphql/mutations/auth/change-password.js b/packages/strapi/src/extensions/users-permissions/server/graphql/mutations/auth/change-password.js
new file mode 100644
index 0000000..956d7b7
--- /dev/null
+++ b/packages/strapi/src/extensions/users-permissions/server/graphql/mutations/auth/change-password.js
@@ -0,0 +1,38 @@
+'use strict';
+
+const { toPlainObject } = require('lodash/fp');
+
+const { checkBadRequest } = require('../../utils');
+
+module.exports = ({ nexus, strapi }) => {
+ const { nonNull } = nexus;
+
+ return {
+ type: 'UsersPermissionsLoginPayload',
+
+ args: {
+ currentPassword: nonNull('String'),
+ password: nonNull('String'),
+ passwordConfirmation: nonNull('String'),
+ },
+
+ description: 'Change user password. Confirm with the current password.',
+
+ async resolve(parent, args, context) {
+ const { koaContext } = context;
+
+ koaContext.request.body = toPlainObject(args);
+
+ await strapi.plugin('users-permissions').controller('auth').changePassword(koaContext);
+
+ const output = koaContext.body;
+
+ checkBadRequest(output);
+
+ return {
+ user: output.user || output,
+ jwt: output.jwt,
+ };
+ },
+ };
+};
diff --git a/packages/strapi/src/extensions/users-permissions/server/graphql/mutations/auth/email-confirmation.js b/packages/strapi/src/extensions/users-permissions/server/graphql/mutations/auth/email-confirmation.js
new file mode 100644
index 0000000..1e97f9a
--- /dev/null
+++ b/packages/strapi/src/extensions/users-permissions/server/graphql/mutations/auth/email-confirmation.js
@@ -0,0 +1,39 @@
+'use strict';
+
+const { toPlainObject } = require('lodash/fp');
+
+const { checkBadRequest } = require('../../utils');
+
+module.exports = ({ nexus, strapi }) => {
+ const { nonNull } = nexus;
+
+ return {
+ type: 'UsersPermissionsLoginPayload',
+
+ args: {
+ confirmation: nonNull('String'),
+ },
+
+ description: 'Confirm an email users email address',
+
+ async resolve(parent, args, context) {
+ const { koaContext } = context;
+
+ koaContext.query = toPlainObject(args);
+
+ await strapi
+ .plugin('users-permissions')
+ .controller('auth')
+ .emailConfirmation(koaContext, null, true);
+
+ const output = koaContext.body;
+
+ checkBadRequest(output);
+
+ return {
+ user: output.user || output,
+ jwt: output.jwt,
+ };
+ },
+ };
+};
diff --git a/packages/strapi/src/extensions/users-permissions/server/graphql/mutations/auth/forgot-password.js b/packages/strapi/src/extensions/users-permissions/server/graphql/mutations/auth/forgot-password.js
new file mode 100644
index 0000000..ceea19a
--- /dev/null
+++ b/packages/strapi/src/extensions/users-permissions/server/graphql/mutations/auth/forgot-password.js
@@ -0,0 +1,35 @@
+'use strict';
+
+const { toPlainObject } = require('lodash/fp');
+
+const { checkBadRequest } = require('../../utils');
+
+module.exports = ({ nexus, strapi }) => {
+ const { nonNull } = nexus;
+
+ return {
+ type: 'UsersPermissionsPasswordPayload',
+
+ args: {
+ email: nonNull('String'),
+ },
+
+ description: 'Request a reset password token',
+
+ async resolve(parent, args, context) {
+ const { koaContext } = context;
+
+ koaContext.request.body = toPlainObject(args);
+
+ await strapi.plugin('users-permissions').controller('auth').forgotPassword(koaContext);
+
+ const output = koaContext.body;
+
+ checkBadRequest(output);
+
+ return {
+ ok: output.ok || output,
+ };
+ },
+ };
+};
diff --git a/packages/strapi/src/extensions/users-permissions/server/graphql/mutations/auth/login.js b/packages/strapi/src/extensions/users-permissions/server/graphql/mutations/auth/login.js
new file mode 100644
index 0000000..cc0f0de
--- /dev/null
+++ b/packages/strapi/src/extensions/users-permissions/server/graphql/mutations/auth/login.js
@@ -0,0 +1,35 @@
+'use strict';
+
+const { toPlainObject } = require('lodash/fp');
+
+const { checkBadRequest } = require('../../utils');
+
+module.exports = ({ nexus, strapi }) => {
+ const { nonNull } = nexus;
+
+ return {
+ type: nonNull('UsersPermissionsLoginPayload'),
+
+ args: {
+ input: nonNull('UsersPermissionsLoginInput'),
+ },
+
+ async resolve(parent, args, context) {
+ const { koaContext } = context;
+
+ koaContext.params = { provider: args.input.provider };
+ koaContext.request.body = toPlainObject(args.input);
+
+ await strapi.plugin('users-permissions').controller('auth').callback(koaContext);
+
+ const output = koaContext.body;
+
+ checkBadRequest(output);
+
+ return {
+ user: output.user || output,
+ jwt: output.jwt,
+ };
+ },
+ };
+};
diff --git a/packages/strapi/src/extensions/users-permissions/server/graphql/mutations/auth/register.js b/packages/strapi/src/extensions/users-permissions/server/graphql/mutations/auth/register.js
new file mode 100644
index 0000000..296d967
--- /dev/null
+++ b/packages/strapi/src/extensions/users-permissions/server/graphql/mutations/auth/register.js
@@ -0,0 +1,36 @@
+'use strict';
+
+const { toPlainObject } = require('lodash/fp');
+
+const { checkBadRequest } = require('../../utils');
+
+module.exports = ({ nexus, strapi }) => {
+ const { nonNull } = nexus;
+
+ return {
+ type: nonNull('UsersPermissionsLoginPayload'),
+
+ args: {
+ input: nonNull('UsersPermissionsRegisterInput'),
+ },
+
+ description: 'Register a user',
+
+ async resolve(parent, args, context) {
+ const { koaContext } = context;
+
+ koaContext.request.body = toPlainObject(args.input);
+
+ await strapi.plugin('users-permissions').controller('auth').register(koaContext);
+
+ const output = koaContext.body;
+
+ checkBadRequest(output);
+
+ return {
+ user: output.user || output,
+ jwt: output.jwt,
+ };
+ },
+ };
+};
diff --git a/packages/strapi/src/extensions/users-permissions/server/graphql/mutations/auth/reset-password.js b/packages/strapi/src/extensions/users-permissions/server/graphql/mutations/auth/reset-password.js
new file mode 100644
index 0000000..65251c7
--- /dev/null
+++ b/packages/strapi/src/extensions/users-permissions/server/graphql/mutations/auth/reset-password.js
@@ -0,0 +1,38 @@
+'use strict';
+
+const { toPlainObject } = require('lodash/fp');
+
+const { checkBadRequest } = require('../../utils');
+
+module.exports = ({ nexus, strapi }) => {
+ const { nonNull } = nexus;
+
+ return {
+ type: 'UsersPermissionsLoginPayload',
+
+ args: {
+ password: nonNull('String'),
+ passwordConfirmation: nonNull('String'),
+ code: nonNull('String'),
+ },
+
+ description: 'Reset user password. Confirm with a code (resetToken from forgotPassword)',
+
+ async resolve(parent, args, context) {
+ const { koaContext } = context;
+
+ koaContext.request.body = toPlainObject(args);
+
+ await strapi.plugin('users-permissions').controller('auth').resetPassword(koaContext);
+
+ const output = koaContext.body;
+
+ checkBadRequest(output);
+
+ return {
+ user: output.user || output,
+ jwt: output.jwt,
+ };
+ },
+ };
+};
diff --git a/packages/strapi/src/extensions/users-permissions/server/graphql/mutations/crud/role/create-role.js b/packages/strapi/src/extensions/users-permissions/server/graphql/mutations/crud/role/create-role.js
new file mode 100644
index 0000000..3dd0fed
--- /dev/null
+++ b/packages/strapi/src/extensions/users-permissions/server/graphql/mutations/crud/role/create-role.js
@@ -0,0 +1,34 @@
+'use strict';
+
+const { toPlainObject } = require('lodash/fp');
+
+const usersPermissionsRoleUID = 'plugin::users-permissions.role';
+
+module.exports = ({ nexus, strapi }) => {
+ const { getContentTypeInputName } = strapi.plugin('graphql').service('utils').naming;
+ const { nonNull } = nexus;
+
+ const roleContentType = strapi.getModel(usersPermissionsRoleUID);
+
+ const roleInputName = getContentTypeInputName(roleContentType);
+
+ return {
+ type: 'UsersPermissionsCreateRolePayload',
+
+ args: {
+ data: nonNull(roleInputName),
+ },
+
+ description: 'Create a new role',
+
+ async resolve(parent, args, context) {
+ const { koaContext } = context;
+
+ koaContext.request.body = toPlainObject(args.data);
+
+ await strapi.plugin('users-permissions').controller('role').createRole(koaContext);
+
+ return { ok: true };
+ },
+ };
+};
diff --git a/packages/strapi/src/extensions/users-permissions/server/graphql/mutations/crud/role/delete-role.js b/packages/strapi/src/extensions/users-permissions/server/graphql/mutations/crud/role/delete-role.js
new file mode 100644
index 0000000..154bbd8
--- /dev/null
+++ b/packages/strapi/src/extensions/users-permissions/server/graphql/mutations/crud/role/delete-role.js
@@ -0,0 +1,25 @@
+'use strict';
+
+module.exports = ({ nexus, strapi }) => {
+ const { nonNull } = nexus;
+
+ return {
+ type: 'UsersPermissionsDeleteRolePayload',
+
+ args: {
+ id: nonNull('ID'),
+ },
+
+ description: 'Delete an existing role',
+
+ async resolve(parent, args, context) {
+ const { koaContext } = context;
+
+ koaContext.params = { role: args.id };
+
+ await strapi.plugin('users-permissions').controller('role').deleteRole(koaContext);
+
+ return { ok: true };
+ },
+ };
+};
diff --git a/packages/strapi/src/extensions/users-permissions/server/graphql/mutations/crud/role/update-role.js b/packages/strapi/src/extensions/users-permissions/server/graphql/mutations/crud/role/update-role.js
new file mode 100644
index 0000000..4d22a01
--- /dev/null
+++ b/packages/strapi/src/extensions/users-permissions/server/graphql/mutations/crud/role/update-role.js
@@ -0,0 +1,35 @@
+'use strict';
+
+const usersPermissionsRoleUID = 'plugin::users-permissions.role';
+
+module.exports = ({ nexus, strapi }) => {
+ const { getContentTypeInputName } = strapi.plugin('graphql').service('utils').naming;
+ const { nonNull } = nexus;
+
+ const roleContentType = strapi.getModel(usersPermissionsRoleUID);
+
+ const roleInputName = getContentTypeInputName(roleContentType);
+
+ return {
+ type: 'UsersPermissionsUpdateRolePayload',
+
+ args: {
+ id: nonNull('ID'),
+ data: nonNull(roleInputName),
+ },
+
+ description: 'Update an existing role',
+
+ async resolve(parent, args, context) {
+ const { koaContext } = context;
+
+ koaContext.params = { role: args.id };
+ koaContext.request.body = args.data;
+ koaContext.request.body.role = args.id;
+
+ await strapi.plugin('users-permissions').controller('role').updateRole(koaContext);
+
+ return { ok: true };
+ },
+ };
+};
diff --git a/packages/strapi/src/extensions/users-permissions/server/graphql/mutations/crud/user/create-user.js b/packages/strapi/src/extensions/users-permissions/server/graphql/mutations/crud/user/create-user.js
new file mode 100644
index 0000000..7c1526e
--- /dev/null
+++ b/packages/strapi/src/extensions/users-permissions/server/graphql/mutations/crud/user/create-user.js
@@ -0,0 +1,45 @@
+'use strict';
+
+const { toPlainObject } = require('lodash/fp');
+
+const { checkBadRequest } = require('../../../utils');
+
+const usersPermissionsUserUID = 'plugin::users-permissions.user';
+
+module.exports = ({ nexus, strapi }) => {
+ const { nonNull } = nexus;
+ const { getContentTypeInputName, getEntityResponseName } = strapi
+ .plugin('graphql')
+ .service('utils').naming;
+
+ const userContentType = strapi.getModel(usersPermissionsUserUID);
+
+ const userInputName = getContentTypeInputName(userContentType);
+ const responseName = getEntityResponseName(userContentType);
+
+ return {
+ type: nonNull(responseName),
+
+ args: {
+ data: nonNull(userInputName),
+ },
+
+ description: 'Create a new user',
+
+ async resolve(parent, args, context) {
+ const { koaContext } = context;
+
+ koaContext.params = {};
+ koaContext.request.body = toPlainObject(args.data);
+
+ await strapi.plugin('users-permissions').controller('user').create(koaContext);
+
+ checkBadRequest(koaContext.body);
+
+ return {
+ value: koaContext.body,
+ info: { args, resourceUID: 'plugin::users-permissions.user' },
+ };
+ },
+ };
+};
diff --git a/packages/strapi/src/extensions/users-permissions/server/graphql/mutations/crud/user/delete-user.js b/packages/strapi/src/extensions/users-permissions/server/graphql/mutations/crud/user/delete-user.js
new file mode 100644
index 0000000..500834e
--- /dev/null
+++ b/packages/strapi/src/extensions/users-permissions/server/graphql/mutations/crud/user/delete-user.js
@@ -0,0 +1,39 @@
+'use strict';
+
+const { checkBadRequest } = require('../../../utils');
+
+const usersPermissionsUserUID = 'plugin::users-permissions.user';
+
+module.exports = ({ nexus, strapi }) => {
+ const { nonNull } = nexus;
+ const { getEntityResponseName } = strapi.plugin('graphql').service('utils').naming;
+
+ const userContentType = strapi.getModel(usersPermissionsUserUID);
+
+ const responseName = getEntityResponseName(userContentType);
+
+ return {
+ type: nonNull(responseName),
+
+ args: {
+ id: nonNull('ID'),
+ },
+
+ description: 'Delete an existing user',
+
+ async resolve(parent, args, context) {
+ const { koaContext } = context;
+
+ koaContext.params = { id: args.id };
+
+ await strapi.plugin('users-permissions').controller('user').destroy(koaContext);
+
+ checkBadRequest(koaContext.body);
+
+ return {
+ value: koaContext.body,
+ info: { args, resourceUID: 'plugin::users-permissions.user' },
+ };
+ },
+ };
+};
diff --git a/packages/strapi/src/extensions/users-permissions/server/graphql/mutations/crud/user/update-user.js b/packages/strapi/src/extensions/users-permissions/server/graphql/mutations/crud/user/update-user.js
new file mode 100644
index 0000000..a89cb3e
--- /dev/null
+++ b/packages/strapi/src/extensions/users-permissions/server/graphql/mutations/crud/user/update-user.js
@@ -0,0 +1,46 @@
+'use strict';
+
+const { toPlainObject } = require('lodash/fp');
+
+const { checkBadRequest } = require('../../../utils');
+
+const usersPermissionsUserUID = 'plugin::users-permissions.user';
+
+module.exports = ({ nexus, strapi }) => {
+ const { nonNull } = nexus;
+ const { getContentTypeInputName, getEntityResponseName } = strapi
+ .plugin('graphql')
+ .service('utils').naming;
+
+ const userContentType = strapi.getModel(usersPermissionsUserUID);
+
+ const userInputName = getContentTypeInputName(userContentType);
+ const responseName = getEntityResponseName(userContentType);
+
+ return {
+ type: nonNull(responseName),
+
+ args: {
+ id: nonNull('ID'),
+ data: nonNull(userInputName),
+ },
+
+ description: 'Update an existing user',
+
+ async resolve(parent, args, context) {
+ const { koaContext } = context;
+
+ koaContext.params = { id: args.id };
+ koaContext.request.body = toPlainObject(args.data);
+
+ await strapi.plugin('users-permissions').controller('user').update(koaContext);
+
+ checkBadRequest(koaContext.body);
+
+ return {
+ value: koaContext.body,
+ info: { args, resourceUID: 'plugin::users-permissions.user' },
+ };
+ },
+ };
+};
diff --git a/packages/strapi/src/extensions/users-permissions/server/graphql/mutations/index.js b/packages/strapi/src/extensions/users-permissions/server/graphql/mutations/index.js
new file mode 100644
index 0000000..801d1f3
--- /dev/null
+++ b/packages/strapi/src/extensions/users-permissions/server/graphql/mutations/index.js
@@ -0,0 +1,43 @@
+'use strict';
+
+const userUID = 'plugin::users-permissions.user';
+const roleUID = 'plugin::users-permissions.role';
+
+module.exports = (context) => {
+ const { nexus, strapi } = context;
+
+ const { naming } = strapi.plugin('graphql').service('utils');
+
+ const user = strapi.getModel(userUID);
+ const role = strapi.getModel(roleUID);
+
+ const mutations = {
+ // CRUD (user & role)
+ [naming.getCreateMutationTypeName(role)]: require('./crud/role/create-role'),
+ [naming.getUpdateMutationTypeName(role)]: require('./crud/role/update-role'),
+ [naming.getDeleteMutationTypeName(role)]: require('./crud/role/delete-role'),
+ [naming.getCreateMutationTypeName(user)]: require('./crud/user/create-user'),
+ [naming.getUpdateMutationTypeName(user)]: require('./crud/user/update-user'),
+ [naming.getDeleteMutationTypeName(user)]: require('./crud/user/delete-user'),
+
+ // Other mutations
+ login: require('./auth/login'),
+ register: require('./auth/register'),
+ forgotPassword: require('./auth/forgot-password'),
+ resetPassword: require('./auth/reset-password'),
+ changePassword: require('./auth/change-password'),
+ emailConfirmation: require('./auth/email-confirmation'),
+ };
+
+ return nexus.extendType({
+ type: 'Mutation',
+
+ definition(t) {
+ for (const [name, getConfig] of Object.entries(mutations)) {
+ const config = getConfig(context);
+
+ t.field(name, config);
+ }
+ },
+ });
+};
diff --git a/packages/strapi/src/extensions/users-permissions/server/graphql/queries/index.js b/packages/strapi/src/extensions/users-permissions/server/graphql/queries/index.js
new file mode 100644
index 0000000..d45d0f2
--- /dev/null
+++ b/packages/strapi/src/extensions/users-permissions/server/graphql/queries/index.js
@@ -0,0 +1,13 @@
+'use strict';
+
+const me = require('./me');
+
+module.exports = ({ nexus }) => {
+ return nexus.extendType({
+ type: 'Query',
+
+ definition(t) {
+ t.field('me', me({ nexus }));
+ },
+ });
+};
diff --git a/packages/strapi/src/extensions/users-permissions/server/graphql/queries/me.js b/packages/strapi/src/extensions/users-permissions/server/graphql/queries/me.js
new file mode 100644
index 0000000..0835ad6
--- /dev/null
+++ b/packages/strapi/src/extensions/users-permissions/server/graphql/queries/me.js
@@ -0,0 +1,17 @@
+'use strict';
+
+module.exports = () => ({
+ type: 'UsersPermissionsMe',
+
+ args: {},
+
+ resolve(parent, args, context) {
+ const { user } = context.state;
+
+ if (!user) {
+ throw new Error('Authentication requested');
+ }
+
+ return user;
+ },
+});
diff --git a/packages/strapi/src/extensions/users-permissions/server/graphql/resolvers-configs.js b/packages/strapi/src/extensions/users-permissions/server/graphql/resolvers-configs.js
new file mode 100644
index 0000000..f149df2
--- /dev/null
+++ b/packages/strapi/src/extensions/users-permissions/server/graphql/resolvers-configs.js
@@ -0,0 +1,42 @@
+'use strict';
+
+const userUID = 'plugin::users-permissions.user';
+const roleUID = 'plugin::users-permissions.role';
+
+module.exports = ({ strapi }) => {
+ const { naming } = strapi.plugin('graphql').service('utils');
+
+ const user = strapi.getModel(userUID);
+ const role = strapi.getModel(roleUID);
+
+ const createRole = naming.getCreateMutationTypeName(role);
+ const updateRole = naming.getUpdateMutationTypeName(role);
+ const deleteRole = naming.getDeleteMutationTypeName(role);
+ const createUser = naming.getCreateMutationTypeName(user);
+ const updateUser = naming.getUpdateMutationTypeName(user);
+ const deleteUser = naming.getDeleteMutationTypeName(user);
+
+ return {
+ // Disabled auth for some operations
+ 'Mutation.login': { auth: false },
+ 'Mutation.register': { auth: false },
+ 'Mutation.forgotPassword': { auth: false },
+ 'Mutation.resetPassword': { auth: false },
+ 'Mutation.emailConfirmation': { auth: false },
+ 'Mutation.changePassword': {
+ auth: {
+ scope: 'plugin::users-permissions.auth.changePassword',
+ },
+ },
+
+ // Scoped auth for replaced CRUD operations
+ // Role
+ [`Mutation.${createRole}`]: { auth: { scope: [`${roleUID}.createRole`] } },
+ [`Mutation.${updateRole}`]: { auth: { scope: [`${roleUID}.updateRole`] } },
+ [`Mutation.${deleteRole}`]: { auth: { scope: [`${roleUID}.deleteRole`] } },
+ // User
+ [`Mutation.${createUser}`]: { auth: { scope: [`${userUID}.create`] } },
+ [`Mutation.${updateUser}`]: { auth: { scope: [`${userUID}.update`] } },
+ [`Mutation.${deleteUser}`]: { auth: { scope: [`${userUID}.destroy`] } },
+ };
+};
diff --git a/packages/strapi/src/extensions/users-permissions/server/graphql/types/create-role-payload.js b/packages/strapi/src/extensions/users-permissions/server/graphql/types/create-role-payload.js
new file mode 100644
index 0000000..33b5c47
--- /dev/null
+++ b/packages/strapi/src/extensions/users-permissions/server/graphql/types/create-role-payload.js
@@ -0,0 +1,11 @@
+'use strict';
+
+module.exports = ({ nexus }) => {
+ return nexus.objectType({
+ name: 'UsersPermissionsCreateRolePayload',
+
+ definition(t) {
+ t.nonNull.boolean('ok');
+ },
+ });
+};
diff --git a/packages/strapi/src/extensions/users-permissions/server/graphql/types/delete-role-payload.js b/packages/strapi/src/extensions/users-permissions/server/graphql/types/delete-role-payload.js
new file mode 100644
index 0000000..7e06005
--- /dev/null
+++ b/packages/strapi/src/extensions/users-permissions/server/graphql/types/delete-role-payload.js
@@ -0,0 +1,11 @@
+'use strict';
+
+module.exports = ({ nexus }) => {
+ return nexus.objectType({
+ name: 'UsersPermissionsDeleteRolePayload',
+
+ definition(t) {
+ t.nonNull.boolean('ok');
+ },
+ });
+};
diff --git a/packages/strapi/src/extensions/users-permissions/server/graphql/types/index.js b/packages/strapi/src/extensions/users-permissions/server/graphql/types/index.js
new file mode 100644
index 0000000..7888e84
--- /dev/null
+++ b/packages/strapi/src/extensions/users-permissions/server/graphql/types/index.js
@@ -0,0 +1,21 @@
+'use strict';
+
+const typesFactories = [
+ require('./me'),
+ require('./me-role'),
+ require('./register-input'),
+ require('./login-input'),
+ require('./password-payload'),
+ require('./login-payload'),
+ require('./create-role-payload'),
+ require('./update-role-payload'),
+ require('./delete-role-payload'),
+];
+
+/**
+ * @param {object} context
+ * @param {object} context.nexus
+ * @param {object} context.strapi
+ * @return {any[]}
+ */
+module.exports = (context) => typesFactories.map((factory) => factory(context));
diff --git a/packages/strapi/src/extensions/users-permissions/server/graphql/types/login-input.js b/packages/strapi/src/extensions/users-permissions/server/graphql/types/login-input.js
new file mode 100644
index 0000000..b8d7f41
--- /dev/null
+++ b/packages/strapi/src/extensions/users-permissions/server/graphql/types/login-input.js
@@ -0,0 +1,13 @@
+'use strict';
+
+module.exports = ({ nexus }) => {
+ return nexus.inputObjectType({
+ name: 'UsersPermissionsLoginInput',
+
+ definition(t) {
+ t.nonNull.string('identifier');
+ t.nonNull.string('password');
+ t.nonNull.string('provider', { default: 'local' });
+ },
+ });
+};
diff --git a/packages/strapi/src/extensions/users-permissions/server/graphql/types/login-payload.js b/packages/strapi/src/extensions/users-permissions/server/graphql/types/login-payload.js
new file mode 100644
index 0000000..65f8ec4
--- /dev/null
+++ b/packages/strapi/src/extensions/users-permissions/server/graphql/types/login-payload.js
@@ -0,0 +1,12 @@
+'use strict';
+
+module.exports = ({ nexus }) => {
+ return nexus.objectType({
+ name: 'UsersPermissionsLoginPayload',
+
+ definition(t) {
+ t.string('jwt');
+ t.nonNull.field('user', { type: 'UsersPermissionsMe' });
+ },
+ });
+};
diff --git a/packages/strapi/src/extensions/users-permissions/server/graphql/types/me-role.js b/packages/strapi/src/extensions/users-permissions/server/graphql/types/me-role.js
new file mode 100644
index 0000000..485fedb
--- /dev/null
+++ b/packages/strapi/src/extensions/users-permissions/server/graphql/types/me-role.js
@@ -0,0 +1,14 @@
+'use strict';
+
+module.exports = ({ nexus }) => {
+ return nexus.objectType({
+ name: 'UsersPermissionsMeRole',
+
+ definition(t) {
+ t.nonNull.id('id');
+ t.nonNull.string('name');
+ t.string('description');
+ t.string('type');
+ },
+ });
+};
diff --git a/packages/strapi/src/extensions/users-permissions/server/graphql/types/me.js b/packages/strapi/src/extensions/users-permissions/server/graphql/types/me.js
new file mode 100644
index 0000000..d3a8aee
--- /dev/null
+++ b/packages/strapi/src/extensions/users-permissions/server/graphql/types/me.js
@@ -0,0 +1,16 @@
+'use strict';
+
+module.exports = ({ nexus }) => {
+ return nexus.objectType({
+ name: 'UsersPermissionsMe',
+
+ definition(t) {
+ t.nonNull.id('id');
+ t.nonNull.string('username');
+ t.string('email');
+ t.boolean('confirmed');
+ t.boolean('blocked');
+ t.field('role', { type: 'UsersPermissionsMeRole' });
+ },
+ });
+};
diff --git a/packages/strapi/src/extensions/users-permissions/server/graphql/types/password-payload.js b/packages/strapi/src/extensions/users-permissions/server/graphql/types/password-payload.js
new file mode 100644
index 0000000..5d68c8e
--- /dev/null
+++ b/packages/strapi/src/extensions/users-permissions/server/graphql/types/password-payload.js
@@ -0,0 +1,11 @@
+'use strict';
+
+module.exports = ({ nexus }) => {
+ return nexus.objectType({
+ name: 'UsersPermissionsPasswordPayload',
+
+ definition(t) {
+ t.nonNull.boolean('ok');
+ },
+ });
+};
diff --git a/packages/strapi/src/extensions/users-permissions/server/graphql/types/register-input.js b/packages/strapi/src/extensions/users-permissions/server/graphql/types/register-input.js
new file mode 100644
index 0000000..1585761
--- /dev/null
+++ b/packages/strapi/src/extensions/users-permissions/server/graphql/types/register-input.js
@@ -0,0 +1,13 @@
+'use strict';
+
+module.exports = ({ nexus }) => {
+ return nexus.inputObjectType({
+ name: 'UsersPermissionsRegisterInput',
+
+ definition(t) {
+ t.nonNull.string('username');
+ t.nonNull.string('email');
+ t.nonNull.string('password');
+ },
+ });
+};
diff --git a/packages/strapi/src/extensions/users-permissions/server/graphql/types/update-role-payload.js b/packages/strapi/src/extensions/users-permissions/server/graphql/types/update-role-payload.js
new file mode 100644
index 0000000..cea281d
--- /dev/null
+++ b/packages/strapi/src/extensions/users-permissions/server/graphql/types/update-role-payload.js
@@ -0,0 +1,11 @@
+'use strict';
+
+module.exports = ({ nexus }) => {
+ return nexus.objectType({
+ name: 'UsersPermissionsUpdateRolePayload',
+
+ definition(t) {
+ t.nonNull.boolean('ok');
+ },
+ });
+};
diff --git a/packages/strapi/src/extensions/users-permissions/server/graphql/utils.js b/packages/strapi/src/extensions/users-permissions/server/graphql/utils.js
new file mode 100644
index 0000000..8439021
--- /dev/null
+++ b/packages/strapi/src/extensions/users-permissions/server/graphql/utils.js
@@ -0,0 +1,27 @@
+'use strict';
+
+const { getOr } = require('lodash/fp');
+
+/**
+ * Throws an ApolloError if context body contains a bad request
+ * @param contextBody - body of the context object given to the resolver
+ * @throws ApolloError if the body is a bad request
+ */
+function checkBadRequest(contextBody) {
+ const statusCode = getOr(200, 'statusCode', contextBody);
+
+ if (statusCode !== 200) {
+ const errorMessage = getOr('Bad Request', 'error', contextBody);
+
+ const exception = new Error(errorMessage);
+
+ exception.code = statusCode || 400;
+ exception.data = contextBody;
+
+ throw exception;
+ }
+}
+
+module.exports = {
+ checkBadRequest,
+};
diff --git a/packages/strapi/src/extensions/users-permissions/server/index.js b/packages/strapi/src/extensions/users-permissions/server/index.js
new file mode 100644
index 0000000..14629aa
--- /dev/null
+++ b/packages/strapi/src/extensions/users-permissions/server/index.js
@@ -0,0 +1,21 @@
+'use strict';
+
+const register = require('./register');
+const bootstrap = require('./bootstrap');
+const contentTypes = require('./content-types');
+const middlewares = require('./middlewares');
+const services = require('./services');
+const routes = require('./routes');
+const controllers = require('./controllers');
+const config = require('./config');
+
+module.exports = () => ({
+ register,
+ bootstrap,
+ config,
+ routes,
+ controllers,
+ contentTypes,
+ middlewares,
+ services,
+});
diff --git a/packages/strapi/src/extensions/users-permissions/server/middlewares/index.js b/packages/strapi/src/extensions/users-permissions/server/middlewares/index.js
new file mode 100644
index 0000000..2abf96c
--- /dev/null
+++ b/packages/strapi/src/extensions/users-permissions/server/middlewares/index.js
@@ -0,0 +1,7 @@
+'use strict';
+
+const rateLimit = require('./rateLimit');
+
+module.exports = {
+ rateLimit,
+};
diff --git a/packages/strapi/src/extensions/users-permissions/server/middlewares/rateLimit.js b/packages/strapi/src/extensions/users-permissions/server/middlewares/rateLimit.js
new file mode 100644
index 0000000..9880aa7
--- /dev/null
+++ b/packages/strapi/src/extensions/users-permissions/server/middlewares/rateLimit.js
@@ -0,0 +1,27 @@
+'use strict';
+
+module.exports =
+ (config, { strapi }) =>
+ async (ctx, next) => {
+ const ratelimit = require('koa2-ratelimit').RateLimit;
+
+ const message = [
+ {
+ messages: [
+ {
+ id: 'Auth.form.error.ratelimit',
+ message: 'Too many attempts, please try again in a minute.',
+ },
+ ],
+ },
+ ];
+
+ return ratelimit.middleware({
+ interval: 1 * 60 * 1000,
+ max: 5,
+ prefixKey: `${ctx.request.path}:${ctx.request.ip}`,
+ message,
+ ...strapi.config.get('plugin.users-permissions.ratelimit'),
+ ...config,
+ })(ctx, next);
+ };
diff --git a/packages/strapi/src/extensions/users-permissions/server/register.js b/packages/strapi/src/extensions/users-permissions/server/register.js
new file mode 100644
index 0000000..214fe30
--- /dev/null
+++ b/packages/strapi/src/extensions/users-permissions/server/register.js
@@ -0,0 +1,29 @@
+'use strict';
+
+const fs = require('fs');
+const path = require('path');
+
+const authStrategy = require('./strategies/users-permissions');
+const sanitizers = require('./utils/sanitize/sanitizers');
+
+module.exports = ({ strapi }) => {
+ strapi.container.get('auth').register('content-api', authStrategy);
+ strapi.sanitizers.add('content-api.output', sanitizers.defaultSanitizeOutput);
+
+ if (strapi.plugin('graphql')) {
+ require('./graphql')({ strapi });
+ }
+
+ if (strapi.plugin('documentation')) {
+ const specPath = path.join(__dirname, '../documentation/content-api.yaml');
+ const spec = fs.readFileSync(specPath, 'utf8');
+
+ strapi
+ .plugin('documentation')
+ .service('override')
+ .registerOverride(spec, {
+ pluginOrigin: 'users-permissions',
+ excludeFromGeneration: ['users-permissions'],
+ });
+ }
+};
diff --git a/packages/strapi/src/extensions/users-permissions/server/routes/admin/index.js b/packages/strapi/src/extensions/users-permissions/server/routes/admin/index.js
new file mode 100644
index 0000000..3ae910e
--- /dev/null
+++ b/packages/strapi/src/extensions/users-permissions/server/routes/admin/index.js
@@ -0,0 +1,10 @@
+'use strict';
+
+const permissionsRoutes = require('./permissions');
+const settingsRoutes = require('./settings');
+const roleRoutes = require('./role');
+
+module.exports = {
+ type: 'admin',
+ routes: [...roleRoutes, ...settingsRoutes, ...permissionsRoutes],
+};
diff --git a/packages/strapi/src/extensions/users-permissions/server/routes/admin/permissions.js b/packages/strapi/src/extensions/users-permissions/server/routes/admin/permissions.js
new file mode 100644
index 0000000..7ad462f
--- /dev/null
+++ b/packages/strapi/src/extensions/users-permissions/server/routes/admin/permissions.js
@@ -0,0 +1,20 @@
+'use strict';
+
+module.exports = [
+ {
+ method: 'GET',
+ path: '/permissions',
+ handler: 'permissions.getPermissions',
+ },
+ {
+ method: 'GET',
+ path: '/policies',
+ handler: 'permissions.getPolicies',
+ },
+
+ {
+ method: 'GET',
+ path: '/routes',
+ handler: 'permissions.getRoutes',
+ },
+];
diff --git a/packages/strapi/src/extensions/users-permissions/server/routes/admin/role.js b/packages/strapi/src/extensions/users-permissions/server/routes/admin/role.js
new file mode 100644
index 0000000..4bdbbda
--- /dev/null
+++ b/packages/strapi/src/extensions/users-permissions/server/routes/admin/role.js
@@ -0,0 +1,79 @@
+'use strict';
+
+module.exports = [
+ {
+ method: 'GET',
+ path: '/roles/:id',
+ handler: 'role.findOne',
+ config: {
+ policies: [
+ {
+ name: 'admin::hasPermissions',
+ config: {
+ actions: ['plugin::users-permissions.roles.read'],
+ },
+ },
+ ],
+ },
+ },
+ {
+ method: 'GET',
+ path: '/roles',
+ handler: 'role.find',
+ config: {
+ policies: [
+ {
+ name: 'admin::hasPermissions',
+ config: {
+ actions: ['plugin::users-permissions.roles.read'],
+ },
+ },
+ ],
+ },
+ },
+ {
+ method: 'POST',
+ path: '/roles',
+ handler: 'role.createRole',
+ config: {
+ policies: [
+ {
+ name: 'admin::hasPermissions',
+ config: {
+ actions: ['plugin::users-permissions.roles.create'],
+ },
+ },
+ ],
+ },
+ },
+ {
+ method: 'PUT',
+ path: '/roles/:role',
+ handler: 'role.updateRole',
+ config: {
+ policies: [
+ {
+ name: 'admin::hasPermissions',
+ config: {
+ actions: ['plugin::users-permissions.roles.update'],
+ },
+ },
+ ],
+ },
+ },
+ {
+ method: 'DELETE',
+ path: '/roles/:role',
+ handler: 'role.deleteRole',
+ config: {
+ policies: [
+ {
+ name: 'admin::hasPermissions',
+ config: {
+ actions: ['plugin::users-permissions.roles.delete'],
+ },
+ },
+ ],
+ },
+ },
+];
diff --git a/packages/strapi/src/extensions/users-permissions/server/routes/admin/settings.js b/packages/strapi/src/extensions/users-permissions/server/routes/admin/settings.js
new file mode 100644
index 0000000..7ac31f6
--- /dev/null
+++ b/packages/strapi/src/extensions/users-permissions/server/routes/admin/settings.js
@@ -0,0 +1,95 @@
+'use strict';
+
+module.exports = [
+ {
+ method: 'GET',
+ path: '/email-templates',
+ handler: 'settings.getEmailTemplate',
+ config: {
+ policies: [
+ {
+ name: 'admin::hasPermissions',
+ config: {
+ actions: ['plugin::users-permissions.email-templates.read'],
+ },
+ },
+ ],
+ },
+ },
+ {
+ method: 'PUT',
+ path: '/email-templates',
+ handler: 'settings.updateEmailTemplate',
+ config: {
+ policies: [
+ {
+ name: 'admin::hasPermissions',
+ config: {
+ actions: ['plugin::users-permissions.email-templates.update'],
+ },
+ },
+ ],
+ },
+ },
+ {
+ method: 'GET',
+ path: '/advanced',
+ handler: 'settings.getAdvancedSettings',
+ config: {
+ policies: [
+ {
+ name: 'admin::hasPermissions',
+ config: {
+ actions: ['plugin::users-permissions.advanced-settings.read'],
+ },
+ },
+ ],
+ },
+ },
+ {
+ method: 'PUT',
+ path: '/advanced',
+ handler: 'settings.updateAdvancedSettings',
+ config: {
+ policies: [
+ {
+ name: 'admin::hasPermissions',
+ config: {
+ actions: ['plugin::users-permissions.advanced-settings.update'],
+ },
+ },
+ ],
+ },
+ },
+ {
+ method: 'GET',
+ path: '/providers',
+ handler: 'settings.getProviders',
+ config: {
+ policies: [
+ {
+ name: 'admin::hasPermissions',
+ config: {
+ actions: ['plugin::users-permissions.providers.read'],
+ },
+ },
+ ],
+ },
+ },
+
+ {
+ method: 'PUT',
+ path: '/providers',
+ handler: 'settings.updateProviders',
+ config: {
+ policies: [
+ {
+ name: 'admin::hasPermissions',
+ config: {
+ actions: ['plugin::users-permissions.providers.update'],
+ },
+ },
+ ],
+ },
+ },
+];
diff --git a/packages/strapi/src/extensions/users-permissions/server/routes/content-api/auth.js b/packages/strapi/src/extensions/users-permissions/server/routes/content-api/auth.js
new file mode 100644
index 0000000..bb34782
--- /dev/null
+++ b/packages/strapi/src/extensions/users-permissions/server/routes/content-api/auth.js
@@ -0,0 +1,82 @@
+'use strict';
+
+module.exports = [
+ {
+ method: 'GET',
+ path: '/connect/(.*)',
+ handler: 'auth.connect',
+ config: {
+ middlewares: ['plugin::users-permissions.rateLimit'],
+ prefix: '',
+ },
+ },
+ {
+ method: 'POST',
+ path: '/auth/local',
+ handler: 'auth.callback',
+ config: {
+ middlewares: ['plugin::users-permissions.rateLimit'],
+ prefix: '',
+ },
+ },
+ {
+ method: 'POST',
+ path: '/auth/local/register',
+ handler: 'auth.register',
+ config: {
+ middlewares: ['plugin::users-permissions.rateLimit'],
+ prefix: '',
+ },
+ },
+ {
+ method: 'GET',
+ path: '/auth/:provider/callback',
+ handler: 'auth.callback',
+ config: {
+ prefix: '',
+ },
+ },
+ {
+ method: 'POST',
+ path: '/auth/forgot-password',
+ handler: 'auth.forgotPassword',
+ config: {
+ middlewares: ['plugin::users-permissions.rateLimit'],
+ prefix: '',
+ },
+ },
+ {
+ method: 'POST',
+ path: '/auth/reset-password',
+ handler: 'auth.resetPassword',
+ config: {
+ middlewares: ['plugin::users-permissions.rateLimit'],
+ prefix: '',
+ },
+ },
+ {
+ method: 'GET',
+ path: '/auth/email-confirmation',
+ handler: 'auth.emailConfirmation',
+ config: {
+ prefix: '',
+ },
+ },
+ {
+ method: 'POST',
+ path: '/auth/send-email-confirmation',
+ handler: 'auth.sendEmailConfirmation',
+ config: {
+ prefix: '',
+ },
+ },
+ {
+ method: 'POST',
+ path: '/auth/change-password',
+ handler: 'auth.changePassword',
+ config: {
+ middlewares: ['plugin::users-permissions.rateLimit'],
+ prefix: '',
+ },
+ },
+];
diff --git a/packages/strapi/src/extensions/users-permissions/server/routes/content-api/index.js b/packages/strapi/src/extensions/users-permissions/server/routes/content-api/index.js
new file mode 100644
index 0000000..b23adf5
--- /dev/null
+++ b/packages/strapi/src/extensions/users-permissions/server/routes/content-api/index.js
@@ -0,0 +1,11 @@
+'use strict';
+
+const authRoutes = require('./auth');
+const userRoutes = require('./user');
+const roleRoutes = require('./role');
+const permissionsRoutes = require('./permissions');
+
+module.exports = {
+ type: 'content-api',
+ routes: [...authRoutes, ...userRoutes, ...roleRoutes, ...permissionsRoutes],
+};
diff --git a/packages/strapi/src/extensions/users-permissions/server/routes/content-api/permissions.js b/packages/strapi/src/extensions/users-permissions/server/routes/content-api/permissions.js
new file mode 100644
index 0000000..f6cf4a0
--- /dev/null
+++ b/packages/strapi/src/extensions/users-permissions/server/routes/content-api/permissions.js
@@ -0,0 +1,9 @@
+'use strict';
+
+module.exports = [
+ {
+ method: 'GET',
+ path: '/permissions',
+ handler: 'permissions.getPermissions',
+ },
+];
diff --git a/packages/strapi/src/extensions/users-permissions/server/routes/content-api/role.js b/packages/strapi/src/extensions/users-permissions/server/routes/content-api/role.js
new file mode 100644
index 0000000..ca72365
--- /dev/null
+++ b/packages/strapi/src/extensions/users-permissions/server/routes/content-api/role.js
@@ -0,0 +1,29 @@
+'use strict';
+
+module.exports = [
+ {
+ method: 'GET',
+ path: '/roles/:id',
+ handler: 'role.findOne',
+ },
+ {
+ method: 'GET',
+ path: '/roles',
+ handler: 'role.find',
+ },
+ {
+ method: 'POST',
+ path: '/roles',
+ handler: 'role.createRole',
+ },
+ {
+ method: 'PUT',
+ path: '/roles/:role',
+ handler: 'role.updateRole',
+ },
+ {
+ method: 'DELETE',
+ path: '/roles/:role',
+ handler: 'role.deleteRole',
+ },
+];
diff --git a/packages/strapi/src/extensions/users-permissions/server/routes/content-api/user.js b/packages/strapi/src/extensions/users-permissions/server/routes/content-api/user.js
new file mode 100644
index 0000000..a573a1e
--- /dev/null
+++ b/packages/strapi/src/extensions/users-permissions/server/routes/content-api/user.js
@@ -0,0 +1,60 @@
+'use strict';
+
+module.exports = [
+ {
+ method: 'GET',
+ path: '/users/count',
+ handler: 'user.count',
+ config: {
+ prefix: '',
+ },
+ },
+ {
+ method: 'GET',
+ path: '/users',
+ handler: 'user.find',
+ config: {
+ prefix: '',
+ },
+ },
+ {
+ method: 'GET',
+ path: '/users/me',
+ handler: 'user.me',
+ config: {
+ prefix: '',
+ },
+ },
+ {
+ method: 'GET',
+ path: '/users/:id',
+ handler: 'user.findOne',
+ config: {
+ prefix: '',
+ },
+ },
+ {
+ method: 'POST',
+ path: '/users',
+ handler: 'user.create',
+ config: {
+ prefix: '',
+ },
+ },
+ {
+ method: 'PUT',
+ path: '/users/:id',
+ handler: 'user.update',
+ config: {
+ prefix: '',
+ },
+ },
+ {
+ method: 'DELETE',
+ path: '/users/:id',
+ handler: 'user.destroy',
+ config: {
+ prefix: '',
+ },
+ },
+];
diff --git a/packages/strapi/src/extensions/users-permissions/server/routes/index.js b/packages/strapi/src/extensions/users-permissions/server/routes/index.js
new file mode 100644
index 0000000..6939f2d
--- /dev/null
+++ b/packages/strapi/src/extensions/users-permissions/server/routes/index.js
@@ -0,0 +1,6 @@
+'use strict';
+
+module.exports = {
+ admin: require('./admin'),
+ 'content-api': require('./content-api'),
+};
diff --git a/packages/strapi/src/extensions/users-permissions/server/services/index.js b/packages/strapi/src/extensions/users-permissions/server/services/index.js
new file mode 100644
index 0000000..3df8e27
--- /dev/null
+++ b/packages/strapi/src/extensions/users-permissions/server/services/index.js
@@ -0,0 +1,19 @@
+'use strict';
+
+const jwt = require('./jwt');
+const providers = require('./providers');
+const user = require('./user');
+const role = require('./role');
+const usersPermissions = require('./users-permissions');
+const providersRegistry = require('./providers-registry');
+const permission = require('./permission');
+
+module.exports = {
+ jwt,
+ providers,
+ 'providers-registry': providersRegistry,
+ role,
+ user,
+ 'users-permissions': usersPermissions,
+ permission,
+};
diff --git a/packages/strapi/src/extensions/users-permissions/server/services/jwt.js b/packages/strapi/src/extensions/users-permissions/server/services/jwt.js
new file mode 100644
index 0000000..e5b300a
--- /dev/null
+++ b/packages/strapi/src/extensions/users-permissions/server/services/jwt.js
@@ -0,0 +1,79 @@
+'use strict';
+
+/**
+ * Jwt.js service
+ *
+ * @description: A set of functions similar to controller's actions to avoid code duplication.
+ */
+
+const _ = require('lodash');
+const jwt = require('jsonwebtoken');
+
+module.exports = ({ strapi }) => ({
+ getToken(ctx) {
+ let token;
+
+ if (ctx.request && ctx.request.header && ctx.request.header.authorization) {
+ const parts = ctx.request.header.authorization.split(/\s+/);
+
+ if (parts[0].toLowerCase() !== 'bearer' || parts.length !== 2) {
+ return null;
+ }
+
+ token = parts[1];
+ } else {
+ return null;
+ }
+
+ return this.verify(token);
+ },
+
+ issue(payload, jwtOptions = {}) {
+ _.defaults(jwtOptions, strapi.config.get('plugin.users-permissions.jwt'));
+
+ // jwt.issue and jwt.verify are modified from stock strapi code because I believe there is an issue with how stock strapi handles JWT.
+ // see https://github.com/auth0/node-jsonwebtoken/issues/208#issuecomment-231861138
+ // console.log(`>>> JWT ISSUE invoked!!! jwtSecret:${strapi.config.get('plugin.users-permissions.jwtSecret')}`)
+
+ // const jwtOne = jwt.sign(
+ // _.clone(payload),
+ // strapi.config.get('plugin.users-permissions.jwtSecret'),
+ // jwtOptions
+ // )
+
+ // const jwtTwo = jwt.sign(
+ // _.clone(payload),
+ // new Buffer.from(strapi.config.get('plugin.users-permissions.jwtSecret'), 'base64'),
+ // jwtOptions
+ // )
+
+ // console.log(`ok so lets do the thing. here is jwtOne:${jwtOne}`)
+ // console.log(`ok so lets do the thing. here is jwtTwo:${jwtTwo}`)
+
+
+ return jwt.sign(
+ _.clone(payload.toJSON ? payload.toJSON() : payload),
+ new Buffer.from(strapi.config.get('plugin.users-permissions.jwtSecret'), 'base64'),
+ jwtOptions
+ );
+ },
+
+ verify(token) {
+ return new Promise((resolve, reject) => {
+ // jwt.issue and jwt.verify are modified from stock strapi code because I believe there is an issue with how stock strapi handles JWT.
+ // see https://github.com/auth0/node-jsonwebtoken/issues/208#issuecomment-231861138
+
+ jwt.verify(
+ token,
+ new Buffer.from(strapi.config.get('plugin.users-permissions.jwtSecret'), 'base64'),
+ {},
+ (err, tokenPayload = {}) => {
+ if (err) {
+ return reject(new Error('Invalid token.'));
+ }
+ resolve(tokenPayload);
+ }
+ );
+ });
+ },
+});
diff --git a/packages/strapi/src/extensions/users-permissions/server/services/permission.js b/packages/strapi/src/extensions/users-permissions/server/services/permission.js
new file mode 100644
index 0000000..fbcdd2d
--- /dev/null
+++ b/packages/strapi/src/extensions/users-permissions/server/services/permission.js
@@ -0,0 +1,45 @@
+'use strict';
+
+const PUBLIC_ROLE_FILTER = { role: { type: 'public' } };
+
+module.exports = ({ strapi }) => ({
+ /**
+ * Find permissions associated to a specific role ID
+ *
+ * @param {number} roleID
+ *
+ * @return {object[]}
+ */
+ async findRolePermissions(roleID) {
+ return strapi.entityService.load(
+ 'plugin::users-permissions.role',
+ { id: roleID },
+ 'permissions'
+ );
+ },
+
+ /**
+ * Find permissions for the public role
+ *
+ * @return {object[]}
+ */
+ async findPublicPermissions() {
+ return strapi.entityService.findMany('plugin::users-permissions.permission', {
+ filters: PUBLIC_ROLE_FILTER,
+ });
+ },
+
+ /**
+ * Transform a Users-Permissions' action into a content API one
+ *
+ * @param {object} permission
+ * @param {string} permission.action
+ *
+ * @return {{ action: string }}
+ */
+ toContentAPIPermission(permission) {
+ const { action } = permission;
+
+ return { action };
+ },
+});
diff --git a/packages/strapi/src/extensions/users-permissions/server/services/providers-registry.js b/packages/strapi/src/extensions/users-permissions/server/services/providers-registry.js
new file mode 100644
index 0000000..fe9490a
--- /dev/null
+++ b/packages/strapi/src/extensions/users-permissions/server/services/providers-registry.js
@@ -0,0 +1,382 @@
+'use strict';
+
+const { strict: assert } = require('assert');
+const jwt = require('jsonwebtoken');
+const jwkToPem = require('jwk-to-pem');
+
+const getCognitoPayload = async ({ idToken, jwksUrl, purest }) => {
+ const {
+ header: { kid },
+ payload,
+ } = jwt.decode(idToken, { complete: true });
+
+ if (!payload || !kid) {
+ throw new Error('The provided token is not valid');
+ }
+
+ const config = {
+ cognito: {
+ discovery: {
+ origin: jwksUrl.origin,
+ path: jwksUrl.pathname,
+ },
+ },
+ };
+ try {
+ const cognito = purest({ provider: 'cognito', config });
+ // get the JSON Web Key (JWK) for the user pool
+ const { body: jwk } = await cognito('discovery').request();
+ // Get the key with the same Key ID as the provided token
+ const key = jwk.keys.find(({ kid: jwkKid }) => jwkKid === kid);
+ const pem = jwkToPem(key);
+
+ // https://docs.aws.amazon.com/cognito/latest/developerguide/amazon-cognito-user-pools-using-tokens-verifying-a-jwt.html
+ const decodedToken = await new Promise((resolve, reject) => {
+ jwt.verify(idToken, pem, { algorithms: ['RS256'] }, (err, decodedToken) => {
+ if (err) {
+ reject();
+ }
+ resolve(decodedToken);
+ });
+ });
+ return decodedToken;
+ } catch (err) {
+ throw new Error('There was an error verifying the token');
+ }
+};
+
+const getInitialProviders = ({ purest }) => ({
+ async discord({ accessToken }) {
+ const discord = purest({ provider: 'discord' });
+
+ return discord
+ .get('users/@me')
+ .auth(accessToken)
+ .request()
+ .then(({ body }) => {
+ // Combine username and discriminator because discord username is not unique
+ const username = `${body.username}#${body.discriminator}`;
+ return {
+ username,
+ email: body.email,
+ };
+ });
+ },
+ async cognito({ query, providers }) {
+ const jwksUrl = new URL(providers.cognito.jwksurl);
+ const idToken = query.id_token;
+ const tokenPayload = await getCognitoPayload({ idToken, jwksUrl, purest });
+ return {
+ username: tokenPayload['cognito:username'],
+ email: tokenPayload.email,
+ };
+ },
+ async facebook({ accessToken }) {
+ const facebook = purest({ provider: 'facebook' });
+
+ return facebook
+ .get('me')
+ .auth(accessToken)
+ .qs({ fields: 'name,email' })
+ .request()
+ .then(({ body }) => ({
+ username: body.name,
+ email: body.email,
+ }));
+ },
+ async google({ accessToken }) {
+ const google = purest({ provider: 'google' });
+
+ return google
+ .query('oauth')
+ .get('tokeninfo')
+ .qs({ accessToken })
+ .request()
+ .then(({ body }) => ({
+ username: body.email.split('@')[0],
+ email: body.email,
+ }));
+ },
+ async github({ accessToken }) {
+ const github = purest({
+ provider: 'github',
+ defaults: {
+ headers: {
+ 'user-agent': 'strapi',
+ },
+ },
+ });
+
+ const { body: userBody } = await github.get('user').auth(accessToken).request();
+
+ // This is the public email on the github profile
+ if (userBody.email) {
+ return {
+ username: userBody.login,
+ email: userBody.email,
+ };
+ }
+ // Get the email with Github's user/emails API
+ const { body: emailBody } = await github.get('user/emails').auth(accessToken).request();
+
+ return {
+ username: userBody.login,
+ email: Array.isArray(emailBody)
+ ? emailBody.find((email) => email.primary === true).email
+ : null,
+ };
+ },
+ async microsoft({ accessToken }) {
+ const microsoft = purest({ provider: 'microsoft' });
+
+ return microsoft
+ .get('me')
+ .auth(accessToken)
+ .request()
+ .then(({ body }) => ({
+ username: body.userPrincipalName,
+ email: body.userPrincipalName,
+ }));
+ },
+ async twitter({ accessToken, query, providers }) {
+ const twitter = purest({
+ provider: 'twitter',
+ defaults: {
+ oauth: {
+ consumer_key: providers.twitter.key,
+ consumer_secret: providers.twitter.secret,
+ },
+ },
+ });
+
+ return twitter
+ .get('account/verify_credentials')
+ .auth(accessToken, query.access_secret)
+ .qs({ screen_name: query['raw[screen_name]'], include_email: 'true' })
+ .request()
+ .then(({ body }) => ({
+ username: body.screen_name,
+ email: body.email,
+ }));
+ },
+ async instagram({ accessToken }) {
+ const instagram = purest({ provider: 'instagram' });
+
+ return instagram
+ .get('me')
+ .auth(accessToken)
+ .qs({ fields: 'id,username' })
+ .request()
+ .then(({ body }) => ({
+ username: body.username,
+ email: `${body.username}@strapi.io`, // dummy email as Instagram does not provide user email
+ }));
+ },
+ async vk({ accessToken, query }) {
+ const vk = purest({ provider: 'vk' });
+
+ return vk
+ .get('users')
+ .auth(accessToken)
+ .qs({ id: query.raw.user_id, v: '5.122' })
+ .request()
+ .then(({ body }) => ({
+ username: `${body.response[0].last_name} ${body.response[0].first_name}`,
+ email: query.raw.email,
+ }));
+ },
+ async twitch({ accessToken, providers }) {
+ const twitch = purest({
+ provider: 'twitch',
+ config: {
+ twitch: {
+ default: {
+ origin: 'https://api.twitch.tv',
+ path: 'helix/{path}',
+ headers: {
+ Authorization: 'Bearer {auth}',
+ 'Client-Id': '{auth}',
+ },
+ },
+ },
+ },
+ });
+
+ return twitch
+ .get('users')
+ .auth(accessToken, providers.twitch.key)
+ .request()
+ .then(({ body }) => ({
+ username: body.data[0].login,
+ email: body.data[0].email,
+ }));
+ },
+ async linkedin({ accessToken }) {
+ const linkedIn = purest({ provider: 'linkedin' });
+ const {
+ body: { localizedFirstName },
+ } = await linkedIn.get('me').auth(accessToken).request();
+ const {
+ body: { elements },
+ } = await linkedIn
+ .get('emailAddress?q=members&projection=(elements*(handle~))')
+ .auth(accessToken)
+ .request();
+
+ const email = elements[0]['handle~'];
+
+ return {
+ username: localizedFirstName,
+ email: email.emailAddress,
+ };
+ },
+ async reddit({ accessToken }) {
+ const reddit = purest({
+ provider: 'reddit',
+ config: {
+ reddit: {
+ default: {
+ origin: 'https://oauth.reddit.com',
+ path: 'api/{version}/{path}',
+ version: 'v1',
+ headers: {
+ Authorization: 'Bearer {auth}',
+ 'user-agent': 'strapi',
+ },
+ },
+ },
+ },
+ });
+
+ return reddit
+ .get('me')
+ .auth(accessToken)
+ .request()
+ .then(({ body }) => ({
+ username: body.name,
+ email: `${body.name}@strapi.io`, // dummy email as Reddit does not provide user email
+ }));
+ },
+ async auth0({ accessToken, providers }) {
+ const auth0 = purest({ provider: 'auth0' });
+
+ return auth0
+ .get('userinfo')
+ .subdomain(providers.auth0.subdomain)
+ .auth(accessToken)
+ .request()
+ .then(({ body }) => {
+ const username = body.username || body.nickname || body.name || body.email.split('@')[0];
+ const email = body.email || `${username.replace(/\s+/g, '.')}@strapi.io`;
+
+ return {
+ username,
+ email,
+ };
+ });
+ },
+ async cas({ accessToken, providers }) {
+ const cas = purest({ provider: 'cas' });
+
+ return cas
+ .get('oidc/profile')
+ .subdomain(providers.cas.subdomain)
+ .auth(accessToken)
+ .request()
+ .then(({ body }) => {
+ // CAS attribute may be in body.attributes or "FLAT", depending on CAS config
+ const username = body.attributes
+ ? body.attributes.strapiusername || body.id || body.sub
+ : body.strapiusername || body.id || body.sub;
+ const email = body.attributes
+ ? body.attributes.strapiemail || body.attributes.email
+ : body.strapiemail || body.email;
+ if (!username || !email) {
+ strapi.log.warn(
+ `CAS Response Body did not contain required attributes: ${JSON.stringify(body)}`
+ );
+ }
+ return {
+ username,
+ email,
+ };
+ });
+ },
+ async patreon({ accessToken }) {
+ const patreon = purest({
+ provider: 'patreon',
+ config: {
+ patreon: {
+ default: {
+ origin: 'https://www.patreon.com',
+ path: 'api/oauth2/{path}',
+ headers: {
+ authorization: 'Bearer {auth}',
+ },
+ },
+ },
+ },
+ });
+
+ return patreon
+ .get('v2/identity')
+ .auth(accessToken)
+ .qs(new URLSearchParams({
+ 'include': 'memberships,memberships.currently_entitled_tiers,memberships.currently_entitled_tiers.benefits,memberships.campaign',
+ 'fields[user]': 'full_name,email',
+ 'fields[member]': 'full_name,is_follower,patron_status,currently_entitled_amount_cents,campaign_lifetime_support_cents',
+ 'fields[tier]': 'title',
+ 'fields[benefit]': 'title',
+ }).toString())
+ .request()
+ .then(({ body }) => {
+ const patreonData = body.data.attributes;
+
+ let memberships = []
+ let benefits = []
+ if (body?.included !== undefined) {
+ memberships = body.included
+ .filter((i) => i.type === 'member')
+ .filter((i) => i.attributes.patron_status === 'active_patron')
+ .map((i) => i.id)
+
+ benefits = body.included
+ .filter((i) => i.type === 'benefit')
+ .map((i) => i.id)
+ }
+
+
+ return {
+ username: patreonData.full_name,
+ email: patreonData.email,
+ memberships: memberships,
+ benefits: benefits,
+ };
+ });
+ },
+});
+
+module.exports = () => {
+ const purest = require('purest');
+
+ const providersCallbacks = getInitialProviders({ purest });
+
+ return {
+ register(providerName, provider) {
+ assert(typeof providerName === 'string', 'Provider name must be a string');
+ assert(typeof provider === 'function', 'Provider callback must be a function');
+
+ providersCallbacks[providerName] = provider({ purest });
+ },
+
+ async run({ provider, accessToken, query, providers }) {
+ if (!providersCallbacks[provider]) {
+ throw new Error('Unknown provider.');
+ }
+
+ const providerCb = providersCallbacks[provider];
+
+ return providerCb({ accessToken, query, providers });
+ },
+ };
+};
diff --git a/packages/strapi/src/extensions/users-permissions/server/services/providers.js b/packages/strapi/src/extensions/users-permissions/server/services/providers.js
new file mode 100644
index 0000000..e5f919e
--- /dev/null
+++ b/packages/strapi/src/extensions/users-permissions/server/services/providers.js
@@ -0,0 +1,156 @@
+'use strict';
+
+/**
+ * Module dependencies
+ */
+
+// Public node modules.
+const _ = require('lodash');
+const urlJoin = require('url-join');
+
+const { getAbsoluteServerUrl } = require('@strapi/utils');
+const { getService } = require('../utils');
+
+module.exports = ({ strapi }) => {
+ /**
+ * Helper to get profiles
+ *
+ * @param {String} provider
+ */
+
+ const getProfile = async (provider, query) => {
+ const accessToken = query.access_token || query.code || query.oauth_token;
+
+ const providers = await strapi
+ .store({ type: 'plugin', name: 'users-permissions', key: 'grant' })
+ .get();
+
+ return getService('providers-registry').run({
+ provider,
+ query,
+ accessToken,
+ providers,
+ });
+ };
+
+ /**
+ * Connect thanks to a third-party provider.
+ *
+ *
+ * @param {String} provider
+ * @param {String} accessToken
+ *
+ * @return {*}
+ */
+
+ const connect = async (provider, query) => {
+ const accessToken = query.access_token || query.code || query.oauth_token;
+
+ if (!accessToken) {
+ throw new Error('No access_token.');
+ }
+
+ // Get the profile.
+ const profile = await getProfile(provider, query);
+
+ const email = _.toLower(profile.email);
+
+ // We need at least the mail.
+ if (!email) {
+ throw new Error('Email was not available.');
+ }
+
+ const users = await strapi.query('plugin::users-permissions.user').findMany({
+ where: { email },
+ });
+
+ const advancedSettings = await strapi
+ .store({ type: 'plugin', name: 'users-permissions', key: 'advanced' })
+ .get();
+
+ const user = _.find(users, { provider });
+
+ if (_.isEmpty(user) && !advancedSettings.allow_register) {
+ throw new Error('Register action is actually not available.');
+ }
+
+ if (!_.isEmpty(user)) {
+ console.log(`>>> welcome back, user!`)
+ console.log(user)
+ }
+
+
+ // Retrieve default role.
+ const defaultRole = await strapi
+ .query('plugin::users-permissions.role')
+ .findOne({ where: { type: advancedSettings.default_role } });
+
+ const patronRole = await strapi
+ .query('plugin::users-permissions.role')
+ .findOne({ where: { name: 'Patron' }});
+
+ if (_.isEmpty(patronRole)) throw new Error('Patron role is missing in Strapi. Please create it in users-permissions plugin.');
+
+ const patreonModel = await strapi
+ .query('api::patreon.patreon')
+ .findOne({ select: ['id', 'accessToken', 'benefitId'], where: { id: 1 } });
+
+ console.log(` >> patreon model`)
+ console.log(patreonModel)
+ console.log(` >> patreon:${patreonModel.id}`)
+
+ // get the user's patron status
+ console.log(` >> HERE is the user's patreon profile`)
+ const isPatron = profile.benefits.includes(patreonModel.benefitId)
+ const patreonBenefits = profile.benefits.join(',')
+ console.log(`isPatron:${isPatron}`)
+
+
+ // Update the user's role to match their patron status
+ const selectedRole = (isPatron) ? patronRole : defaultRole
+
+
+ if (!_.isEmpty(user)) {
+ const updatedUser = await strapi
+ .query('plugin::users-permissions.user')
+ .update({
+ where: { email },
+ data: {
+ ...user,
+ role: selectedRole.id,
+ patreonBenefits
+ }
+ })
+ return updatedUser;
+ }
+
+ if (users.length && advancedSettings.unique_email) {
+ throw new Error('Email is already taken.');
+ }
+
+ // Create the new user.
+ const newUser = {
+ ...profile,
+ email, // overwrite with lowercased email
+ provider,
+ role: selectedRole.id,
+ confirmed: true,
+ };
+
+ const createdUser = await strapi
+ .query('plugin::users-permissions.user')
+ .create({ data: newUser });
+
+ return createdUser;
+ };
+
+ const buildRedirectUri = (provider = '') => {
+ const apiPrefix = strapi.config.get('api.rest.prefix');
+ return urlJoin(getAbsoluteServerUrl(strapi.config), apiPrefix, 'connect', provider, 'callback');
+ };
+
+ return {
+ connect,
+ buildRedirectUri,
+ };
+};
diff --git a/packages/strapi/src/extensions/users-permissions/server/services/role.js b/packages/strapi/src/extensions/users-permissions/server/services/role.js
new file mode 100644
index 0000000..7b2ab81
--- /dev/null
+++ b/packages/strapi/src/extensions/users-permissions/server/services/role.js
@@ -0,0 +1,177 @@
+'use strict';
+
+const _ = require('lodash');
+const { NotFoundError } = require('@strapi/utils').errors;
+const { getService } = require('../utils');
+
+module.exports = ({ strapi }) => ({
+ async createRole(params) {
+ if (!params.type) {
+ params.type = _.snakeCase(_.deburr(_.toLower(params.name)));
+ }
+
+ const role = await strapi
+ .query('plugin::users-permissions.role')
+ .create({ data: _.omit(params, ['users', 'permissions']) });
+
+ const createPromises = _.flatMap(params.permissions, (type, typeName) => {
+ return _.flatMap(type.controllers, (controller, controllerName) => {
+ return _.reduce(
+ controller,
+ (acc, action, actionName) => {
+ const { enabled /* policy */ } = action;
+
+ if (enabled) {
+ const actionID = `${typeName}.${controllerName}.${actionName}`;
+
+ acc.push(
+ strapi
+ .query('plugin::users-permissions.permission')
+ .create({ data: { action: actionID, role: role.id } })
+ );
+ }
+
+ return acc;
+ },
+ []
+ );
+ });
+ });
+
+ await Promise.all(createPromises);
+ },
+
+ async findOne(roleID) {
+ const role = await strapi
+ .query('plugin::users-permissions.role')
+ .findOne({ where: { id: roleID }, populate: ['permissions'] });
+
+ if (!role) {
+ throw new NotFoundError('Role not found');
+ }
+
+ const allActions = getService('users-permissions').getActions();
+
+ // Group by `type`.
+ role.permissions.forEach((permission) => {
+ const [type, controller, action] = permission.action.split('.');
+
+ _.set(allActions, `${type}.controllers.${controller}.${action}`, {
+ enabled: true,
+ policy: '',
+ });
+ });
+
+ return {
+ ...role,
+ permissions: allActions,
+ };
+ },
+
+ async find() {
+ const roles = await strapi.query('plugin::users-permissions.role').findMany({ sort: ['name'] });
+
+ for (const role of roles) {
+ role.nb_users = await strapi
+ .query('plugin::users-permissions.user')
+ .count({ where: { role: { id: role.id } } });
+ }
+
+ return roles;
+ },
+
+ async updateRole(roleID, data) {
+ const role = await strapi
+ .query('plugin::users-permissions.role')
+ .findOne({ where: { id: roleID }, populate: ['permissions'] });
+
+ if (!role) {
+ throw new NotFoundError('Role not found');
+ }
+
+ await strapi.query('plugin::users-permissions.role').update({
+ where: { id: roleID },
+ data: _.pick(data, ['name', 'description']),
+ });
+
+ const { permissions } = data;
+
+ const newActions = _.flatMap(permissions, (type, typeName) => {
+ return _.flatMap(type.controllers, (controller, controllerName) => {
+ return _.reduce(
+ controller,
+ (acc, action, actionName) => {
+ const { enabled /* policy */ } = action;
+
+ if (enabled) {
+ acc.push(`${typeName}.${controllerName}.${actionName}`);
+ }
+
+ return acc;
+ },
+ []
+ );
+ });
+ });
+
+ const oldActions = role.permissions.map(({ action }) => action);
+
+ const toDelete = role.permissions.reduce((acc, permission) => {
+ if (!newActions.includes(permission.action)) {
+ acc.push(permission);
+ }
+ return acc;
+ }, []);
+
+ const toCreate = newActions
+ .filter((action) => !oldActions.includes(action))
+ .map((action) => ({ action, role: role.id }));
+
+ await Promise.all(
+ toDelete.map((permission) =>
+ strapi
+ .query('plugin::users-permissions.permission')
+ .delete({ where: { id: permission.id } })
+ )
+ );
+
+ await Promise.all(
+ toCreate.map((permissionInfo) =>
+ strapi.query('plugin::users-permissions.permission').create({ data: permissionInfo })
+ )
+ );
+ },
+
+ async deleteRole(roleID, publicRoleID) {
+ const role = await strapi
+ .query('plugin::users-permissions.role')
+ .findOne({ where: { id: roleID }, populate: ['users', 'permissions'] });
+
+ if (!role) {
+ throw new NotFoundError('Role not found');
+ }
+
+ // Move users to guest role.
+ await Promise.all(
+ role.users.map((user) => {
+ return strapi.query('plugin::users-permissions.user').update({
+ where: { id: user.id },
+ data: { role: publicRoleID },
+ });
+ })
+ );
+
+ // Remove permissions related to this role.
+ // TODO: use delete many
+ await Promise.all(
+ role.permissions.map((permission) => {
+ return strapi.query('plugin::users-permissions.permission').delete({
+ where: { id: permission.id },
+ });
+ })
+ );
+
+ // Delete the role.
+ await strapi.query('plugin::users-permissions.role').delete({ where: { id: roleID } });
+ },
+});
diff --git a/packages/strapi/src/extensions/users-permissions/server/services/user.js b/packages/strapi/src/extensions/users-permissions/server/services/user.js
new file mode 100644
index 0000000..27cf71a
--- /dev/null
+++ b/packages/strapi/src/extensions/users-permissions/server/services/user.js
@@ -0,0 +1,148 @@
+'use strict';
+
+/**
+ * User.js service
+ *
+ * @description: A set of functions similar to controller's actions to avoid code duplication.
+ */
+
+const crypto = require('crypto');
+const bcrypt = require('bcryptjs');
+const urlJoin = require('url-join');
+
+const { getAbsoluteAdminUrl, getAbsoluteServerUrl, sanitize } = require('@strapi/utils');
+const { getService } = require('../utils');
+
+module.exports = ({ strapi }) => ({
+ /**
+ * Promise to count users
+ *
+ * @return {Promise}
+ */
+
+ count(params) {
+ return strapi.query('plugin::users-permissions.user').count({ where: params });
+ },
+
+ /**
+ * Promise to search count users
+ *
+ * @return {Promise}
+ */
+
+ /**
+ * Promise to add a/an user.
+ * @return {Promise}
+ */
+ async add(values) {
+ return strapi.entityService.create('plugin::users-permissions.user', {
+ data: values,
+ populate: ['role'],
+ });
+ },
+
+ /**
+ * Promise to edit a/an user.
+ * @param {string} userId
+ * @param {object} params
+ * @return {Promise}
+ */
+ async edit(userId, params = {}) {
+ return strapi.entityService.update('plugin::users-permissions.user', userId, {
+ data: params,
+ populate: ['role'],
+ });
+ },
+
+ /**
+ * Promise to fetch a/an user.
+ * @return {Promise}
+ */
+ fetch(id, params) {
+ return strapi.entityService.findOne('plugin::users-permissions.user', id, params);
+ },
+
+ /**
+ * Promise to fetch authenticated user.
+ * @return {Promise}
+ */
+ fetchAuthenticatedUser(id) {
+ return strapi
+ .query('plugin::users-permissions.user')
+ .findOne({ where: { id }, populate: ['role'] });
+ },
+
+ /**
+ * Promise to fetch all users.
+ * @return {Promise}
+ */
+ fetchAll(params) {
+ return strapi.entityService.findMany('plugin::users-permissions.user', params);
+ },
+
+ /**
+ * Promise to remove a/an user.
+ * @return {Promise}
+ */
+ async remove(params) {
+ return strapi.query('plugin::users-permissions.user').delete({ where: params });
+ },
+
+ validatePassword(password, hash) {
+ return bcrypt.compare(password, hash);
+ },
+
+ async sendConfirmationEmail(user) {
+ const userPermissionService = getService('users-permissions');
+ const pluginStore = await strapi.store({ type: 'plugin', name: 'users-permissions' });
+ const userSchema = strapi.getModel('plugin::users-permissions.user');
+
+ const settings = await pluginStore
+ .get({ key: 'email' })
+ .then((storeEmail) => storeEmail.email_confirmation.options);
+
+ // Sanitize the template's user information
+ const sanitizedUserInfo = await sanitize.sanitizers.defaultSanitizeOutput(userSchema, user);
+
+ const confirmationToken = crypto.randomBytes(20).toString('hex');
+
+ await this.edit(user.id, { confirmationToken });
+
+ const apiPrefix = strapi.config.get('api.rest.prefix');
+
+ try {
+ settings.message = await userPermissionService.template(settings.message, {
+ URL: urlJoin(getAbsoluteServerUrl(strapi.config), apiPrefix, '/auth/email-confirmation'),
+ SERVER_URL: getAbsoluteServerUrl(strapi.config),
+ ADMIN_URL: getAbsoluteAdminUrl(strapi.config),
+ USER: sanitizedUserInfo,
+ CODE: confirmationToken,
+ });
+
+ settings.object = await userPermissionService.template(settings.object, {
+ USER: sanitizedUserInfo,
+ });
+ } catch {
+ strapi.log.error(
+ '[plugin::users-permissions.sendConfirmationEmail]: Failed to generate a template for "user confirmation email". Please make sure your email template is valid and does not contain invalid characters or patterns'
+ );
+ return;
+ }
+
+ // Send an email to the user.
+ await strapi
+ .plugin('email')
+ .service('email')
+ .send({
+ to: user.email,
+ from:
+ settings.from.email && settings.from.name
+ ? `${settings.from.name} <${settings.from.email}>`
+ : undefined,
+ replyTo: settings.response_email,
+ subject: settings.object,
+ text: settings.message,
+ html: settings.message,
+ });
+ },
+});
diff --git a/packages/strapi/src/extensions/users-permissions/server/services/users-permissions.js b/packages/strapi/src/extensions/users-permissions/server/services/users-permissions.js
new file mode 100644
index 0000000..3389cdb
--- /dev/null
+++ b/packages/strapi/src/extensions/users-permissions/server/services/users-permissions.js
@@ -0,0 +1,249 @@
+'use strict';
+
+const _ = require('lodash');
+const { filter, map, pipe, prop } = require('lodash/fp');
+const urlJoin = require('url-join');
+const {
+ template: { createStrictInterpolationRegExp },
+ errors,
+ keysDeep,
+} = require('@strapi/utils');
+
+const { getService } = require('../utils');
+
+const DEFAULT_PERMISSIONS = [
+ { action: 'plugin::users-permissions.auth.callback', roleType: 'public' },
+ { action: 'plugin::users-permissions.auth.connect', roleType: 'public' },
+ { action: 'plugin::users-permissions.auth.forgotPassword', roleType: 'public' },
+ { action: 'plugin::users-permissions.auth.resetPassword', roleType: 'public' },
+ { action: 'plugin::users-permissions.auth.register', roleType: 'public' },
+ { action: 'plugin::users-permissions.auth.emailConfirmation', roleType: 'public' },
+ { action: 'plugin::users-permissions.auth.sendEmailConfirmation', roleType: 'public' },
+ { action: 'plugin::users-permissions.user.me', roleType: 'authenticated' },
+ { action: 'plugin::users-permissions.auth.changePassword', roleType: 'authenticated' },
+];
+
+const transformRoutePrefixFor = (pluginName) => (route) => {
+ const prefix = route.config && route.config.prefix;
+ const path = prefix !== undefined ? `${prefix}${route.path}` : `/${pluginName}${route.path}`;
+
+ return {
+ ...route,
+ path,
+ };
+};
+
+module.exports = ({ strapi }) => ({
+ getActions({ defaultEnable = false } = {}) {
+ const actionMap = {};
+
+ const isContentApi = (action) => {
+ if (!_.has(action, Symbol.for('__type__'))) {
+ return false;
+ }
+
+ return action[Symbol.for('__type__')].includes('content-api');
+ };
+
+ _.forEach(strapi.api, (api, apiName) => {
+ const controllers = _.reduce(
+ api.controllers,
+ (acc, controller, controllerName) => {
+ const contentApiActions = _.pickBy(controller, isContentApi);
+
+ if (_.isEmpty(contentApiActions)) {
+ return acc;
+ }
+
+ acc[controllerName] = _.mapValues(contentApiActions, () => {
+ return {
+ enabled: defaultEnable,
+ policy: '',
+ };
+ });
+
+ return acc;
+ },
+ {}
+ );
+
+ if (!_.isEmpty(controllers)) {
+ actionMap[`api::${apiName}`] = { controllers };
+ }
+ });
+
+ _.forEach(strapi.plugins, (plugin, pluginName) => {
+ const controllers = _.reduce(
+ plugin.controllers,
+ (acc, controller, controllerName) => {
+ const contentApiActions = _.pickBy(controller, isContentApi);
+
+ if (_.isEmpty(contentApiActions)) {
+ return acc;
+ }
+
+ acc[controllerName] = _.mapValues(contentApiActions, () => {
+ return {
+ enabled: defaultEnable,
+ policy: '',
+ };
+ });
+
+ return acc;
+ },
+ {}
+ );
+
+ if (!_.isEmpty(controllers)) {
+ actionMap[`plugin::${pluginName}`] = { controllers };
+ }
+ });
+
+ return actionMap;
+ },
+
+ async getRoutes() {
+ const routesMap = {};
+
+ _.forEach(strapi.api, (api, apiName) => {
+ const routes = _.flatMap(api.routes, (route) => {
+ if (_.has(route, 'routes')) {
+ return route.routes;
+ }
+
+ return route;
+ }).filter((route) => route.info.type === 'content-api');
+
+ if (routes.length === 0) {
+ return;
+ }
+
+ const apiPrefix = strapi.config.get('api.rest.prefix');
+ routesMap[`api::${apiName}`] = routes.map((route) => ({
+ ...route,
+ path: urlJoin(apiPrefix, route.path),
+ }));
+ });
+
+ _.forEach(strapi.plugins, (plugin, pluginName) => {
+ const transformPrefix = transformRoutePrefixFor(pluginName);
+
+ const routes = _.flatMap(plugin.routes, (route) => {
+ if (_.has(route, 'routes')) {
+ return route.routes.map(transformPrefix);
+ }
+
+ return transformPrefix(route);
+ }).filter((route) => route.info.type === 'content-api');
+
+ if (routes.length === 0) {
+ return;
+ }
+
+ const apiPrefix = strapi.config.get('api.rest.prefix');
+ routesMap[`plugin::${pluginName}`] = routes.map((route) => ({
+ ...route,
+ path: urlJoin(apiPrefix, route.path),
+ }));
+ });
+
+ return routesMap;
+ },
+
+ async syncPermissions() {
+ const roles = await strapi.query('plugin::users-permissions.role').findMany();
+ const dbPermissions = await strapi.query('plugin::users-permissions.permission').findMany();
+
+ const permissionsFoundInDB = _.uniq(_.map(dbPermissions, 'action'));
+
+ const appActions = _.flatMap(strapi.api, (api, apiName) => {
+ return _.flatMap(api.controllers, (controller, controllerName) => {
+ return _.keys(controller).map((actionName) => {
+ return `api::${apiName}.${controllerName}.${actionName}`;
+ });
+ });
+ });
+
+ const pluginsActions = _.flatMap(strapi.plugins, (plugin, pluginName) => {
+ return _.flatMap(plugin.controllers, (controller, controllerName) => {
+ return _.keys(controller).map((actionName) => {
+ return `plugin::${pluginName}.${controllerName}.${actionName}`;
+ });
+ });
+ });
+
+ const allActions = [...appActions, ...pluginsActions];
+
+ const toDelete = _.difference(permissionsFoundInDB, allActions);
+
+ await Promise.all(
+ toDelete.map((action) => {
+ return strapi.query('plugin::users-permissions.permission').delete({ where: { action } });
+ })
+ );
+
+ if (permissionsFoundInDB.length === 0) {
+ // create default permissions
+ for (const role of roles) {
+ const toCreate = pipe(
+ filter(({ roleType }) => roleType === role.type || roleType === null),
+ map(prop('action'))
+ )(DEFAULT_PERMISSIONS);
+
+ await Promise.all(
+ toCreate.map((action) => {
+ return strapi.query('plugin::users-permissions.permission').create({
+ data: {
+ action,
+ role: role.id,
+ },
+ });
+ })
+ );
+ }
+ }
+ },
+
+ async initialize() {
+ const roleCount = await strapi.query('plugin::users-permissions.role').count();
+
+ if (roleCount === 0) {
+ await strapi.query('plugin::users-permissions.role').create({
+ data: {
+ name: 'Authenticated',
+ description: 'Default role given to authenticated user.',
+ type: 'authenticated',
+ },
+ });
+
+ await strapi.query('plugin::users-permissions.role').create({
+ data: {
+ name: 'Public',
+ description: 'Default role given to unauthenticated user.',
+ type: 'public',
+ },
+ });
+ }
+
+ return getService('users-permissions').syncPermissions();
+ },
+
+ async updateUserRole(user, role) {
+ return strapi
+ .query('plugin::users-permissions.user')
+ .update({ where: { id: user.id }, data: { role } });
+ },
+
+ template(layout, data) {
+ const allowedTemplateVariables = keysDeep(data);
+
+ // Create a strict interpolation RegExp based on possible variable names
+ const interpolate = createStrictInterpolationRegExp(allowedTemplateVariables, 'g');
+
+ try {
+ return _.template(layout, { interpolate, evaluate: false, escape: false })(data);
+ } catch (e) {
+ throw new errors.ApplicationError('Invalid email template');
+ }
+ },
+});
diff --git a/packages/strapi/src/extensions/users-permissions/server/strategies/users-permissions.js b/packages/strapi/src/extensions/users-permissions/server/strategies/users-permissions.js
new file mode 100644
index 0000000..7ff3421
--- /dev/null
+++ b/packages/strapi/src/extensions/users-permissions/server/strategies/users-permissions.js
@@ -0,0 +1,114 @@
+'use strict';
+
+const { castArray, map, every, pipe } = require('lodash/fp');
+const { ForbiddenError, UnauthorizedError } = require('@strapi/utils').errors;
+
+const { getService } = require('../utils');
+
+const getAdvancedSettings = () => {
+ return strapi.store({ type: 'plugin', name: 'users-permissions' }).get({ key: 'advanced' });
+};
+
+const authenticate = async (ctx) => {
+ try {
+ const token = await getService('jwt').getToken(ctx);
+
+ if (token) {
+ const { id } = token;
+
+ // Invalid token
+ if (id === undefined) {
+ return { authenticated: false };
+ }
+
+ const user = await getService('user').fetchAuthenticatedUser(id);
+
+ // No user associated to the token
+ if (!user) {
+ return { error: 'Invalid credentials' };
+ }
+
+ const advancedSettings = await getAdvancedSettings();
+
+ // User not confirmed
+ if (advancedSettings.email_confirmation && !user.confirmed) {
+ return { error: 'Invalid credentials' };
+ }
+
+ // User blocked
+ if (user.blocked) {
+ return { error: 'Invalid credentials' };
+ }
+
+ // Fetch user's permissions
+ const permissions = await Promise.resolve(user.role.id)
+ .then(getService('permission').findRolePermissions)
+ .then(map(getService('permission').toContentAPIPermission));
+
+ // Generate an ability (content API engine) based on the given permissions
+ const ability = await strapi.contentAPI.permissions.engine.generateAbility(permissions);
+
+ ctx.state.user = user;
+
+ return {
+ authenticated: true,
+ credentials: user,
+ ability,
+ };
+ }
+
+ const publicPermissions = await getService('permission')
+ .findPublicPermissions()
+ .then(map(getService('permission').toContentAPIPermission));
+
+ if (publicPermissions.length === 0) {
+ return { authenticated: false };
+ }
+
+ const ability = await strapi.contentAPI.permissions.engine.generateAbility(publicPermissions);
+
+ return {
+ authenticated: true,
+ credentials: null,
+ ability,
+ };
+ } catch (err) {
+ return { authenticated: false };
+ }
+};
+
+const verify = async (auth, config) => {
+ const { credentials: user, ability } = auth;
+
+ if (!config.scope) {
+ if (!user) {
+ // A non authenticated user cannot access routes that do not have a scope
+ throw new UnauthorizedError();
+ } else {
+ // An authenticated user can access non scoped routes
+ return;
+ }
+ }
+
+ // If no ability have been generated, then consider auth is missing
+ if (!ability) {
+ throw new UnauthorizedError();
+ }
+
+ const isAllowed = pipe(
+ // Make sure we're dealing with an array
+ castArray,
+ // Transform the scope array into an action array
+ every((scope) => ability.can(scope))
+ )(config.scope);
+
+ if (!isAllowed) {
+ throw new ForbiddenError();
+ }
+};
+
+module.exports = {
+ name: 'users-permissions',
+ authenticate,
+ verify,
+};
diff --git a/packages/strapi/src/extensions/users-permissions/server/utils/index.d.ts b/packages/strapi/src/extensions/users-permissions/server/utils/index.d.ts
new file mode 100644
index 0000000..b9d7e20
--- /dev/null
+++ b/packages/strapi/src/extensions/users-permissions/server/utils/index.d.ts
@@ -0,0 +1,18 @@
+import * as usersPermissions from '../services/users-permissions';
+import * as user from '../services/user';
+import * as role from '../services/role';
+import * as jwt from '../services/jwt';
+import * as providers from '../services/providers';
+import * as permission from '../services/permission';
+
+type S = {
+ ['users-permissions']: typeof usersPermissions;
+ ['role']: typeof role;
+ user: typeof user;
+ jwt: typeof jwt;
+ providers: typeof providers;
+ ['providers-registry']: typeof providers;
+ permission: typeof permission;
+};
+
+export function getService(name: T): ReturnType;
diff --git a/packages/strapi/src/extensions/users-permissions/server/utils/index.js b/packages/strapi/src/extensions/users-permissions/server/utils/index.js
new file mode 100644
index 0000000..c87a858
--- /dev/null
+++ b/packages/strapi/src/extensions/users-permissions/server/utils/index.js
@@ -0,0 +1,12 @@
+'use strict';
+
+const sanitize = require('./sanitize');
+
+const getService = (name) => {
+ return strapi.plugin('users-permissions').service(name);
+};
+
+module.exports = {
+ getService,
+ sanitize,
+};
diff --git a/packages/strapi/src/extensions/users-permissions/server/utils/sanitize/index.js b/packages/strapi/src/extensions/users-permissions/server/utils/sanitize/index.js
new file mode 100644
index 0000000..db0884f
--- /dev/null
+++ b/packages/strapi/src/extensions/users-permissions/server/utils/sanitize/index.js
@@ -0,0 +1,9 @@
+'use strict';
+
+const visitors = require('./visitors');
+const sanitizers = require('./sanitizers');
+
+module.exports = {
+ sanitizers,
+ visitors,
+};
diff --git a/packages/strapi/src/extensions/users-permissions/server/utils/sanitize/sanitizers.js b/packages/strapi/src/extensions/users-permissions/server/utils/sanitize/sanitizers.js
new file mode 100644
index 0000000..940dbd0
--- /dev/null
+++ b/packages/strapi/src/extensions/users-permissions/server/utils/sanitize/sanitizers.js
@@ -0,0 +1,19 @@
+'use strict';
+
+const { curry } = require('lodash/fp');
+const { traverseEntity, pipeAsync } = require('@strapi/utils');
+
+const { removeUserRelationFromRoleEntities } = require('./visitors');
+
+const sanitizeUserRelationFromRoleEntities = curry((schema, entity) => {
+ return traverseEntity(removeUserRelationFromRoleEntities, { schema }, entity);
+});
+
+const defaultSanitizeOutput = curry((schema, entity) => {
+ return pipeAsync(sanitizeUserRelationFromRoleEntities(schema))(entity);
+});
+
+module.exports = {
+ sanitizeUserRelationFromRoleEntities,
+ defaultSanitizeOutput,
+};
diff --git a/packages/strapi/src/extensions/users-permissions/server/utils/sanitize/visitors/index.js b/packages/strapi/src/extensions/users-permissions/server/utils/sanitize/visitors/index.js
new file mode 100644
index 0000000..bc20d0f
--- /dev/null
+++ b/packages/strapi/src/extensions/users-permissions/server/utils/sanitize/visitors/index.js
@@ -0,0 +1,5 @@
+'use strict';
+
+module.exports = {
+ removeUserRelationFromRoleEntities: require('./remove-user-relation-from-role-entities'),
+};
diff --git a/packages/strapi/src/extensions/users-permissions/server/utils/sanitize/visitors/remove-user-relation-from-role-entities.js b/packages/strapi/src/extensions/users-permissions/server/utils/sanitize/visitors/remove-user-relation-from-role-entities.js
new file mode 100644
index 0000000..e20f85a
--- /dev/null
+++ b/packages/strapi/src/extensions/users-permissions/server/utils/sanitize/visitors/remove-user-relation-from-role-entities.js
@@ -0,0 +1,11 @@
+'use strict';
+
+module.exports = ({ schema, key, attribute }, { remove }) => {
+ if (
+ attribute.type === 'relation' &&
+ attribute.target === 'plugin::users-permissions.user' &&
+ schema.uid === 'plugin::users-permissions.role'
+ ) {
+ remove(key);
+ }
+};
diff --git a/packages/strapi/src/extensions/users-permissions/strapi-admin.js b/packages/strapi/src/extensions/users-permissions/strapi-admin.js
new file mode 100644
index 0000000..2d1a3d9
--- /dev/null
+++ b/packages/strapi/src/extensions/users-permissions/strapi-admin.js
@@ -0,0 +1,3 @@
+'use strict';
+
+module.exports = require('./admin/src').default;
diff --git a/packages/strapi/src/extensions/users-permissions/strapi-server.js b/packages/strapi/src/extensions/users-permissions/strapi-server.js
new file mode 100644
index 0000000..74205c9
--- /dev/null
+++ b/packages/strapi/src/extensions/users-permissions/strapi-server.js
@@ -0,0 +1,12 @@
+'use strict';
+
+// Yes, this file is custom.
+module.exports = (plugin) => {
+ plugin.bootstrap = require('./server/bootstrap');
+ plugin.services['providers'] = require('./server/services/providers');
+ plugin.services['providers-registry'] = require('./server/services/providers-registry');
+ plugin.services['jwt'] = require('./server/services/jwt');
+ return plugin;
+}
+
+
diff --git a/packages/strapi/src/index.js b/packages/strapi/src/index.js
new file mode 100644
index 0000000..316be2c
--- /dev/null
+++ b/packages/strapi/src/index.js
@@ -0,0 +1,80 @@
+'use strict';
+
+
+
+// const purest = require('purest');
+
+// const patreon = async function patreon({ accessToken }) {
+// console.log(` >> patreon callback ascivated with accessToken:${accessToken}`)
+// const patreon = purest({
+// provider: 'patreon',
+// config: {
+// patreon: {
+// default: {
+// origin: 'https://www.patreon.com',
+// path: 'api/oauth2/{path}',
+// headers: {
+// authorization: 'Bearer {auth}',
+// },
+// },
+// },
+// },
+// });
+
+// return patreon
+// .get('v2/identity')
+// .auth(accessToken)
+// .qs(new URLSearchParams({
+// "include": "memberships,memberships.currently_entitled_tiers,memberships.currently_entitled_tiers.benefits,memberships.campaign",
+// "fields[member]": "full_name,is_follower,patron_status,currently_entitled_amount_cents,campaign_lifetime_support_cents",
+// 'fields[user]': 'full_name',
+// }).toString())
+// .request()
+// .then(({ body }) => {
+// const patreonData = body.data.attributes;
+// console.log(` >> patreonData`)
+// console.log(patreonData)
+// return {
+// username: patreonData.full_name,
+// memberships: patreonData
+// };
+// });
+// }
+
+
+module.exports = {
+ /**
+ * An asynchronous register function that runs before
+ * your application is initialized.
+ *
+ * This gives you an opportunity to extend code.
+ */
+ register({ strapi }) {
+
+ // console.log(strapi.plugin('users-permissions').service('providers-registry'))
+ // strapi.plugin('users-permissions').service('providers-registry').register('taco', patreon)
+ },
+
+ /**
+ * An asynchronous bootstrap function that runs before
+ * your application gets started.
+ *
+ * This gives you an opportunity to set up your data model,
+ * run jobs, or perform some special logic.
+ */
+ bootstrap(/*{ strapi }*/) {
+
+ },
+};
+
+
+
+
+// module.exports = async () => {
+// await strapi.admin.services.permission.conditionProvider.register({
+// displayName: 'Billing amount under 10K',
+// name: 'billing-amount-under-10k',
+// plugin: 'admin',
+// handler: { amount: { $lt: 10000 } },
+// });
+// };
\ No newline at end of file
diff --git a/packages/strapi/src/policies/updateOwnerOnly.js b/packages/strapi/src/policies/updateOwnerOnly.js
new file mode 100644
index 0000000..86d2786
--- /dev/null
+++ b/packages/strapi/src/policies/updateOwnerOnly.js
@@ -0,0 +1,34 @@
+'use strict';
+
+/**
+ * `updateOwnerOnly` policy.
+ */
+module.exports = (policyContext, config, { strapi }) => {
+ const { PolicyError } = require("@strapi/utils").errors;
+
+ if (policyContext.state.auth.strategy.name === "api-token") {
+ if (policyContext.state.auth.credentials.type === "full-access")
+ return true;
+ } else if (
+ policyContext.state.auth.strategy.name === "users-permissions"
+ ) {
+
+ // Skip for admins
+ if (policyContext.state.auth.credentials.role.type === "admin") {
+ return true;
+ }
+
+ const currentUserId = policyContext.state.auth.credentials.id;
+ const userToUpdate = policyContext.params.id;
+
+ // Unable that an user can update another user
+ if (currentUserId != userToUpdate) {
+ strapi.log.info(`WARNING: User ${currentUserId} tried to edit user ${userToUpdate}`);
+ throw new PolicyError('Unable to edit this user ID');
+ }
+
+ return true
+ }
+
+ return false;
+};
\ No newline at end of file
diff --git a/packages/strapi/yarn.lock b/packages/strapi/yarn.lock
new file mode 100644
index 0000000..3d06ce7
--- /dev/null
+++ b/packages/strapi/yarn.lock
@@ -0,0 +1,11853 @@
+# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
+# yarn lockfile v1
+
+
+"@11ty/eleventy-fetch@^4.0.0":
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/@11ty/eleventy-fetch/-/eleventy-fetch-4.0.0.tgz#500d69b9ec336d8e4fd1e618cabb9a262c7a333f"
+ integrity sha512-wGAd0r+8DUWr22fK5r07dOKuNY6ltA7hX+sJzngGZL1yJmuUVdM/xPQZ+iq0BFgf/ZeRdpVEzf2D0cpVZUuiTg==
+ dependencies:
+ debug "^4.3.4"
+ flat-cache "^3.0.4"
+ node-fetch "^2.6.7"
+ p-queue "^6.6.2"
+
+"@ampproject/remapping@^2.2.0":
+ version "2.2.1"
+ resolved "https://registry.yarnpkg.com/@ampproject/remapping/-/remapping-2.2.1.tgz#99e8e11851128b8702cd57c33684f1d0f260b630"
+ integrity sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==
+ dependencies:
+ "@jridgewell/gen-mapping" "^0.3.0"
+ "@jridgewell/trace-mapping" "^0.3.9"
+
+"@aws-crypto/crc32@3.0.0":
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/@aws-crypto/crc32/-/crc32-3.0.0.tgz#07300eca214409c33e3ff769cd5697b57fdd38fa"
+ integrity sha512-IzSgsrxUcsrejQbPVilIKy16kAT52EwB6zSaI+M3xxIhKh5+aldEyvI+z6erM7TCLB2BJsFrtHjp6/4/sr+3dA==
+ dependencies:
+ "@aws-crypto/util" "^3.0.0"
+ "@aws-sdk/types" "^3.222.0"
+ tslib "^1.11.1"
+
+"@aws-crypto/crc32c@3.0.0":
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/@aws-crypto/crc32c/-/crc32c-3.0.0.tgz#016c92da559ef638a84a245eecb75c3e97cb664f"
+ integrity sha512-ENNPPManmnVJ4BTXlOjAgD7URidbAznURqD0KvfREyc4o20DPYdEldU1f5cQ7Jbj0CJJSPaMIk/9ZshdB3210w==
+ dependencies:
+ "@aws-crypto/util" "^3.0.0"
+ "@aws-sdk/types" "^3.222.0"
+ tslib "^1.11.1"
+
+"@aws-crypto/ie11-detection@^3.0.0":
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/@aws-crypto/ie11-detection/-/ie11-detection-3.0.0.tgz#640ae66b4ec3395cee6a8e94ebcd9f80c24cd688"
+ integrity sha512-341lBBkiY1DfDNKai/wXM3aujNBkXR7tq1URPQDL9wi3AUbI80NR74uF1TXHMm7po1AcnFk8iu2S2IeU/+/A+Q==
+ dependencies:
+ tslib "^1.11.1"
+
+"@aws-crypto/sha1-browser@3.0.0":
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/@aws-crypto/sha1-browser/-/sha1-browser-3.0.0.tgz#f9083c00782b24714f528b1a1fef2174002266a3"
+ integrity sha512-NJth5c997GLHs6nOYTzFKTbYdMNA6/1XlKVgnZoaZcQ7z7UJlOgj2JdbHE8tiYLS3fzXNCguct77SPGat2raSw==
+ dependencies:
+ "@aws-crypto/ie11-detection" "^3.0.0"
+ "@aws-crypto/supports-web-crypto" "^3.0.0"
+ "@aws-crypto/util" "^3.0.0"
+ "@aws-sdk/types" "^3.222.0"
+ "@aws-sdk/util-locate-window" "^3.0.0"
+ "@aws-sdk/util-utf8-browser" "^3.0.0"
+ tslib "^1.11.1"
+
+"@aws-crypto/sha256-browser@3.0.0":
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/@aws-crypto/sha256-browser/-/sha256-browser-3.0.0.tgz#05f160138ab893f1c6ba5be57cfd108f05827766"
+ integrity sha512-8VLmW2B+gjFbU5uMeqtQM6Nj0/F1bro80xQXCW6CQBWgosFWXTx77aeOF5CAIAmbOK64SdMBJdNr6J41yP5mvQ==
+ dependencies:
+ "@aws-crypto/ie11-detection" "^3.0.0"
+ "@aws-crypto/sha256-js" "^3.0.0"
+ "@aws-crypto/supports-web-crypto" "^3.0.0"
+ "@aws-crypto/util" "^3.0.0"
+ "@aws-sdk/types" "^3.222.0"
+ "@aws-sdk/util-locate-window" "^3.0.0"
+ "@aws-sdk/util-utf8-browser" "^3.0.0"
+ tslib "^1.11.1"
+
+"@aws-crypto/sha256-js@3.0.0", "@aws-crypto/sha256-js@^3.0.0":
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/@aws-crypto/sha256-js/-/sha256-js-3.0.0.tgz#f06b84d550d25521e60d2a0e2a90139341e007c2"
+ integrity sha512-PnNN7os0+yd1XvXAy23CFOmTbMaDxgxXtTKHybrJ39Y8kGzBATgBFibWJKH6BhytLI/Zyszs87xCOBNyBig6vQ==
+ dependencies:
+ "@aws-crypto/util" "^3.0.0"
+ "@aws-sdk/types" "^3.222.0"
+ tslib "^1.11.1"
+
+"@aws-crypto/supports-web-crypto@^3.0.0":
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/@aws-crypto/supports-web-crypto/-/supports-web-crypto-3.0.0.tgz#5d1bf825afa8072af2717c3e455f35cda0103ec2"
+ integrity sha512-06hBdMwUAb2WFTuGG73LSC0wfPu93xWwo5vL2et9eymgmu3Id5vFAHBbajVWiGhPO37qcsdCap/FqXvJGJWPIg==
+ dependencies:
+ tslib "^1.11.1"
+
+"@aws-crypto/util@^3.0.0":
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/@aws-crypto/util/-/util-3.0.0.tgz#1c7ca90c29293f0883468ad48117937f0fe5bfb0"
+ integrity sha512-2OJlpeJpCR48CC8r+uKVChzs9Iungj9wkZrl8Z041DWEWvyIHILYKCPNzJghKsivj+S3mLo6BVc7mBNzdxA46w==
+ dependencies:
+ "@aws-sdk/types" "^3.222.0"
+ "@aws-sdk/util-utf8-browser" "^3.0.0"
+ tslib "^1.11.1"
+
+"@aws-sdk/client-s3@^3.485.0":
+ version "3.489.0"
+ resolved "https://registry.yarnpkg.com/@aws-sdk/client-s3/-/client-s3-3.489.0.tgz#d3fadc2ccd5098fd91806b069044589a5b897488"
+ integrity sha512-8NvXqtncf0GJIVqunxwIKjCZv7L7LEEYgY38Mm/EWjiKZ76E7TJ7gsZAB7Wgp2kabmMvDDqDsA7Q5X2qg65AdA==
+ dependencies:
+ "@aws-crypto/sha1-browser" "3.0.0"
+ "@aws-crypto/sha256-browser" "3.0.0"
+ "@aws-crypto/sha256-js" "3.0.0"
+ "@aws-sdk/client-sts" "3.489.0"
+ "@aws-sdk/core" "3.485.0"
+ "@aws-sdk/credential-provider-node" "3.489.0"
+ "@aws-sdk/middleware-bucket-endpoint" "3.489.0"
+ "@aws-sdk/middleware-expect-continue" "3.489.0"
+ "@aws-sdk/middleware-flexible-checksums" "3.489.0"
+ "@aws-sdk/middleware-host-header" "3.489.0"
+ "@aws-sdk/middleware-location-constraint" "3.489.0"
+ "@aws-sdk/middleware-logger" "3.489.0"
+ "@aws-sdk/middleware-recursion-detection" "3.489.0"
+ "@aws-sdk/middleware-sdk-s3" "3.489.0"
+ "@aws-sdk/middleware-signing" "3.489.0"
+ "@aws-sdk/middleware-ssec" "3.489.0"
+ "@aws-sdk/middleware-user-agent" "3.489.0"
+ "@aws-sdk/region-config-resolver" "3.489.0"
+ "@aws-sdk/signature-v4-multi-region" "3.489.0"
+ "@aws-sdk/types" "3.489.0"
+ "@aws-sdk/util-endpoints" "3.489.0"
+ "@aws-sdk/util-user-agent-browser" "3.489.0"
+ "@aws-sdk/util-user-agent-node" "3.489.0"
+ "@aws-sdk/xml-builder" "3.485.0"
+ "@smithy/config-resolver" "^2.0.23"
+ "@smithy/core" "^1.2.2"
+ "@smithy/eventstream-serde-browser" "^2.0.16"
+ "@smithy/eventstream-serde-config-resolver" "^2.0.16"
+ "@smithy/eventstream-serde-node" "^2.0.16"
+ "@smithy/fetch-http-handler" "^2.3.2"
+ "@smithy/hash-blob-browser" "^2.0.17"
+ "@smithy/hash-node" "^2.0.18"
+ "@smithy/hash-stream-node" "^2.0.18"
+ "@smithy/invalid-dependency" "^2.0.16"
+ "@smithy/md5-js" "^2.0.18"
+ "@smithy/middleware-content-length" "^2.0.18"
+ "@smithy/middleware-endpoint" "^2.3.0"
+ "@smithy/middleware-retry" "^2.0.26"
+ "@smithy/middleware-serde" "^2.0.16"
+ "@smithy/middleware-stack" "^2.0.10"
+ "@smithy/node-config-provider" "^2.1.9"
+ "@smithy/node-http-handler" "^2.2.2"
+ "@smithy/protocol-http" "^3.0.12"
+ "@smithy/smithy-client" "^2.2.1"
+ "@smithy/types" "^2.8.0"
+ "@smithy/url-parser" "^2.0.16"
+ "@smithy/util-base64" "^2.0.1"
+ "@smithy/util-body-length-browser" "^2.0.1"
+ "@smithy/util-body-length-node" "^2.1.0"
+ "@smithy/util-defaults-mode-browser" "^2.0.24"
+ "@smithy/util-defaults-mode-node" "^2.0.32"
+ "@smithy/util-endpoints" "^1.0.8"
+ "@smithy/util-retry" "^2.0.9"
+ "@smithy/util-stream" "^2.0.24"
+ "@smithy/util-utf8" "^2.0.2"
+ "@smithy/util-waiter" "^2.0.16"
+ fast-xml-parser "4.2.5"
+ tslib "^2.5.0"
+
+"@aws-sdk/client-sso@3.489.0":
+ version "3.489.0"
+ resolved "https://registry.yarnpkg.com/@aws-sdk/client-sso/-/client-sso-3.489.0.tgz#349b81ad84269df1fdda1bdde2b4b30708864020"
+ integrity sha512-SZPXiYnByYnd3Vy0qY/PnWD2e9JA3Lwi000Tyz+ZQvjK9emH0B6aeWaxFZ7W4jscJVwQVc5kgvRPsJi5zY3w1w==
+ dependencies:
+ "@aws-crypto/sha256-browser" "3.0.0"
+ "@aws-crypto/sha256-js" "3.0.0"
+ "@aws-sdk/core" "3.485.0"
+ "@aws-sdk/middleware-host-header" "3.489.0"
+ "@aws-sdk/middleware-logger" "3.489.0"
+ "@aws-sdk/middleware-recursion-detection" "3.489.0"
+ "@aws-sdk/middleware-user-agent" "3.489.0"
+ "@aws-sdk/region-config-resolver" "3.489.0"
+ "@aws-sdk/types" "3.489.0"
+ "@aws-sdk/util-endpoints" "3.489.0"
+ "@aws-sdk/util-user-agent-browser" "3.489.0"
+ "@aws-sdk/util-user-agent-node" "3.489.0"
+ "@smithy/config-resolver" "^2.0.23"
+ "@smithy/core" "^1.2.2"
+ "@smithy/fetch-http-handler" "^2.3.2"
+ "@smithy/hash-node" "^2.0.18"
+ "@smithy/invalid-dependency" "^2.0.16"
+ "@smithy/middleware-content-length" "^2.0.18"
+ "@smithy/middleware-endpoint" "^2.3.0"
+ "@smithy/middleware-retry" "^2.0.26"
+ "@smithy/middleware-serde" "^2.0.16"
+ "@smithy/middleware-stack" "^2.0.10"
+ "@smithy/node-config-provider" "^2.1.9"
+ "@smithy/node-http-handler" "^2.2.2"
+ "@smithy/protocol-http" "^3.0.12"
+ "@smithy/smithy-client" "^2.2.1"
+ "@smithy/types" "^2.8.0"
+ "@smithy/url-parser" "^2.0.16"
+ "@smithy/util-base64" "^2.0.1"
+ "@smithy/util-body-length-browser" "^2.0.1"
+ "@smithy/util-body-length-node" "^2.1.0"
+ "@smithy/util-defaults-mode-browser" "^2.0.24"
+ "@smithy/util-defaults-mode-node" "^2.0.32"
+ "@smithy/util-endpoints" "^1.0.8"
+ "@smithy/util-retry" "^2.0.9"
+ "@smithy/util-utf8" "^2.0.2"
+ tslib "^2.5.0"
+
+"@aws-sdk/client-sts@3.489.0":
+ version "3.489.0"
+ resolved "https://registry.yarnpkg.com/@aws-sdk/client-sts/-/client-sts-3.489.0.tgz#28956e75be6c6803e64cb47b2d89eaf873b7af0b"
+ integrity sha512-AAQ9+oEJPIPHXWtQL7ahZCKata+d+vZMXpQp92st7KzgmcgsUBdDTBOH0ImN8LXwZwIMAzfn98wWf4s1xtqUeg==
+ dependencies:
+ "@aws-crypto/sha256-browser" "3.0.0"
+ "@aws-crypto/sha256-js" "3.0.0"
+ "@aws-sdk/core" "3.485.0"
+ "@aws-sdk/credential-provider-node" "3.489.0"
+ "@aws-sdk/middleware-host-header" "3.489.0"
+ "@aws-sdk/middleware-logger" "3.489.0"
+ "@aws-sdk/middleware-recursion-detection" "3.489.0"
+ "@aws-sdk/middleware-user-agent" "3.489.0"
+ "@aws-sdk/region-config-resolver" "3.489.0"
+ "@aws-sdk/types" "3.489.0"
+ "@aws-sdk/util-endpoints" "3.489.0"
+ "@aws-sdk/util-user-agent-browser" "3.489.0"
+ "@aws-sdk/util-user-agent-node" "3.489.0"
+ "@smithy/config-resolver" "^2.0.23"
+ "@smithy/core" "^1.2.2"
+ "@smithy/fetch-http-handler" "^2.3.2"
+ "@smithy/hash-node" "^2.0.18"
+ "@smithy/invalid-dependency" "^2.0.16"
+ "@smithy/middleware-content-length" "^2.0.18"
+ "@smithy/middleware-endpoint" "^2.3.0"
+ "@smithy/middleware-retry" "^2.0.26"
+ "@smithy/middleware-serde" "^2.0.16"
+ "@smithy/middleware-stack" "^2.0.10"
+ "@smithy/node-config-provider" "^2.1.9"
+ "@smithy/node-http-handler" "^2.2.2"
+ "@smithy/protocol-http" "^3.0.12"
+ "@smithy/smithy-client" "^2.2.1"
+ "@smithy/types" "^2.8.0"
+ "@smithy/url-parser" "^2.0.16"
+ "@smithy/util-base64" "^2.0.1"
+ "@smithy/util-body-length-browser" "^2.0.1"
+ "@smithy/util-body-length-node" "^2.1.0"
+ "@smithy/util-defaults-mode-browser" "^2.0.24"
+ "@smithy/util-defaults-mode-node" "^2.0.32"
+ "@smithy/util-endpoints" "^1.0.8"
+ "@smithy/util-middleware" "^2.0.9"
+ "@smithy/util-retry" "^2.0.9"
+ "@smithy/util-utf8" "^2.0.2"
+ fast-xml-parser "4.2.5"
+ tslib "^2.5.0"
+
+"@aws-sdk/core@3.485.0":
+ version "3.485.0"
+ resolved "https://registry.yarnpkg.com/@aws-sdk/core/-/core-3.485.0.tgz#3fdbd21d9619320f19c1074aeef91cf1498b94d8"
+ integrity sha512-Yvi80DQcbjkYCft471ClE3HuetuNVqntCs6eFOomDcrJaqdOFrXv2kJAxky84MRA/xb7bGlDGAPbTuj1ICputg==
+ dependencies:
+ "@smithy/core" "^1.2.2"
+ "@smithy/protocol-http" "^3.0.12"
+ "@smithy/signature-v4" "^2.0.0"
+ "@smithy/smithy-client" "^2.2.1"
+ "@smithy/types" "^2.8.0"
+ tslib "^2.5.0"
+
+"@aws-sdk/credential-provider-env@3.489.0":
+ version "3.489.0"
+ resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-env/-/credential-provider-env-3.489.0.tgz#69aeee7251047dbf3b1533514cb87c5fae333a47"
+ integrity sha512-5PqYsx9G5SB2tqPT9/z/u0EkF6D4wP6HTMWQs+DfMdmwXihrqQAgeYaTtV3KbXqb88p6sfacwxhUvE6+Rm494w==
+ dependencies:
+ "@aws-sdk/types" "3.489.0"
+ "@smithy/property-provider" "^2.0.0"
+ "@smithy/types" "^2.8.0"
+ tslib "^2.5.0"
+
+"@aws-sdk/credential-provider-ini@3.489.0":
+ version "3.489.0"
+ resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.489.0.tgz#8ddf53617d79b02ba5d99a4e30fd89e5f84a27c0"
+ integrity sha512-lB5yufriHMzraQaAlsVKgzXKLGhRHt+ybgcVD+SIegw0QwabWL2va8h1KuRUGqEOUFH6BNTCx9HnI+uH5EadVA==
+ dependencies:
+ "@aws-sdk/credential-provider-env" "3.489.0"
+ "@aws-sdk/credential-provider-process" "3.489.0"
+ "@aws-sdk/credential-provider-sso" "3.489.0"
+ "@aws-sdk/credential-provider-web-identity" "3.489.0"
+ "@aws-sdk/types" "3.489.0"
+ "@smithy/credential-provider-imds" "^2.0.0"
+ "@smithy/property-provider" "^2.0.0"
+ "@smithy/shared-ini-file-loader" "^2.0.6"
+ "@smithy/types" "^2.8.0"
+ tslib "^2.5.0"
+
+"@aws-sdk/credential-provider-node@3.489.0":
+ version "3.489.0"
+ resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-node/-/credential-provider-node-3.489.0.tgz#06aeaa17c54763093313b8d2f8722a76531573a7"
+ integrity sha512-HXjYjG5oqQflLOSkxjDTfWOeE5UX3CvPhcvexZLen8TWyI7azIT81PjFVLq5CJdnFaoeVRxvhp/DIgL7RrNivw==
+ dependencies:
+ "@aws-sdk/credential-provider-env" "3.489.0"
+ "@aws-sdk/credential-provider-ini" "3.489.0"
+ "@aws-sdk/credential-provider-process" "3.489.0"
+ "@aws-sdk/credential-provider-sso" "3.489.0"
+ "@aws-sdk/credential-provider-web-identity" "3.489.0"
+ "@aws-sdk/types" "3.489.0"
+ "@smithy/credential-provider-imds" "^2.0.0"
+ "@smithy/property-provider" "^2.0.0"
+ "@smithy/shared-ini-file-loader" "^2.0.6"
+ "@smithy/types" "^2.8.0"
+ tslib "^2.5.0"
+
+"@aws-sdk/credential-provider-process@3.489.0":
+ version "3.489.0"
+ resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-process/-/credential-provider-process-3.489.0.tgz#f0c2b5b22a1ca364ec89cd7e469673824606dec4"
+ integrity sha512-3vKQYJZ5cZYjy0870CPmbmKRBgATw2xCygxhn4m4UDCjOXVXcGUtYD51DMWsvBo3S0W8kH+FIJV4yuEDMFqLFQ==
+ dependencies:
+ "@aws-sdk/types" "3.489.0"
+ "@smithy/property-provider" "^2.0.0"
+ "@smithy/shared-ini-file-loader" "^2.0.6"
+ "@smithy/types" "^2.8.0"
+ tslib "^2.5.0"
+
+"@aws-sdk/credential-provider-sso@3.489.0":
+ version "3.489.0"
+ resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.489.0.tgz#91d1c203c59914419b0f27f7c7c3e9ae6b4bb3bc"
+ integrity sha512-tN+7q7xKA4VZmVSMolStvBd8UeHf43kt3TR/tTfqaSvOQR1hKUrDyVgg2rTdyXWxyQPy1O3rtwMKPsorhc/BTA==
+ dependencies:
+ "@aws-sdk/client-sso" "3.489.0"
+ "@aws-sdk/token-providers" "3.489.0"
+ "@aws-sdk/types" "3.489.0"
+ "@smithy/property-provider" "^2.0.0"
+ "@smithy/shared-ini-file-loader" "^2.0.6"
+ "@smithy/types" "^2.8.0"
+ tslib "^2.5.0"
+
+"@aws-sdk/credential-provider-web-identity@3.489.0":
+ version "3.489.0"
+ resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.489.0.tgz#28e2ba4d1ee4de4d055875028ed205a2264611c1"
+ integrity sha512-mjIuE2Wg1H/ds0nXQ/7vfusEDudmdd8YzKZI1y5O4n60iZZtyB2RNIECtvLMx1EQAKclidY7/06qQkArrGau5Q==
+ dependencies:
+ "@aws-sdk/types" "3.489.0"
+ "@smithy/property-provider" "^2.0.0"
+ "@smithy/types" "^2.8.0"
+ tslib "^2.5.0"
+
+"@aws-sdk/middleware-bucket-endpoint@3.489.0":
+ version "3.489.0"
+ resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-bucket-endpoint/-/middleware-bucket-endpoint-3.489.0.tgz#80a06f1c229fae364b5916e47178d118340e0f51"
+ integrity sha512-6rJ5bpNMKo7sEKQ6p2DMbQwM+ahMYASRxfdyH7hs18blvlcS20H1RYpNmJMqPPjxMwUWruty2JPMIRl4DFcv8w==
+ dependencies:
+ "@aws-sdk/types" "3.489.0"
+ "@aws-sdk/util-arn-parser" "3.465.0"
+ "@smithy/node-config-provider" "^2.1.9"
+ "@smithy/protocol-http" "^3.0.12"
+ "@smithy/types" "^2.8.0"
+ "@smithy/util-config-provider" "^2.1.0"
+ tslib "^2.5.0"
+
+"@aws-sdk/middleware-expect-continue@3.489.0":
+ version "3.489.0"
+ resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-expect-continue/-/middleware-expect-continue-3.489.0.tgz#c03f1a867e836c8ca844fcb8c527d2d782d1b659"
+ integrity sha512-2RZfnVZFaGHwzPDQJsyf9SXufu1gUd4VsMhm7dC7SWF85XmpDrozbFznS/tD22QdtyWjerLoydZJMq229hpPqg==
+ dependencies:
+ "@aws-sdk/types" "3.489.0"
+ "@smithy/protocol-http" "^3.0.12"
+ "@smithy/types" "^2.8.0"
+ tslib "^2.5.0"
+
+"@aws-sdk/middleware-flexible-checksums@3.489.0":
+ version "3.489.0"
+ resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-flexible-checksums/-/middleware-flexible-checksums-3.489.0.tgz#50413d053e7b62bef81772d6b0c00d5521cf4e30"
+ integrity sha512-Cy3rBUMr4P7raxzrJFWNRshfKrKV2EojawaC9Bfk/T8aFlV+FmVrRg4ISAXMOfS5pfy3xfAbvkzjOaeqCsGfrA==
+ dependencies:
+ "@aws-crypto/crc32" "3.0.0"
+ "@aws-crypto/crc32c" "3.0.0"
+ "@aws-sdk/types" "3.489.0"
+ "@smithy/is-array-buffer" "^2.0.0"
+ "@smithy/protocol-http" "^3.0.12"
+ "@smithy/types" "^2.8.0"
+ "@smithy/util-utf8" "^2.0.2"
+ tslib "^2.5.0"
+
+"@aws-sdk/middleware-host-header@3.489.0":
+ version "3.489.0"
+ resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-host-header/-/middleware-host-header-3.489.0.tgz#7c00fa49c6d359bdc9b4d27be09af29ac6700968"
+ integrity sha512-Cl7HJ1jhOfllwf0CRx1eB4ypRGMqdGKWpc0eSTXty7wWSvCdMZUhwfjQqu2bIOIlgYxg/gFu6TVmVZ6g4O8PlA==
+ dependencies:
+ "@aws-sdk/types" "3.489.0"
+ "@smithy/protocol-http" "^3.0.12"
+ "@smithy/types" "^2.8.0"
+ tslib "^2.5.0"
+
+"@aws-sdk/middleware-location-constraint@3.489.0":
+ version "3.489.0"
+ resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-location-constraint/-/middleware-location-constraint-3.489.0.tgz#aa00bc9b2d7ab857b1b8405b1a688684f2c44ae7"
+ integrity sha512-NIVr+kHR2N6gxFeE3TNw2mEBxgj0N9xXBLy3dNYMMlAUvQlT/0z9HlC9+3XqcTS/Z5ElF/+pei6nqXTVt0He9A==
+ dependencies:
+ "@aws-sdk/types" "3.489.0"
+ "@smithy/types" "^2.8.0"
+ tslib "^2.5.0"
+
+"@aws-sdk/middleware-logger@3.489.0":
+ version "3.489.0"
+ resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-logger/-/middleware-logger-3.489.0.tgz#36855ec7ac8af4604f2a0b739358f0411878abea"
+ integrity sha512-+EVDnWese61MdImcBNAgz/AhTcIZJaska/xsU3GWU9CP905x4a4qZdB7fExFMDu1Jlz5pJqNteFYYHCFMJhHfg==
+ dependencies:
+ "@aws-sdk/types" "3.489.0"
+ "@smithy/types" "^2.8.0"
+ tslib "^2.5.0"
+
+"@aws-sdk/middleware-recursion-detection@3.489.0":
+ version "3.489.0"
+ resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.489.0.tgz#bdcbfcebd3d27aad2e0b2808af7c1d3d380c52a2"
+ integrity sha512-m4rU+fTzziQcu9DKjRNZ4nQlXENEd2ZnJblJV4ONdWqqEjbmOgOj3P6aCCQlJdIbzuNvX1FBOZ5tY59ZpERo7Q==
+ dependencies:
+ "@aws-sdk/types" "3.489.0"
+ "@smithy/protocol-http" "^3.0.12"
+ "@smithy/types" "^2.8.0"
+ tslib "^2.5.0"
+
+"@aws-sdk/middleware-sdk-s3@3.489.0":
+ version "3.489.0"
+ resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-sdk-s3/-/middleware-sdk-s3-3.489.0.tgz#45c57501427f789cf8701b282e5e5136eb320c8b"
+ integrity sha512-/GGASx7mK9qEgy1znvleYMZKVqm3sOdGghqKdy2zgoGcH2jH+fZrLM0lDMT9bvdITmOCbJJs2rVHP3xm/ZWcXg==
+ dependencies:
+ "@aws-sdk/types" "3.489.0"
+ "@aws-sdk/util-arn-parser" "3.465.0"
+ "@smithy/node-config-provider" "^2.1.9"
+ "@smithy/protocol-http" "^3.0.12"
+ "@smithy/signature-v4" "^2.0.0"
+ "@smithy/smithy-client" "^2.2.1"
+ "@smithy/types" "^2.8.0"
+ "@smithy/util-config-provider" "^2.1.0"
+ tslib "^2.5.0"
+
+"@aws-sdk/middleware-signing@3.489.0":
+ version "3.489.0"
+ resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-signing/-/middleware-signing-3.489.0.tgz#ad92c3a4fb3afc2798b4f99a7ca6abaaf75461b8"
+ integrity sha512-rlHcWYZn6Ym3v/u0DvKNDiD7ogIzEsHlerm0lowTiQbszkFobOiUClRTALwvsUZdAAztl706qO1OKbnGnD6Ubw==
+ dependencies:
+ "@aws-sdk/types" "3.489.0"
+ "@smithy/property-provider" "^2.0.0"
+ "@smithy/protocol-http" "^3.0.12"
+ "@smithy/signature-v4" "^2.0.0"
+ "@smithy/types" "^2.8.0"
+ "@smithy/util-middleware" "^2.0.9"
+ tslib "^2.5.0"
+
+"@aws-sdk/middleware-ssec@3.489.0":
+ version "3.489.0"
+ resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-ssec/-/middleware-ssec-3.489.0.tgz#9991f6189fa1d3bf360e24f8d958f5456e4da7ce"
+ integrity sha512-5RQg8dqERAmi1OfVEV9fbTA5NKmcvKDYP79YtH08IEFIsHWU1Y5NoqL7mXkkNyBrJNBVyasYijAbTzOuM707eg==
+ dependencies:
+ "@aws-sdk/types" "3.489.0"
+ "@smithy/types" "^2.8.0"
+ tslib "^2.5.0"
+
+"@aws-sdk/middleware-user-agent@3.489.0":
+ version "3.489.0"
+ resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.489.0.tgz#84b2f7e3038b631ecd9e3cddd0205d9b6a266444"
+ integrity sha512-M54Cv2fAN3GGgdfUjLtZ4wFUIrfM/ivbXv4DgpcNsacEQ2g4H+weQgKp41X7XZW8MWAzl+k1zJaryK69RYNQkQ==
+ dependencies:
+ "@aws-sdk/types" "3.489.0"
+ "@aws-sdk/util-endpoints" "3.489.0"
+ "@smithy/protocol-http" "^3.0.12"
+ "@smithy/types" "^2.8.0"
+ tslib "^2.5.0"
+
+"@aws-sdk/region-config-resolver@3.489.0":
+ version "3.489.0"
+ resolved "https://registry.yarnpkg.com/@aws-sdk/region-config-resolver/-/region-config-resolver-3.489.0.tgz#58bd9dfbe148e2de8bfd0e5e4a3719d56b594c85"
+ integrity sha512-UvrnB78XTz9ddby7mr0vuUHn2MO3VTjzaIu+GQhyedMGQU0QlIQrYOlzbbu4LC5rL1O8FxFLUxRe/AAjgwyuGw==
+ dependencies:
+ "@aws-sdk/types" "3.489.0"
+ "@smithy/node-config-provider" "^2.1.9"
+ "@smithy/types" "^2.8.0"
+ "@smithy/util-config-provider" "^2.1.0"
+ "@smithy/util-middleware" "^2.0.9"
+ tslib "^2.5.0"
+
+"@aws-sdk/signature-v4-multi-region@3.489.0":
+ version "3.489.0"
+ resolved "https://registry.yarnpkg.com/@aws-sdk/signature-v4-multi-region/-/signature-v4-multi-region-3.489.0.tgz#d36574d34bc084f29c19d3bc51acbd821767dda0"
+ integrity sha512-kYFM7Opu36EkFlzXdVNOBFpQApgnuaTu/U/qYhGyuzeD+HNnYgZEsd/tDro1DQ074jVy3GN9ttJSYxq5I4oTkA==
+ dependencies:
+ "@aws-sdk/middleware-sdk-s3" "3.489.0"
+ "@aws-sdk/types" "3.489.0"
+ "@smithy/protocol-http" "^3.0.12"
+ "@smithy/signature-v4" "^2.0.0"
+ "@smithy/types" "^2.8.0"
+ tslib "^2.5.0"
+
+"@aws-sdk/token-providers@3.489.0":
+ version "3.489.0"
+ resolved "https://registry.yarnpkg.com/@aws-sdk/token-providers/-/token-providers-3.489.0.tgz#69897270f71595449f665b9f40754dfa21ea7be1"
+ integrity sha512-hSgjB8CMQoA8EIQ0ripDjDtbBcWDSa+7vSBYPIzksyknaGERR/GUfGXLV2dpm5t17FgFG6irT5f3ZlBzarL8Dw==
+ dependencies:
+ "@aws-crypto/sha256-browser" "3.0.0"
+ "@aws-crypto/sha256-js" "3.0.0"
+ "@aws-sdk/middleware-host-header" "3.489.0"
+ "@aws-sdk/middleware-logger" "3.489.0"
+ "@aws-sdk/middleware-recursion-detection" "3.489.0"
+ "@aws-sdk/middleware-user-agent" "3.489.0"
+ "@aws-sdk/region-config-resolver" "3.489.0"
+ "@aws-sdk/types" "3.489.0"
+ "@aws-sdk/util-endpoints" "3.489.0"
+ "@aws-sdk/util-user-agent-browser" "3.489.0"
+ "@aws-sdk/util-user-agent-node" "3.489.0"
+ "@smithy/config-resolver" "^2.0.23"
+ "@smithy/fetch-http-handler" "^2.3.2"
+ "@smithy/hash-node" "^2.0.18"
+ "@smithy/invalid-dependency" "^2.0.16"
+ "@smithy/middleware-content-length" "^2.0.18"
+ "@smithy/middleware-endpoint" "^2.3.0"
+ "@smithy/middleware-retry" "^2.0.26"
+ "@smithy/middleware-serde" "^2.0.16"
+ "@smithy/middleware-stack" "^2.0.10"
+ "@smithy/node-config-provider" "^2.1.9"
+ "@smithy/node-http-handler" "^2.2.2"
+ "@smithy/property-provider" "^2.0.0"
+ "@smithy/protocol-http" "^3.0.12"
+ "@smithy/shared-ini-file-loader" "^2.0.6"
+ "@smithy/smithy-client" "^2.2.1"
+ "@smithy/types" "^2.8.0"
+ "@smithy/url-parser" "^2.0.16"
+ "@smithy/util-base64" "^2.0.1"
+ "@smithy/util-body-length-browser" "^2.0.1"
+ "@smithy/util-body-length-node" "^2.1.0"
+ "@smithy/util-defaults-mode-browser" "^2.0.24"
+ "@smithy/util-defaults-mode-node" "^2.0.32"
+ "@smithy/util-endpoints" "^1.0.8"
+ "@smithy/util-retry" "^2.0.9"
+ "@smithy/util-utf8" "^2.0.2"
+ tslib "^2.5.0"
+
+"@aws-sdk/types@3.489.0", "@aws-sdk/types@^3.222.0":
+ version "3.489.0"
+ resolved "https://registry.yarnpkg.com/@aws-sdk/types/-/types-3.489.0.tgz#0fa29adaace3e407ac15428524aa67e9bd229f65"
+ integrity sha512-kcDtLfKog/p0tC4gAeqJqWxAiEzfe2LRPnKamvSG2Mjbthx4R/alE2dxyIq/wW+nvRv0fqR3OD5kD1+eVfdr/w==
+ dependencies:
+ "@smithy/types" "^2.8.0"
+ tslib "^2.5.0"
+
+"@aws-sdk/util-arn-parser@3.465.0":
+ version "3.465.0"
+ resolved "https://registry.yarnpkg.com/@aws-sdk/util-arn-parser/-/util-arn-parser-3.465.0.tgz#2896f6b06f69770378586853c97a0f283cbb2e20"
+ integrity sha512-zOJ82vzDJFqBX9yZBlNeHHrul/kpx/DCoxzW5UBbZeb26kfV53QhMSoEmY8/lEbBqlqargJ/sgRC845GFhHNQw==
+ dependencies:
+ tslib "^2.5.0"
+
+"@aws-sdk/util-endpoints@3.489.0":
+ version "3.489.0"
+ resolved "https://registry.yarnpkg.com/@aws-sdk/util-endpoints/-/util-endpoints-3.489.0.tgz#8adfa6da0cac973a8ca0f2c4aa66f7d587310acb"
+ integrity sha512-uGyG1u84ATX03mf7bT4xD9XD/vlYJGD5+RxMN/UpzeTfzXfh+jvCQWbOQ44z8ttFJWYQQqrLxkfpF/JgvALzLA==
+ dependencies:
+ "@aws-sdk/types" "3.489.0"
+ "@smithy/types" "^2.8.0"
+ "@smithy/util-endpoints" "^1.0.8"
+ tslib "^2.5.0"
+
+"@aws-sdk/util-locate-window@^3.0.0":
+ version "3.465.0"
+ resolved "https://registry.yarnpkg.com/@aws-sdk/util-locate-window/-/util-locate-window-3.465.0.tgz#0471428fb5eb749d4b72c427f5726f7b61fb90eb"
+ integrity sha512-f+QNcWGswredzC1ExNAB/QzODlxwaTdXkNT5cvke2RLX8SFU5pYk6h4uCtWC0vWPELzOfMfloBrJefBzlarhsw==
+ dependencies:
+ tslib "^2.5.0"
+
+"@aws-sdk/util-user-agent-browser@3.489.0":
+ version "3.489.0"
+ resolved "https://registry.yarnpkg.com/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.489.0.tgz#d59c3386c71ac08d658c123a1487cd6473c65627"
+ integrity sha512-85B9KMsuMpAZauzWQ16r52ZBAHYnznW6BVitnBglsibN7oJKn10Hggt4QGuRhvQFCxQ8YhvBl7r+vQGFO4hxIw==
+ dependencies:
+ "@aws-sdk/types" "3.489.0"
+ "@smithy/types" "^2.8.0"
+ bowser "^2.11.0"
+ tslib "^2.5.0"
+
+"@aws-sdk/util-user-agent-node@3.489.0":
+ version "3.489.0"
+ resolved "https://registry.yarnpkg.com/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.489.0.tgz#bc8f96710aadec4f5e327817cf5945c473150621"
+ integrity sha512-CYdkBHig8sFNc0dv11Ni9WXvZQHeI5+z77OrDHKkbidFx/V4BDTuwZw4K1vWg62pzFOEfzunJFiULRcDZWJR3w==
+ dependencies:
+ "@aws-sdk/types" "3.489.0"
+ "@smithy/node-config-provider" "^2.1.9"
+ "@smithy/types" "^2.8.0"
+ tslib "^2.5.0"
+
+"@aws-sdk/util-utf8-browser@^3.0.0":
+ version "3.259.0"
+ resolved "https://registry.yarnpkg.com/@aws-sdk/util-utf8-browser/-/util-utf8-browser-3.259.0.tgz#3275a6f5eb334f96ca76635b961d3c50259fd9ff"
+ integrity sha512-UvFa/vR+e19XookZF8RzFZBrw2EUkQWxiBW0yYQAhvk3C+QVGl0H3ouca8LDBlBfQKXwmW3huo/59H8rwb1wJw==
+ dependencies:
+ tslib "^2.3.1"
+
+"@aws-sdk/xml-builder@3.485.0":
+ version "3.485.0"
+ resolved "https://registry.yarnpkg.com/@aws-sdk/xml-builder/-/xml-builder-3.485.0.tgz#e1fc573d6cb6b76e0ba6a2b63bc67bc65e52c3e0"
+ integrity sha512-xQexPM6LINOIkf3NLFywplcbApifZRMWFN41TDWYSNgCUa5uC9fntfenw8N/HTx1n+McRCWSAFBTjDqY/2OLCQ==
+ dependencies:
+ "@smithy/types" "^2.8.0"
+ tslib "^2.5.0"
+
+"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.10.4", "@babel/code-frame@^7.16.7", "@babel/code-frame@^7.22.13", "@babel/code-frame@^7.23.5":
+ version "7.23.5"
+ resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.23.5.tgz#9009b69a8c602293476ad598ff53e4562e15c244"
+ integrity sha512-CgH3s1a96LipHCmSUmYFPwY7MNx8C3avkq7i4Wl3cfa662ldtUe4VM1TPXX70pfmrlWTb6jLqTYrZyT2ZTJBgA==
+ dependencies:
+ "@babel/highlight" "^7.23.4"
+ chalk "^2.4.2"
+
+"@babel/compat-data@^7.23.5":
+ version "7.23.5"
+ resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.23.5.tgz#ffb878728bb6bdcb6f4510aa51b1be9afb8cfd98"
+ integrity sha512-uU27kfDRlhfKl+w1U6vp16IuvSLtjAxdArVXPa9BvLkrr7CYIsxH5adpHObeAGY/41+syctUWOZ140a2Rvkgjw==
+
+"@babel/core@^7.22.20":
+ version "7.23.7"
+ resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.23.7.tgz#4d8016e06a14b5f92530a13ed0561730b5c6483f"
+ integrity sha512-+UpDgowcmqe36d4NwqvKsyPMlOLNGMsfMmQ5WGCu+siCe3t3dfe9njrzGfdN4qq+bcNUt0+Vw6haRxBOycs4dw==
+ dependencies:
+ "@ampproject/remapping" "^2.2.0"
+ "@babel/code-frame" "^7.23.5"
+ "@babel/generator" "^7.23.6"
+ "@babel/helper-compilation-targets" "^7.23.6"
+ "@babel/helper-module-transforms" "^7.23.3"
+ "@babel/helpers" "^7.23.7"
+ "@babel/parser" "^7.23.6"
+ "@babel/template" "^7.22.15"
+ "@babel/traverse" "^7.23.7"
+ "@babel/types" "^7.23.6"
+ convert-source-map "^2.0.0"
+ debug "^4.1.0"
+ gensync "^1.0.0-beta.2"
+ json5 "^2.2.3"
+ semver "^6.3.1"
+
+"@babel/generator@^7.23.6":
+ version "7.23.6"
+ resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.23.6.tgz#9e1fca4811c77a10580d17d26b57b036133f3c2e"
+ integrity sha512-qrSfCYxYQB5owCmGLbl8XRpX1ytXlpueOb0N0UmQwA073KZxejgQTzAmJezxvpwQD9uGtK2shHdi55QT+MbjIw==
+ dependencies:
+ "@babel/types" "^7.23.6"
+ "@jridgewell/gen-mapping" "^0.3.2"
+ "@jridgewell/trace-mapping" "^0.3.17"
+ jsesc "^2.5.1"
+
+"@babel/helper-annotate-as-pure@^7.22.5":
+ version "7.22.5"
+ resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.22.5.tgz#e7f06737b197d580a01edf75d97e2c8be99d3882"
+ integrity sha512-LvBTxu8bQSQkcyKOU+a1btnNFQ1dMAd0R6PyW3arXes06F6QLWLIrd681bxRPIXlrMGR3XYnW9JyML7dP3qgxg==
+ dependencies:
+ "@babel/types" "^7.22.5"
+
+"@babel/helper-compilation-targets@^7.23.6":
+ version "7.23.6"
+ resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.23.6.tgz#4d79069b16cbcf1461289eccfbbd81501ae39991"
+ integrity sha512-9JB548GZoQVmzrFgp8o7KxdgkTGm6xs9DW0o/Pim72UDjzr5ObUQ6ZzYPqA+g9OTS2bBQoctLJrky0RDCAWRgQ==
+ dependencies:
+ "@babel/compat-data" "^7.23.5"
+ "@babel/helper-validator-option" "^7.23.5"
+ browserslist "^4.22.2"
+ lru-cache "^5.1.1"
+ semver "^6.3.1"
+
+"@babel/helper-environment-visitor@^7.22.20":
+ version "7.22.20"
+ resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz#96159db61d34a29dba454c959f5ae4a649ba9167"
+ integrity sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==
+
+"@babel/helper-function-name@^7.23.0":
+ version "7.23.0"
+ resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz#1f9a3cdbd5b2698a670c30d2735f9af95ed52759"
+ integrity sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==
+ dependencies:
+ "@babel/template" "^7.22.15"
+ "@babel/types" "^7.23.0"
+
+"@babel/helper-hoist-variables@^7.22.5":
+ version "7.22.5"
+ resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz#c01a007dac05c085914e8fb652b339db50d823bb"
+ integrity sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==
+ dependencies:
+ "@babel/types" "^7.22.5"
+
+"@babel/helper-module-imports@^7.0.0", "@babel/helper-module-imports@^7.16.7", "@babel/helper-module-imports@^7.22.15", "@babel/helper-module-imports@^7.22.5":
+ version "7.22.15"
+ resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.22.15.tgz#16146307acdc40cc00c3b2c647713076464bdbf0"
+ integrity sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w==
+ dependencies:
+ "@babel/types" "^7.22.15"
+
+"@babel/helper-module-transforms@^7.23.3":
+ version "7.23.3"
+ resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.23.3.tgz#d7d12c3c5d30af5b3c0fcab2a6d5217773e2d0f1"
+ integrity sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ==
+ dependencies:
+ "@babel/helper-environment-visitor" "^7.22.20"
+ "@babel/helper-module-imports" "^7.22.15"
+ "@babel/helper-simple-access" "^7.22.5"
+ "@babel/helper-split-export-declaration" "^7.22.6"
+ "@babel/helper-validator-identifier" "^7.22.20"
+
+"@babel/helper-plugin-utils@^7.22.5":
+ version "7.22.5"
+ resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz#dd7ee3735e8a313b9f7b05a773d892e88e6d7295"
+ integrity sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==
+
+"@babel/helper-simple-access@^7.22.5":
+ version "7.22.5"
+ resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz#4938357dc7d782b80ed6dbb03a0fba3d22b1d5de"
+ integrity sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==
+ dependencies:
+ "@babel/types" "^7.22.5"
+
+"@babel/helper-split-export-declaration@^7.22.6":
+ version "7.22.6"
+ resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz#322c61b7310c0997fe4c323955667f18fcefb91c"
+ integrity sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==
+ dependencies:
+ "@babel/types" "^7.22.5"
+
+"@babel/helper-string-parser@^7.23.4":
+ version "7.23.4"
+ resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.23.4.tgz#9478c707febcbbe1ddb38a3d91a2e054ae622d83"
+ integrity sha512-803gmbQdqwdf4olxrX4AJyFBV/RTr3rSmOj0rKwesmzlfhYNDEs+/iOcznzpNWlJlIlTJC2QfPFcHB6DlzdVLQ==
+
+"@babel/helper-validator-identifier@^7.22.20":
+ version "7.22.20"
+ resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz#c4ae002c61d2879e724581d96665583dbc1dc0e0"
+ integrity sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==
+
+"@babel/helper-validator-option@^7.23.5":
+ version "7.23.5"
+ resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.23.5.tgz#907a3fbd4523426285365d1206c423c4c5520307"
+ integrity sha512-85ttAOMLsr53VgXkTbkx8oA6YTfT4q7/HzXSLEYmjcSTJPMPQtvq1BD79Byep5xMUYbGRzEpDsjUf3dyp54IKw==
+
+"@babel/helpers@^7.23.7":
+ version "7.23.8"
+ resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.23.8.tgz#fc6b2d65b16847fd50adddbd4232c76378959e34"
+ integrity sha512-KDqYz4PiOWvDFrdHLPhKtCThtIcKVy6avWD2oG4GEvyQ+XDZwHD4YQd+H2vNMnq2rkdxsDkU82T+Vk8U/WXHRQ==
+ dependencies:
+ "@babel/template" "^7.22.15"
+ "@babel/traverse" "^7.23.7"
+ "@babel/types" "^7.23.6"
+
+"@babel/highlight@^7.23.4":
+ version "7.23.4"
+ resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.23.4.tgz#edaadf4d8232e1a961432db785091207ead0621b"
+ integrity sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A==
+ dependencies:
+ "@babel/helper-validator-identifier" "^7.22.20"
+ chalk "^2.4.2"
+ js-tokens "^4.0.0"
+
+"@babel/parser@^7.1.0", "@babel/parser@^7.20.7", "@babel/parser@^7.22.15", "@babel/parser@^7.23.6":
+ version "7.23.6"
+ resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.23.6.tgz#ba1c9e512bda72a47e285ae42aff9d2a635a9e3b"
+ integrity sha512-Z2uID7YJ7oNvAI20O9X0bblw7Qqs8Q2hFy0R9tAfnfLkp5MW0UH9eUvnDSnFwKZ0AvgS1ucqR4KzvVHgnke1VQ==
+
+"@babel/plugin-syntax-jsx@^7.22.5":
+ version "7.23.3"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.23.3.tgz#8f2e4f8a9b5f9aa16067e142c1ac9cd9f810f473"
+ integrity sha512-EB2MELswq55OHUoRZLGg/zC7QWUKfNLpE57m/S2yr1uEneIgsTgrSzXP3NXEsMkVn76OlaVVnzN+ugObuYGwhg==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.22.5"
+
+"@babel/plugin-transform-react-jsx-self@^7.22.5":
+ version "7.23.3"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.23.3.tgz#ed3e7dadde046cce761a8e3cf003a13d1a7972d9"
+ integrity sha512-qXRvbeKDSfwnlJnanVRp0SfuWE5DQhwQr5xtLBzp56Wabyo+4CMosF6Kfp+eOD/4FYpql64XVJ2W0pVLlJZxOQ==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.22.5"
+
+"@babel/plugin-transform-react-jsx-source@^7.22.5":
+ version "7.23.3"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.23.3.tgz#03527006bdc8775247a78643c51d4e715fe39a3e"
+ integrity sha512-91RS0MDnAWDNvGC6Wio5XYkyWI39FMFO+JK9+4AlgaTH+yWwVTsw7/sn6LK0lH7c5F+TFkpv/3LfCJ1Ydwof/g==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.22.5"
+
+"@babel/runtime-corejs3@^7.9.2":
+ version "7.23.8"
+ resolved "https://registry.yarnpkg.com/@babel/runtime-corejs3/-/runtime-corejs3-7.23.8.tgz#b8aa3d47570bdd08fed77fdfd69542118af0df26"
+ integrity sha512-2ZzmcDugdm0/YQKFVYsXiwUN7USPX8PM7cytpb4PFl87fM+qYPSvTZX//8tyeJB1j0YDmafBJEbl5f8NfLyuKw==
+ dependencies:
+ core-js-pure "^3.30.2"
+ regenerator-runtime "^0.14.0"
+
+"@babel/runtime@^7.0.0", "@babel/runtime@^7.1.2", "@babel/runtime@^7.10.5", "@babel/runtime@^7.12.0", "@babel/runtime@^7.12.1", "@babel/runtime@^7.12.13", "@babel/runtime@^7.12.5", "@babel/runtime@^7.13.10", "@babel/runtime@^7.15.4", "@babel/runtime@^7.18.3", "@babel/runtime@^7.18.6", "@babel/runtime@^7.21.0", "@babel/runtime@^7.5.5", "@babel/runtime@^7.6.2", "@babel/runtime@^7.7.2", "@babel/runtime@^7.8.7", "@babel/runtime@^7.9.2":
+ version "7.23.8"
+ resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.23.8.tgz#8ee6fe1ac47add7122902f257b8ddf55c898f650"
+ integrity sha512-Y7KbAP984rn1VGMbGqKmBLio9V7y5Je9GvU4rQPCPinCyNfUcToxIXl06d59URp/F3LwinvODxab5N/G6qggkw==
+ dependencies:
+ regenerator-runtime "^0.14.0"
+
+"@babel/template@^7.22.15":
+ version "7.22.15"
+ resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.22.15.tgz#09576efc3830f0430f4548ef971dde1350ef2f38"
+ integrity sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==
+ dependencies:
+ "@babel/code-frame" "^7.22.13"
+ "@babel/parser" "^7.22.15"
+ "@babel/types" "^7.22.15"
+
+"@babel/traverse@^7.23.7", "@babel/traverse@^7.4.5":
+ version "7.23.7"
+ resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.23.7.tgz#9a7bf285c928cb99b5ead19c3b1ce5b310c9c305"
+ integrity sha512-tY3mM8rH9jM0YHFGyfC0/xf+SB5eKUu7HPj7/k3fpi9dAlsMc5YbQvDi0Sh2QTPXqMhyaAtzAr807TIyfQrmyg==
+ dependencies:
+ "@babel/code-frame" "^7.23.5"
+ "@babel/generator" "^7.23.6"
+ "@babel/helper-environment-visitor" "^7.22.20"
+ "@babel/helper-function-name" "^7.23.0"
+ "@babel/helper-hoist-variables" "^7.22.5"
+ "@babel/helper-split-export-declaration" "^7.22.6"
+ "@babel/parser" "^7.23.6"
+ "@babel/types" "^7.23.6"
+ debug "^4.3.1"
+ globals "^11.1.0"
+
+"@babel/types@^7.0.0", "@babel/types@^7.20.7", "@babel/types@^7.22.15", "@babel/types@^7.22.5", "@babel/types@^7.23.0", "@babel/types@^7.23.6":
+ version "7.23.6"
+ resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.23.6.tgz#be33fdb151e1f5a56877d704492c240fc71c7ccd"
+ integrity sha512-+uarb83brBzPKN38NX1MkB6vb6+mwvR6amUulqAE7ccQw1pEl+bCia9TbdG1lsnFP7lZySvUn37CHyXQdfTwzg==
+ dependencies:
+ "@babel/helper-string-parser" "^7.23.4"
+ "@babel/helper-validator-identifier" "^7.22.20"
+ to-fast-properties "^2.0.0"
+
+"@casl/ability@6.5.0":
+ version "6.5.0"
+ resolved "https://registry.yarnpkg.com/@casl/ability/-/ability-6.5.0.tgz#a151a7637886099b8ffe52a96601225004a5c157"
+ integrity sha512-3guc94ugr5ylZQIpJTLz0CDfwNi0mxKVECj1vJUPAvs+Lwunh/dcuUjwzc4MHM9D8JOYX0XUZMEPedpB3vIbOw==
+ dependencies:
+ "@ucast/mongo2js" "^1.3.0"
+
+"@codemirror/autocomplete@^6.0.0":
+ version "6.11.1"
+ resolved "https://registry.yarnpkg.com/@codemirror/autocomplete/-/autocomplete-6.11.1.tgz#c733900eee58ac2de817317b9fd1e91b857c4329"
+ integrity sha512-L5UInv8Ffd6BPw0P3EF7JLYAMeEbclY7+6Q11REt8vhih8RuLreKtPy/xk8wPxs4EQgYqzI7cdgpiYwWlbS/ow==
+ dependencies:
+ "@codemirror/language" "^6.0.0"
+ "@codemirror/state" "^6.0.0"
+ "@codemirror/view" "^6.17.0"
+ "@lezer/common" "^1.0.0"
+
+"@codemirror/commands@^6.0.0", "@codemirror/commands@^6.1.0":
+ version "6.3.3"
+ resolved "https://registry.yarnpkg.com/@codemirror/commands/-/commands-6.3.3.tgz#03face5bf5f3de0fc4e09b177b3c91eda2ceb7e9"
+ integrity sha512-dO4hcF0fGT9tu1Pj1D2PvGvxjeGkbC6RGcZw6Qs74TH+Ed1gw98jmUgd2axWvIZEqTeTuFrg1lEB1KV6cK9h1A==
+ dependencies:
+ "@codemirror/language" "^6.0.0"
+ "@codemirror/state" "^6.4.0"
+ "@codemirror/view" "^6.0.0"
+ "@lezer/common" "^1.1.0"
+
+"@codemirror/lang-json@^6.0.1":
+ version "6.0.1"
+ resolved "https://registry.yarnpkg.com/@codemirror/lang-json/-/lang-json-6.0.1.tgz#0a0be701a5619c4b0f8991f9b5e95fe33f462330"
+ integrity sha512-+T1flHdgpqDDlJZ2Lkil/rLiRy684WMLc74xUnjJH48GQdfJo/pudlTRreZmKwzP8/tGdKf83wlbAdOCzlJOGQ==
+ dependencies:
+ "@codemirror/language" "^6.0.0"
+ "@lezer/json" "^1.0.0"
+
+"@codemirror/language@^6.0.0":
+ version "6.10.0"
+ resolved "https://registry.yarnpkg.com/@codemirror/language/-/language-6.10.0.tgz#2d0e818716825ee2ed0dacd04595eaa61bae8f23"
+ integrity sha512-2vaNn9aPGCRFKWcHPFksctzJ8yS5p7YoaT+jHpc0UGKzNuAIx4qy6R5wiqbP+heEEdyaABA582mNqSHzSoYdmg==
+ dependencies:
+ "@codemirror/state" "^6.0.0"
+ "@codemirror/view" "^6.23.0"
+ "@lezer/common" "^1.1.0"
+ "@lezer/highlight" "^1.0.0"
+ "@lezer/lr" "^1.0.0"
+ style-mod "^4.0.0"
+
+"@codemirror/lint@^6.0.0":
+ version "6.4.2"
+ resolved "https://registry.yarnpkg.com/@codemirror/lint/-/lint-6.4.2.tgz#c13be5320bde9707efdc94e8bcd3c698abae0b92"
+ integrity sha512-wzRkluWb1ptPKdzlsrbwwjYCPLgzU6N88YBAmlZi8WFyuiEduSd05MnJYNogzyc8rPK7pj6m95ptUApc8sHKVA==
+ dependencies:
+ "@codemirror/state" "^6.0.0"
+ "@codemirror/view" "^6.0.0"
+ crelt "^1.0.5"
+
+"@codemirror/search@^6.0.0":
+ version "6.5.5"
+ resolved "https://registry.yarnpkg.com/@codemirror/search/-/search-6.5.5.tgz#cf97e201da364da2285c2a250167af25bbd2a4a2"
+ integrity sha512-PIEN3Ke1buPod2EHbJsoQwlbpkz30qGZKcnmH1eihq9+bPQx8gelauUwLYaY4vBOuBAuEhmpDLii4rj/uO0yMA==
+ dependencies:
+ "@codemirror/state" "^6.0.0"
+ "@codemirror/view" "^6.0.0"
+ crelt "^1.0.5"
+
+"@codemirror/state@^6.0.0", "@codemirror/state@^6.1.1", "@codemirror/state@^6.4.0":
+ version "6.4.0"
+ resolved "https://registry.yarnpkg.com/@codemirror/state/-/state-6.4.0.tgz#8bc3e096c84360b34525a84696a84f86b305363a"
+ integrity sha512-hm8XshYj5Fo30Bb922QX9hXB/bxOAVH+qaqHBzw5TKa72vOeslyGwd4X8M0c1dJ9JqxlaMceOQ8RsL9tC7gU0A==
+
+"@codemirror/theme-one-dark@^6.0.0":
+ version "6.1.2"
+ resolved "https://registry.yarnpkg.com/@codemirror/theme-one-dark/-/theme-one-dark-6.1.2.tgz#fcef9f9cfc17a07836cb7da17c9f6d7231064df8"
+ integrity sha512-F+sH0X16j/qFLMAfbciKTxVOwkdAS336b7AXTKOZhy8BR3eH/RelsnLgLFINrpST63mmN2OuwUt0W2ndUgYwUA==
+ dependencies:
+ "@codemirror/language" "^6.0.0"
+ "@codemirror/state" "^6.0.0"
+ "@codemirror/view" "^6.0.0"
+ "@lezer/highlight" "^1.0.0"
+
+"@codemirror/view@^6.0.0", "@codemirror/view@^6.17.0", "@codemirror/view@^6.23.0":
+ version "6.23.0"
+ resolved "https://registry.yarnpkg.com/@codemirror/view/-/view-6.23.0.tgz#8054a2043273abad7f1587d15accb0623e1960ed"
+ integrity sha512-/51px9N4uW8NpuWkyUX+iam5+PM6io2fm+QmRnzwqBy5v/pwGg9T0kILFtYeum8hjuvENtgsGNKluOfqIICmeQ==
+ dependencies:
+ "@codemirror/state" "^6.4.0"
+ style-mod "^4.1.0"
+ w3c-keyname "^2.2.4"
+
+"@colors/colors@1.5.0":
+ version "1.5.0"
+ resolved "https://registry.yarnpkg.com/@colors/colors/-/colors-1.5.0.tgz#bb504579c1cae923e6576a4f5da43d25f97bdbd9"
+ integrity sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==
+
+"@colors/colors@1.6.0":
+ version "1.6.0"
+ resolved "https://registry.yarnpkg.com/@colors/colors/-/colors-1.6.0.tgz#ec6cd237440700bc23ca23087f513c75508958b0"
+ integrity sha512-Ir+AOibqzrIsL6ajt3Rz3LskB7OiMVHqltZmspbW/TJuTVuyOMirVqAkjfY6JISiLHgyNqicAC8AyHHGzNd/dA==
+
+"@dabh/diagnostics@^2.0.2":
+ version "2.0.3"
+ resolved "https://registry.yarnpkg.com/@dabh/diagnostics/-/diagnostics-2.0.3.tgz#7f7e97ee9a725dffc7808d93668cc984e1dc477a"
+ integrity sha512-hrlQOIi7hAfzsMqlGSFyVucrx38O+j6wiGOf//H2ecvIEqYN4ADBSS2iLMh5UFyDunCNniUIPk/q3riFv45xRA==
+ dependencies:
+ colorspace "1.1.x"
+ enabled "2.0.x"
+ kuler "^2.0.0"
+
+"@discoveryjs/json-ext@0.5.7":
+ version "0.5.7"
+ resolved "https://registry.yarnpkg.com/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz#1d572bfbbe14b7704e0ba0f39b74815b84870d70"
+ integrity sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==
+
+"@emotion/babel-plugin@^11.11.0":
+ version "11.11.0"
+ resolved "https://registry.yarnpkg.com/@emotion/babel-plugin/-/babel-plugin-11.11.0.tgz#c2d872b6a7767a9d176d007f5b31f7d504bb5d6c"
+ integrity sha512-m4HEDZleaaCH+XgDDsPF15Ht6wTLsgDTeR3WYj9Q/k76JtWhrJjcP4+/XlG8LGT/Rol9qUfOIztXeA84ATpqPQ==
+ dependencies:
+ "@babel/helper-module-imports" "^7.16.7"
+ "@babel/runtime" "^7.18.3"
+ "@emotion/hash" "^0.9.1"
+ "@emotion/memoize" "^0.8.1"
+ "@emotion/serialize" "^1.1.2"
+ babel-plugin-macros "^3.1.0"
+ convert-source-map "^1.5.0"
+ escape-string-regexp "^4.0.0"
+ find-root "^1.1.0"
+ source-map "^0.5.7"
+ stylis "4.2.0"
+
+"@emotion/cache@^11.11.0", "@emotion/cache@^11.4.0":
+ version "11.11.0"
+ resolved "https://registry.yarnpkg.com/@emotion/cache/-/cache-11.11.0.tgz#809b33ee6b1cb1a625fef7a45bc568ccd9b8f3ff"
+ integrity sha512-P34z9ssTCBi3e9EI1ZsWpNHcfY1r09ZO0rZbRO2ob3ZQMnFI35jB536qoXbkdesr5EUhYi22anuEJuyxifaqAQ==
+ dependencies:
+ "@emotion/memoize" "^0.8.1"
+ "@emotion/sheet" "^1.2.2"
+ "@emotion/utils" "^1.2.1"
+ "@emotion/weak-memoize" "^0.3.1"
+ stylis "4.2.0"
+
+"@emotion/hash@^0.9.1":
+ version "0.9.1"
+ resolved "https://registry.yarnpkg.com/@emotion/hash/-/hash-0.9.1.tgz#4ffb0055f7ef676ebc3a5a91fb621393294e2f43"
+ integrity sha512-gJB6HLm5rYwSLI6PQa+X1t5CFGrv1J1TWG+sOyMCeKz2ojaj6Fnl/rZEspogG+cvqbt4AE/2eIyD2QfLKTBNlQ==
+
+"@emotion/is-prop-valid@^0.8.8":
+ version "0.8.8"
+ resolved "https://registry.yarnpkg.com/@emotion/is-prop-valid/-/is-prop-valid-0.8.8.tgz#db28b1c4368a259b60a97311d6a952d4fd01ac1a"
+ integrity sha512-u5WtneEAr5IDG2Wv65yhunPSMLIpuKsbuOktRojfrEiEvRyC85LgPMZI63cr7NUqT8ZIGdSVg8ZKGxIug4lXcA==
+ dependencies:
+ "@emotion/memoize" "0.7.4"
+
+"@emotion/memoize@0.7.4":
+ version "0.7.4"
+ resolved "https://registry.yarnpkg.com/@emotion/memoize/-/memoize-0.7.4.tgz#19bf0f5af19149111c40d98bb0cf82119f5d9eeb"
+ integrity sha512-Ja/Vfqe3HpuzRsG1oBtWTHk2PGZ7GR+2Vz5iYGelAw8dx32K0y7PjVuxK6z1nMpZOqAFsRUPCkK1YjJ56qJlgw==
+
+"@emotion/memoize@^0.8.1":
+ version "0.8.1"
+ resolved "https://registry.yarnpkg.com/@emotion/memoize/-/memoize-0.8.1.tgz#c1ddb040429c6d21d38cc945fe75c818cfb68e17"
+ integrity sha512-W2P2c/VRW1/1tLox0mVUalvnWXxavmv/Oum2aPsRcoDJuob75FC3Y8FbpfLwUegRcxINtGUMPq0tFCvYNTBXNA==
+
+"@emotion/react@^11.8.1":
+ version "11.11.3"
+ resolved "https://registry.yarnpkg.com/@emotion/react/-/react-11.11.3.tgz#96b855dc40a2a55f52a72f518a41db4f69c31a25"
+ integrity sha512-Cnn0kuq4DoONOMcnoVsTOR8E+AdnKFf//6kUWc4LCdnxj31pZWn7rIULd6Y7/Js1PiPHzn7SKCM9vB/jBni8eA==
+ dependencies:
+ "@babel/runtime" "^7.18.3"
+ "@emotion/babel-plugin" "^11.11.0"
+ "@emotion/cache" "^11.11.0"
+ "@emotion/serialize" "^1.1.3"
+ "@emotion/use-insertion-effect-with-fallbacks" "^1.0.1"
+ "@emotion/utils" "^1.2.1"
+ "@emotion/weak-memoize" "^0.3.1"
+ hoist-non-react-statics "^3.3.1"
+
+"@emotion/serialize@^1.1.2", "@emotion/serialize@^1.1.3":
+ version "1.1.3"
+ resolved "https://registry.yarnpkg.com/@emotion/serialize/-/serialize-1.1.3.tgz#84b77bfcfe3b7bb47d326602f640ccfcacd5ffb0"
+ integrity sha512-iD4D6QVZFDhcbH0RAG1uVu1CwVLMWUkCvAqqlewO/rxf8+87yIBAlt4+AxMiiKPLs5hFc0owNk/sLLAOROw3cA==
+ dependencies:
+ "@emotion/hash" "^0.9.1"
+ "@emotion/memoize" "^0.8.1"
+ "@emotion/unitless" "^0.8.1"
+ "@emotion/utils" "^1.2.1"
+ csstype "^3.0.2"
+
+"@emotion/sheet@^1.2.2":
+ version "1.2.2"
+ resolved "https://registry.yarnpkg.com/@emotion/sheet/-/sheet-1.2.2.tgz#d58e788ee27267a14342303e1abb3d508b6d0fec"
+ integrity sha512-0QBtGvaqtWi+nx6doRwDdBIzhNdZrXUppvTM4dtZZWEGTXL/XE/yJxLMGlDT1Gt+UHH5IX1n+jkXyytE/av7OA==
+
+"@emotion/stylis@^0.8.4":
+ version "0.8.5"
+ resolved "https://registry.yarnpkg.com/@emotion/stylis/-/stylis-0.8.5.tgz#deacb389bd6ee77d1e7fcaccce9e16c5c7e78e04"
+ integrity sha512-h6KtPihKFn3T9fuIrwvXXUOwlx3rfUvfZIcP5a6rh8Y7zjE3O06hT5Ss4S/YI1AYhuZ1kjaE/5EaOOI2NqSylQ==
+
+"@emotion/unitless@^0.7.4":
+ version "0.7.5"
+ resolved "https://registry.yarnpkg.com/@emotion/unitless/-/unitless-0.7.5.tgz#77211291c1900a700b8a78cfafda3160d76949ed"
+ integrity sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg==
+
+"@emotion/unitless@^0.8.1":
+ version "0.8.1"
+ resolved "https://registry.yarnpkg.com/@emotion/unitless/-/unitless-0.8.1.tgz#182b5a4704ef8ad91bde93f7a860a88fd92c79a3"
+ integrity sha512-KOEGMu6dmJZtpadb476IsZBclKvILjopjUii3V+7MnXIQCYh8W3NgNcgwo21n9LXZX6EDIKvqfjYxXebDwxKmQ==
+
+"@emotion/use-insertion-effect-with-fallbacks@^1.0.1":
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/@emotion/use-insertion-effect-with-fallbacks/-/use-insertion-effect-with-fallbacks-1.0.1.tgz#08de79f54eb3406f9daaf77c76e35313da963963"
+ integrity sha512-jT/qyKZ9rzLErtrjGgdkMBn2OP8wl0G3sQlBb3YPryvKHsjvINUhVaPFfP+fpBcOkmrVOVEEHQFJ7nbj2TH2gw==
+
+"@emotion/utils@^1.2.1":
+ version "1.2.1"
+ resolved "https://registry.yarnpkg.com/@emotion/utils/-/utils-1.2.1.tgz#bbab58465738d31ae4cb3dbb6fc00a5991f755e4"
+ integrity sha512-Y2tGf3I+XVnajdItskUCn6LX+VUDmP6lTL4fcqsXAv43dnlbZiuW4MWQW38rW/BVWSE7Q/7+XQocmpnRYILUmg==
+
+"@emotion/weak-memoize@^0.3.1":
+ version "0.3.1"
+ resolved "https://registry.yarnpkg.com/@emotion/weak-memoize/-/weak-memoize-0.3.1.tgz#d0fce5d07b0620caa282b5131c297bb60f9d87e6"
+ integrity sha512-EsBwpc7hBUJWAsNPBmJy4hxWx12v6bshQsldrVmjxJoc3isbxhOrF2IcCpaXxfvq03NwkI7sbsOLXbYuqF/8Ww==
+
+"@esbuild/android-arm64@0.16.17":
+ version "0.16.17"
+ resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.16.17.tgz#cf91e86df127aa3d141744edafcba0abdc577d23"
+ integrity sha512-MIGl6p5sc3RDTLLkYL1MyL8BMRN4tLMRCn+yRJJmEDvYZ2M7tmAf80hx1kbNEUX2KJ50RRtxZ4JHLvCfuB6kBg==
+
+"@esbuild/android-arm64@0.18.20":
+ version "0.18.20"
+ resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.18.20.tgz#984b4f9c8d0377443cc2dfcef266d02244593622"
+ integrity sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ==
+
+"@esbuild/android-arm64@0.19.2":
+ version "0.19.2"
+ resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.19.2.tgz#bc35990f412a749e948b792825eef7df0ce0e073"
+ integrity sha512-lsB65vAbe90I/Qe10OjkmrdxSX4UJDjosDgb8sZUKcg3oefEuW2OT2Vozz8ef7wrJbMcmhvCC+hciF8jY/uAkw==
+
+"@esbuild/android-arm@0.16.17":
+ version "0.16.17"
+ resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.16.17.tgz#025b6246d3f68b7bbaa97069144fb5fb70f2fff2"
+ integrity sha512-N9x1CMXVhtWEAMS7pNNONyA14f71VPQN9Cnavj1XQh6T7bskqiLLrSca4O0Vr8Wdcga943eThxnVp3JLnBMYtw==
+
+"@esbuild/android-arm@0.18.20":
+ version "0.18.20"
+ resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.18.20.tgz#fedb265bc3a589c84cc11f810804f234947c3682"
+ integrity sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw==
+
+"@esbuild/android-arm@0.19.2":
+ version "0.19.2"
+ resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.19.2.tgz#edd1c8f23ba353c197f5b0337123c58ff2a56999"
+ integrity sha512-tM8yLeYVe7pRyAu9VMi/Q7aunpLwD139EY1S99xbQkT4/q2qa6eA4ige/WJQYdJ8GBL1K33pPFhPfPdJ/WzT8Q==
+
+"@esbuild/android-x64@0.16.17":
+ version "0.16.17"
+ resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.16.17.tgz#c820e0fef982f99a85c4b8bfdd582835f04cd96e"
+ integrity sha512-a3kTv3m0Ghh4z1DaFEuEDfz3OLONKuFvI4Xqczqx4BqLyuFaFkuaG4j2MtA6fuWEFeC5x9IvqnX7drmRq/fyAQ==
+
+"@esbuild/android-x64@0.18.20":
+ version "0.18.20"
+ resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.18.20.tgz#35cf419c4cfc8babe8893d296cd990e9e9f756f2"
+ integrity sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg==
+
+"@esbuild/android-x64@0.19.2":
+ version "0.19.2"
+ resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.19.2.tgz#2dcdd6e6f1f2d82ea1b746abd8da5b284960f35a"
+ integrity sha512-qK/TpmHt2M/Hg82WXHRc/W/2SGo/l1thtDHZWqFq7oi24AjZ4O/CpPSu6ZuYKFkEgmZlFoa7CooAyYmuvnaG8w==
+
+"@esbuild/darwin-arm64@0.16.17":
+ version "0.16.17"
+ resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.16.17.tgz#edef4487af6b21afabba7be5132c26d22379b220"
+ integrity sha512-/2agbUEfmxWHi9ARTX6OQ/KgXnOWfsNlTeLcoV7HSuSTv63E4DqtAc+2XqGw1KHxKMHGZgbVCZge7HXWX9Vn+w==
+
+"@esbuild/darwin-arm64@0.18.20":
+ version "0.18.20"
+ resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.18.20.tgz#08172cbeccf95fbc383399a7f39cfbddaeb0d7c1"
+ integrity sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA==
+
+"@esbuild/darwin-arm64@0.19.2":
+ version "0.19.2"
+ resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.19.2.tgz#55b36bc06d76f5c243987c1f93a11a80d8fc3b26"
+ integrity sha512-Ora8JokrvrzEPEpZO18ZYXkH4asCdc1DLdcVy8TGf5eWtPO1Ie4WroEJzwI52ZGtpODy3+m0a2yEX9l+KUn0tA==
+
+"@esbuild/darwin-x64@0.16.17":
+ version "0.16.17"
+ resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.16.17.tgz#42829168730071c41ef0d028d8319eea0e2904b4"
+ integrity sha512-2By45OBHulkd9Svy5IOCZt376Aa2oOkiE9QWUK9fe6Tb+WDr8hXL3dpqi+DeLiMed8tVXspzsTAvd0jUl96wmg==
+
+"@esbuild/darwin-x64@0.18.20":
+ version "0.18.20"
+ resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.18.20.tgz#d70d5790d8bf475556b67d0f8b7c5bdff053d85d"
+ integrity sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ==
+
+"@esbuild/darwin-x64@0.19.2":
+ version "0.19.2"
+ resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.19.2.tgz#982524af33a6424a3b5cb44bbd52559623ad719c"
+ integrity sha512-tP+B5UuIbbFMj2hQaUr6EALlHOIOmlLM2FK7jeFBobPy2ERdohI4Ka6ZFjZ1ZYsrHE/hZimGuU90jusRE0pwDw==
+
+"@esbuild/freebsd-arm64@0.16.17":
+ version "0.16.17"
+ resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.16.17.tgz#1f4af488bfc7e9ced04207034d398e793b570a27"
+ integrity sha512-mt+cxZe1tVx489VTb4mBAOo2aKSnJ33L9fr25JXpqQqzbUIw/yzIzi+NHwAXK2qYV1lEFp4OoVeThGjUbmWmdw==
+
+"@esbuild/freebsd-arm64@0.18.20":
+ version "0.18.20"
+ resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.18.20.tgz#98755cd12707f93f210e2494d6a4b51b96977f54"
+ integrity sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw==
+
+"@esbuild/freebsd-arm64@0.19.2":
+ version "0.19.2"
+ resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.19.2.tgz#8e478a0856645265fe79eac4b31b52193011ee06"
+ integrity sha512-YbPY2kc0acfzL1VPVK6EnAlig4f+l8xmq36OZkU0jzBVHcOTyQDhnKQaLzZudNJQyymd9OqQezeaBgkTGdTGeQ==
+
+"@esbuild/freebsd-x64@0.16.17":
+ version "0.16.17"
+ resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.16.17.tgz#636306f19e9bc981e06aa1d777302dad8fddaf72"
+ integrity sha512-8ScTdNJl5idAKjH8zGAsN7RuWcyHG3BAvMNpKOBaqqR7EbUhhVHOqXRdL7oZvz8WNHL2pr5+eIT5c65kA6NHug==
+
+"@esbuild/freebsd-x64@0.18.20":
+ version "0.18.20"
+ resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.18.20.tgz#c1eb2bff03915f87c29cece4c1a7fa1f423b066e"
+ integrity sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ==
+
+"@esbuild/freebsd-x64@0.19.2":
+ version "0.19.2"
+ resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.19.2.tgz#01b96604f2540db023c73809bb8ae6cd1692d6f3"
+ integrity sha512-nSO5uZT2clM6hosjWHAsS15hLrwCvIWx+b2e3lZ3MwbYSaXwvfO528OF+dLjas1g3bZonciivI8qKR/Hm7IWGw==
+
+"@esbuild/linux-arm64@0.16.17":
+ version "0.16.17"
+ resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.16.17.tgz#a003f7ff237c501e095d4f3a09e58fc7b25a4aca"
+ integrity sha512-7S8gJnSlqKGVJunnMCrXHU9Q8Q/tQIxk/xL8BqAP64wchPCTzuM6W3Ra8cIa1HIflAvDnNOt2jaL17vaW+1V0g==
+
+"@esbuild/linux-arm64@0.18.20":
+ version "0.18.20"
+ resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.18.20.tgz#bad4238bd8f4fc25b5a021280c770ab5fc3a02a0"
+ integrity sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA==
+
+"@esbuild/linux-arm64@0.19.2":
+ version "0.19.2"
+ resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.19.2.tgz#7e5d2c7864c5c83ec789b59c77cd9c20d2594916"
+ integrity sha512-ig2P7GeG//zWlU0AggA3pV1h5gdix0MA3wgB+NsnBXViwiGgY77fuN9Wr5uoCrs2YzaYfogXgsWZbm+HGr09xg==
+
+"@esbuild/linux-arm@0.16.17":
+ version "0.16.17"
+ resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.16.17.tgz#b591e6a59d9c4fe0eeadd4874b157ab78cf5f196"
+ integrity sha512-iihzrWbD4gIT7j3caMzKb/RsFFHCwqqbrbH9SqUSRrdXkXaygSZCZg1FybsZz57Ju7N/SHEgPyaR0LZ8Zbe9gQ==
+
+"@esbuild/linux-arm@0.18.20":
+ version "0.18.20"
+ resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.18.20.tgz#3e617c61f33508a27150ee417543c8ab5acc73b0"
+ integrity sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg==
+
+"@esbuild/linux-arm@0.19.2":
+ version "0.19.2"
+ resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.19.2.tgz#c32ae97bc0246664a1cfbdb4a98e7b006d7db8ae"
+ integrity sha512-Odalh8hICg7SOD7XCj0YLpYCEc+6mkoq63UnExDCiRA2wXEmGlK5JVrW50vZR9Qz4qkvqnHcpH+OFEggO3PgTg==
+
+"@esbuild/linux-ia32@0.16.17":
+ version "0.16.17"
+ resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.16.17.tgz#24333a11027ef46a18f57019450a5188918e2a54"
+ integrity sha512-kiX69+wcPAdgl3Lonh1VI7MBr16nktEvOfViszBSxygRQqSpzv7BffMKRPMFwzeJGPxcio0pdD3kYQGpqQ2SSg==
+
+"@esbuild/linux-ia32@0.18.20":
+ version "0.18.20"
+ resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.18.20.tgz#699391cccba9aee6019b7f9892eb99219f1570a7"
+ integrity sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA==
+
+"@esbuild/linux-ia32@0.19.2":
+ version "0.19.2"
+ resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.19.2.tgz#3fc4f0fa026057fe885e4a180b3956e704f1ceaa"
+ integrity sha512-mLfp0ziRPOLSTek0Gd9T5B8AtzKAkoZE70fneiiyPlSnUKKI4lp+mGEnQXcQEHLJAcIYDPSyBvsUbKUG2ri/XQ==
+
+"@esbuild/linux-loong64@0.16.17":
+ version "0.16.17"
+ resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.16.17.tgz#d5ad459d41ed42bbd4d005256b31882ec52227d8"
+ integrity sha512-dTzNnQwembNDhd654cA4QhbS9uDdXC3TKqMJjgOWsC0yNCbpzfWoXdZvp0mY7HU6nzk5E0zpRGGx3qoQg8T2DQ==
+
+"@esbuild/linux-loong64@0.18.20":
+ version "0.18.20"
+ resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.18.20.tgz#e6fccb7aac178dd2ffb9860465ac89d7f23b977d"
+ integrity sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg==
+
+"@esbuild/linux-loong64@0.19.2":
+ version "0.19.2"
+ resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.19.2.tgz#633bcaea443f3505fb0ed109ab840c99ad3451a4"
+ integrity sha512-hn28+JNDTxxCpnYjdDYVMNTR3SKavyLlCHHkufHV91fkewpIyQchS1d8wSbmXhs1fiYDpNww8KTFlJ1dHsxeSw==
+
+"@esbuild/linux-mips64el@0.16.17":
+ version "0.16.17"
+ resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.16.17.tgz#4e5967a665c38360b0a8205594377d4dcf9c3726"
+ integrity sha512-ezbDkp2nDl0PfIUn0CsQ30kxfcLTlcx4Foz2kYv8qdC6ia2oX5Q3E/8m6lq84Dj/6b0FrkgD582fJMIfHhJfSw==
+
+"@esbuild/linux-mips64el@0.18.20":
+ version "0.18.20"
+ resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.18.20.tgz#eeff3a937de9c2310de30622a957ad1bd9183231"
+ integrity sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ==
+
+"@esbuild/linux-mips64el@0.19.2":
+ version "0.19.2"
+ resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.19.2.tgz#e0bff2898c46f52be7d4dbbcca8b887890805823"
+ integrity sha512-KbXaC0Sejt7vD2fEgPoIKb6nxkfYW9OmFUK9XQE4//PvGIxNIfPk1NmlHmMg6f25x57rpmEFrn1OotASYIAaTg==
+
+"@esbuild/linux-ppc64@0.16.17":
+ version "0.16.17"
+ resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.16.17.tgz#206443a02eb568f9fdf0b438fbd47d26e735afc8"
+ integrity sha512-dzS678gYD1lJsW73zrFhDApLVdM3cUF2MvAa1D8K8KtcSKdLBPP4zZSLy6LFZ0jYqQdQ29bjAHJDgz0rVbLB3g==
+
+"@esbuild/linux-ppc64@0.18.20":
+ version "0.18.20"
+ resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.18.20.tgz#2f7156bde20b01527993e6881435ad79ba9599fb"
+ integrity sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA==
+
+"@esbuild/linux-ppc64@0.19.2":
+ version "0.19.2"
+ resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.19.2.tgz#d75798da391f54a9674f8c143b9a52d1dbfbfdde"
+ integrity sha512-dJ0kE8KTqbiHtA3Fc/zn7lCd7pqVr4JcT0JqOnbj4LLzYnp+7h8Qi4yjfq42ZlHfhOCM42rBh0EwHYLL6LEzcw==
+
+"@esbuild/linux-riscv64@0.16.17":
+ version "0.16.17"
+ resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.16.17.tgz#c351e433d009bf256e798ad048152c8d76da2fc9"
+ integrity sha512-ylNlVsxuFjZK8DQtNUwiMskh6nT0vI7kYl/4fZgV1llP5d6+HIeL/vmmm3jpuoo8+NuXjQVZxmKuhDApK0/cKw==
+
+"@esbuild/linux-riscv64@0.18.20":
+ version "0.18.20"
+ resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.18.20.tgz#6628389f210123d8b4743045af8caa7d4ddfc7a6"
+ integrity sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A==
+
+"@esbuild/linux-riscv64@0.19.2":
+ version "0.19.2"
+ resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.19.2.tgz#012409bd489ed1bb9b775541d4a46c5ded8e6dd8"
+ integrity sha512-7Z/jKNFufZ/bbu4INqqCN6DDlrmOTmdw6D0gH+6Y7auok2r02Ur661qPuXidPOJ+FSgbEeQnnAGgsVynfLuOEw==
+
+"@esbuild/linux-s390x@0.16.17":
+ version "0.16.17"
+ resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.16.17.tgz#661f271e5d59615b84b6801d1c2123ad13d9bd87"
+ integrity sha512-gzy7nUTO4UA4oZ2wAMXPNBGTzZFP7mss3aKR2hH+/4UUkCOyqmjXiKpzGrY2TlEUhbbejzXVKKGazYcQTZWA/w==
+
+"@esbuild/linux-s390x@0.18.20":
+ version "0.18.20"
+ resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.18.20.tgz#255e81fb289b101026131858ab99fba63dcf0071"
+ integrity sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ==
+
+"@esbuild/linux-s390x@0.19.2":
+ version "0.19.2"
+ resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.19.2.tgz#ece3ed75c5a150de8a5c110f02e97d315761626b"
+ integrity sha512-U+RinR6aXXABFCcAY4gSlv4CL1oOVvSSCdseQmGO66H+XyuQGZIUdhG56SZaDJQcLmrSfRmx5XZOWyCJPRqS7g==
+
+"@esbuild/linux-x64@0.16.17":
+ version "0.16.17"
+ resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.16.17.tgz#e4ba18e8b149a89c982351443a377c723762b85f"
+ integrity sha512-mdPjPxfnmoqhgpiEArqi4egmBAMYvaObgn4poorpUaqmvzzbvqbowRllQ+ZgzGVMGKaPkqUmPDOOFQRUFDmeUw==
+
+"@esbuild/linux-x64@0.18.20":
+ version "0.18.20"
+ resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.18.20.tgz#c7690b3417af318a9b6f96df3031a8865176d338"
+ integrity sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w==
+
+"@esbuild/linux-x64@0.19.2":
+ version "0.19.2"
+ resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.19.2.tgz#dea187019741602d57aaf189a80abba261fbd2aa"
+ integrity sha512-oxzHTEv6VPm3XXNaHPyUTTte+3wGv7qVQtqaZCrgstI16gCuhNOtBXLEBkBREP57YTd68P0VgDgG73jSD8bwXQ==
+
+"@esbuild/netbsd-x64@0.16.17":
+ version "0.16.17"
+ resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.16.17.tgz#7d4f4041e30c5c07dd24ffa295c73f06038ec775"
+ integrity sha512-/PzmzD/zyAeTUsduZa32bn0ORug+Jd1EGGAUJvqfeixoEISYpGnAezN6lnJoskauoai0Jrs+XSyvDhppCPoKOA==
+
+"@esbuild/netbsd-x64@0.18.20":
+ version "0.18.20"
+ resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.18.20.tgz#30e8cd8a3dded63975e2df2438ca109601ebe0d1"
+ integrity sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A==
+
+"@esbuild/netbsd-x64@0.19.2":
+ version "0.19.2"
+ resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.19.2.tgz#bbfd7cf9ab236a23ee3a41b26f0628c57623d92a"
+ integrity sha512-WNa5zZk1XpTTwMDompZmvQLHszDDDN7lYjEHCUmAGB83Bgs20EMs7ICD+oKeT6xt4phV4NDdSi/8OfjPbSbZfQ==
+
+"@esbuild/openbsd-x64@0.16.17":
+ version "0.16.17"
+ resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.16.17.tgz#970fa7f8470681f3e6b1db0cc421a4af8060ec35"
+ integrity sha512-2yaWJhvxGEz2RiftSk0UObqJa/b+rIAjnODJgv2GbGGpRwAfpgzyrg1WLK8rqA24mfZa9GvpjLcBBg8JHkoodg==
+
+"@esbuild/openbsd-x64@0.18.20":
+ version "0.18.20"
+ resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.18.20.tgz#7812af31b205055874c8082ea9cf9ab0da6217ae"
+ integrity sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg==
+
+"@esbuild/openbsd-x64@0.19.2":
+ version "0.19.2"
+ resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.19.2.tgz#fa5c4c6ee52a360618f00053652e2902e1d7b4a7"
+ integrity sha512-S6kI1aT3S++Dedb7vxIuUOb3oAxqxk2Rh5rOXOTYnzN8JzW1VzBd+IqPiSpgitu45042SYD3HCoEyhLKQcDFDw==
+
+"@esbuild/sunos-x64@0.16.17":
+ version "0.16.17"
+ resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.16.17.tgz#abc60e7c4abf8b89fb7a4fe69a1484132238022c"
+ integrity sha512-xtVUiev38tN0R3g8VhRfN7Zl42YCJvyBhRKw1RJjwE1d2emWTVToPLNEQj/5Qxc6lVFATDiy6LjVHYhIPrLxzw==
+
+"@esbuild/sunos-x64@0.18.20":
+ version "0.18.20"
+ resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.18.20.tgz#d5c275c3b4e73c9b0ecd38d1ca62c020f887ab9d"
+ integrity sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ==
+
+"@esbuild/sunos-x64@0.19.2":
+ version "0.19.2"
+ resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.19.2.tgz#52a2ac8ac6284c02d25df22bb4cfde26fbddd68d"
+ integrity sha512-VXSSMsmb+Z8LbsQGcBMiM+fYObDNRm8p7tkUDMPG/g4fhFX5DEFmjxIEa3N8Zr96SjsJ1woAhF0DUnS3MF3ARw==
+
+"@esbuild/win32-arm64@0.16.17":
+ version "0.16.17"
+ resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.16.17.tgz#7b0ff9e8c3265537a7a7b1fd9a24e7bd39fcd87a"
+ integrity sha512-ga8+JqBDHY4b6fQAmOgtJJue36scANy4l/rL97W+0wYmijhxKetzZdKOJI7olaBaMhWt8Pac2McJdZLxXWUEQw==
+
+"@esbuild/win32-arm64@0.18.20":
+ version "0.18.20"
+ resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.18.20.tgz#73bc7f5a9f8a77805f357fab97f290d0e4820ac9"
+ integrity sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg==
+
+"@esbuild/win32-arm64@0.19.2":
+ version "0.19.2"
+ resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.19.2.tgz#719ed5870855de8537aef8149694a97d03486804"
+ integrity sha512-5NayUlSAyb5PQYFAU9x3bHdsqB88RC3aM9lKDAz4X1mo/EchMIT1Q+pSeBXNgkfNmRecLXA0O8xP+x8V+g/LKg==
+
+"@esbuild/win32-ia32@0.16.17":
+ version "0.16.17"
+ resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.16.17.tgz#e90fe5267d71a7b7567afdc403dfd198c292eb09"
+ integrity sha512-WnsKaf46uSSF/sZhwnqE4L/F89AYNMiD4YtEcYekBt9Q7nj0DiId2XH2Ng2PHM54qi5oPrQ8luuzGszqi/veig==
+
+"@esbuild/win32-ia32@0.18.20":
+ version "0.18.20"
+ resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.18.20.tgz#ec93cbf0ef1085cc12e71e0d661d20569ff42102"
+ integrity sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g==
+
+"@esbuild/win32-ia32@0.19.2":
+ version "0.19.2"
+ resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.19.2.tgz#24832223880b0f581962c8660f8fb8797a1e046a"
+ integrity sha512-47gL/ek1v36iN0wL9L4Q2MFdujR0poLZMJwhO2/N3gA89jgHp4MR8DKCmwYtGNksbfJb9JoTtbkoe6sDhg2QTA==
+
+"@esbuild/win32-x64@0.16.17":
+ version "0.16.17"
+ resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.16.17.tgz#c5a1a4bfe1b57f0c3e61b29883525c6da3e5c091"
+ integrity sha512-y+EHuSchhL7FjHgvQL/0fnnFmO4T1bhvWANX6gcnqTjtnKWbTvUMCpGnv2+t+31d7RzyEAYAd4u2fnIhHL6N/Q==
+
+"@esbuild/win32-x64@0.18.20":
+ version "0.18.20"
+ resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.18.20.tgz#786c5f41f043b07afb1af37683d7c33668858f6d"
+ integrity sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ==
+
+"@esbuild/win32-x64@0.19.2":
+ version "0.19.2"
+ resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.19.2.tgz#1205014625790c7ff0e471644a878a65d1e34ab0"
+ integrity sha512-tcuhV7ncXBqbt/Ybf0IyrMcwVOAPDckMK9rXNHtF17UTK18OKLpg08glminN06pt2WCoALhXdLfSPbVvK/6fxw==
+
+"@esm2cjs/execa@6.1.1-cjs.1":
+ version "6.1.1-cjs.1"
+ resolved "https://registry.yarnpkg.com/@esm2cjs/execa/-/execa-6.1.1-cjs.1.tgz#e6bdede1ce4a89cfbfe8b2d6f687b674b4149f38"
+ integrity sha512-FHxfnmuDIjY1VS/BLzDkL8EkbcFvi8s6x1nYQ1Nyu0An0n88EJcGhDBcRWLFwt3C3nT7xwI+MwHRH1TZcAFW2w==
+ dependencies:
+ "@esm2cjs/human-signals" "^3.0.1"
+ "@esm2cjs/is-stream" "^3.0.0"
+ "@esm2cjs/npm-run-path" "^5.1.1-cjs.0"
+ "@esm2cjs/onetime" "^6.0.1-cjs.0"
+ "@esm2cjs/strip-final-newline" "^3.0.1-cjs.0"
+ cross-spawn "^7.0.3"
+ get-stream "^6.0.1"
+ merge-stream "^2.0.0"
+ signal-exit "^3.0.7"
+
+"@esm2cjs/human-signals@^3.0.1":
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/@esm2cjs/human-signals/-/human-signals-3.0.1.tgz#87c205899668d3f6c370eb82a7e9b896e2a1efbc"
+ integrity sha512-QZme4eF/PwTpeSbMB4AaWGQ4VSygzE30jI+Oas1NPTtZQAgcHwWVDOQpIW8FUmtzn5Q+2cS7AjnTzbtqtc5P6g==
+
+"@esm2cjs/is-stream@^3.0.0":
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/@esm2cjs/is-stream/-/is-stream-3.0.0.tgz#868e24882efdd35cfd6f139332abde30e7b3a946"
+ integrity sha512-qcBscHlJpZFOD5nnmMHkzOrq2xyvsp9fbVreQLS8x2LOs8N3CrNi3fqvFY0GVJR+YSOHscwhG9T5t4Ck7R7QGw==
+
+"@esm2cjs/mimic-fn@^4.0.0":
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/@esm2cjs/mimic-fn/-/mimic-fn-4.0.0.tgz#7ac5185e4902638b7ed68f6e2f4f2e4bd14532bb"
+ integrity sha512-LIIAjcpjLr4rcbYmRQ+eRu55Upy/MMB78seIlwqbnyiA+cTa1/pxWnJ1NHJQrw6tx2wMQmlYoJj+wf16NjWH6Q==
+
+"@esm2cjs/npm-run-path@^5.1.1-cjs.0":
+ version "5.1.1-cjs.0"
+ resolved "https://registry.yarnpkg.com/@esm2cjs/npm-run-path/-/npm-run-path-5.1.1-cjs.0.tgz#bbd9531acee450168f68a535f3df4ff6fff2ee1e"
+ integrity sha512-CWeAIyE8iNSCgP2ItPE8iPgS+lACqgH+MuFRaWOIl2T7hnHqPFfhAJJ/LcLJJ/RMIxNMeenjFMwc91HW7NWr1A==
+ dependencies:
+ "@esm2cjs/path-key" "^4.0.0"
+
+"@esm2cjs/onetime@^6.0.1-cjs.0":
+ version "6.0.1-cjs.0"
+ resolved "https://registry.yarnpkg.com/@esm2cjs/onetime/-/onetime-6.0.1-cjs.0.tgz#24ed91716f4e1e7daebc416f26357be08b4f8050"
+ integrity sha512-MkZMZSxrSC/6yUuAw6Azc56XOgwHQQIsNDlO/zgFmOcycJBhRwRuc/gdYUUOFNZIh7y+f0JSIxkNdJPFvJ5W0w==
+ dependencies:
+ "@esm2cjs/mimic-fn" "^4.0.0"
+
+"@esm2cjs/path-key@^4.0.0":
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/@esm2cjs/path-key/-/path-key-4.0.0.tgz#4c406fe897f9bb880d8619751ce72395867eb9e2"
+ integrity sha512-fKzZ3uIIP4j+7WfyG0MEkomGHL0hUXWCx1kY2Zct3GTdl4pyY+3k5lCUxjgdDa2Ld1BCjMNorXnRHiBP6jW6CQ==
+
+"@esm2cjs/strip-final-newline@^3.0.1-cjs.0":
+ version "3.0.1-cjs.0"
+ resolved "https://registry.yarnpkg.com/@esm2cjs/strip-final-newline/-/strip-final-newline-3.0.1-cjs.0.tgz#79a891eaa0414e4898fc2dc8220583ab7bd4bb0a"
+ integrity sha512-o41riCGPiOEStayoikBCAqwa6igbv9L9rP+k5UCfQ24EJD/wGrdDs/KTNwkHG5JzDK3T60D5dMkWkLKEPy8gjA==
+
+"@floating-ui/core@^1.5.3":
+ version "1.5.3"
+ resolved "https://registry.yarnpkg.com/@floating-ui/core/-/core-1.5.3.tgz#b6aa0827708d70971c8679a16cf680a515b8a52a"
+ integrity sha512-O0WKDOo0yhJuugCx6trZQj5jVJ9yR0ystG2JaNAemYUWce+pmM6WUEFIibnWyEJKdrDxhm75NoSRME35FNaM/Q==
+ dependencies:
+ "@floating-ui/utils" "^0.2.0"
+
+"@floating-ui/dom@^1.0.1", "@floating-ui/dom@^1.5.4":
+ version "1.5.4"
+ resolved "https://registry.yarnpkg.com/@floating-ui/dom/-/dom-1.5.4.tgz#28df1e1cb373884224a463235c218dcbd81a16bb"
+ integrity sha512-jByEsHIY+eEdCjnTVu+E3ephzTOzkQ8hgUfGwos+bg7NlH33Zc5uO+QHz1mrQUOgIKKDD1RtS201P9NvAfq3XQ==
+ dependencies:
+ "@floating-ui/core" "^1.5.3"
+ "@floating-ui/utils" "^0.2.0"
+
+"@floating-ui/react-dom@^2.0.0", "@floating-ui/react-dom@^2.0.5":
+ version "2.0.5"
+ resolved "https://registry.yarnpkg.com/@floating-ui/react-dom/-/react-dom-2.0.5.tgz#851522899c34e3e2be1e29f3294f150834936e28"
+ integrity sha512-UsBK30Bg+s6+nsgblXtZmwHhgS2vmbuQK22qgt2pTQM6M3X6H1+cQcLXqgRY3ihVLcZJE6IvqDQozhsnIVqK/Q==
+ dependencies:
+ "@floating-ui/dom" "^1.5.4"
+
+"@floating-ui/utils@^0.2.0":
+ version "0.2.1"
+ resolved "https://registry.yarnpkg.com/@floating-ui/utils/-/utils-0.2.1.tgz#16308cea045f0fc777b6ff20a9f25474dd8293d2"
+ integrity sha512-9TANp6GPoMtYzQdt54kfAyMmz1+osLlXdg2ENroU7zzrtflTLrrC/lgrIfaSe+Wu0b89GKccT7vxXA0MoAIO+Q==
+
+"@formatjs/ecma402-abstract@1.14.3":
+ version "1.14.3"
+ resolved "https://registry.yarnpkg.com/@formatjs/ecma402-abstract/-/ecma402-abstract-1.14.3.tgz#6428f243538a11126180d121ce8d4b2f17465738"
+ integrity sha512-SlsbRC/RX+/zg4AApWIFNDdkLtFbkq3LNoZWXZCE/nHVKqoIJyaoQyge/I0Y38vLxowUn9KTtXgusLD91+orbg==
+ dependencies:
+ "@formatjs/intl-localematcher" "0.2.32"
+ tslib "^2.4.0"
+
+"@formatjs/fast-memoize@2.0.1":
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/@formatjs/fast-memoize/-/fast-memoize-2.0.1.tgz#f15aaa73caad5562899c69bdcad8db82adcd3b0b"
+ integrity sha512-M2GgV+qJn5WJQAYewz7q2Cdl6fobQa69S1AzSM2y0P68ZDbK5cWrJIcPCO395Of1ksftGZoOt4LYCO/j9BKBSA==
+ dependencies:
+ tslib "^2.4.0"
+
+"@formatjs/icu-messageformat-parser@2.3.0":
+ version "2.3.0"
+ resolved "https://registry.yarnpkg.com/@formatjs/icu-messageformat-parser/-/icu-messageformat-parser-2.3.0.tgz#8e8fd577c3e39454ef14bba4963f2e1d5f2cc46c"
+ integrity sha512-xqtlqYAbfJDF4b6e4O828LBNOWXrFcuYadqAbYORlDRwhyJ2bH+xpUBPldZbzRGUN2mxlZ4Ykhm7jvERtmI8NQ==
+ dependencies:
+ "@formatjs/ecma402-abstract" "1.14.3"
+ "@formatjs/icu-skeleton-parser" "1.3.18"
+ tslib "^2.4.0"
+
+"@formatjs/icu-messageformat-parser@2.3.1":
+ version "2.3.1"
+ resolved "https://registry.yarnpkg.com/@formatjs/icu-messageformat-parser/-/icu-messageformat-parser-2.3.1.tgz#953080ea5c053bc73bdf55d0a524a3c3c133ae6b"
+ integrity sha512-knF2AkAKN4Upv4oIiKY4Wd/dLH68TNMPgV/tJMu/T6FP9aQwbv8fpj7U3lkyniPaNVxvia56Gxax8MKOjtxLSQ==
+ dependencies:
+ "@formatjs/ecma402-abstract" "1.14.3"
+ "@formatjs/icu-skeleton-parser" "1.3.18"
+ tslib "^2.4.0"
+
+"@formatjs/icu-skeleton-parser@1.3.18":
+ version "1.3.18"
+ resolved "https://registry.yarnpkg.com/@formatjs/icu-skeleton-parser/-/icu-skeleton-parser-1.3.18.tgz#7aed3d60e718c8ad6b0e64820be44daa1e29eeeb"
+ integrity sha512-ND1ZkZfmLPcHjAH1sVpkpQxA+QYfOX3py3SjKWMUVGDow18gZ0WPqz3F+pJLYQMpS2LnnQ5zYR2jPVYTbRwMpg==
+ dependencies:
+ "@formatjs/ecma402-abstract" "1.14.3"
+ tslib "^2.4.0"
+
+"@formatjs/intl-displaynames@6.2.6":
+ version "6.2.6"
+ resolved "https://registry.yarnpkg.com/@formatjs/intl-displaynames/-/intl-displaynames-6.2.6.tgz#6bc02fe0bf6571391aac0e01e74ecbf38542ff32"
+ integrity sha512-scf5AQTk9EjpvPhboo5sizVOvidTdMOnajv9z+0cejvl7JNl9bl/aMrNBgC72UH+bP3l45usPUKAGskV6sNIrA==
+ dependencies:
+ "@formatjs/ecma402-abstract" "1.14.3"
+ "@formatjs/intl-localematcher" "0.2.32"
+ tslib "^2.4.0"
+
+"@formatjs/intl-displaynames@6.3.1":
+ version "6.3.1"
+ resolved "https://registry.yarnpkg.com/@formatjs/intl-displaynames/-/intl-displaynames-6.3.1.tgz#6dcea7cb801460e2a8fa63eb38c54aa1b24f92c0"
+ integrity sha512-TlxguMDUbnFrJ4NA8fSyqXC62M7czvlRJ5mrJgtB91JVA+QPjjNdcRm1qPIC/DcU/pGUDcEzThn/x5A+jp15gg==
+ dependencies:
+ "@formatjs/ecma402-abstract" "1.14.3"
+ "@formatjs/intl-localematcher" "0.2.32"
+ tslib "^2.4.0"
+
+"@formatjs/intl-listformat@7.1.9":
+ version "7.1.9"
+ resolved "https://registry.yarnpkg.com/@formatjs/intl-listformat/-/intl-listformat-7.1.9.tgz#0c2ce67b610054f215dd2635a6da7da308cfbe3d"
+ integrity sha512-5YikxwRqRXTVWVujhswDOTCq6gs+m9IcNbNZLa6FLtyBStAjEsuE2vAU+lPsbz9ZTST57D5fodjIh2JXT6sMWQ==
+ dependencies:
+ "@formatjs/ecma402-abstract" "1.14.3"
+ "@formatjs/intl-localematcher" "0.2.32"
+ tslib "^2.4.0"
+
+"@formatjs/intl-listformat@7.2.1":
+ version "7.2.1"
+ resolved "https://registry.yarnpkg.com/@formatjs/intl-listformat/-/intl-listformat-7.2.1.tgz#874eddc7d53ba2e3fd911bf30efc459fc99f08db"
+ integrity sha512-fRJFWLrGa7d25I4JSxNjKX29oXGcIXx8fJjgURnvs2C3ijS4gurUgFrUwLbv/2KfPfyJ5g567pz2INelNJZBdw==
+ dependencies:
+ "@formatjs/ecma402-abstract" "1.14.3"
+ "@formatjs/intl-localematcher" "0.2.32"
+ tslib "^2.4.0"
+
+"@formatjs/intl-localematcher@0.2.32":
+ version "0.2.32"
+ resolved "https://registry.yarnpkg.com/@formatjs/intl-localematcher/-/intl-localematcher-0.2.32.tgz#00d4d307cd7d514b298e15a11a369b86c8933ec1"
+ integrity sha512-k/MEBstff4sttohyEpXxCmC3MqbUn9VvHGlZ8fauLzkbwXmVrEeyzS+4uhrvAk9DWU9/7otYWxyDox4nT/KVLQ==
+ dependencies:
+ tslib "^2.4.0"
+
+"@formatjs/intl@2.6.9":
+ version "2.6.9"
+ resolved "https://registry.yarnpkg.com/@formatjs/intl/-/intl-2.6.9.tgz#d4bdd8c21888f579a95341580141d0aafe761610"
+ integrity sha512-EtcMZ9O24YSASu/jGOaTQtArx7XROjlKiO4KmkxJ/3EyAQLCr5hrS+KKvNud0a7GIwBucOb3IFrZ7WiSm2A/Cw==
+ dependencies:
+ "@formatjs/ecma402-abstract" "1.14.3"
+ "@formatjs/fast-memoize" "2.0.1"
+ "@formatjs/icu-messageformat-parser" "2.3.0"
+ "@formatjs/intl-displaynames" "6.2.6"
+ "@formatjs/intl-listformat" "7.1.9"
+ intl-messageformat "10.3.3"
+ tslib "^2.4.0"
+
+"@formatjs/intl@2.7.1":
+ version "2.7.1"
+ resolved "https://registry.yarnpkg.com/@formatjs/intl/-/intl-2.7.1.tgz#f7e052ff09e9fe019ad83d4139af0de40084a2ae"
+ integrity sha512-se6vxidsN3PCmzqTsDd3YDT4IX9ZySPy39LYhF7x2ssNvlGMOuW3umkrIhKkXB7ZskqsJGY53LVCdiHsSwhGng==
+ dependencies:
+ "@formatjs/ecma402-abstract" "1.14.3"
+ "@formatjs/fast-memoize" "2.0.1"
+ "@formatjs/icu-messageformat-parser" "2.3.1"
+ "@formatjs/intl-displaynames" "6.3.1"
+ "@formatjs/intl-listformat" "7.2.1"
+ intl-messageformat "10.3.4"
+ tslib "^2.4.0"
+
+"@internationalized/date@^3.5.1":
+ version "3.5.1"
+ resolved "https://registry.yarnpkg.com/@internationalized/date/-/date-3.5.1.tgz#14401139f70c1ef14b845d3cac8912e82e82adcc"
+ integrity sha512-LUQIfwU9e+Fmutc/DpRTGXSdgYZLBegi4wygCWDSVmUdLTaMHsQyASDiJtREwanwKuQLq0hY76fCJ9J/9I2xOQ==
+ dependencies:
+ "@swc/helpers" "^0.5.0"
+
+"@internationalized/number@^3.5.0":
+ version "3.5.0"
+ resolved "https://registry.yarnpkg.com/@internationalized/number/-/number-3.5.0.tgz#9de6018424b441a6545f209afa286ad7df4a2906"
+ integrity sha512-ZY1BW8HT9WKYvaubbuqXbbDdHhOUMfE2zHHFJeTppid0S+pc8HtdIxFxaYMsGjCb4UsF+MEJ4n2TfU7iHnUK8w==
+ dependencies:
+ "@swc/helpers" "^0.5.0"
+
+"@jridgewell/gen-mapping@^0.3.0", "@jridgewell/gen-mapping@^0.3.2":
+ version "0.3.3"
+ resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz#7e02e6eb5df901aaedb08514203b096614024098"
+ integrity sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==
+ dependencies:
+ "@jridgewell/set-array" "^1.0.1"
+ "@jridgewell/sourcemap-codec" "^1.4.10"
+ "@jridgewell/trace-mapping" "^0.3.9"
+
+"@jridgewell/resolve-uri@^3.1.0":
+ version "3.1.1"
+ resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz#c08679063f279615a3326583ba3a90d1d82cc721"
+ integrity sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==
+
+"@jridgewell/set-array@^1.0.1":
+ version "1.1.2"
+ resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.1.2.tgz#7c6cf998d6d20b914c0a55a91ae928ff25965e72"
+ integrity sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==
+
+"@jridgewell/source-map@^0.3.3":
+ version "0.3.5"
+ resolved "https://registry.yarnpkg.com/@jridgewell/source-map/-/source-map-0.3.5.tgz#a3bb4d5c6825aab0d281268f47f6ad5853431e91"
+ integrity sha512-UTYAUj/wviwdsMfzoSJspJxbkH5o1snzwX0//0ENX1u/55kkZZkcTZP6u9bwKGkv+dkk9at4m1Cpt0uY80kcpQ==
+ dependencies:
+ "@jridgewell/gen-mapping" "^0.3.0"
+ "@jridgewell/trace-mapping" "^0.3.9"
+
+"@jridgewell/sourcemap-codec@^1.4.10", "@jridgewell/sourcemap-codec@^1.4.14":
+ version "1.4.15"
+ resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz#d7c6e6755c78567a951e04ab52ef0fd26de59f32"
+ integrity sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==
+
+"@jridgewell/trace-mapping@^0.3.17", "@jridgewell/trace-mapping@^0.3.20", "@jridgewell/trace-mapping@^0.3.9":
+ version "0.3.20"
+ resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.20.tgz#72e45707cf240fa6b081d0366f8265b0cd10197f"
+ integrity sha512-R8LcPeWZol2zR8mmH3JeKQ6QRCFb7XgUhV9ZlGhHLGyg4wpPiPZNQOOWhFZhxKw8u//yTbNGI42Bx/3paXEQ+Q==
+ dependencies:
+ "@jridgewell/resolve-uri" "^3.1.0"
+ "@jridgewell/sourcemap-codec" "^1.4.14"
+
+"@juggle/resize-observer@^3.4.0":
+ version "3.4.0"
+ resolved "https://registry.yarnpkg.com/@juggle/resize-observer/-/resize-observer-3.4.0.tgz#08d6c5e20cf7e4cc02fd181c4b0c225cd31dbb60"
+ integrity sha512-dfLbk+PwWvFzSxwk3n5ySL0hfBog779o8h68wK/7/APo/7cgyWp5jcXockbxdk5kFRkbeXWm4Fbi9FrdN381sA==
+
+"@koa/cors@3.4.3":
+ version "3.4.3"
+ resolved "https://registry.yarnpkg.com/@koa/cors/-/cors-3.4.3.tgz#d669ee6e8d6e4f0ec4a7a7b0a17e7a3ed3752ebb"
+ integrity sha512-WPXQUaAeAMVaLTEFpoq3T2O1C+FstkjJnDQqy95Ck1UdILajsRhu6mhJ8H2f4NFPRBoCNN+qywTJfq/gGki5mw==
+ dependencies:
+ vary "^1.1.2"
+
+"@koa/router@10.1.1":
+ version "10.1.1"
+ resolved "https://registry.yarnpkg.com/@koa/router/-/router-10.1.1.tgz#8e5a85c9b243e0bc776802c0de564561e57a5f78"
+ integrity sha512-ORNjq5z4EmQPriKbR0ER3k4Gh7YGNhWDL7JBW+8wXDrHLbWYKYSJaOJ9aN06npF5tbTxe2JBOsurpJDAvjiXKw==
+ dependencies:
+ debug "^4.1.1"
+ http-errors "^1.7.3"
+ koa-compose "^4.1.0"
+ methods "^1.1.2"
+ path-to-regexp "^6.1.0"
+
+"@lezer/common@^1.0.0", "@lezer/common@^1.1.0", "@lezer/common@^1.2.0":
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/@lezer/common/-/common-1.2.0.tgz#f10493d12c4a196a02ff5fcf5695a516a4039aae"
+ integrity sha512-Wmvlm4q6tRpwiy20TnB3yyLTZim38Tkc50dPY8biQRwqE+ati/wD84rm3N15hikvdT4uSg9phs9ubjvcLmkpKg==
+
+"@lezer/highlight@^1.0.0":
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/@lezer/highlight/-/highlight-1.2.0.tgz#e5898c3644208b4b589084089dceeea2966f7780"
+ integrity sha512-WrS5Mw51sGrpqjlh3d4/fOwpEV2Hd3YOkp9DBt4k8XZQcoTHZFB7sx030A6OcahF4J1nDQAa3jXlTVVYH50IFA==
+ dependencies:
+ "@lezer/common" "^1.0.0"
+
+"@lezer/json@^1.0.0":
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/@lezer/json/-/json-1.0.2.tgz#bdc849e174113e2d9a569a5e6fb1a27e2f703eaf"
+ integrity sha512-xHT2P4S5eeCYECyKNPhr4cbEL9tc8w83SPwRC373o9uEdrvGKTZoJVAGxpOsZckMlEh9W23Pc72ew918RWQOBQ==
+ dependencies:
+ "@lezer/common" "^1.2.0"
+ "@lezer/highlight" "^1.0.0"
+ "@lezer/lr" "^1.0.0"
+
+"@lezer/lr@^1.0.0":
+ version "1.3.14"
+ resolved "https://registry.yarnpkg.com/@lezer/lr/-/lr-1.3.14.tgz#59d4a3b25698bdac0ef182fa6eadab445fc4f29a"
+ integrity sha512-z5mY4LStlA3yL7aHT/rqgG614cfcvklS+8oFRFBYrs4YaWLJyKKM4+nN6KopToX0o9Hj6zmH6M5kinOYuy06ug==
+ dependencies:
+ "@lezer/common" "^1.0.0"
+
+"@mapbox/node-pre-gyp@^1.0.0":
+ version "1.0.11"
+ resolved "https://registry.yarnpkg.com/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.11.tgz#417db42b7f5323d79e93b34a6d7a2a12c0df43fa"
+ integrity sha512-Yhlar6v9WQgUp/He7BdgzOz8lqMQ8sU+jkCq7Wx8Myc5YFJLbEe7lgui/V7G1qB1DJykHSGwreceSaD60Y0PUQ==
+ dependencies:
+ detect-libc "^2.0.0"
+ https-proxy-agent "^5.0.0"
+ make-dir "^3.1.0"
+ node-fetch "^2.6.7"
+ nopt "^5.0.0"
+ npmlog "^5.0.1"
+ rimraf "^3.0.2"
+ semver "^7.3.5"
+ tar "^6.1.11"
+
+"@mswjs/cookies@^0.2.2":
+ version "0.2.2"
+ resolved "https://registry.yarnpkg.com/@mswjs/cookies/-/cookies-0.2.2.tgz#b4e207bf6989e5d5427539c2443380a33ebb922b"
+ integrity sha512-mlN83YSrcFgk7Dm1Mys40DLssI1KdJji2CMKN8eOlBqsTADYzj2+jWzsANsUTFbxDMWPD5e9bfA1RGqBpS3O1g==
+ dependencies:
+ "@types/set-cookie-parser" "^2.4.0"
+ set-cookie-parser "^2.4.6"
+
+"@mswjs/interceptors@^0.17.5":
+ version "0.17.10"
+ resolved "https://registry.yarnpkg.com/@mswjs/interceptors/-/interceptors-0.17.10.tgz#857b41f30e2b92345ed9a4e2b1d0a08b8b6fcad4"
+ integrity sha512-N8x7eSLGcmUFNWZRxT1vsHvypzIRgQYdG0rJey/rZCy6zT/30qDt8Joj7FxzGNLSwXbeZqJOMqDurp7ra4hgbw==
+ dependencies:
+ "@open-draft/until" "^1.0.3"
+ "@types/debug" "^4.1.7"
+ "@xmldom/xmldom" "^0.8.3"
+ debug "^4.3.3"
+ headers-polyfill "3.2.5"
+ outvariant "^1.2.1"
+ strict-event-emitter "^0.2.4"
+ web-encoding "^1.1.5"
+
+"@mux/mux-node@^7.3.3":
+ version "7.3.3"
+ resolved "https://registry.yarnpkg.com/@mux/mux-node/-/mux-node-7.3.3.tgz#a31efbd35793d2a9d6b761729dc9edbebe7fc22b"
+ integrity sha512-t98SW0rhUP56Qn3vly+NApzy7Ebo51fcMYVQL379dpU5exsCoRBYc9lf6a4V+U0fXJ4Ke2asfToXfXMvfsMC+Q==
+ dependencies:
+ axios "^1.2.6"
+ esdoc-ecmascript-proposal-plugin "^1.0.0"
+ jsonwebtoken "^9.0.0"
+
+"@noble/hashes@^1.1.5":
+ version "1.3.3"
+ resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.3.3.tgz#39908da56a4adc270147bb07968bf3b16cfe1699"
+ integrity sha512-V7/fPHgl+jsVPXqqeOzT8egNj2iBIVt+ECeMMG8TdcnTikP3oaBtUVqpT/gYCR68aEBJSF+XbYUxStjbFMqIIA==
+
+"@nodelib/fs.scandir@2.1.5":
+ version "2.1.5"
+ resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5"
+ integrity sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==
+ dependencies:
+ "@nodelib/fs.stat" "2.0.5"
+ run-parallel "^1.1.9"
+
+"@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2":
+ version "2.0.5"
+ resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz#5bd262af94e9d25bd1e71b05deed44876a222e8b"
+ integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==
+
+"@nodelib/fs.walk@^1.2.3":
+ version "1.2.8"
+ resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz#e95737e8bb6746ddedf69c556953494f196fe69a"
+ integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==
+ dependencies:
+ "@nodelib/fs.scandir" "2.1.5"
+ fastq "^1.6.0"
+
+"@open-draft/until@^1.0.3":
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/@open-draft/until/-/until-1.0.3.tgz#db9cc719191a62e7d9200f6e7bab21c5b848adca"
+ integrity sha512-Aq58f5HiWdyDlFffbbSjAlv596h/cOnt2DO1w3DOC7OJ5EHs0hd/nycJfiu9RJbT6Yk6F1knnRRXNSpxoIVZ9Q==
+
+"@paralleldrive/cuid2@^2.2.2":
+ version "2.2.2"
+ resolved "https://registry.yarnpkg.com/@paralleldrive/cuid2/-/cuid2-2.2.2.tgz#7f91364d53b89e2c9cb9e02e8dd0f129e834455f"
+ integrity sha512-ZOBkgDwEdoYVlSeRbYYXs0S9MejQofiVYoTbKzy/6GQa39/q5tQU2IX46+shYnUkpEl3wc+J6wRlar7r2EK2xA==
+ dependencies:
+ "@noble/hashes" "^1.1.5"
+
+"@pkgr/utils@^2.3.1":
+ version "2.4.2"
+ resolved "https://registry.yarnpkg.com/@pkgr/utils/-/utils-2.4.2.tgz#9e638bbe9a6a6f165580dc943f138fd3309a2cbc"
+ integrity sha512-POgTXhjrTfbTV63DiFXav4lBHiICLKKwDeaKn9Nphwj7WH6m0hMMCaJkMyRWjgtPFyRKRVoMXXjczsTQRDEhYw==
+ dependencies:
+ cross-spawn "^7.0.3"
+ fast-glob "^3.3.0"
+ is-glob "^4.0.3"
+ open "^9.1.0"
+ picocolors "^1.0.0"
+ tslib "^2.6.0"
+
+"@pmmmwh/react-refresh-webpack-plugin@0.5.10":
+ version "0.5.10"
+ resolved "https://registry.yarnpkg.com/@pmmmwh/react-refresh-webpack-plugin/-/react-refresh-webpack-plugin-0.5.10.tgz#2eba163b8e7dbabb4ce3609ab5e32ab63dda3ef8"
+ integrity sha512-j0Ya0hCFZPd4x40qLzbhGsh9TMtdb+CJQiso+WxLOPNasohq9cc5SNUcwsZaRH6++Xh91Xkm/xHCkuIiIu0LUA==
+ dependencies:
+ ansi-html-community "^0.0.8"
+ common-path-prefix "^3.0.0"
+ core-js-pure "^3.23.3"
+ error-stack-parser "^2.0.6"
+ find-up "^5.0.0"
+ html-entities "^2.1.0"
+ loader-utils "^2.0.4"
+ schema-utils "^3.0.0"
+ source-map "^0.7.3"
+
+"@pnpm/config.env-replace@^1.1.0":
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/@pnpm/config.env-replace/-/config.env-replace-1.1.0.tgz#ab29da53df41e8948a00f2433f085f54de8b3a4c"
+ integrity sha512-htyl8TWnKL7K/ESFa1oW2UB5lVDxuF5DpM7tBi6Hu2LNL3mWkIzNLG6N4zoCUP1lCKNxWy/3iu8mS8MvToGd6w==
+
+"@pnpm/network.ca-file@^1.0.1":
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/@pnpm/network.ca-file/-/network.ca-file-1.0.2.tgz#2ab05e09c1af0cdf2fcf5035bea1484e222f7983"
+ integrity sha512-YcPQ8a0jwYU9bTdJDpXjMi7Brhkr1mXsXrUJvjqM2mQDgkRiz8jFaQGOdaLxgjtUfQgZhKy/O3cG/YwmgKaxLA==
+ dependencies:
+ graceful-fs "4.2.10"
+
+"@pnpm/npm-conf@^2.1.0":
+ version "2.2.2"
+ resolved "https://registry.yarnpkg.com/@pnpm/npm-conf/-/npm-conf-2.2.2.tgz#0058baf1c26cbb63a828f0193795401684ac86f0"
+ integrity sha512-UA91GwWPhFExt3IizW6bOeY/pQ0BkuNwKjk9iQW9KqxluGCrg4VenZ0/L+2Y0+ZOtme72EVvg6v0zo3AMQRCeA==
+ dependencies:
+ "@pnpm/config.env-replace" "^1.1.0"
+ "@pnpm/network.ca-file" "^1.0.1"
+ config-chain "^1.1.11"
+
+"@polka/url@^1.0.0-next.24":
+ version "1.0.0-next.24"
+ resolved "https://registry.yarnpkg.com/@polka/url/-/url-1.0.0-next.24.tgz#58601079e11784d20f82d0585865bb42305c4df3"
+ integrity sha512-2LuNTFBIO0m7kKIQvvPHN6UE63VjpmL9rnEEaOOaiSPbZK+zUOYIzBAWcED+3XYzhYsd/0mD57VdxAEqqV52CQ==
+
+"@radix-ui/number@^1.0.1":
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/@radix-ui/number/-/number-1.0.1.tgz#644161a3557f46ed38a042acf4a770e826021674"
+ integrity sha512-T5gIdVO2mmPW3NNhjNgEP3cqMXjXL9UbO0BzWcXfvdBs+BohbQxvd/K5hSVKmn9/lbTdsQVKbUcP5WLCwvUbBg==
+ dependencies:
+ "@babel/runtime" "^7.13.10"
+
+"@radix-ui/primitive@1.0.1", "@radix-ui/primitive@^1.0.1":
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/@radix-ui/primitive/-/primitive-1.0.1.tgz#e46f9958b35d10e9f6dc71c497305c22e3e55dbd"
+ integrity sha512-yQ8oGX2GVsEYMWGxcovu1uGWPCxV5BFfeeYxqPmuAzUyLT9qmaMXSAhXpb0WrspIeqYzdJpkh2vHModJPgRIaw==
+ dependencies:
+ "@babel/runtime" "^7.13.10"
+
+"@radix-ui/react-arrow@1.0.3":
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/@radix-ui/react-arrow/-/react-arrow-1.0.3.tgz#c24f7968996ed934d57fe6cde5d6ec7266e1d25d"
+ integrity sha512-wSP+pHsB/jQRaL6voubsQ/ZlrGBHHrOjmBnr19hxYgtS0WvAFwZhK2WP/YY5yF9uKECCEEDGxuLxq1NBK51wFA==
+ dependencies:
+ "@babel/runtime" "^7.13.10"
+ "@radix-ui/react-primitive" "1.0.3"
+
+"@radix-ui/react-collection@1.0.3":
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/@radix-ui/react-collection/-/react-collection-1.0.3.tgz#9595a66e09026187524a36c6e7e9c7d286469159"
+ integrity sha512-3SzW+0PW7yBBoQlT8wNcGtaxaD0XSu0uLUFgrtHY08Acx05TaHaOmVLR73c0j/cqpDy53KBMO7s0dx2wmOIDIA==
+ dependencies:
+ "@babel/runtime" "^7.13.10"
+ "@radix-ui/react-compose-refs" "1.0.1"
+ "@radix-ui/react-context" "1.0.1"
+ "@radix-ui/react-primitive" "1.0.3"
+ "@radix-ui/react-slot" "1.0.2"
+
+"@radix-ui/react-compose-refs@1.0.1", "@radix-ui/react-compose-refs@^1.0.1":
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/@radix-ui/react-compose-refs/-/react-compose-refs-1.0.1.tgz#7ed868b66946aa6030e580b1ffca386dd4d21989"
+ integrity sha512-fDSBgd44FKHa1FRMU59qBMPFcl2PZE+2nmqunj+BWFyYYjnhIDWL2ItDs3rrbJDQOtzt5nIebLCQc4QRfz6LJw==
+ dependencies:
+ "@babel/runtime" "^7.13.10"
+
+"@radix-ui/react-context@1.0.1", "@radix-ui/react-context@^1.0.1":
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/@radix-ui/react-context/-/react-context-1.0.1.tgz#fe46e67c96b240de59187dcb7a1a50ce3e2ec00c"
+ integrity sha512-ebbrdFoYTcuZ0v4wG5tedGnp9tzcV8awzsxYph7gXUyvnNLuTIcCk1q17JEbnVhXAKG9oX3KtchwiMIAYp9NLg==
+ dependencies:
+ "@babel/runtime" "^7.13.10"
+
+"@radix-ui/react-direction@1.0.1":
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/@radix-ui/react-direction/-/react-direction-1.0.1.tgz#9cb61bf2ccf568f3421422d182637b7f47596c9b"
+ integrity sha512-RXcvnXgyvYvBEOhCBuddKecVkoMiI10Jcm5cTI7abJRAHYfFxeu+FBQs/DvdxSYucxR5mna0dNsL6QFlds5TMA==
+ dependencies:
+ "@babel/runtime" "^7.13.10"
+
+"@radix-ui/react-dismissable-layer@1.0.5", "@radix-ui/react-dismissable-layer@^1.0.5":
+ version "1.0.5"
+ resolved "https://registry.yarnpkg.com/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.0.5.tgz#3f98425b82b9068dfbab5db5fff3df6ebf48b9d4"
+ integrity sha512-aJeDjQhywg9LBu2t/At58hCvr7pEm0o2Ke1x33B+MhjNmmZ17sy4KImo0KPLgsnc/zN7GPdce8Cnn0SWvwZO7g==
+ dependencies:
+ "@babel/runtime" "^7.13.10"
+ "@radix-ui/primitive" "1.0.1"
+ "@radix-ui/react-compose-refs" "1.0.1"
+ "@radix-ui/react-primitive" "1.0.3"
+ "@radix-ui/react-use-callback-ref" "1.0.1"
+ "@radix-ui/react-use-escape-keydown" "1.0.3"
+
+"@radix-ui/react-dropdown-menu@^2.0.6":
+ version "2.0.6"
+ resolved "https://registry.yarnpkg.com/@radix-ui/react-dropdown-menu/-/react-dropdown-menu-2.0.6.tgz#cdf13c956c5e263afe4e5f3587b3071a25755b63"
+ integrity sha512-i6TuFOoWmLWq+M/eCLGd/bQ2HfAX1RJgvrBQ6AQLmzfvsLdefxbWu8G9zczcPFfcSPehz9GcpF6K9QYreFV8hA==
+ dependencies:
+ "@babel/runtime" "^7.13.10"
+ "@radix-ui/primitive" "1.0.1"
+ "@radix-ui/react-compose-refs" "1.0.1"
+ "@radix-ui/react-context" "1.0.1"
+ "@radix-ui/react-id" "1.0.1"
+ "@radix-ui/react-menu" "2.0.6"
+ "@radix-ui/react-primitive" "1.0.3"
+ "@radix-ui/react-use-controllable-state" "1.0.1"
+
+"@radix-ui/react-focus-guards@1.0.1":
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/@radix-ui/react-focus-guards/-/react-focus-guards-1.0.1.tgz#1ea7e32092216b946397866199d892f71f7f98ad"
+ integrity sha512-Rect2dWbQ8waGzhMavsIbmSVCgYxkXLxxR3ZvCX79JOglzdEy4JXMb98lq4hPxUbLr77nP0UOGf4rcMU+s1pUA==
+ dependencies:
+ "@babel/runtime" "^7.13.10"
+
+"@radix-ui/react-focus-scope@1.0.4":
+ version "1.0.4"
+ resolved "https://registry.yarnpkg.com/@radix-ui/react-focus-scope/-/react-focus-scope-1.0.4.tgz#2ac45fce8c5bb33eb18419cdc1905ef4f1906525"
+ integrity sha512-sL04Mgvf+FmyvZeYfNu1EPAaaxD+aw7cYeIB9L9Fvq8+urhltTRaEo5ysKOpHuKPclsZcSUMKlN05x4u+CINpA==
+ dependencies:
+ "@babel/runtime" "^7.13.10"
+ "@radix-ui/react-compose-refs" "1.0.1"
+ "@radix-ui/react-primitive" "1.0.3"
+ "@radix-ui/react-use-callback-ref" "1.0.1"
+
+"@radix-ui/react-id@1.0.1", "@radix-ui/react-id@^1.0.1":
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/@radix-ui/react-id/-/react-id-1.0.1.tgz#73cdc181f650e4df24f0b6a5b7aa426b912c88c0"
+ integrity sha512-tI7sT/kqYp8p96yGWY1OAnLHrqDgzHefRBKQ2YAkBS5ja7QLcZ9Z/uY7bEjPUatf8RomoXM8/1sMj1IJaE5UzQ==
+ dependencies:
+ "@babel/runtime" "^7.13.10"
+ "@radix-ui/react-use-layout-effect" "1.0.1"
+
+"@radix-ui/react-menu@2.0.6":
+ version "2.0.6"
+ resolved "https://registry.yarnpkg.com/@radix-ui/react-menu/-/react-menu-2.0.6.tgz#2c9e093c1a5d5daa87304b2a2f884e32288ae79e"
+ integrity sha512-BVkFLS+bUC8HcImkRKPSiVumA1VPOOEC5WBMiT+QAVsPzW1FJzI9KnqgGxVDPBcql5xXrHkD3JOVoXWEXD8SYA==
+ dependencies:
+ "@babel/runtime" "^7.13.10"
+ "@radix-ui/primitive" "1.0.1"
+ "@radix-ui/react-collection" "1.0.3"
+ "@radix-ui/react-compose-refs" "1.0.1"
+ "@radix-ui/react-context" "1.0.1"
+ "@radix-ui/react-direction" "1.0.1"
+ "@radix-ui/react-dismissable-layer" "1.0.5"
+ "@radix-ui/react-focus-guards" "1.0.1"
+ "@radix-ui/react-focus-scope" "1.0.4"
+ "@radix-ui/react-id" "1.0.1"
+ "@radix-ui/react-popper" "1.1.3"
+ "@radix-ui/react-portal" "1.0.4"
+ "@radix-ui/react-presence" "1.0.1"
+ "@radix-ui/react-primitive" "1.0.3"
+ "@radix-ui/react-roving-focus" "1.0.4"
+ "@radix-ui/react-slot" "1.0.2"
+ "@radix-ui/react-use-callback-ref" "1.0.1"
+ aria-hidden "^1.1.1"
+ react-remove-scroll "2.5.5"
+
+"@radix-ui/react-popper@1.1.3", "@radix-ui/react-popper@^1.1.3":
+ version "1.1.3"
+ resolved "https://registry.yarnpkg.com/@radix-ui/react-popper/-/react-popper-1.1.3.tgz#24c03f527e7ac348fabf18c89795d85d21b00b42"
+ integrity sha512-cKpopj/5RHZWjrbF2846jBNacjQVwkP068DfmgrNJXpvVWrOvlAmE9xSiy5OqeE+Gi8D9fP+oDhUnPqNMY8/5w==
+ dependencies:
+ "@babel/runtime" "^7.13.10"
+ "@floating-ui/react-dom" "^2.0.0"
+ "@radix-ui/react-arrow" "1.0.3"
+ "@radix-ui/react-compose-refs" "1.0.1"
+ "@radix-ui/react-context" "1.0.1"
+ "@radix-ui/react-primitive" "1.0.3"
+ "@radix-ui/react-use-callback-ref" "1.0.1"
+ "@radix-ui/react-use-layout-effect" "1.0.1"
+ "@radix-ui/react-use-rect" "1.0.1"
+ "@radix-ui/react-use-size" "1.0.1"
+ "@radix-ui/rect" "1.0.1"
+
+"@radix-ui/react-portal@1.0.4", "@radix-ui/react-portal@^1.0.4":
+ version "1.0.4"
+ resolved "https://registry.yarnpkg.com/@radix-ui/react-portal/-/react-portal-1.0.4.tgz#df4bfd353db3b1e84e639e9c63a5f2565fb00e15"
+ integrity sha512-Qki+C/EuGUVCQTOTD5vzJzJuMUlewbzuKyUy+/iHM2uwGiru9gZeBJtHAPKAEkB5KWGi9mP/CHKcY0wt1aW45Q==
+ dependencies:
+ "@babel/runtime" "^7.13.10"
+ "@radix-ui/react-primitive" "1.0.3"
+
+"@radix-ui/react-presence@1.0.1":
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/@radix-ui/react-presence/-/react-presence-1.0.1.tgz#491990ba913b8e2a5db1b06b203cb24b5cdef9ba"
+ integrity sha512-UXLW4UAbIY5ZjcvzjfRFo5gxva8QirC9hF7wRE4U5gz+TP0DbRk+//qyuAQ1McDxBt1xNMBTaciFGvEmJvAZCg==
+ dependencies:
+ "@babel/runtime" "^7.13.10"
+ "@radix-ui/react-compose-refs" "1.0.1"
+ "@radix-ui/react-use-layout-effect" "1.0.1"
+
+"@radix-ui/react-primitive@1.0.3", "@radix-ui/react-primitive@^1.0.3":
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/@radix-ui/react-primitive/-/react-primitive-1.0.3.tgz#d49ea0f3f0b2fe3ab1cb5667eb03e8b843b914d0"
+ integrity sha512-yi58uVyoAcK/Nq1inRY56ZSjKypBNKTa/1mcL8qdl6oJeEaDbOldlzrGn7P6Q3Id5d+SYNGc5AJgc4vGhjs5+g==
+ dependencies:
+ "@babel/runtime" "^7.13.10"
+ "@radix-ui/react-slot" "1.0.2"
+
+"@radix-ui/react-roving-focus@1.0.4":
+ version "1.0.4"
+ resolved "https://registry.yarnpkg.com/@radix-ui/react-roving-focus/-/react-roving-focus-1.0.4.tgz#e90c4a6a5f6ac09d3b8c1f5b5e81aab2f0db1974"
+ integrity sha512-2mUg5Mgcu001VkGy+FfzZyzbmuUWzgWkj3rvv4yu+mLw03+mTzbxZHvfcGyFp2b8EkQeMkpRQ5FiA2Vr2O6TeQ==
+ dependencies:
+ "@babel/runtime" "^7.13.10"
+ "@radix-ui/primitive" "1.0.1"
+ "@radix-ui/react-collection" "1.0.3"
+ "@radix-ui/react-compose-refs" "1.0.1"
+ "@radix-ui/react-context" "1.0.1"
+ "@radix-ui/react-direction" "1.0.1"
+ "@radix-ui/react-id" "1.0.1"
+ "@radix-ui/react-primitive" "1.0.3"
+ "@radix-ui/react-use-callback-ref" "1.0.1"
+ "@radix-ui/react-use-controllable-state" "1.0.1"
+
+"@radix-ui/react-separator@1.0.3":
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/@radix-ui/react-separator/-/react-separator-1.0.3.tgz#be5a931a543d5726336b112f465f58585c04c8aa"
+ integrity sha512-itYmTy/kokS21aiV5+Z56MZB54KrhPgn6eHDKkFeOLR34HMN2s8PaN47qZZAGnvupcjxHaFZnW4pQEh0BvvVuw==
+ dependencies:
+ "@babel/runtime" "^7.13.10"
+ "@radix-ui/react-primitive" "1.0.3"
+
+"@radix-ui/react-slot@1.0.2", "@radix-ui/react-slot@^1.0.2":
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/@radix-ui/react-slot/-/react-slot-1.0.2.tgz#a9ff4423eade67f501ffb32ec22064bc9d3099ab"
+ integrity sha512-YeTpuq4deV+6DusvVUW4ivBgnkHwECUu0BiN43L5UCDFgdhsRUWAghhTF5MbvNTPzmiFOx90asDSUjWuCNapwg==
+ dependencies:
+ "@babel/runtime" "^7.13.10"
+ "@radix-ui/react-compose-refs" "1.0.1"
+
+"@radix-ui/react-toggle-group@1.0.4":
+ version "1.0.4"
+ resolved "https://registry.yarnpkg.com/@radix-ui/react-toggle-group/-/react-toggle-group-1.0.4.tgz#f5b5c8c477831b013bec3580c55e20a68179d6ec"
+ integrity sha512-Uaj/M/cMyiyT9Bx6fOZO0SAG4Cls0GptBWiBmBxofmDbNVnYYoyRWj/2M/6VCi/7qcXFWnHhRUfdfZFvvkuu8A==
+ dependencies:
+ "@babel/runtime" "^7.13.10"
+ "@radix-ui/primitive" "1.0.1"
+ "@radix-ui/react-context" "1.0.1"
+ "@radix-ui/react-direction" "1.0.1"
+ "@radix-ui/react-primitive" "1.0.3"
+ "@radix-ui/react-roving-focus" "1.0.4"
+ "@radix-ui/react-toggle" "1.0.3"
+ "@radix-ui/react-use-controllable-state" "1.0.1"
+
+"@radix-ui/react-toggle@1.0.3":
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/@radix-ui/react-toggle/-/react-toggle-1.0.3.tgz#aecb2945630d1dc5c512997556c57aba894e539e"
+ integrity sha512-Pkqg3+Bc98ftZGsl60CLANXQBBQ4W3mTFS9EJvNxKMZ7magklKV69/id1mlAlOFDDfHvlCms0fx8fA4CMKDJHg==
+ dependencies:
+ "@babel/runtime" "^7.13.10"
+ "@radix-ui/primitive" "1.0.1"
+ "@radix-ui/react-primitive" "1.0.3"
+ "@radix-ui/react-use-controllable-state" "1.0.1"
+
+"@radix-ui/react-toolbar@1.0.4":
+ version "1.0.4"
+ resolved "https://registry.yarnpkg.com/@radix-ui/react-toolbar/-/react-toolbar-1.0.4.tgz#3211a105567fa016e89921b5b514877f833de559"
+ integrity sha512-tBgmM/O7a07xbaEkYJWYTXkIdU/1pW4/KZORR43toC/4XWyBCURK0ei9kMUdp+gTPPKBgYLxXmRSH1EVcIDp8Q==
+ dependencies:
+ "@babel/runtime" "^7.13.10"
+ "@radix-ui/primitive" "1.0.1"
+ "@radix-ui/react-context" "1.0.1"
+ "@radix-ui/react-direction" "1.0.1"
+ "@radix-ui/react-primitive" "1.0.3"
+ "@radix-ui/react-roving-focus" "1.0.4"
+ "@radix-ui/react-separator" "1.0.3"
+ "@radix-ui/react-toggle-group" "1.0.4"
+
+"@radix-ui/react-use-callback-ref@1.0.1", "@radix-ui/react-use-callback-ref@^1.0.1":
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.0.1.tgz#f4bb1f27f2023c984e6534317ebc411fc181107a"
+ integrity sha512-D94LjX4Sp0xJFVaoQOd3OO9k7tpBYNOXdVhkltUbGv2Qb9OXdrg/CpsjlZv7ia14Sylv398LswWBVVu5nqKzAQ==
+ dependencies:
+ "@babel/runtime" "^7.13.10"
+
+"@radix-ui/react-use-controllable-state@1.0.1", "@radix-ui/react-use-controllable-state@^1.0.1":
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.0.1.tgz#ecd2ced34e6330caf89a82854aa2f77e07440286"
+ integrity sha512-Svl5GY5FQeN758fWKrjM6Qb7asvXeiZltlT4U2gVfl8Gx5UAv2sMR0LWo8yhsIZh2oQ0eFdZ59aoOOMV7b47VA==
+ dependencies:
+ "@babel/runtime" "^7.13.10"
+ "@radix-ui/react-use-callback-ref" "1.0.1"
+
+"@radix-ui/react-use-escape-keydown@1.0.3":
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/@radix-ui/react-use-escape-keydown/-/react-use-escape-keydown-1.0.3.tgz#217b840c250541609c66f67ed7bab2b733620755"
+ integrity sha512-vyL82j40hcFicA+M4Ex7hVkB9vHgSse1ZWomAqV2Je3RleKGO5iM8KMOEtfoSB0PnIelMd2lATjTGMYqN5ylTg==
+ dependencies:
+ "@babel/runtime" "^7.13.10"
+ "@radix-ui/react-use-callback-ref" "1.0.1"
+
+"@radix-ui/react-use-layout-effect@1.0.1":
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.0.1.tgz#be8c7bc809b0c8934acf6657b577daf948a75399"
+ integrity sha512-v/5RegiJWYdoCvMnITBkNNx6bCj20fiaJnWtRkU18yITptraXjffz5Qbn05uOiQnOvi+dbkznkoaMltz1GnszQ==
+ dependencies:
+ "@babel/runtime" "^7.13.10"
+
+"@radix-ui/react-use-previous@^1.0.1":
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/@radix-ui/react-use-previous/-/react-use-previous-1.0.1.tgz#b595c087b07317a4f143696c6a01de43b0d0ec66"
+ integrity sha512-cV5La9DPwiQ7S0gf/0qiD6YgNqM5Fk97Kdrlc5yBcrF3jyEZQwm7vYFqMo4IfeHgJXsRaMvLABFtd0OVEmZhDw==
+ dependencies:
+ "@babel/runtime" "^7.13.10"
+
+"@radix-ui/react-use-rect@1.0.1":
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/@radix-ui/react-use-rect/-/react-use-rect-1.0.1.tgz#fde50b3bb9fd08f4a1cd204572e5943c244fcec2"
+ integrity sha512-Cq5DLuSiuYVKNU8orzJMbl15TXilTnJKUCltMVQg53BQOF1/C5toAaGrowkgksdBQ9H+SRL23g0HDmg9tvmxXw==
+ dependencies:
+ "@babel/runtime" "^7.13.10"
+ "@radix-ui/rect" "1.0.1"
+
+"@radix-ui/react-use-size@1.0.1":
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/@radix-ui/react-use-size/-/react-use-size-1.0.1.tgz#1c5f5fea940a7d7ade77694bb98116fb49f870b2"
+ integrity sha512-ibay+VqrgcaI6veAojjofPATwledXiSmX+C0KrBk/xgpX9rBzPV3OsfwlhQdUOFbh+LKQorLYT+xTXW9V8yd0g==
+ dependencies:
+ "@babel/runtime" "^7.13.10"
+ "@radix-ui/react-use-layout-effect" "1.0.1"
+
+"@radix-ui/react-visually-hidden@^1.0.3":
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/@radix-ui/react-visually-hidden/-/react-visually-hidden-1.0.3.tgz#51aed9dd0fe5abcad7dee2a234ad36106a6984ac"
+ integrity sha512-D4w41yN5YRKtu464TLnByKzMDG/JlMPHtfZgQAu9v6mNakUqGUI9vUrfQKz8NK41VMm/xbZbh76NUTVtIYqOMA==
+ dependencies:
+ "@babel/runtime" "^7.13.10"
+ "@radix-ui/react-primitive" "1.0.3"
+
+"@radix-ui/rect@1.0.1":
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/@radix-ui/rect/-/rect-1.0.1.tgz#bf8e7d947671996da2e30f4904ece343bc4a883f"
+ integrity sha512-fyrgCaedtvMg9NK3en0pnOYJdtfwxUcNolezkNPUsoX57X8oQk+NkqcvzHXD2uKNij6GXmWU9NDru2IWjrO4BQ==
+ dependencies:
+ "@babel/runtime" "^7.13.10"
+
+"@react-dnd/asap@4.0.1":
+ version "4.0.1"
+ resolved "https://registry.yarnpkg.com/@react-dnd/asap/-/asap-4.0.1.tgz#5291850a6b58ce6f2da25352a64f1b0674871aab"
+ integrity sha512-kLy0PJDDwvwwTXxqTFNAAllPHD73AycE9ypWeln/IguoGBEbvFcPDbCV03G52bEcC5E+YgupBE0VzHGdC8SIXg==
+
+"@react-dnd/invariant@3.0.1":
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/@react-dnd/invariant/-/invariant-3.0.1.tgz#7e70be19ea21b539e8bf1da28466f4f05df2a4cc"
+ integrity sha512-blqduwV86oiKw2Gr44wbe3pj3Z/OsXirc7ybCv9F/pLAR+Aih8F3rjeJzK0ANgtYKv5lCpkGVoZAeKitKDaD/g==
+
+"@react-dnd/shallowequal@3.0.1":
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/@react-dnd/shallowequal/-/shallowequal-3.0.1.tgz#8056fe046a8d10a275e321ec0557ae652d7a4d06"
+ integrity sha512-XjDVbs3ZU16CO1h5Q3Ew2RPJqmZBDE/EVf1LYp6ePEffs3V/MX9ZbL5bJr8qiK5SbGmUMuDoaFgyKacYz8prRA==
+
+"@reduxjs/toolkit@1.9.7":
+ version "1.9.7"
+ resolved "https://registry.yarnpkg.com/@reduxjs/toolkit/-/toolkit-1.9.7.tgz#7fc07c0b0ebec52043f8cb43510cf346405f78a6"
+ integrity sha512-t7v8ZPxhhKgOKtU+uyJT13lu4vL7az5aFi4IdoDs/eS548edn2M8Ik9h8fxgvMjGoAUVFSt6ZC1P5cWmQ014QQ==
+ dependencies:
+ immer "^9.0.21"
+ redux "^4.2.1"
+ redux-thunk "^2.4.2"
+ reselect "^4.1.8"
+
+"@rushstack/ts-command-line@^4.12.2":
+ version "4.17.1"
+ resolved "https://registry.yarnpkg.com/@rushstack/ts-command-line/-/ts-command-line-4.17.1.tgz#c78db928ce5b93f2e98fd9e14c24f3f3876e57f1"
+ integrity sha512-2jweO1O57BYP5qdBGl6apJLB+aRIn5ccIRTPDyULh0KMwVzFqWtw6IZWt1qtUoZD/pD2RNkIOosH6Cq45rIYeg==
+ dependencies:
+ "@types/argparse" "1.0.38"
+ argparse "~1.0.9"
+ colors "~1.2.1"
+ string-argv "~0.3.1"
+
+"@sendgrid/client@^7.7.0":
+ version "7.7.0"
+ resolved "https://registry.yarnpkg.com/@sendgrid/client/-/client-7.7.0.tgz#f8f67abd604205a0d0b1af091b61517ef465fdbf"
+ integrity sha512-SxH+y8jeAQSnDavrTD0uGDXYIIkFylCo+eDofVmZLQ0f862nnqbC3Vd1ej6b7Le7lboyzQF6F7Fodv02rYspuA==
+ dependencies:
+ "@sendgrid/helpers" "^7.7.0"
+ axios "^0.26.0"
+
+"@sendgrid/helpers@^7.7.0":
+ version "7.7.0"
+ resolved "https://registry.yarnpkg.com/@sendgrid/helpers/-/helpers-7.7.0.tgz#93fb4b6e2f0dc65080440d6a784cc93e8e148757"
+ integrity sha512-3AsAxfN3GDBcXoZ/y1mzAAbKzTtUZ5+ZrHOmWQ279AuaFXUNCh9bPnRpN504bgveTqoW+11IzPg3I0WVgDINpw==
+ dependencies:
+ deepmerge "^4.2.2"
+
+"@sendgrid/mail@7.7.0":
+ version "7.7.0"
+ resolved "https://registry.yarnpkg.com/@sendgrid/mail/-/mail-7.7.0.tgz#aba09f5ce2e9d8ceee92284c3ea8b4a90b0e38fe"
+ integrity sha512-5+nApPE9wINBvHSUxwOxkkQqM/IAAaBYoP9hw7WwgDNQPxraruVqHizeTitVtKGiqWCKm2mnjh4XGN3fvFLqaw==
+ dependencies:
+ "@sendgrid/client" "^7.7.0"
+ "@sendgrid/helpers" "^7.7.0"
+
+"@sentry/core@6.19.7":
+ version "6.19.7"
+ resolved "https://registry.yarnpkg.com/@sentry/core/-/core-6.19.7.tgz#156aaa56dd7fad8c89c145be6ad7a4f7209f9785"
+ integrity sha512-tOfZ/umqB2AcHPGbIrsFLcvApdTm9ggpi/kQZFkej7kMphjT+SGBiQfYtjyg9jcRW+ilAR4JXC9BGKsdEQ+8Vw==
+ dependencies:
+ "@sentry/hub" "6.19.7"
+ "@sentry/minimal" "6.19.7"
+ "@sentry/types" "6.19.7"
+ "@sentry/utils" "6.19.7"
+ tslib "^1.9.3"
+
+"@sentry/hub@6.19.7":
+ version "6.19.7"
+ resolved "https://registry.yarnpkg.com/@sentry/hub/-/hub-6.19.7.tgz#58ad7776bbd31e9596a8ec46365b45cd8b9cfd11"
+ integrity sha512-y3OtbYFAqKHCWezF0EGGr5lcyI2KbaXW2Ik7Xp8Mu9TxbSTuwTe4rTntwg8ngPjUQU3SUHzgjqVB8qjiGqFXCA==
+ dependencies:
+ "@sentry/types" "6.19.7"
+ "@sentry/utils" "6.19.7"
+ tslib "^1.9.3"
+
+"@sentry/minimal@6.19.7":
+ version "6.19.7"
+ resolved "https://registry.yarnpkg.com/@sentry/minimal/-/minimal-6.19.7.tgz#b3ee46d6abef9ef3dd4837ebcb6bdfd01b9aa7b4"
+ integrity sha512-wcYmSJOdvk6VAPx8IcmZgN08XTXRwRtB1aOLZm+MVHjIZIhHoBGZJYTVQS/BWjldsamj2cX3YGbGXNunaCfYJQ==
+ dependencies:
+ "@sentry/hub" "6.19.7"
+ "@sentry/types" "6.19.7"
+ tslib "^1.9.3"
+
+"@sentry/node@6.19.7":
+ version "6.19.7"
+ resolved "https://registry.yarnpkg.com/@sentry/node/-/node-6.19.7.tgz#32963b36b48daebbd559e6f13b1deb2415448592"
+ integrity sha512-gtmRC4dAXKODMpHXKfrkfvyBL3cI8y64vEi3fDD046uqYcrWdgoQsffuBbxMAizc6Ez1ia+f0Flue6p15Qaltg==
+ dependencies:
+ "@sentry/core" "6.19.7"
+ "@sentry/hub" "6.19.7"
+ "@sentry/types" "6.19.7"
+ "@sentry/utils" "6.19.7"
+ cookie "^0.4.1"
+ https-proxy-agent "^5.0.0"
+ lru_map "^0.3.3"
+ tslib "^1.9.3"
+
+"@sentry/types@6.19.7":
+ version "6.19.7"
+ resolved "https://registry.yarnpkg.com/@sentry/types/-/types-6.19.7.tgz#c6b337912e588083fc2896eb012526cf7cfec7c7"
+ integrity sha512-jH84pDYE+hHIbVnab3Hr+ZXr1v8QABfhx39KknxqKWr2l0oEItzepV0URvbEhB446lk/S/59230dlUUIBGsXbg==
+
+"@sentry/utils@6.19.7":
+ version "6.19.7"
+ resolved "https://registry.yarnpkg.com/@sentry/utils/-/utils-6.19.7.tgz#6edd739f8185fd71afe49cbe351c1bbf5e7b7c79"
+ integrity sha512-z95ECmE3i9pbWoXQrD/7PgkBAzJYR+iXtPuTkpBjDKs86O3mT+PXOT3BAn79w2wkn7/i3vOGD2xVr1uiMl26dA==
+ dependencies:
+ "@sentry/types" "6.19.7"
+ tslib "^1.9.3"
+
+"@simov/deep-extend@^1.0.0":
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/@simov/deep-extend/-/deep-extend-1.0.0.tgz#dff17d38305614e296eb80bf4898b9d10b061325"
+ integrity sha512-Arv8/ZPcdKAMJnNF8cks35mPq1y3JnwH1lWpfWDKlJoj+Vw2xmA4+oL7m9GVHTgdX0mGFR7bCPTBTGbxhnfJJw==
+
+"@sindresorhus/is@^4.0.0":
+ version "4.6.0"
+ resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-4.6.0.tgz#3c7c9c46e678feefe7a2e5bb609d3dbd665ffb3f"
+ integrity sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==
+
+"@sindresorhus/slugify@1.1.0":
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/@sindresorhus/slugify/-/slugify-1.1.0.tgz#2f195365d9b953384305b62664b44b4036c49430"
+ integrity sha512-ujZRbmmizX26yS/HnB3P9QNlNa4+UvHh+rIse3RbOXLp8yl6n1TxB4t7NHggtVgS8QmmOtzXo48kCxZGACpkPw==
+ dependencies:
+ "@sindresorhus/transliterate" "^0.1.1"
+ escape-string-regexp "^4.0.0"
+
+"@sindresorhus/transliterate@^0.1.1":
+ version "0.1.2"
+ resolved "https://registry.yarnpkg.com/@sindresorhus/transliterate/-/transliterate-0.1.2.tgz#ffce368271d153550e87de81486004f2637425af"
+ integrity sha512-5/kmIOY9FF32nicXH+5yLNTX4NJ4atl7jRgqAJuIn/iyDFXBktOKDxCvyGE/EzmF4ngSUvjXxQUQlQiZ5lfw+w==
+ dependencies:
+ escape-string-regexp "^2.0.0"
+ lodash.deburr "^4.1.0"
+
+"@smithy/abort-controller@^2.0.16":
+ version "2.0.16"
+ resolved "https://registry.yarnpkg.com/@smithy/abort-controller/-/abort-controller-2.0.16.tgz#31a86748e0c55a97ead1d179040160c6fc55ba1b"
+ integrity sha512-4foO7738k8kM9flMHu3VLabqu7nPgvIj8TB909S0CnKx0YZz/dcDH3pZ/4JHdatfxlZdKF1JWOYCw9+v3HVVsw==
+ dependencies:
+ "@smithy/types" "^2.8.0"
+ tslib "^2.5.0"
+
+"@smithy/chunked-blob-reader-native@^2.0.1":
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/@smithy/chunked-blob-reader-native/-/chunked-blob-reader-native-2.0.1.tgz#0599eaed8c2cd15c7ab43a1838cef1258ff27133"
+ integrity sha512-N2oCZRglhWKm7iMBu7S6wDzXirjAofi7tAd26cxmgibRYOBS4D3hGfmkwCpHdASZzwZDD8rluh0Rcqw1JeZDRw==
+ dependencies:
+ "@smithy/util-base64" "^2.0.1"
+ tslib "^2.5.0"
+
+"@smithy/chunked-blob-reader@^2.0.0":
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/@smithy/chunked-blob-reader/-/chunked-blob-reader-2.0.0.tgz#c44fe2c780eaf77f9e5381d982ac99a880cce51b"
+ integrity sha512-k+J4GHJsMSAIQPChGBrjEmGS+WbPonCXesoqP9fynIqjn7rdOThdH8FAeCmokP9mxTYKQAKoHCLPzNlm6gh7Wg==
+ dependencies:
+ tslib "^2.5.0"
+
+"@smithy/config-resolver@^2.0.23":
+ version "2.0.23"
+ resolved "https://registry.yarnpkg.com/@smithy/config-resolver/-/config-resolver-2.0.23.tgz#45496bea277c00d52efcdf88a5f483b3d6a7e62d"
+ integrity sha512-XakUqgtP2YY8Mi+Nlif5BiqJgWdvfxJafSpOSQeCOMizu+PUhE4fBQSy6xFcR+eInrwVadaABNxoJyGUMn15ew==
+ dependencies:
+ "@smithy/node-config-provider" "^2.1.9"
+ "@smithy/types" "^2.8.0"
+ "@smithy/util-config-provider" "^2.1.0"
+ "@smithy/util-middleware" "^2.0.9"
+ tslib "^2.5.0"
+
+"@smithy/core@^1.2.2":
+ version "1.2.2"
+ resolved "https://registry.yarnpkg.com/@smithy/core/-/core-1.2.2.tgz#9e10d6055f2a05c2c677737b9b0c4f7507a80c75"
+ integrity sha512-uLjrskLT+mWb0emTR5QaiAIxVEU7ndpptDaVDrTwwhD+RjvHhjIiGQ3YL5jKk1a5VSDQUA2RGkXvJ6XKRcz6Dg==
+ dependencies:
+ "@smithy/middleware-endpoint" "^2.3.0"
+ "@smithy/middleware-retry" "^2.0.26"
+ "@smithy/middleware-serde" "^2.0.16"
+ "@smithy/protocol-http" "^3.0.12"
+ "@smithy/smithy-client" "^2.2.1"
+ "@smithy/types" "^2.8.0"
+ "@smithy/util-middleware" "^2.0.9"
+ tslib "^2.5.0"
+
+"@smithy/credential-provider-imds@^2.0.0", "@smithy/credential-provider-imds@^2.1.5":
+ version "2.1.5"
+ resolved "https://registry.yarnpkg.com/@smithy/credential-provider-imds/-/credential-provider-imds-2.1.5.tgz#18e238067c0d9c5598a12fabb13ce1545554e691"
+ integrity sha512-VfvE6Wg1MUWwpTZFBnUD7zxvPhLY8jlHCzu6bCjlIYoWgXCDzZAML76IlZUEf45nib3rjehnFgg0s1rgsuN/bg==
+ dependencies:
+ "@smithy/node-config-provider" "^2.1.9"
+ "@smithy/property-provider" "^2.0.17"
+ "@smithy/types" "^2.8.0"
+ "@smithy/url-parser" "^2.0.16"
+ tslib "^2.5.0"
+
+"@smithy/eventstream-codec@^2.0.16":
+ version "2.0.16"
+ resolved "https://registry.yarnpkg.com/@smithy/eventstream-codec/-/eventstream-codec-2.0.16.tgz#c213e25d7f05f1e6b40675835a141d23d3f3b6ca"
+ integrity sha512-umYh5pdCE9GHgiMAH49zu9wXWZKNHHdKPm/lK22WYISTjqu29SepmpWNmPiBLy/yUu4HFEGJHIFrDWhbDlApaw==
+ dependencies:
+ "@aws-crypto/crc32" "3.0.0"
+ "@smithy/types" "^2.8.0"
+ "@smithy/util-hex-encoding" "^2.0.0"
+ tslib "^2.5.0"
+
+"@smithy/eventstream-serde-browser@^2.0.16":
+ version "2.0.16"
+ resolved "https://registry.yarnpkg.com/@smithy/eventstream-serde-browser/-/eventstream-serde-browser-2.0.16.tgz#f265c3605a861d7f4feaa8657f475c8da7c9f45e"
+ integrity sha512-W+BdiN728R57KuZOcG0GczpIOEFf8S5RP/OdVH7T3FMCy8HU2bBU0vB5xZZR5c00VRdoeWrohNv3XlHoZuGRoA==
+ dependencies:
+ "@smithy/eventstream-serde-universal" "^2.0.16"
+ "@smithy/types" "^2.8.0"
+ tslib "^2.5.0"
+
+"@smithy/eventstream-serde-config-resolver@^2.0.16":
+ version "2.0.16"
+ resolved "https://registry.yarnpkg.com/@smithy/eventstream-serde-config-resolver/-/eventstream-serde-config-resolver-2.0.16.tgz#0a6fd6312605de6f0505d3fdec4235f7c4388413"
+ integrity sha512-8qrE4nh+Tg6m1SMFK8vlzoK+8bUFTlIhXidmmQfASMninXW3Iu0T0bI4YcIk4nLznHZdybQ0qGydIanvVZxzVg==
+ dependencies:
+ "@smithy/types" "^2.8.0"
+ tslib "^2.5.0"
+
+"@smithy/eventstream-serde-node@^2.0.16":
+ version "2.0.16"
+ resolved "https://registry.yarnpkg.com/@smithy/eventstream-serde-node/-/eventstream-serde-node-2.0.16.tgz#24bca6ab0dbf7d81b42bc3435db42e36385c7480"
+ integrity sha512-NRNQuOa6mQdFSkqzY0IV37swHWx0SEoKxFtUfdZvfv0AVQPlSw4N7E3kcRSCpnHBr1kCuWWirdDlWcjWuD81MA==
+ dependencies:
+ "@smithy/eventstream-serde-universal" "^2.0.16"
+ "@smithy/types" "^2.8.0"
+ tslib "^2.5.0"
+
+"@smithy/eventstream-serde-universal@^2.0.16":
+ version "2.0.16"
+ resolved "https://registry.yarnpkg.com/@smithy/eventstream-serde-universal/-/eventstream-serde-universal-2.0.16.tgz#e554aa59d0c3bdd6f8b9eae9b2e3d6c6ae702611"
+ integrity sha512-ZyLnGaYQMLc75j9kKEVMJ3X6bdBE9qWxhZdTXM5RIltuytxJC3FaOhawBxjE+IL1enmWSIohHGZCm/pLwEliQA==
+ dependencies:
+ "@smithy/eventstream-codec" "^2.0.16"
+ "@smithy/types" "^2.8.0"
+ tslib "^2.5.0"
+
+"@smithy/fetch-http-handler@^2.3.2":
+ version "2.3.2"
+ resolved "https://registry.yarnpkg.com/@smithy/fetch-http-handler/-/fetch-http-handler-2.3.2.tgz#930ee473b2a43d0bcf62c3b659f38122442ad514"
+ integrity sha512-O9R/OlnAOTsnysuSDjt0v2q6DcSvCz5cCFC/CFAWWcLyBwJDeFyGTCTszgpQTb19+Fi8uRwZE5/3ziAQBFeDMQ==
+ dependencies:
+ "@smithy/protocol-http" "^3.0.12"
+ "@smithy/querystring-builder" "^2.0.16"
+ "@smithy/types" "^2.8.0"
+ "@smithy/util-base64" "^2.0.1"
+ tslib "^2.5.0"
+
+"@smithy/hash-blob-browser@^2.0.17":
+ version "2.0.17"
+ resolved "https://registry.yarnpkg.com/@smithy/hash-blob-browser/-/hash-blob-browser-2.0.17.tgz#4249f1fba27cb7c40dbf1fa38a31e61dbf9149b9"
+ integrity sha512-/mPpv1sRiRDdjO4zZuO8be6eeabmg5AVgKDfnmmqkpBtRyMGSJb968fjRuHt+FRAsIGywgIKJFmUUAYjhsi1oQ==
+ dependencies:
+ "@smithy/chunked-blob-reader" "^2.0.0"
+ "@smithy/chunked-blob-reader-native" "^2.0.1"
+ "@smithy/types" "^2.8.0"
+ tslib "^2.5.0"
+
+"@smithy/hash-node@^2.0.18":
+ version "2.0.18"
+ resolved "https://registry.yarnpkg.com/@smithy/hash-node/-/hash-node-2.0.18.tgz#4bf4ec392b5d6715426338b6828e6b25cd939bd5"
+ integrity sha512-gN2JFvAgnZCyDN9rJgcejfpK0uPPJrSortVVVVWsru9whS7eQey6+gj2eM5ln2i6rHNntIXzal1Fm9XOPuoaKA==
+ dependencies:
+ "@smithy/types" "^2.8.0"
+ "@smithy/util-buffer-from" "^2.0.0"
+ "@smithy/util-utf8" "^2.0.2"
+ tslib "^2.5.0"
+
+"@smithy/hash-stream-node@^2.0.18":
+ version "2.0.18"
+ resolved "https://registry.yarnpkg.com/@smithy/hash-stream-node/-/hash-stream-node-2.0.18.tgz#6f7b214e785b8cf445e5095f9a9b9b38e689e7ce"
+ integrity sha512-OuFk+ITpv8CtxGjQcS8GA04faNycu9UMm6YobvQzjeEoXZ0dLF6sRfuzD+3S8RHPKpTyLuXtKG1+GiJycZ5TcA==
+ dependencies:
+ "@smithy/types" "^2.8.0"
+ "@smithy/util-utf8" "^2.0.2"
+ tslib "^2.5.0"
+
+"@smithy/invalid-dependency@^2.0.16":
+ version "2.0.16"
+ resolved "https://registry.yarnpkg.com/@smithy/invalid-dependency/-/invalid-dependency-2.0.16.tgz#b32a6284ef4ce48129d00a6d63f977ec3e05befb"
+ integrity sha512-apEHakT/kmpNo1VFHP4W/cjfeP9U0x5qvfsLJubgp7UM/gq4qYp0GbqdE7QhsjUaYvEnrftRqs7+YrtWreV0wA==
+ dependencies:
+ "@smithy/types" "^2.8.0"
+ tslib "^2.5.0"
+
+"@smithy/is-array-buffer@^2.0.0":
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/@smithy/is-array-buffer/-/is-array-buffer-2.0.0.tgz#8fa9b8040651e7ba0b2f6106e636a91354ff7d34"
+ integrity sha512-z3PjFjMyZNI98JFRJi/U0nGoLWMSJlDjAW4QUX2WNZLas5C0CmVV6LJ01JI0k90l7FvpmixjWxPFmENSClQ7ug==
+ dependencies:
+ tslib "^2.5.0"
+
+"@smithy/md5-js@^2.0.18":
+ version "2.0.18"
+ resolved "https://registry.yarnpkg.com/@smithy/md5-js/-/md5-js-2.0.18.tgz#85f26fc83e75b440144341292cbb75ddf69dd0de"
+ integrity sha512-bHwZ8/m6RbERQdVW5rJ2LzeW8qxfXv6Q/S7Fiudhso4pWRrksqLx3nsGZw7bmqqfN4zLqkxydxSa9+4c7s5zxg==
+ dependencies:
+ "@smithy/types" "^2.8.0"
+ "@smithy/util-utf8" "^2.0.2"
+ tslib "^2.5.0"
+
+"@smithy/middleware-content-length@^2.0.18":
+ version "2.0.18"
+ resolved "https://registry.yarnpkg.com/@smithy/middleware-content-length/-/middleware-content-length-2.0.18.tgz#a3b13beb300290f5d0d48ace0f818e44261356fa"
+ integrity sha512-ZJ9uKPTfxYheTKSKYB+GCvcj+izw9WGzRLhjn8n254q0jWLojUzn7Vw0l4R/Gq7Wdpf/qmk/ptD+6CCXHNVCaw==
+ dependencies:
+ "@smithy/protocol-http" "^3.0.12"
+ "@smithy/types" "^2.8.0"
+ tslib "^2.5.0"
+
+"@smithy/middleware-endpoint@^2.3.0":
+ version "2.3.0"
+ resolved "https://registry.yarnpkg.com/@smithy/middleware-endpoint/-/middleware-endpoint-2.3.0.tgz#135c30f38087ba52e692a73212854d0809ce1168"
+ integrity sha512-VsOAG2YQ8ykjSmKO+CIXdJBIWFo6AAvG6Iw95BakBTqk66/4BI7XyqLevoNSq/lZ6NgZv24sLmrcIN+fLDWBCg==
+ dependencies:
+ "@smithy/middleware-serde" "^2.0.16"
+ "@smithy/node-config-provider" "^2.1.9"
+ "@smithy/shared-ini-file-loader" "^2.2.8"
+ "@smithy/types" "^2.8.0"
+ "@smithy/url-parser" "^2.0.16"
+ "@smithy/util-middleware" "^2.0.9"
+ tslib "^2.5.0"
+
+"@smithy/middleware-retry@^2.0.26":
+ version "2.0.26"
+ resolved "https://registry.yarnpkg.com/@smithy/middleware-retry/-/middleware-retry-2.0.26.tgz#894cf86b0f5bc742e09c52df8df4c2941fbd9883"
+ integrity sha512-Qzpxo0U5jfNiq9iD38U3e2bheXwvTEX4eue9xruIvEgh+UKq6dKuGqcB66oBDV7TD/mfoJi9Q/VmaiqwWbEp7A==
+ dependencies:
+ "@smithy/node-config-provider" "^2.1.9"
+ "@smithy/protocol-http" "^3.0.12"
+ "@smithy/service-error-classification" "^2.0.9"
+ "@smithy/smithy-client" "^2.2.1"
+ "@smithy/types" "^2.8.0"
+ "@smithy/util-middleware" "^2.0.9"
+ "@smithy/util-retry" "^2.0.9"
+ tslib "^2.5.0"
+ uuid "^8.3.2"
+
+"@smithy/middleware-serde@^2.0.16":
+ version "2.0.16"
+ resolved "https://registry.yarnpkg.com/@smithy/middleware-serde/-/middleware-serde-2.0.16.tgz#a127e7fa48c0106bd7a81e1ea27e7193cb08e701"
+ integrity sha512-5EAd4t30pcc4M8TSSGq7q/x5IKrxfXR5+SrU4bgxNy7RPHQo2PSWBUco9C+D9Tfqp/JZvprRpK42dnupZafk2g==
+ dependencies:
+ "@smithy/types" "^2.8.0"
+ tslib "^2.5.0"
+
+"@smithy/middleware-stack@^2.0.10":
+ version "2.0.10"
+ resolved "https://registry.yarnpkg.com/@smithy/middleware-stack/-/middleware-stack-2.0.10.tgz#fb7c660dcc921b61a77e6cb39ed3eada9ed38585"
+ integrity sha512-I2rbxctNq9FAPPEcuA1ntZxkTKOPQFy7YBPOaD/MLg1zCvzv21CoNxR0py6J8ZVC35l4qE4nhxB0f7TF5/+Ldw==
+ dependencies:
+ "@smithy/types" "^2.8.0"
+ tslib "^2.5.0"
+
+"@smithy/node-config-provider@^2.1.9":
+ version "2.1.9"
+ resolved "https://registry.yarnpkg.com/@smithy/node-config-provider/-/node-config-provider-2.1.9.tgz#2e9e5ee7c4412be6696a74b26f9ed2a66e2a5fb4"
+ integrity sha512-tUyW/9xrRy+s7RXkmQhgYkAPMpTIF8izK4orhHjNFEKR3QZiOCbWB546Y8iB/Fpbm3O9+q0Af9rpywLKJOwtaQ==
+ dependencies:
+ "@smithy/property-provider" "^2.0.17"
+ "@smithy/shared-ini-file-loader" "^2.2.8"
+ "@smithy/types" "^2.8.0"
+ tslib "^2.5.0"
+
+"@smithy/node-http-handler@^2.2.2":
+ version "2.2.2"
+ resolved "https://registry.yarnpkg.com/@smithy/node-http-handler/-/node-http-handler-2.2.2.tgz#f9f8cd49f270bc50a0de8a4587bbdaae1c7c4e80"
+ integrity sha512-XO58TO/Eul/IBQKFKaaBtXJi0ItEQQCT+NI4IiKHCY/4KtqaUT6y/wC1EvDqlA9cP7Dyjdj7FdPs4DyynH3u7g==
+ dependencies:
+ "@smithy/abort-controller" "^2.0.16"
+ "@smithy/protocol-http" "^3.0.12"
+ "@smithy/querystring-builder" "^2.0.16"
+ "@smithy/types" "^2.8.0"
+ tslib "^2.5.0"
+
+"@smithy/property-provider@^2.0.0", "@smithy/property-provider@^2.0.17":
+ version "2.0.17"
+ resolved "https://registry.yarnpkg.com/@smithy/property-provider/-/property-provider-2.0.17.tgz#288475021613649811dc79a9fab4894be01cd069"
+ integrity sha512-+VkeZbVu7qtQ2DjI48Qwaf9fPOr3gZIwxQpuLJgRRSkWsdSvmaTCxI3gzRFKePB63Ts9r4yjn4HkxSCSkdWmcQ==
+ dependencies:
+ "@smithy/types" "^2.8.0"
+ tslib "^2.5.0"
+
+"@smithy/protocol-http@^3.0.12":
+ version "3.0.12"
+ resolved "https://registry.yarnpkg.com/@smithy/protocol-http/-/protocol-http-3.0.12.tgz#9f606efd191593f6dbde58fa822465b92b8afbca"
+ integrity sha512-Xz4iaqLiaBfbQpB9Hgi3VcZYbP7xRDXYhd8XWChh4v94uw7qwmvlxdU5yxzfm6ACJM66phHrTbS5TVvj5uQ72w==
+ dependencies:
+ "@smithy/types" "^2.8.0"
+ tslib "^2.5.0"
+
+"@smithy/querystring-builder@^2.0.16":
+ version "2.0.16"
+ resolved "https://registry.yarnpkg.com/@smithy/querystring-builder/-/querystring-builder-2.0.16.tgz#1a9a02b1fb938688cdab5e585cb7c62c8054bc41"
+ integrity sha512-Q/GsJT0C0mijXMRs7YhZLLCP5FcuC4797lYjKQkME5CZohnLC4bEhylAd2QcD3gbMKNjCw8+T2I27WKiV/wToA==
+ dependencies:
+ "@smithy/types" "^2.8.0"
+ "@smithy/util-uri-escape" "^2.0.0"
+ tslib "^2.5.0"
+
+"@smithy/querystring-parser@^2.0.16":
+ version "2.0.16"
+ resolved "https://registry.yarnpkg.com/@smithy/querystring-parser/-/querystring-parser-2.0.16.tgz#90d9589539ffe8fb4864c8bf6f1f1c9def962a40"
+ integrity sha512-c4ueAuL6BDYKWpkubjrQthZKoC3L5kql5O++ovekNxiexRXTlLIVlCR4q3KziOktLIw66EU9SQljPXd/oN6Okg==
+ dependencies:
+ "@smithy/types" "^2.8.0"
+ tslib "^2.5.0"
+
+"@smithy/service-error-classification@^2.0.9":
+ version "2.0.9"
+ resolved "https://registry.yarnpkg.com/@smithy/service-error-classification/-/service-error-classification-2.0.9.tgz#4459433f6727f1b7e953a9bab189672b3b157224"
+ integrity sha512-0K+8GvtwI7VkGmmInPydM2XZyBfIqLIbfR7mDQ+oPiz8mIinuHbV6sxOLdvX1Jv/myk7XTK9orgt3tuEpBu/zg==
+ dependencies:
+ "@smithy/types" "^2.8.0"
+
+"@smithy/shared-ini-file-loader@^2.0.6", "@smithy/shared-ini-file-loader@^2.2.8":
+ version "2.2.8"
+ resolved "https://registry.yarnpkg.com/@smithy/shared-ini-file-loader/-/shared-ini-file-loader-2.2.8.tgz#b5fa153d4920a3c740215c60ad1667972d67a164"
+ integrity sha512-E62byatbwSWrtq9RJ7xN40tqrRKDGrEL4EluyNpaIDvfvet06a/QC58oHw2FgVaEgkj0tXZPjZaKrhPfpoU0qw==
+ dependencies:
+ "@smithy/types" "^2.8.0"
+ tslib "^2.5.0"
+
+"@smithy/signature-v4@^2.0.0":
+ version "2.0.19"
+ resolved "https://registry.yarnpkg.com/@smithy/signature-v4/-/signature-v4-2.0.19.tgz#2b926fc00b2e61ec586289fe28927e10766a3afd"
+ integrity sha512-nwc3JihdM+kcJjtORv/n7qRHN2Kfh7S2RJI2qr8pz9UcY5TD8rSCRGQ0g81HgyS3jZ5X9U/L4p014P3FonBPhg==
+ dependencies:
+ "@smithy/eventstream-codec" "^2.0.16"
+ "@smithy/is-array-buffer" "^2.0.0"
+ "@smithy/types" "^2.8.0"
+ "@smithy/util-hex-encoding" "^2.0.0"
+ "@smithy/util-middleware" "^2.0.9"
+ "@smithy/util-uri-escape" "^2.0.0"
+ "@smithy/util-utf8" "^2.0.2"
+ tslib "^2.5.0"
+
+"@smithy/smithy-client@^2.2.1":
+ version "2.2.1"
+ resolved "https://registry.yarnpkg.com/@smithy/smithy-client/-/smithy-client-2.2.1.tgz#ed1aa11f36dae2ca9b3eabcbc498bcc96d79fdfd"
+ integrity sha512-SpD7FLK92XV2fon2hMotaNDa2w5VAy5/uVjP9WFmjGSgWM8pTPVkHcDl1yFs5Z8LYbij0FSz+DbCBK6i+uXXUA==
+ dependencies:
+ "@smithy/middleware-endpoint" "^2.3.0"
+ "@smithy/middleware-stack" "^2.0.10"
+ "@smithy/protocol-http" "^3.0.12"
+ "@smithy/types" "^2.8.0"
+ "@smithy/util-stream" "^2.0.24"
+ tslib "^2.5.0"
+
+"@smithy/types@^2.8.0":
+ version "2.8.0"
+ resolved "https://registry.yarnpkg.com/@smithy/types/-/types-2.8.0.tgz#bdbaa0a54c9c3538d6c763c6f32d3e4f76fe0df9"
+ integrity sha512-h9sz24cFgt/W1Re22OlhQKmUZkNh244ApgRsUDYinqF8R+QgcsBIX344u2j61TPshsTz3CvL6HYU1DnQdsSrHA==
+ dependencies:
+ tslib "^2.5.0"
+
+"@smithy/url-parser@^2.0.16":
+ version "2.0.16"
+ resolved "https://registry.yarnpkg.com/@smithy/url-parser/-/url-parser-2.0.16.tgz#25f860effe465acbbe61beb69b6def052878ee58"
+ integrity sha512-Wfz5WqAoRT91TjRy1JeLR0fXtkIXHGsMbgzKFTx7E68SrZ55TB8xoG+vm11Ru4gheFTMXjAjwAxv1jQdC+pAQA==
+ dependencies:
+ "@smithy/querystring-parser" "^2.0.16"
+ "@smithy/types" "^2.8.0"
+ tslib "^2.5.0"
+
+"@smithy/util-base64@^2.0.1":
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/@smithy/util-base64/-/util-base64-2.0.1.tgz#57f782dafc187eddea7c8a1ff2a7c188ed1a02c4"
+ integrity sha512-DlI6XFYDMsIVN+GH9JtcRp3j02JEVuWIn/QOZisVzpIAprdsxGveFed0bjbMRCqmIFe8uetn5rxzNrBtIGrPIQ==
+ dependencies:
+ "@smithy/util-buffer-from" "^2.0.0"
+ tslib "^2.5.0"
+
+"@smithy/util-body-length-browser@^2.0.1":
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/@smithy/util-body-length-browser/-/util-body-length-browser-2.0.1.tgz#424485cc81c640d18c17c683e0e6edb57e8e2ab9"
+ integrity sha512-NXYp3ttgUlwkaug4bjBzJ5+yIbUbUx8VsSLuHZROQpoik+gRkIBeEG9MPVYfvPNpuXb/puqodeeUXcKFe7BLOQ==
+ dependencies:
+ tslib "^2.5.0"
+
+"@smithy/util-body-length-node@^2.1.0":
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/@smithy/util-body-length-node/-/util-body-length-node-2.1.0.tgz#313a5f7c5017947baf5fa018bfc22628904bbcfa"
+ integrity sha512-/li0/kj/y3fQ3vyzn36NTLGmUwAICb7Jbe/CsWCktW363gh1MOcpEcSO3mJ344Gv2dqz8YJCLQpb6hju/0qOWw==
+ dependencies:
+ tslib "^2.5.0"
+
+"@smithy/util-buffer-from@^2.0.0":
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/@smithy/util-buffer-from/-/util-buffer-from-2.0.0.tgz#7eb75d72288b6b3001bc5f75b48b711513091deb"
+ integrity sha512-/YNnLoHsR+4W4Vf2wL5lGv0ksg8Bmk3GEGxn2vEQt52AQaPSCuaO5PM5VM7lP1K9qHRKHwrPGktqVoAHKWHxzw==
+ dependencies:
+ "@smithy/is-array-buffer" "^2.0.0"
+ tslib "^2.5.0"
+
+"@smithy/util-config-provider@^2.1.0":
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/@smithy/util-config-provider/-/util-config-provider-2.1.0.tgz#c733a862892772aaeb373a3e8af5182556da0ef9"
+ integrity sha512-S6V0JvvhQgFSGLcJeT1CBsaTR03MM8qTuxMH9WPCCddlSo2W0V5jIHimHtIQALMLEDPGQ0ROSRr/dU0O+mxiQg==
+ dependencies:
+ tslib "^2.5.0"
+
+"@smithy/util-defaults-mode-browser@^2.0.24":
+ version "2.0.24"
+ resolved "https://registry.yarnpkg.com/@smithy/util-defaults-mode-browser/-/util-defaults-mode-browser-2.0.24.tgz#bfa8fa441db0d0d309c11d091ca9746f2b8e4797"
+ integrity sha512-TsP5mBuLgO2C21+laNG2nHYZEyUdkbGURv2tHvSuQQxLz952MegX95uwdxOY2jR2H4GoKuVRfdJq7w4eIjGYeg==
+ dependencies:
+ "@smithy/property-provider" "^2.0.17"
+ "@smithy/smithy-client" "^2.2.1"
+ "@smithy/types" "^2.8.0"
+ bowser "^2.11.0"
+ tslib "^2.5.0"
+
+"@smithy/util-defaults-mode-node@^2.0.32":
+ version "2.0.32"
+ resolved "https://registry.yarnpkg.com/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-2.0.32.tgz#a0665ef2feed845de7825059072e312e22393698"
+ integrity sha512-d0S33dXA2cq1NyorVMroMrEtqKMr3MlyLITcfTBf9pXiigYiPMOtbSI7czHIfDbuVuM89Cg0urAgpt73QV9mPQ==
+ dependencies:
+ "@smithy/config-resolver" "^2.0.23"
+ "@smithy/credential-provider-imds" "^2.1.5"
+ "@smithy/node-config-provider" "^2.1.9"
+ "@smithy/property-provider" "^2.0.17"
+ "@smithy/smithy-client" "^2.2.1"
+ "@smithy/types" "^2.8.0"
+ tslib "^2.5.0"
+
+"@smithy/util-endpoints@^1.0.8":
+ version "1.0.8"
+ resolved "https://registry.yarnpkg.com/@smithy/util-endpoints/-/util-endpoints-1.0.8.tgz#10ec9b228e96fc67b42ed06dabdab118a5869532"
+ integrity sha512-l8zVuyZZ61IzZBYp5NWvsAhbaAjYkt0xg9R4xUASkg5SEeTT2meHOJwJHctKMFUXe4QZbn9fR2MaBYjP2119+w==
+ dependencies:
+ "@smithy/node-config-provider" "^2.1.9"
+ "@smithy/types" "^2.8.0"
+ tslib "^2.5.0"
+
+"@smithy/util-hex-encoding@^2.0.0":
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/@smithy/util-hex-encoding/-/util-hex-encoding-2.0.0.tgz#0aa3515acd2b005c6d55675e377080a7c513b59e"
+ integrity sha512-c5xY+NUnFqG6d7HFh1IFfrm3mGl29lC+vF+geHv4ToiuJCBmIfzx6IeHLg+OgRdPFKDXIw6pvi+p3CsscaMcMA==
+ dependencies:
+ tslib "^2.5.0"
+
+"@smithy/util-middleware@^2.0.9":
+ version "2.0.9"
+ resolved "https://registry.yarnpkg.com/@smithy/util-middleware/-/util-middleware-2.0.9.tgz#54a372fa723ace66046cdf91439fb1648a246d5c"
+ integrity sha512-PnCnBJ07noMX1lMDTEefmxSlusWJUiLfrme++MfK5TD0xz8NYmakgoXy5zkF/16zKGmiwOeKAztWT/Vjk1KRIQ==
+ dependencies:
+ "@smithy/types" "^2.8.0"
+ tslib "^2.5.0"
+
+"@smithy/util-retry@^2.0.9":
+ version "2.0.9"
+ resolved "https://registry.yarnpkg.com/@smithy/util-retry/-/util-retry-2.0.9.tgz#ef6d6e41bcc5df330b76cca913d5e637c70497fc"
+ integrity sha512-46BFWe9RqB6g7f4mxm3W3HlqknqQQmWHKlhoqSFZuGNuiDU5KqmpebMbvC3tjTlUkqn4xa2Z7s3Hwb0HNs5scw==
+ dependencies:
+ "@smithy/service-error-classification" "^2.0.9"
+ "@smithy/types" "^2.8.0"
+ tslib "^2.5.0"
+
+"@smithy/util-stream@^2.0.24":
+ version "2.0.24"
+ resolved "https://registry.yarnpkg.com/@smithy/util-stream/-/util-stream-2.0.24.tgz#fa896c8df828ce7758963b758c1f374407d812be"
+ integrity sha512-hRpbcRrOxDriMVmbya+Mv77VZVupxRAsfxVDKS54XuiURhdiwCUXJP0X1iJhHinuUf6n8pBF0MkG9C8VooMnWw==
+ dependencies:
+ "@smithy/fetch-http-handler" "^2.3.2"
+ "@smithy/node-http-handler" "^2.2.2"
+ "@smithy/types" "^2.8.0"
+ "@smithy/util-base64" "^2.0.1"
+ "@smithy/util-buffer-from" "^2.0.0"
+ "@smithy/util-hex-encoding" "^2.0.0"
+ "@smithy/util-utf8" "^2.0.2"
+ tslib "^2.5.0"
+
+"@smithy/util-uri-escape@^2.0.0":
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/@smithy/util-uri-escape/-/util-uri-escape-2.0.0.tgz#19955b1a0f517a87ae77ac729e0e411963dfda95"
+ integrity sha512-ebkxsqinSdEooQduuk9CbKcI+wheijxEb3utGXkCoYQkJnwTnLbH1JXGimJtUkQwNQbsbuYwG2+aFVyZf5TLaw==
+ dependencies:
+ tslib "^2.5.0"
+
+"@smithy/util-utf8@^2.0.2":
+ version "2.0.2"
+ resolved "https://registry.yarnpkg.com/@smithy/util-utf8/-/util-utf8-2.0.2.tgz#626b3e173ad137208e27ed329d6bea70f4a1a7f7"
+ integrity sha512-qOiVORSPm6Ce4/Yu6hbSgNHABLP2VMv8QOC3tTDNHHlWY19pPyc++fBTbZPtx6egPXi4HQxKDnMxVxpbtX2GoA==
+ dependencies:
+ "@smithy/util-buffer-from" "^2.0.0"
+ tslib "^2.5.0"
+
+"@smithy/util-waiter@^2.0.16":
+ version "2.0.16"
+ resolved "https://registry.yarnpkg.com/@smithy/util-waiter/-/util-waiter-2.0.16.tgz#3065566dd81951e24d843979ed1e6278794a955c"
+ integrity sha512-5i4YONHQ6HoUWDd+X0frpxTXxSXgJhUFl+z0iMy/zpUmVeCQY2or3Vss6DzHKKMMQL4pmVHpQm9WayHDorFdZg==
+ dependencies:
+ "@smithy/abort-controller" "^2.0.16"
+ "@smithy/types" "^2.8.0"
+ tslib "^2.5.0"
+
+"@strapi/admin@4.17.0":
+ version "4.17.0"
+ resolved "https://registry.yarnpkg.com/@strapi/admin/-/admin-4.17.0.tgz#17a817eb21778bfebb66ada554e758e250e4d824"
+ integrity sha512-tslug6rrrWOqlOe9QONRCfPyL62WIeHWIvsSKWaY3Bt+vJQYaWjgC6OA53sb2go0TRXT1wr6+/p86tMv9zppDw==
+ dependencies:
+ "@casl/ability" "6.5.0"
+ "@pmmmwh/react-refresh-webpack-plugin" "0.5.10"
+ "@radix-ui/react-context" "1.0.1"
+ "@radix-ui/react-toolbar" "1.0.4"
+ "@reduxjs/toolkit" "1.9.7"
+ "@strapi/data-transfer" "4.17.0"
+ "@strapi/design-system" "1.14.1"
+ "@strapi/helper-plugin" "4.17.0"
+ "@strapi/icons" "1.14.1"
+ "@strapi/permissions" "4.17.0"
+ "@strapi/provider-audit-logs-local" "4.17.0"
+ "@strapi/types" "4.17.0"
+ "@strapi/typescript-utils" "4.17.0"
+ "@strapi/utils" "4.17.0"
+ axios "1.6.0"
+ bcryptjs "2.4.3"
+ boxen "5.1.2"
+ browserslist "^4.22.1"
+ browserslist-to-esbuild "1.2.0"
+ chalk "^4.1.2"
+ chokidar "3.5.3"
+ codemirror5 "npm:codemirror@^5.65.11"
+ cross-env "^7.0.3"
+ css-loader "^6.8.1"
+ date-fns "2.30.0"
+ dotenv "14.2.0"
+ esbuild "0.19.2"
+ esbuild-loader "^2.21.0"
+ esbuild-register "3.5.0"
+ execa "5.1.1"
+ fast-deep-equal "3.1.3"
+ find-root "1.1.0"
+ fork-ts-checker-webpack-plugin "8.0.0"
+ formik "2.4.0"
+ fractional-indexing "3.2.0"
+ fs-extra "10.0.0"
+ highlight.js "^10.4.1"
+ history "^4.9.0"
+ html-webpack-plugin "5.5.0"
+ immer "9.0.19"
+ inquirer "8.2.5"
+ invariant "^2.2.4"
+ js-cookie "2.2.1"
+ jsonwebtoken "9.0.0"
+ koa "2.13.4"
+ koa-bodyparser "4.4.1"
+ koa-compose "4.1.0"
+ koa-passport "5.0.0"
+ koa-static "5.0.0"
+ koa2-ratelimit "^1.1.2"
+ lodash "4.17.21"
+ markdown-it "^12.3.2"
+ markdown-it-abbr "^1.0.4"
+ markdown-it-container "^3.0.0"
+ markdown-it-deflist "^2.1.0"
+ markdown-it-emoji "^2.0.0"
+ markdown-it-footnote "^3.0.3"
+ markdown-it-ins "^3.0.1"
+ markdown-it-mark "^3.0.1"
+ markdown-it-sub "^1.0.0"
+ markdown-it-sup "1.0.0"
+ mini-css-extract-plugin "2.7.6"
+ node-schedule "2.1.0"
+ ora "5.4.1"
+ outdent "0.8.0"
+ p-map "4.0.0"
+ passport-local "1.0.0"
+ pluralize "8.0.0"
+ prettier "2.8.4"
+ prop-types "^15.8.1"
+ qs "6.11.1"
+ react "^18.2.0"
+ react-dnd "15.1.2"
+ react-dnd-html5-backend "15.1.3"
+ react-dom "^18.2.0"
+ react-error-boundary "3.1.4"
+ react-helmet "^6.1.0"
+ react-intl "6.4.1"
+ react-is "^18.2.0"
+ react-query "3.39.3"
+ react-redux "8.1.1"
+ react-refresh "0.14.0"
+ react-router-dom "5.3.4"
+ react-select "5.7.0"
+ react-window "1.8.8"
+ read-pkg-up "7.0.1"
+ resolve-from "5.0.0"
+ rimraf "3.0.2"
+ sanitize-html "2.11.0"
+ semver "7.5.4"
+ sift "16.0.1"
+ slate "0.94.1"
+ slate-history "0.93.0"
+ slate-react "0.98.3"
+ style-loader "3.3.1"
+ styled-components "5.3.3"
+ typescript "5.2.2"
+ webpack "^5.88.1"
+ webpack-bundle-analyzer "^4.9.0"
+ webpack-dev-middleware "6.1.1"
+ webpack-hot-middleware "2.25.4"
+ yup "0.32.9"
+
+"@strapi/content-releases@4.17.0":
+ version "4.17.0"
+ resolved "https://registry.yarnpkg.com/@strapi/content-releases/-/content-releases-4.17.0.tgz#ce712418d001a9b462602b3d2db147306fd2e091"
+ integrity sha512-U2uqJFYkl90uW0Q9aMsy2IU5+Pivy7GZLGg2wfaRcNXlwtWpil/GF5vtjffr/Icj3s3fbYuCYi9L7FWiteAkVg==
+ dependencies:
+ "@reduxjs/toolkit" "1.9.7"
+ "@strapi/design-system" "1.14.1"
+ "@strapi/helper-plugin" "4.17.0"
+ "@strapi/icons" "1.14.1"
+ "@strapi/types" "4.17.0"
+ "@strapi/utils" "4.17.0"
+ axios "1.6.0"
+ formik "2.4.0"
+ react-intl "6.4.1"
+ react-redux "8.1.1"
+ yup "0.32.9"
+
+"@strapi/data-transfer@4.17.0":
+ version "4.17.0"
+ resolved "https://registry.yarnpkg.com/@strapi/data-transfer/-/data-transfer-4.17.0.tgz#4bff0e9452028b47c83aaf77f89cc3dfa3b70077"
+ integrity sha512-BhEVfKtDMTQk/GpXAv7CYwzURwRsT5Dzgm42qfqp7JCbI/4HSu1G56BEejKLT8KGTwKdzf1qz+ie+p0bAFYmxw==
+ dependencies:
+ "@strapi/logger" "4.17.0"
+ "@strapi/strapi" "4.17.0"
+ "@strapi/types" "4.17.0"
+ "@strapi/utils" "4.17.0"
+ chalk "4.1.2"
+ cli-table3 "0.6.2"
+ commander "8.3.0"
+ fs-extra "10.0.0"
+ inquirer "8.2.5"
+ lodash "4.17.21"
+ ora "5.4.1"
+ resolve-cwd "3.0.0"
+ semver "7.5.4"
+ stream-chain "2.2.5"
+ stream-json "1.8.0"
+ tar "6.1.13"
+ tar-stream "2.2.0"
+ ws "8.13.0"
+
+"@strapi/database@4.17.0":
+ version "4.17.0"
+ resolved "https://registry.yarnpkg.com/@strapi/database/-/database-4.17.0.tgz#099cbbd0e251e3a939e8d838003a327bd57cb8ec"
+ integrity sha512-r925pGVPoOSqbK2+/MuFmOPh+We2b/HJHFtmd3x1q68EBkc9JguiRJdIpICCRdVSozZ5n8fayhgZg130nFFizA==
+ dependencies:
+ "@strapi/utils" "4.17.0"
+ date-fns "2.30.0"
+ debug "4.3.4"
+ fs-extra "10.0.0"
+ knex "2.5.0"
+ lodash "4.17.21"
+ semver "7.5.4"
+ umzug "3.2.1"
+
+"@strapi/design-system@1.14.1":
+ version "1.14.1"
+ resolved "https://registry.yarnpkg.com/@strapi/design-system/-/design-system-1.14.1.tgz#cac587cc3859e34c385b3f3e9072434ef0ec1e4b"
+ integrity sha512-BHWX0f8l4JNhds4c4S2Vop60eF+wK2c0dLoq+8fKB3rZOftS5deO1BuFWo7XzZHF4MFbGT5mYWys9J5ANVBA6A==
+ dependencies:
+ "@codemirror/lang-json" "^6.0.1"
+ "@floating-ui/react-dom" "^2.0.5"
+ "@internationalized/date" "^3.5.1"
+ "@internationalized/number" "^3.5.0"
+ "@radix-ui/react-dismissable-layer" "^1.0.5"
+ "@radix-ui/react-dropdown-menu" "^2.0.6"
+ "@radix-ui/react-focus-scope" "1.0.4"
+ "@strapi/ui-primitives" "^1.14.1"
+ "@uiw/react-codemirror" "^4.21.21"
+ aria-hidden "^1.2.3"
+ compute-scroll-into-view "^3.1.0"
+ prop-types "^15.8.1"
+ react-remove-scroll "^2.5.7"
+
+"@strapi/generate-new@4.17.0":
+ version "4.17.0"
+ resolved "https://registry.yarnpkg.com/@strapi/generate-new/-/generate-new-4.17.0.tgz#d95411089a377294c1dd8ca966f6d400edcda335"
+ integrity sha512-2SQd1aisBL4wRHFO0JUBkLKDaIOkjhGUiI4u6SFgj2rW5INJn5GARHJCcZtfrbLH4KjyD5C2aNeMq5hPQJxvBw==
+ dependencies:
+ "@sentry/node" "6.19.7"
+ chalk "^4.1.2"
+ execa "5.1.1"
+ fs-extra "10.0.0"
+ inquirer "8.2.5"
+ lodash "4.17.21"
+ node-fetch "2.7.0"
+ node-machine-id "^1.1.10"
+ ora "^5.4.1"
+ semver "7.5.4"
+ tar "6.1.13"
+
+"@strapi/generators@4.17.0":
+ version "4.17.0"
+ resolved "https://registry.yarnpkg.com/@strapi/generators/-/generators-4.17.0.tgz#1321eea3a22ec3bdf3ce352e87e3d823586971be"
+ integrity sha512-+gWlQOiMcDBSBDmsmx6jgggHyDGBknTVTQzqxnIBm9/eIZDoA5fnK/6/ygOwNyEYOZ635Xcjkh9QoWVNFg4uJw==
+ dependencies:
+ "@sindresorhus/slugify" "1.1.0"
+ "@strapi/typescript-utils" "4.17.0"
+ "@strapi/utils" "4.17.0"
+ chalk "4.1.2"
+ copyfiles "2.4.1"
+ fs-extra "10.0.0"
+ node-plop "0.26.3"
+ plop "2.7.6"
+ pluralize "8.0.0"
+
+"@strapi/helper-plugin@4.17.0":
+ version "4.17.0"
+ resolved "https://registry.yarnpkg.com/@strapi/helper-plugin/-/helper-plugin-4.17.0.tgz#75bd419146b776bb692ee223636121d4632178e8"
+ integrity sha512-D/O1Rlmk5vmC+U4429HAFj9f2UXQ/Tfw+i3XX004rJorRx0P5qEPajY4w2hUd/SBpqGwzNCJTdr+iYa5npUpWw==
+ dependencies:
+ axios "1.6.0"
+ date-fns "2.30.0"
+ formik "2.4.0"
+ immer "9.0.19"
+ lodash "4.17.21"
+ qs "6.11.1"
+ react-helmet "6.1.0"
+ react-intl "6.4.1"
+ react-query "3.39.3"
+ react-select "5.7.0"
+
+"@strapi/icons@1.14.1":
+ version "1.14.1"
+ resolved "https://registry.yarnpkg.com/@strapi/icons/-/icons-1.14.1.tgz#8f820512d0c9a8b75570f7a96ea42c969f65263b"
+ integrity sha512-ja3et1QIo+6kTfk/mzeSiLTtZ6pCC6mwvUlp8qGyBTQ5BJvMacgxEdXBnYRn6fbYt6fl7gAKCORRQpnHNQfwjg==
+
+"@strapi/logger@4.17.0":
+ version "4.17.0"
+ resolved "https://registry.yarnpkg.com/@strapi/logger/-/logger-4.17.0.tgz#a2b1d1c547bc6880b3a1fcbb395d24c8628e5d96"
+ integrity sha512-jnCpnDvEcPzW/eufwyuFRlY8JZkd2FXx3CCL7YOQaiwmwXktNQ+ristbeLNXTbGlcEKLLXpl+lHymr+GtCIBfg==
+ dependencies:
+ lodash "4.17.21"
+ winston "3.10.0"
+
+"@strapi/pack-up@4.17.0":
+ version "4.17.0"
+ resolved "https://registry.yarnpkg.com/@strapi/pack-up/-/pack-up-4.17.0.tgz#aed0ae64c26e127dd800b7445e1b4be9959a3883"
+ integrity sha512-TBrsL+7Vp9KiEB+wVQ0lkHj7p0563K6mvP4e01iTEI1tzDAA08pYtUY3mpyL8fQWJWPt8qZPt+rk+3kLAJiEqA==
+ dependencies:
+ "@vitejs/plugin-react" "4.1.0"
+ boxen "5.1.2"
+ browserslist-to-esbuild "1.2.0"
+ chalk "4.1.2"
+ chokidar "3.5.3"
+ commander "8.3.0"
+ esbuild "0.19.2"
+ esbuild-register "3.5.0"
+ get-latest-version "5.1.0"
+ git-url-parse "13.1.0"
+ ini "4.1.1"
+ ora "5.4.1"
+ outdent "0.8.0"
+ pkg-up "3.1.0"
+ prettier "2.8.4"
+ prettier-plugin-packagejson "2.4.5"
+ prompts "2.4.2"
+ rxjs "7.8.1"
+ typescript "5.2.2"
+ vite "4.4.9"
+ yup "0.32.9"
+
+"@strapi/permissions@4.17.0":
+ version "4.17.0"
+ resolved "https://registry.yarnpkg.com/@strapi/permissions/-/permissions-4.17.0.tgz#1648a071880a1a44d52e05339ba13c3562f708e1"
+ integrity sha512-l0/UA7swCDdYLVQxLtv3eRpWvTm7it+t9eW0491sVDlN89Ov7Olm3KgkzrYpmjHYFkbM8Vtc5QFDwr8dWiULaQ==
+ dependencies:
+ "@casl/ability" "6.5.0"
+ "@strapi/utils" "4.17.0"
+ lodash "4.17.21"
+ qs "6.11.1"
+ sift "16.0.1"
+
+"@strapi/plugin-content-manager@4.17.0":
+ version "4.17.0"
+ resolved "https://registry.yarnpkg.com/@strapi/plugin-content-manager/-/plugin-content-manager-4.17.0.tgz#c4117f6a9b851fcc2feb39e02956513265b3bf08"
+ integrity sha512-oBGSI2S7hWfcUq0h+UhgHTJ2Qz3GMbmRet/1jH5Ytntz6+tH8mR0D2kOFDKeaWGk0SpJu10kmyKamCcdTpqoDQ==
+ dependencies:
+ "@sindresorhus/slugify" "1.1.0"
+ "@strapi/types" "4.17.0"
+ "@strapi/utils" "4.17.0"
+ koa "2.13.4"
+ koa-bodyparser "4.4.1"
+ lodash "4.17.21"
+ qs "6.11.1"
+
+"@strapi/plugin-content-type-builder@4.17.0":
+ version "4.17.0"
+ resolved "https://registry.yarnpkg.com/@strapi/plugin-content-type-builder/-/plugin-content-type-builder-4.17.0.tgz#13156a9e7b0e32ce99dce2a50702fd40fcc05f64"
+ integrity sha512-+Y7sYuUL2rj0Gh1McmgoSMqE0aXfpIrLnLWe86VTLikSsLpEoHFD3NhRqrtKMYrALbHnk1AxO+O8O0mP7CYO8A==
+ dependencies:
+ "@reduxjs/toolkit" "1.9.7"
+ "@sindresorhus/slugify" "1.1.0"
+ "@strapi/design-system" "1.14.1"
+ "@strapi/generators" "4.17.0"
+ "@strapi/helper-plugin" "4.17.0"
+ "@strapi/icons" "1.14.1"
+ "@strapi/utils" "4.17.0"
+ fs-extra "10.0.0"
+ immer "9.0.19"
+ koa-bodyparser "4.4.1"
+ lodash "4.17.21"
+ pluralize "8.0.0"
+ prop-types "^15.8.1"
+ qs "6.11.1"
+ react-helmet "^6.1.0"
+ react-intl "6.4.1"
+ react-redux "8.1.1"
+ yup "0.32.9"
+
+"@strapi/plugin-email@4.17.0":
+ version "4.17.0"
+ resolved "https://registry.yarnpkg.com/@strapi/plugin-email/-/plugin-email-4.17.0.tgz#53c79b906d9b9fc6c516915f3d14c8ae85011188"
+ integrity sha512-jKTg3RREoMrdWEdN7l0T5MloodbXBdsw+LS0Inp1Ji+mVlqTbV4qmYA5ciCpGVew7L35xBcMLUiiFD+Ai6vStg==
+ dependencies:
+ "@strapi/design-system" "1.14.1"
+ "@strapi/helper-plugin" "4.17.0"
+ "@strapi/icons" "1.14.1"
+ "@strapi/provider-email-sendmail" "4.17.0"
+ "@strapi/utils" "4.17.0"
+ lodash "4.17.21"
+ prop-types "^15.8.1"
+ react-intl "6.4.1"
+ react-query "3.39.3"
+ yup "0.32.9"
+
+"@strapi/plugin-i18n@4.17.0":
+ version "4.17.0"
+ resolved "https://registry.yarnpkg.com/@strapi/plugin-i18n/-/plugin-i18n-4.17.0.tgz#1169d8c7ca66f05e366dc7269a0c32c78aadd6fe"
+ integrity sha512-ZPPXUSOK0wWRgM7fqKGCuNQDI8Dz5ODsHDp7LZUOy+4Mhj4aQhn4speAOWLD4aDhx8JPZH8xoFf1bAIHzXCplg==
+ dependencies:
+ "@reduxjs/toolkit" "1.9.7"
+ "@strapi/design-system" "1.14.1"
+ "@strapi/helper-plugin" "4.17.0"
+ "@strapi/icons" "1.14.1"
+ "@strapi/utils" "4.17.0"
+ axios "1.6.0"
+ formik "2.4.0"
+ immer "9.0.19"
+ lodash "4.17.21"
+ prop-types "^15.8.1"
+ qs "6.11.1"
+ react-intl "6.4.1"
+ react-query "3.39.3"
+ react-redux "8.1.1"
+ yup "0.32.9"
+
+"@strapi/plugin-upload@4.17.0":
+ version "4.17.0"
+ resolved "https://registry.yarnpkg.com/@strapi/plugin-upload/-/plugin-upload-4.17.0.tgz#d53426ca67499b3dc90e4131795687915b1e3f62"
+ integrity sha512-Z5M1+S943OrSbBbnnG+1MgNsJPr7Ko4zlwqYt7zREdTBZBeCEvuPpucBFvwlzV505EHw7+YSIm2doxGF5kqUbw==
+ dependencies:
+ "@strapi/design-system" "1.14.1"
+ "@strapi/helper-plugin" "4.17.0"
+ "@strapi/icons" "1.14.1"
+ "@strapi/provider-upload-local" "4.17.0"
+ "@strapi/utils" "4.17.0"
+ axios "1.6.0"
+ byte-size "7.0.1"
+ cropperjs "1.6.0"
+ date-fns "2.30.0"
+ formik "2.4.0"
+ fs-extra "10.0.0"
+ immer "9.0.19"
+ koa-range "0.3.0"
+ koa-static "5.0.0"
+ lodash "4.17.21"
+ mime-types "2.1.35"
+ prop-types "^15.8.1"
+ qs "6.11.1"
+ react-dnd "15.1.2"
+ react-helmet "^6.1.0"
+ react-intl "6.4.1"
+ react-query "3.39.3"
+ react-redux "8.1.1"
+ react-select "5.7.0"
+ sharp "0.32.6"
+ yup "0.32.9"
+
+"@strapi/plugin-users-permissions@4.17.0":
+ version "4.17.0"
+ resolved "https://registry.yarnpkg.com/@strapi/plugin-users-permissions/-/plugin-users-permissions-4.17.0.tgz#054af72dabba1f360ade8569c7ef26302795074b"
+ integrity sha512-P6rDujdDKDU3ufy/9LO6ifCLhDyAtDIoIZ7Y5j60uwADhvpBKSpGxqhU9oKDkdrKJr76SBzus+Qj05gdgSO67Q==
+ dependencies:
+ "@strapi/design-system" "1.14.1"
+ "@strapi/helper-plugin" "4.17.0"
+ "@strapi/icons" "1.14.1"
+ "@strapi/utils" "4.17.0"
+ bcryptjs "2.4.3"
+ formik "2.4.0"
+ grant-koa "5.4.8"
+ immer "9.0.19"
+ jsonwebtoken "9.0.0"
+ jwk-to-pem "2.0.5"
+ koa "2.13.4"
+ koa2-ratelimit "^1.1.2"
+ lodash "4.17.21"
+ prop-types "^15.8.1"
+ purest "4.0.2"
+ react-intl "6.4.1"
+ react-query "3.39.3"
+ react-redux "8.1.1"
+ url-join "4.0.1"
+ yup "0.32.9"
+
+"@strapi/provider-audit-logs-local@4.17.0":
+ version "4.17.0"
+ resolved "https://registry.yarnpkg.com/@strapi/provider-audit-logs-local/-/provider-audit-logs-local-4.17.0.tgz#b63fe89d82fad450bc39adbe80009356758cd857"
+ integrity sha512-RwDz+Nrw9CSnHbuO94TQRQL3TV7sykCGw7alwV+FdwWUG2KFe7RL1aeFnnXa+8Uq+Eh6zkjcz4yJB1KgfW1/lQ==
+
+"@strapi/provider-email-sendgrid@4.17.0":
+ version "4.17.0"
+ resolved "https://registry.yarnpkg.com/@strapi/provider-email-sendgrid/-/provider-email-sendgrid-4.17.0.tgz#283f6da0f1691f3e9fffadcffab2aeb6b661777d"
+ integrity sha512-SIohvZi0PlF9/2lN3M6UVoaT0J7oUMQE/FLGVQIgD1kdqxYtfmqXq3IUe9MoZh7NY3eQTvD/O9kFcuywabmySw==
+ dependencies:
+ "@sendgrid/mail" "7.7.0"
+ "@strapi/utils" "4.17.0"
+
+"@strapi/provider-email-sendmail@4.17.0":
+ version "4.17.0"
+ resolved "https://registry.yarnpkg.com/@strapi/provider-email-sendmail/-/provider-email-sendmail-4.17.0.tgz#dc7161a2c2ca703603df2dcd334c3e91482fe1d9"
+ integrity sha512-8EPv1ie2SZJvq1B3owfGKLEVynFrJiRIDRk2LdAEixaaRD40fRzsD3ULYiZEtNGST6Cy/bVRj25pe+8OmGxy+Q==
+ dependencies:
+ "@strapi/utils" "4.17.0"
+ sendmail "^1.6.1"
+
+"@strapi/provider-upload-cloudinary@4.17.0":
+ version "4.17.0"
+ resolved "https://registry.yarnpkg.com/@strapi/provider-upload-cloudinary/-/provider-upload-cloudinary-4.17.0.tgz#b94f2cfe485544548304c25861705c4581ef6cab"
+ integrity sha512-Zw5aRzgicaa0o2B4oRdID0ylmAk+u5GFKeEyiHSVLYXgv5DfqJLcBWiVi1djqE7xXBoDnSd8zN4UFAT1MtDUCQ==
+ dependencies:
+ "@strapi/utils" "4.17.0"
+ cloudinary "^1.41.0"
+ into-stream "^5.1.0"
+
+"@strapi/provider-upload-local@4.17.0":
+ version "4.17.0"
+ resolved "https://registry.yarnpkg.com/@strapi/provider-upload-local/-/provider-upload-local-4.17.0.tgz#ca06e9b65d64efa429b2ecea49c77809ba21c0dd"
+ integrity sha512-Z9YoU6tNDA47/KlYxQ+xLGDtvGBGNiWiurddV5WIQHoTJIaXSRjcneaw4WTUQy2TAu9AmYx2APP+uyPV0N5t/Q==
+ dependencies:
+ "@strapi/utils" "4.17.0"
+ fs-extra "10.0.0"
+
+"@strapi/strapi@4.17.0":
+ version "4.17.0"
+ resolved "https://registry.yarnpkg.com/@strapi/strapi/-/strapi-4.17.0.tgz#2b2cf6fb24731fdea9b852b2d3d504a5f981a10b"
+ integrity sha512-IKJaLgqrFE5Ep4dzs0mdVy1k90MvHeBoFuXXFsLkPVzNr/XHXmJ1OKQycuBaAqW5iNMIDqdrfKZD7ec2Pg5WoA==
+ dependencies:
+ "@koa/cors" "3.4.3"
+ "@koa/router" "10.1.1"
+ "@strapi/admin" "4.17.0"
+ "@strapi/content-releases" "4.17.0"
+ "@strapi/data-transfer" "4.17.0"
+ "@strapi/database" "4.17.0"
+ "@strapi/generate-new" "4.17.0"
+ "@strapi/generators" "4.17.0"
+ "@strapi/logger" "4.17.0"
+ "@strapi/pack-up" "4.17.0"
+ "@strapi/permissions" "4.17.0"
+ "@strapi/plugin-content-manager" "4.17.0"
+ "@strapi/plugin-content-type-builder" "4.17.0"
+ "@strapi/plugin-email" "4.17.0"
+ "@strapi/plugin-upload" "4.17.0"
+ "@strapi/types" "4.17.0"
+ "@strapi/typescript-utils" "4.17.0"
+ "@strapi/utils" "4.17.0"
+ bcryptjs "2.4.3"
+ boxen "5.1.2"
+ chalk "4.1.2"
+ ci-info "3.8.0"
+ cli-table3 "0.6.2"
+ commander "8.3.0"
+ configstore "5.0.1"
+ copyfiles "2.4.1"
+ debug "4.3.4"
+ delegates "1.0.0"
+ dotenv "14.2.0"
+ execa "5.1.1"
+ fs-extra "10.0.0"
+ get-latest-version "5.1.0"
+ git-url-parse "13.1.0"
+ glob "7.2.3"
+ http-errors "1.8.1"
+ https-proxy-agent "5.0.1"
+ inquirer "8.2.5"
+ is-docker "2.2.1"
+ koa "2.13.4"
+ koa-body "4.2.0"
+ koa-compose "4.1.0"
+ koa-compress "5.1.0"
+ koa-favicon "2.1.0"
+ koa-helmet "7.0.2"
+ koa-ip "^2.1.2"
+ koa-session "6.4.0"
+ koa-static "5.0.0"
+ lodash "4.17.21"
+ mime-types "2.1.35"
+ node-fetch "2.7.0"
+ node-machine-id "1.1.12"
+ node-schedule "2.1.0"
+ open "8.4.0"
+ ora "5.4.1"
+ outdent "0.8.0"
+ package-json "7.0.0"
+ pkg-up "3.1.0"
+ qs "6.11.1"
+ semver "7.5.4"
+ statuses "2.0.1"
+ typescript "5.2.2"
+ yup "0.32.9"
+
+"@strapi/types@4.17.0":
+ version "4.17.0"
+ resolved "https://registry.yarnpkg.com/@strapi/types/-/types-4.17.0.tgz#5098d731d8828390ad9d3489c854913537f5587f"
+ integrity sha512-j7nXdRTS0Y+79WDecNgA7UkTAj5b9gZcEKbYDPOD07OV4p/FUXGrtfFqAI6vONSWxI5O83f2U7Wh/knTKRl5mg==
+ dependencies:
+ "@casl/ability" "6.5.0"
+ "@koa/cors" "3.4.3"
+ "@koa/router" "10.1.1"
+ "@strapi/database" "4.17.0"
+ "@strapi/logger" "4.17.0"
+ "@strapi/permissions" "4.17.0"
+ "@strapi/utils" "4.17.0"
+ commander "8.3.0"
+ https-proxy-agent "5.0.1"
+ koa "2.13.4"
+ node-fetch "2.7.0"
+ node-schedule "2.1.0"
+
+"@strapi/typescript-utils@4.17.0":
+ version "4.17.0"
+ resolved "https://registry.yarnpkg.com/@strapi/typescript-utils/-/typescript-utils-4.17.0.tgz#c0a0c702dce6437cc2e13dbc3459a7d60d591222"
+ integrity sha512-lI+r0HHzyGq6hAcckM77o/VdpP6DVJA28SQYJB5iKr+Efi0vT42w5oJ24gSt4eu5/S7y9PW6tR19hYawX9TZHg==
+ dependencies:
+ chalk "4.1.2"
+ cli-table3 "0.6.2"
+ fs-extra "10.0.0"
+ lodash "4.17.21"
+ prettier "2.8.4"
+ typescript "5.2.2"
+
+"@strapi/ui-primitives@^1.14.1":
+ version "1.14.1"
+ resolved "https://registry.yarnpkg.com/@strapi/ui-primitives/-/ui-primitives-1.14.1.tgz#f4100f68874754088322bdb6da98a206fa9fbc2d"
+ integrity sha512-AmwyfZuazN7J1AgVf7i7oly+zwcJdWFqh/UCd3uPtoonnPmdCIRjkK8aBWlU9M+k3277FGIaCHOwNHiMSiBbbA==
+ dependencies:
+ "@radix-ui/number" "^1.0.1"
+ "@radix-ui/primitive" "^1.0.1"
+ "@radix-ui/react-collection" "1.0.3"
+ "@radix-ui/react-compose-refs" "^1.0.1"
+ "@radix-ui/react-context" "^1.0.1"
+ "@radix-ui/react-direction" "1.0.1"
+ "@radix-ui/react-dismissable-layer" "^1.0.5"
+ "@radix-ui/react-focus-guards" "1.0.1"
+ "@radix-ui/react-focus-scope" "1.0.4"
+ "@radix-ui/react-id" "^1.0.1"
+ "@radix-ui/react-popper" "^1.1.3"
+ "@radix-ui/react-portal" "^1.0.4"
+ "@radix-ui/react-primitive" "^1.0.3"
+ "@radix-ui/react-slot" "^1.0.2"
+ "@radix-ui/react-use-callback-ref" "^1.0.1"
+ "@radix-ui/react-use-controllable-state" "^1.0.1"
+ "@radix-ui/react-use-layout-effect" "1.0.1"
+ "@radix-ui/react-use-previous" "^1.0.1"
+ "@radix-ui/react-visually-hidden" "^1.0.3"
+ aria-hidden "^1.2.3"
+ react-remove-scroll "^2.5.7"
+
+"@strapi/utils@4.17.0":
+ version "4.17.0"
+ resolved "https://registry.yarnpkg.com/@strapi/utils/-/utils-4.17.0.tgz#23da12dcf2535aef6f2e1dd76537b9ce81346e5a"
+ integrity sha512-jiiYilc8BNZJkGgvLkLOJvsP4ra1N82fWcAL+xuvC2K31Vl+8ugX1S3xVCVnRwokUGVNu5qk+CdN5h23pIVFxQ==
+ dependencies:
+ "@sindresorhus/slugify" "1.1.0"
+ date-fns "2.30.0"
+ http-errors "1.8.1"
+ lodash "4.17.21"
+ p-map "4.0.0"
+ yup "0.32.9"
+
+"@swc/helpers@^0.5.0":
+ version "0.5.3"
+ resolved "https://registry.yarnpkg.com/@swc/helpers/-/helpers-0.5.3.tgz#98c6da1e196f5f08f977658b80d6bd941b5f294f"
+ integrity sha512-FaruWX6KdudYloq1AHD/4nU+UsMTdNE8CKyrseXWEcgjDAbvkwJg2QGPAnfIJLIWsjZOSPLOAykK6fuYp4vp4A==
+ dependencies:
+ tslib "^2.4.0"
+
+"@szmarczak/http-timer@^4.0.5":
+ version "4.0.6"
+ resolved "https://registry.yarnpkg.com/@szmarczak/http-timer/-/http-timer-4.0.6.tgz#b4a914bb62e7c272d4e5989fe4440f812ab1d807"
+ integrity sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w==
+ dependencies:
+ defer-to-connect "^2.0.0"
+
+"@testing-library/dom@8.19.0":
+ version "8.19.0"
+ resolved "https://registry.yarnpkg.com/@testing-library/dom/-/dom-8.19.0.tgz#bd3f83c217ebac16694329e413d9ad5fdcfd785f"
+ integrity sha512-6YWYPPpxG3e/xOo6HIWwB/58HukkwIVTOaZ0VwdMVjhRUX/01E4FtQbck9GazOOj7MXHc5RBzMrU86iBJHbI+A==
+ dependencies:
+ "@babel/code-frame" "^7.10.4"
+ "@babel/runtime" "^7.12.5"
+ "@types/aria-query" "^4.2.0"
+ aria-query "^5.0.0"
+ chalk "^4.1.0"
+ dom-accessibility-api "^0.5.9"
+ lz-string "^1.4.4"
+ pretty-format "^27.0.2"
+
+"@testing-library/dom@^8.0.0":
+ version "8.20.1"
+ resolved "https://registry.yarnpkg.com/@testing-library/dom/-/dom-8.20.1.tgz#2e52a32e46fc88369eef7eef634ac2a192decd9f"
+ integrity sha512-/DiOQ5xBxgdYRC8LNk7U+RWat0S3qRLeIw3ZIkMQ9kkVlRmwD/Eg8k8CqIpD6GW7u20JIUOfMKbxtiLutpjQ4g==
+ dependencies:
+ "@babel/code-frame" "^7.10.4"
+ "@babel/runtime" "^7.12.5"
+ "@types/aria-query" "^5.0.1"
+ aria-query "5.1.3"
+ chalk "^4.1.0"
+ dom-accessibility-api "^0.5.9"
+ lz-string "^1.5.0"
+ pretty-format "^27.0.2"
+
+"@testing-library/react-hooks@8.0.1":
+ version "8.0.1"
+ resolved "https://registry.yarnpkg.com/@testing-library/react-hooks/-/react-hooks-8.0.1.tgz#0924bbd5b55e0c0c0502d1754657ada66947ca12"
+ integrity sha512-Aqhl2IVmLt8IovEVarNDFuJDVWVvhnr9/GCU6UUnrYXwgDFF9h2L2o2P9KBni1AST5sT6riAyoukFLyjQUgD/g==
+ dependencies:
+ "@babel/runtime" "^7.12.5"
+ react-error-boundary "^3.1.0"
+
+"@testing-library/react@12.1.4":
+ version "12.1.4"
+ resolved "https://registry.yarnpkg.com/@testing-library/react/-/react-12.1.4.tgz#09674b117e550af713db3f4ec4c0942aa8bbf2c0"
+ integrity sha512-jiPKOm7vyUw311Hn/HlNQ9P8/lHNtArAx0PisXyFixDDvfl8DbD6EUdbshK5eqauvBSvzZd19itqQ9j3nferJA==
+ dependencies:
+ "@babel/runtime" "^7.12.5"
+ "@testing-library/dom" "^8.0.0"
+ "@types/react-dom" "*"
+
+"@testing-library/user-event@14.4.3":
+ version "14.4.3"
+ resolved "https://registry.yarnpkg.com/@testing-library/user-event/-/user-event-14.4.3.tgz#af975e367743fa91989cd666666aec31a8f50591"
+ integrity sha512-kCUc5MEwaEMakkO5x7aoD+DLi02ehmEM2QCGWvNqAS1dV/fAvORWEjnjsEIvml59M7Y5kCkWN6fCCyPOe8OL6Q==
+
+"@types/argparse@1.0.38":
+ version "1.0.38"
+ resolved "https://registry.yarnpkg.com/@types/argparse/-/argparse-1.0.38.tgz#a81fd8606d481f873a3800c6ebae4f1d768a56a9"
+ integrity sha512-ebDJ9b0e702Yr7pWgB0jzm+CX4Srzz8RcXtLJDJB+BSccqMa36uyH/zUsSYao5+BD1ytv3k3rPYCq4mAE1hsXA==
+
+"@types/aria-query@^4.2.0":
+ version "4.2.2"
+ resolved "https://registry.yarnpkg.com/@types/aria-query/-/aria-query-4.2.2.tgz#ed4e0ad92306a704f9fb132a0cfcf77486dbe2bc"
+ integrity sha512-HnYpAE1Y6kRyKM/XkEuiRQhTHvkzMBurTHnpFLYLBGPIylZNPs9jJcuOOYWxPLJCSEtmZT0Y8rHDokKN7rRTig==
+
+"@types/aria-query@^5.0.1":
+ version "5.0.4"
+ resolved "https://registry.yarnpkg.com/@types/aria-query/-/aria-query-5.0.4.tgz#1a31c3d378850d2778dabb6374d036dcba4ba708"
+ integrity sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==
+
+"@types/babel__core@^7.20.2":
+ version "7.20.5"
+ resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.20.5.tgz#3df15f27ba85319caa07ba08d0721889bb39c017"
+ integrity sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==
+ dependencies:
+ "@babel/parser" "^7.20.7"
+ "@babel/types" "^7.20.7"
+ "@types/babel__generator" "*"
+ "@types/babel__template" "*"
+ "@types/babel__traverse" "*"
+
+"@types/babel__generator@*":
+ version "7.6.8"
+ resolved "https://registry.yarnpkg.com/@types/babel__generator/-/babel__generator-7.6.8.tgz#f836c61f48b1346e7d2b0d93c6dacc5b9535d3ab"
+ integrity sha512-ASsj+tpEDsEiFr1arWrlN6V3mdfjRMZt6LtK/Vp/kreFLnr5QH5+DhvD5nINYZXzwJvXeGq+05iUXcAzVrqWtw==
+ dependencies:
+ "@babel/types" "^7.0.0"
+
+"@types/babel__template@*":
+ version "7.4.4"
+ resolved "https://registry.yarnpkg.com/@types/babel__template/-/babel__template-7.4.4.tgz#5672513701c1b2199bc6dad636a9d7491586766f"
+ integrity sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==
+ dependencies:
+ "@babel/parser" "^7.1.0"
+ "@babel/types" "^7.0.0"
+
+"@types/babel__traverse@*":
+ version "7.20.5"
+ resolved "https://registry.yarnpkg.com/@types/babel__traverse/-/babel__traverse-7.20.5.tgz#7b7502be0aa80cc4ef22978846b983edaafcd4dd"
+ integrity sha512-WXCyOcRtH37HAUkpXhUduaxdm82b4GSlyTqajXviN4EfiuPgNYR109xMCKvpl6zPIpua0DGlMEDCq+g8EdoheQ==
+ dependencies:
+ "@babel/types" "^7.20.7"
+
+"@types/cacheable-request@^6.0.1":
+ version "6.0.3"
+ resolved "https://registry.yarnpkg.com/@types/cacheable-request/-/cacheable-request-6.0.3.tgz#a430b3260466ca7b5ca5bfd735693b36e7a9d183"
+ integrity sha512-IQ3EbTzGxIigb1I3qPZc1rWJnH0BmSKv5QYTalEwweFvyBDLSAe24zP0le/hyi7ecGfZVlIVAg4BZqb8WBwKqw==
+ dependencies:
+ "@types/http-cache-semantics" "*"
+ "@types/keyv" "^3.1.4"
+ "@types/node" "*"
+ "@types/responselike" "^1.0.0"
+
+"@types/cookie@^0.4.1":
+ version "0.4.1"
+ resolved "https://registry.yarnpkg.com/@types/cookie/-/cookie-0.4.1.tgz#bfd02c1f2224567676c1545199f87c3a861d878d"
+ integrity sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q==
+
+"@types/debug@^4.1.7":
+ version "4.1.12"
+ resolved "https://registry.yarnpkg.com/@types/debug/-/debug-4.1.12.tgz#a155f21690871953410df4b6b6f53187f0500917"
+ integrity sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==
+ dependencies:
+ "@types/ms" "*"
+
+"@types/eslint-scope@^3.7.3":
+ version "3.7.7"
+ resolved "https://registry.yarnpkg.com/@types/eslint-scope/-/eslint-scope-3.7.7.tgz#3108bd5f18b0cdb277c867b3dd449c9ed7079ac5"
+ integrity sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==
+ dependencies:
+ "@types/eslint" "*"
+ "@types/estree" "*"
+
+"@types/eslint@*":
+ version "8.56.2"
+ resolved "https://registry.yarnpkg.com/@types/eslint/-/eslint-8.56.2.tgz#1c72a9b794aa26a8b94ad26d5b9aa51c8a6384bb"
+ integrity sha512-uQDwm1wFHmbBbCZCqAlq6Do9LYwByNZHWzXppSnay9SuwJ+VRbjkbLABer54kcPnMSlG6Fdiy2yaFXm/z9Z5gw==
+ dependencies:
+ "@types/estree" "*"
+ "@types/json-schema" "*"
+
+"@types/estree@*", "@types/estree@^1.0.0":
+ version "1.0.5"
+ resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.5.tgz#a6ce3e556e00fd9895dd872dd172ad0d4bd687f4"
+ integrity sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==
+
+"@types/fined@*":
+ version "1.1.5"
+ resolved "https://registry.yarnpkg.com/@types/fined/-/fined-1.1.5.tgz#504b87a0de8813e06e7d226f34c1cefb70d9afb0"
+ integrity sha512-2N93vadEGDFhASTIRbizbl4bNqpMOId5zZfj6hHqYZfEzEfO9onnU4Im8xvzo8uudySDveDHBOOSlTWf38ErfQ==
+
+"@types/formidable@^1.0.31":
+ version "1.2.8"
+ resolved "https://registry.yarnpkg.com/@types/formidable/-/formidable-1.2.8.tgz#78a95c12606920aeb1165ab2670943d726a79325"
+ integrity sha512-6psvrUy5VDYb+yaPJReF1WrRsz+FBwyJutK9Twz1Efa27tm07bARNIkK2B8ZPWq80dXqpKfrxTO96xrtPp+AuA==
+ dependencies:
+ "@types/node" "*"
+
+"@types/glob@^7.1.1":
+ version "7.2.0"
+ resolved "https://registry.yarnpkg.com/@types/glob/-/glob-7.2.0.tgz#bc1b5bf3aa92f25bd5dd39f35c57361bdce5b2eb"
+ integrity sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA==
+ dependencies:
+ "@types/minimatch" "*"
+ "@types/node" "*"
+
+"@types/hoist-non-react-statics@^3.3.1":
+ version "3.3.5"
+ resolved "https://registry.yarnpkg.com/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.5.tgz#dab7867ef789d87e2b4b0003c9d65c49cc44a494"
+ integrity sha512-SbcrWzkKBw2cdwRTwQAswfpB9g9LJWfjtUeW/jvNwbhC8cpmmNYVePa+ncbUe0rGTQ7G3Ff6mYUN2VMfLVr+Sg==
+ dependencies:
+ "@types/react" "*"
+ hoist-non-react-statics "^3.3.0"
+
+"@types/html-minifier-terser@^6.0.0":
+ version "6.1.0"
+ resolved "https://registry.yarnpkg.com/@types/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz#4fc33a00c1d0c16987b1a20cf92d20614c55ac35"
+ integrity sha512-oh/6byDPnL1zeNXFrDXFLyZjkr1MsBG667IM792caf1L2UPOOMf65NFzjUH/ltyfwjAGfs1rsX1eftK0jC/KIg==
+
+"@types/http-cache-semantics@*":
+ version "4.0.4"
+ resolved "https://registry.yarnpkg.com/@types/http-cache-semantics/-/http-cache-semantics-4.0.4.tgz#b979ebad3919799c979b17c72621c0bc0a31c6c4"
+ integrity sha512-1m0bIFVc7eJWyve9S0RnuRgcQqF/Xd5QsUZAZeQFr1Q3/p9JWoQQEqmVy+DPTNpGXwhgIetAoYF8JSc33q29QA==
+
+"@types/inquirer@^6.5.0":
+ version "6.5.0"
+ resolved "https://registry.yarnpkg.com/@types/inquirer/-/inquirer-6.5.0.tgz#b83b0bf30b88b8be7246d40e51d32fe9d10e09be"
+ integrity sha512-rjaYQ9b9y/VFGOpqBEXRavc3jh0a+e6evAbI31tMda8VlPaSy0AZJfXsvmIe3wklc7W6C3zCSfleuMXR7NOyXw==
+ dependencies:
+ "@types/through" "*"
+ rxjs "^6.4.0"
+
+"@types/interpret@*":
+ version "1.1.3"
+ resolved "https://registry.yarnpkg.com/@types/interpret/-/interpret-1.1.3.tgz#fa7695584530077e0338948188bb59270077ab7a"
+ integrity sha512-uBaBhj/BhilG58r64mtDb/BEdH51HIQLgP5bmWzc5qCtFMja8dCk/IOJmk36j0lbi9QHwI6sbtUNGuqXdKCAtQ==
+ dependencies:
+ "@types/node" "*"
+
+"@types/is-hotkey@^0.1.1":
+ version "0.1.10"
+ resolved "https://registry.yarnpkg.com/@types/is-hotkey/-/is-hotkey-0.1.10.tgz#cf440fab9bf75ffba4e1a16e8df28938de0778c9"
+ integrity sha512-RvC8KMw5BCac1NvRRyaHgMMEtBaZ6wh0pyPTBu7izn4Sj/AX9Y4aXU5c7rX8PnM/knsuUpC1IeoBkANtxBypsQ==
+
+"@types/js-levenshtein@^1.1.1":
+ version "1.1.3"
+ resolved "https://registry.yarnpkg.com/@types/js-levenshtein/-/js-levenshtein-1.1.3.tgz#a6fd0bdc8255b274e5438e0bfb25f154492d1106"
+ integrity sha512-jd+Q+sD20Qfu9e2aEXogiO3vpOC1PYJOUdyN9gvs4Qrvkg4wF43L5OhqrPeokdv8TL0/mXoYfpkcoGZMNN2pkQ==
+
+"@types/json-schema@*", "@types/json-schema@^7.0.8", "@types/json-schema@^7.0.9":
+ version "7.0.15"
+ resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.15.tgz#596a1747233694d50f6ad8a7869fcb6f56cf5841"
+ integrity sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==
+
+"@types/keyv@^3.1.4":
+ version "3.1.4"
+ resolved "https://registry.yarnpkg.com/@types/keyv/-/keyv-3.1.4.tgz#3ccdb1c6751b0c7e52300bcdacd5bcbf8faa75b6"
+ integrity sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==
+ dependencies:
+ "@types/node" "*"
+
+"@types/liftoff@^2.5.1":
+ version "2.5.1"
+ resolved "https://registry.yarnpkg.com/@types/liftoff/-/liftoff-2.5.1.tgz#2eb4c1f86e9d5ee85571e56db0084b26af129ced"
+ integrity sha512-nB3R6Q9CZcM07JgiTK6ibxqrG1reiHE+UX7em/W1DKwVBxDlfKWOefQjk4jubY5xX+GDxVsWR2KD1SenPby8ow==
+ dependencies:
+ "@types/fined" "*"
+ "@types/interpret" "*"
+ "@types/node" "*"
+
+"@types/lodash@^4.14.149", "@types/lodash@^4.14.165", "@types/lodash@^4.14.175":
+ version "4.14.202"
+ resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.202.tgz#f09dbd2fb082d507178b2f2a5c7e74bd72ff98f8"
+ integrity sha512-OvlIYQK9tNneDlS0VN54LLd5uiPCBOp7gS5Z0f1mjoJYBrtStzgmJBxONW3U6OZqdtNzZPmn9BS/7WI7BFFcFQ==
+
+"@types/minimatch@*":
+ version "5.1.2"
+ resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-5.1.2.tgz#07508b45797cb81ec3f273011b054cd0755eddca"
+ integrity sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA==
+
+"@types/ms@*":
+ version "0.7.34"
+ resolved "https://registry.yarnpkg.com/@types/ms/-/ms-0.7.34.tgz#10964ba0dee6ac4cd462e2795b6bebd407303433"
+ integrity sha512-nG96G3Wp6acyAgJqGasjODb+acrI7KltPiRxzHPXnP3NgI28bpQDRv53olbqGXbfcgF5aiiHmO3xpwEpS5Ld9g==
+
+"@types/node@*":
+ version "20.11.0"
+ resolved "https://registry.yarnpkg.com/@types/node/-/node-20.11.0.tgz#8e0b99e70c0c1ade1a86c4a282f7b7ef87c9552f"
+ integrity sha512-o9bjXmDNcF7GbM4CNQpmi+TutCgap/K3w1JyKgxAjqx41zp9qlIAVFi0IhCNsJcXolEqLWhbFbEeL0PvYm4pcQ==
+ dependencies:
+ undici-types "~5.26.4"
+
+"@types/normalize-package-data@^2.4.0":
+ version "2.4.4"
+ resolved "https://registry.yarnpkg.com/@types/normalize-package-data/-/normalize-package-data-2.4.4.tgz#56e2cc26c397c038fab0e3a917a12d5c5909e901"
+ integrity sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==
+
+"@types/parse-json@^4.0.0":
+ version "4.0.2"
+ resolved "https://registry.yarnpkg.com/@types/parse-json/-/parse-json-4.0.2.tgz#5950e50960793055845e956c427fc2b0d70c5239"
+ integrity sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==
+
+"@types/prop-types@*":
+ version "15.7.11"
+ resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.11.tgz#2596fb352ee96a1379c657734d4b913a613ad563"
+ integrity sha512-ga8y9v9uyeiLdpKddhxYQkxNDrfvuPrlFb0N1qnZZByvcElJaXthF1UhvCh9TLWJBEHeNtdnbysW7Y6Uq8CVng==
+
+"@types/react-dom@*":
+ version "18.2.18"
+ resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-18.2.18.tgz#16946e6cd43971256d874bc3d0a72074bb8571dd"
+ integrity sha512-TJxDm6OfAX2KJWJdMEVTwWke5Sc/E/RlnPGvGfS0W7+6ocy2xhDVQVh/KvC2Uf7kACs+gDytdusDSdWfWkaNzw==
+ dependencies:
+ "@types/react" "*"
+
+"@types/react-transition-group@^4.4.0":
+ version "4.4.10"
+ resolved "https://registry.yarnpkg.com/@types/react-transition-group/-/react-transition-group-4.4.10.tgz#6ee71127bdab1f18f11ad8fb3322c6da27c327ac"
+ integrity sha512-hT/+s0VQs2ojCX823m60m5f0sL5idt9SO6Tj6Dg+rdphGPIeJbJ6CxvBYkgkGKrYeDjvIpKTR38UzmtHJOGW3Q==
+ dependencies:
+ "@types/react" "*"
+
+"@types/react@*", "@types/react@16 || 17 || 18":
+ version "18.2.47"
+ resolved "https://registry.yarnpkg.com/@types/react/-/react-18.2.47.tgz#85074b27ab563df01fbc3f68dc64bf7050b0af40"
+ integrity sha512-xquNkkOirwyCgoClNk85BjP+aqnIS+ckAJ8i37gAbDs14jfW/J23f2GItAf33oiUPQnqNMALiFeoM9Y5mbjpVQ==
+ dependencies:
+ "@types/prop-types" "*"
+ "@types/scheduler" "*"
+ csstype "^3.0.2"
+
+"@types/responselike@^1.0.0":
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/@types/responselike/-/responselike-1.0.3.tgz#cc29706f0a397cfe6df89debfe4bf5cea159db50"
+ integrity sha512-H/+L+UkTV33uf49PH5pCAUBVPNj2nDBXTN+qS1dOwyyg24l3CcicicCA7ca+HMvJBZcFgl5r8e+RR6elsb4Lyw==
+ dependencies:
+ "@types/node" "*"
+
+"@types/scheduler@*":
+ version "0.16.8"
+ resolved "https://registry.yarnpkg.com/@types/scheduler/-/scheduler-0.16.8.tgz#ce5ace04cfeabe7ef87c0091e50752e36707deff"
+ integrity sha512-WZLiwShhwLRmeV6zH+GkbOFT6Z6VklCItrDioxUnv+u4Ll+8vKeFySoFyK/0ctcRpOmwAicELfmys1sDc/Rw+A==
+
+"@types/set-cookie-parser@^2.4.0":
+ version "2.4.7"
+ resolved "https://registry.yarnpkg.com/@types/set-cookie-parser/-/set-cookie-parser-2.4.7.tgz#4a341ed1d3a922573ee54db70b6f0a6d818290e7"
+ integrity sha512-+ge/loa0oTozxip6zmhRIk8Z/boU51wl9Q6QdLZcokIGMzY5lFXYy/x7Htj2HTC6/KZP1hUbZ1ekx8DYXICvWg==
+ dependencies:
+ "@types/node" "*"
+
+"@types/through@*":
+ version "0.0.33"
+ resolved "https://registry.yarnpkg.com/@types/through/-/through-0.0.33.tgz#14ebf599320e1c7851e7d598149af183c6b9ea56"
+ integrity sha512-HsJ+z3QuETzP3cswwtzt2vEIiHBk/dCcHGhbmG5X3ecnwFD/lPrMpliGXxSCg03L9AhrdwA4Oz/qfspkDW+xGQ==
+ dependencies:
+ "@types/node" "*"
+
+"@types/triple-beam@^1.3.2":
+ version "1.3.5"
+ resolved "https://registry.yarnpkg.com/@types/triple-beam/-/triple-beam-1.3.5.tgz#74fef9ffbaa198eb8b588be029f38b00299caa2c"
+ integrity sha512-6WaYesThRMCl19iryMYP7/x2OVgCtbIVflDGFpWnb9irXI3UjYE4AzmYuiUKY1AJstGijoY+MgUszMgRxIYTYw==
+
+"@types/use-sync-external-store@^0.0.3":
+ version "0.0.3"
+ resolved "https://registry.yarnpkg.com/@types/use-sync-external-store/-/use-sync-external-store-0.0.3.tgz#b6725d5f4af24ace33b36fafd295136e75509f43"
+ integrity sha512-EwmlvuaxPNej9+T4v5AuBPJa2x2UOJVdjCtDHgcDqitUeOtjnJKJ+apYjVcAoBEMjKW1VVFGZLUb5+qqa09XFA==
+
+"@ucast/core@^1.0.0", "@ucast/core@^1.4.1", "@ucast/core@^1.6.1":
+ version "1.10.2"
+ resolved "https://registry.yarnpkg.com/@ucast/core/-/core-1.10.2.tgz#30b6b893479823265368e528b61b042f752f2c92"
+ integrity sha512-ons5CwXZ/51wrUPfoduC+cO7AS1/wRb0ybpQJ9RrssossDxVy4t49QxWoWgfBDvVKsz9VXzBk9z0wqTdZ+Cq8g==
+
+"@ucast/js@^3.0.0":
+ version "3.0.3"
+ resolved "https://registry.yarnpkg.com/@ucast/js/-/js-3.0.3.tgz#6ff618a85bd95f1a8f46658cc663a1f798de327f"
+ integrity sha512-jBBqt57T5WagkAjqfCIIE5UYVdaXYgGkOFYv2+kjq2AVpZ2RIbwCo/TujJpDlwTVluUI+WpnRpoGU2tSGlEvFQ==
+ dependencies:
+ "@ucast/core" "^1.0.0"
+
+"@ucast/mongo2js@^1.3.0":
+ version "1.3.4"
+ resolved "https://registry.yarnpkg.com/@ucast/mongo2js/-/mongo2js-1.3.4.tgz#579f9e5eb074cba54640d5c70c71c500580f3af3"
+ integrity sha512-ahazOr1HtelA5AC1KZ9x0UwPMqqimvfmtSm/PRRSeKKeE5G2SCqTgwiNzO7i9jS8zA3dzXpKVPpXMkcYLnyItA==
+ dependencies:
+ "@ucast/core" "^1.6.1"
+ "@ucast/js" "^3.0.0"
+ "@ucast/mongo" "^2.4.0"
+
+"@ucast/mongo@^2.4.0":
+ version "2.4.3"
+ resolved "https://registry.yarnpkg.com/@ucast/mongo/-/mongo-2.4.3.tgz#92b1dd7c0ab06a907f2ab1422aa3027518ccc05e"
+ integrity sha512-XcI8LclrHWP83H+7H2anGCEeDq0n+12FU2mXCTz6/Tva9/9ddK/iacvvhCyW6cijAAOILmt0tWplRyRhVyZLsA==
+ dependencies:
+ "@ucast/core" "^1.4.1"
+
+"@uiw/codemirror-extensions-basic-setup@4.21.21":
+ version "4.21.21"
+ resolved "https://registry.yarnpkg.com/@uiw/codemirror-extensions-basic-setup/-/codemirror-extensions-basic-setup-4.21.21.tgz#243ef309cb53253b14187649a7abc0d996420a20"
+ integrity sha512-+0i9dPrRSa8Mf0CvyrMvnAhajnqwsP3IMRRlaHDRgsSGL8igc4z7MhvUPn+7cWFAAqWzQRhMdMSWzo6/TEa3EA==
+ dependencies:
+ "@codemirror/autocomplete" "^6.0.0"
+ "@codemirror/commands" "^6.0.0"
+ "@codemirror/language" "^6.0.0"
+ "@codemirror/lint" "^6.0.0"
+ "@codemirror/search" "^6.0.0"
+ "@codemirror/state" "^6.0.0"
+ "@codemirror/view" "^6.0.0"
+
+"@uiw/react-codemirror@^4.21.21":
+ version "4.21.21"
+ resolved "https://registry.yarnpkg.com/@uiw/react-codemirror/-/react-codemirror-4.21.21.tgz#986b18dbd6dc69aa470fc3d4e47b89b504af6778"
+ integrity sha512-PaxBMarufMWoR0qc5zuvBSt76rJ9POm9qoOaJbqRmnNL2viaF+d+Paf2blPSlm1JSnqn7hlRjio+40nZJ9TKzw==
+ dependencies:
+ "@babel/runtime" "^7.18.6"
+ "@codemirror/commands" "^6.1.0"
+ "@codemirror/state" "^6.1.1"
+ "@codemirror/theme-one-dark" "^6.0.0"
+ "@uiw/codemirror-extensions-basic-setup" "4.21.21"
+ codemirror "^6.0.0"
+
+"@vitejs/plugin-react@4.1.0":
+ version "4.1.0"
+ resolved "https://registry.yarnpkg.com/@vitejs/plugin-react/-/plugin-react-4.1.0.tgz#e4f56f46fd737c5d386bb1f1ade86ba275fe09bd"
+ integrity sha512-rM0SqazU9iqPUraQ2JlIvReeaxOoRj6n+PzB1C0cBzIbd8qP336nC39/R9yPi3wVcah7E7j/kdU1uCUqMEU4OQ==
+ dependencies:
+ "@babel/core" "^7.22.20"
+ "@babel/plugin-transform-react-jsx-self" "^7.22.5"
+ "@babel/plugin-transform-react-jsx-source" "^7.22.5"
+ "@types/babel__core" "^7.20.2"
+ react-refresh "^0.14.0"
+
+"@webassemblyjs/ast@1.11.6", "@webassemblyjs/ast@^1.11.5":
+ version "1.11.6"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.11.6.tgz#db046555d3c413f8966ca50a95176a0e2c642e24"
+ integrity sha512-IN1xI7PwOvLPgjcf180gC1bqn3q/QaOCwYUahIOhbYUu8KA/3tw2RT/T0Gidi1l7Hhj5D/INhJxiICObqpMu4Q==
+ dependencies:
+ "@webassemblyjs/helper-numbers" "1.11.6"
+ "@webassemblyjs/helper-wasm-bytecode" "1.11.6"
+
+"@webassemblyjs/floating-point-hex-parser@1.11.6":
+ version "1.11.6"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.6.tgz#dacbcb95aff135c8260f77fa3b4c5fea600a6431"
+ integrity sha512-ejAj9hfRJ2XMsNHk/v6Fu2dGS+i4UaXBXGemOfQ/JfQ6mdQg/WXtwleQRLLS4OvfDhv8rYnVwH27YJLMyYsxhw==
+
+"@webassemblyjs/helper-api-error@1.11.6":
+ version "1.11.6"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.6.tgz#6132f68c4acd59dcd141c44b18cbebbd9f2fa768"
+ integrity sha512-o0YkoP4pVu4rN8aTJgAyj9hC2Sv5UlkzCHhxqWj8butaLvnpdc2jOwh4ewE6CX0txSfLn/UYaV/pheS2Txg//Q==
+
+"@webassemblyjs/helper-buffer@1.11.6":
+ version "1.11.6"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.6.tgz#b66d73c43e296fd5e88006f18524feb0f2c7c093"
+ integrity sha512-z3nFzdcp1mb8nEOFFk8DrYLpHvhKC3grJD2ardfKOzmbmJvEf/tPIqCY+sNcwZIY8ZD7IkB2l7/pqhUhqm7hLA==
+
+"@webassemblyjs/helper-numbers@1.11.6":
+ version "1.11.6"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.6.tgz#cbce5e7e0c1bd32cf4905ae444ef64cea919f1b5"
+ integrity sha512-vUIhZ8LZoIWHBohiEObxVm6hwP034jwmc9kuq5GdHZH0wiLVLIPcMCdpJzG4C11cHoQ25TFIQj9kaVADVX7N3g==
+ dependencies:
+ "@webassemblyjs/floating-point-hex-parser" "1.11.6"
+ "@webassemblyjs/helper-api-error" "1.11.6"
+ "@xtuc/long" "4.2.2"
+
+"@webassemblyjs/helper-wasm-bytecode@1.11.6":
+ version "1.11.6"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.6.tgz#bb2ebdb3b83aa26d9baad4c46d4315283acd51e9"
+ integrity sha512-sFFHKwcmBprO9e7Icf0+gddyWYDViL8bpPjJJl0WHxCdETktXdmtWLGVzoHbqUcY4Be1LkNfwTmXOJUFZYSJdA==
+
+"@webassemblyjs/helper-wasm-section@1.11.6":
+ version "1.11.6"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.6.tgz#ff97f3863c55ee7f580fd5c41a381e9def4aa577"
+ integrity sha512-LPpZbSOwTpEC2cgn4hTydySy1Ke+XEu+ETXuoyvuyezHO3Kjdu90KK95Sh9xTbmjrCsUwvWwCOQQNta37VrS9g==
+ dependencies:
+ "@webassemblyjs/ast" "1.11.6"
+ "@webassemblyjs/helper-buffer" "1.11.6"
+ "@webassemblyjs/helper-wasm-bytecode" "1.11.6"
+ "@webassemblyjs/wasm-gen" "1.11.6"
+
+"@webassemblyjs/ieee754@1.11.6":
+ version "1.11.6"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/ieee754/-/ieee754-1.11.6.tgz#bb665c91d0b14fffceb0e38298c329af043c6e3a"
+ integrity sha512-LM4p2csPNvbij6U1f19v6WR56QZ8JcHg3QIJTlSwzFcmx6WSORicYj6I63f9yU1kEUtrpG+kjkiIAkevHpDXrg==
+ dependencies:
+ "@xtuc/ieee754" "^1.2.0"
+
+"@webassemblyjs/leb128@1.11.6":
+ version "1.11.6"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/leb128/-/leb128-1.11.6.tgz#70e60e5e82f9ac81118bc25381a0b283893240d7"
+ integrity sha512-m7a0FhE67DQXgouf1tbN5XQcdWoNgaAuoULHIfGFIEVKA6tu/edls6XnIlkmS6FrXAquJRPni3ZZKjw6FSPjPQ==
+ dependencies:
+ "@xtuc/long" "4.2.2"
+
+"@webassemblyjs/utf8@1.11.6":
+ version "1.11.6"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/utf8/-/utf8-1.11.6.tgz#90f8bc34c561595fe156603be7253cdbcd0fab5a"
+ integrity sha512-vtXf2wTQ3+up9Zsg8sa2yWiQpzSsMyXj0qViVP6xKGCUT8p8YJ6HqI7l5eCnWx1T/FYdsv07HQs2wTFbbof/RA==
+
+"@webassemblyjs/wasm-edit@^1.11.5":
+ version "1.11.6"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.6.tgz#c72fa8220524c9b416249f3d94c2958dfe70ceab"
+ integrity sha512-Ybn2I6fnfIGuCR+Faaz7YcvtBKxvoLV3Lebn1tM4o/IAJzmi9AWYIPWpyBfU8cC+JxAO57bk4+zdsTjJR+VTOw==
+ dependencies:
+ "@webassemblyjs/ast" "1.11.6"
+ "@webassemblyjs/helper-buffer" "1.11.6"
+ "@webassemblyjs/helper-wasm-bytecode" "1.11.6"
+ "@webassemblyjs/helper-wasm-section" "1.11.6"
+ "@webassemblyjs/wasm-gen" "1.11.6"
+ "@webassemblyjs/wasm-opt" "1.11.6"
+ "@webassemblyjs/wasm-parser" "1.11.6"
+ "@webassemblyjs/wast-printer" "1.11.6"
+
+"@webassemblyjs/wasm-gen@1.11.6":
+ version "1.11.6"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.6.tgz#fb5283e0e8b4551cc4e9c3c0d7184a65faf7c268"
+ integrity sha512-3XOqkZP/y6B4F0PBAXvI1/bky7GryoogUtfwExeP/v7Nzwo1QLcq5oQmpKlftZLbT+ERUOAZVQjuNVak6UXjPA==
+ dependencies:
+ "@webassemblyjs/ast" "1.11.6"
+ "@webassemblyjs/helper-wasm-bytecode" "1.11.6"
+ "@webassemblyjs/ieee754" "1.11.6"
+ "@webassemblyjs/leb128" "1.11.6"
+ "@webassemblyjs/utf8" "1.11.6"
+
+"@webassemblyjs/wasm-opt@1.11.6":
+ version "1.11.6"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.6.tgz#d9a22d651248422ca498b09aa3232a81041487c2"
+ integrity sha512-cOrKuLRE7PCe6AsOVl7WasYf3wbSo4CeOk6PkrjS7g57MFfVUF9u6ysQBBODX0LdgSvQqRiGz3CXvIDKcPNy4g==
+ dependencies:
+ "@webassemblyjs/ast" "1.11.6"
+ "@webassemblyjs/helper-buffer" "1.11.6"
+ "@webassemblyjs/wasm-gen" "1.11.6"
+ "@webassemblyjs/wasm-parser" "1.11.6"
+
+"@webassemblyjs/wasm-parser@1.11.6", "@webassemblyjs/wasm-parser@^1.11.5":
+ version "1.11.6"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.6.tgz#bb85378c527df824004812bbdb784eea539174a1"
+ integrity sha512-6ZwPeGzMJM3Dqp3hCsLgESxBGtT/OeCvCZ4TA1JUPYgmhAx38tTPR9JaKy0S5H3evQpO/h2uWs2j6Yc/fjkpTQ==
+ dependencies:
+ "@webassemblyjs/ast" "1.11.6"
+ "@webassemblyjs/helper-api-error" "1.11.6"
+ "@webassemblyjs/helper-wasm-bytecode" "1.11.6"
+ "@webassemblyjs/ieee754" "1.11.6"
+ "@webassemblyjs/leb128" "1.11.6"
+ "@webassemblyjs/utf8" "1.11.6"
+
+"@webassemblyjs/wast-printer@1.11.6":
+ version "1.11.6"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-printer/-/wast-printer-1.11.6.tgz#a7bf8dd7e362aeb1668ff43f35cb849f188eff20"
+ integrity sha512-JM7AhRcE+yW2GWYaKeHL5vt4xqee5N2WcezptmgyhNS+ScggqcT1OtXykhAb13Sn5Yas0j2uv9tHgrjwvzAP4A==
+ dependencies:
+ "@webassemblyjs/ast" "1.11.6"
+ "@xtuc/long" "4.2.2"
+
+"@xmldom/xmldom@^0.8.3":
+ version "0.8.10"
+ resolved "https://registry.yarnpkg.com/@xmldom/xmldom/-/xmldom-0.8.10.tgz#a1337ca426aa61cef9fe15b5b28e340a72f6fa99"
+ integrity sha512-2WALfTl4xo2SkGCYRt6rDTFfk9R1czmBvUQy12gK2KuRKIpWEhcbbzy8EZXtz/jkRqHX8bFEc6FC1HjX4TUWYw==
+
+"@xtuc/ieee754@^1.2.0":
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/@xtuc/ieee754/-/ieee754-1.2.0.tgz#eef014a3145ae477a1cbc00cd1e552336dceb790"
+ integrity sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==
+
+"@xtuc/long@4.2.2":
+ version "4.2.2"
+ resolved "https://registry.yarnpkg.com/@xtuc/long/-/long-4.2.2.tgz#d291c6a4e97989b5c61d9acf396ae4fe133a718d"
+ integrity sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==
+
+"@zxing/text-encoding@0.9.0":
+ version "0.9.0"
+ resolved "https://registry.yarnpkg.com/@zxing/text-encoding/-/text-encoding-0.9.0.tgz#fb50ffabc6c7c66a0c96b4c03e3d9be74864b70b"
+ integrity sha512-U/4aVJ2mxI0aDNI8Uq0wEhMgY+u4CNtEb0om3+y3+niDAsoTCOB33UF0sxpzqzdqXLqmvc+vZyAt4O8pPdfkwA==
+
+abbrev@1:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8"
+ integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==
+
+accepts@^1.3.5:
+ version "1.3.8"
+ resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.8.tgz#0bf0be125b67014adcb0b0921e62db7bffe16b2e"
+ integrity sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==
+ dependencies:
+ mime-types "~2.1.34"
+ negotiator "0.6.3"
+
+acorn-import-assertions@^1.9.0:
+ version "1.9.0"
+ resolved "https://registry.yarnpkg.com/acorn-import-assertions/-/acorn-import-assertions-1.9.0.tgz#507276249d684797c84e0734ef84860334cfb1ac"
+ integrity sha512-cmMwop9x+8KFhxvKrKfPYmN6/pKTYYHBqLa0DfvVZcKMJWNyWLnaqND7dx/qn66R7ewM1UX5XMaDVP5wlVTaVA==
+
+acorn-walk@^8.0.0:
+ version "8.3.1"
+ resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.3.1.tgz#2f10f5b69329d90ae18c58bf1fa8fccd8b959a43"
+ integrity sha512-TgUZgYvqZprrl7YldZNoa9OciCAyZR+Ejm9eXzKCmjsF5IKp/wgQ7Z/ZpjpGTIUPwrHQIcYeI8qDh4PsEwxMbw==
+
+acorn@^8.0.4, acorn@^8.7.1, acorn@^8.8.2:
+ version "8.11.3"
+ resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.11.3.tgz#71e0b14e13a4ec160724b38fb7b0f233b1b81d7a"
+ integrity sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==
+
+addressparser@1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/addressparser/-/addressparser-1.0.1.tgz#47afbe1a2a9262191db6838e4fd1d39b40821746"
+ integrity sha512-aQX7AISOMM7HFE0iZ3+YnD07oIeJqWGVnJ+ZIKaBZAk03ftmVYVqsGas/rbXKR21n4D/hKCSHypvcyOkds/xzg==
+
+agent-base@6:
+ version "6.0.2"
+ resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-6.0.2.tgz#49fff58577cfee3f37176feab4c22e00f86d7f77"
+ integrity sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==
+ dependencies:
+ debug "4"
+
+aggregate-error@^3.0.0:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/aggregate-error/-/aggregate-error-3.1.0.tgz#92670ff50f5359bdb7a3e0d40d0ec30c5737687a"
+ integrity sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==
+ dependencies:
+ clean-stack "^2.0.0"
+ indent-string "^4.0.0"
+
+ajv-formats@^2.1.1:
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/ajv-formats/-/ajv-formats-2.1.1.tgz#6e669400659eb74973bbf2e33327180a0996b520"
+ integrity sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==
+ dependencies:
+ ajv "^8.0.0"
+
+ajv-keywords@^3.5.2:
+ version "3.5.2"
+ resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.5.2.tgz#31f29da5ab6e00d1c2d329acf7b5929614d5014d"
+ integrity sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==
+
+ajv-keywords@^5.1.0:
+ version "5.1.0"
+ resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-5.1.0.tgz#69d4d385a4733cdbeab44964a1170a88f87f0e16"
+ integrity sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==
+ dependencies:
+ fast-deep-equal "^3.1.3"
+
+ajv@^6.12.5:
+ version "6.12.6"
+ resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4"
+ integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==
+ dependencies:
+ fast-deep-equal "^3.1.1"
+ fast-json-stable-stringify "^2.0.0"
+ json-schema-traverse "^0.4.1"
+ uri-js "^4.2.2"
+
+ajv@^8.0.0, ajv@^8.9.0:
+ version "8.12.0"
+ resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.12.0.tgz#d1a0527323e22f53562c567c00991577dfbe19d1"
+ integrity sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==
+ dependencies:
+ fast-deep-equal "^3.1.1"
+ json-schema-traverse "^1.0.0"
+ require-from-string "^2.0.2"
+ uri-js "^4.2.2"
+
+ansi-align@^3.0.0:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/ansi-align/-/ansi-align-3.0.1.tgz#0cdf12e111ace773a86e9a1fad1225c43cb19a59"
+ integrity sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==
+ dependencies:
+ string-width "^4.1.0"
+
+ansi-escapes@^4.2.1:
+ version "4.3.2"
+ resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.3.2.tgz#6b2291d1db7d98b6521d5f1efa42d0f3a9feb65e"
+ integrity sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==
+ dependencies:
+ type-fest "^0.21.3"
+
+ansi-html-community@0.0.8, ansi-html-community@^0.0.8:
+ version "0.0.8"
+ resolved "https://registry.yarnpkg.com/ansi-html-community/-/ansi-html-community-0.0.8.tgz#69fbc4d6ccbe383f9736934ae34c3f8290f1bf41"
+ integrity sha512-1APHAyr3+PCamwNw3bXCPp4HFLONZt/yIH0sZp0/469KWNTEy+qN5jQ3GVX6DMZ1UXAi34yVwtTeaG/HpBuuzw==
+
+ansi-regex@^2.0.0:
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df"
+ integrity sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==
+
+ansi-regex@^4.1.0:
+ version "4.1.1"
+ resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.1.tgz#164daac87ab2d6f6db3a29875e2d1766582dabed"
+ integrity sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==
+
+ansi-regex@^5.0.1:
+ version "5.0.1"
+ resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304"
+ integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==
+
+ansi-styles@^2.2.1:
+ version "2.2.1"
+ resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe"
+ integrity sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA==
+
+ansi-styles@^3.2.1:
+ version "3.2.1"
+ resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d"
+ integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==
+ dependencies:
+ color-convert "^1.9.0"
+
+ansi-styles@^4.0.0, ansi-styles@^4.1.0:
+ version "4.3.0"
+ resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937"
+ integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==
+ dependencies:
+ color-convert "^2.0.1"
+
+ansi-styles@^5.0.0:
+ version "5.2.0"
+ resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-5.2.0.tgz#07449690ad45777d1924ac2abb2fc8895dba836b"
+ integrity sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==
+
+any-promise@^1.0.0:
+ version "1.3.0"
+ resolved "https://registry.yarnpkg.com/any-promise/-/any-promise-1.3.0.tgz#abc6afeedcea52e809cdc0376aed3ce39635d17f"
+ integrity sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==
+
+anymatch@~3.1.2:
+ version "3.1.3"
+ resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.3.tgz#790c58b19ba1720a84205b57c618d5ad8524973e"
+ integrity sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==
+ dependencies:
+ normalize-path "^3.0.0"
+ picomatch "^2.0.4"
+
+"aproba@^1.0.3 || ^2.0.0":
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/aproba/-/aproba-2.0.0.tgz#52520b8ae5b569215b354efc0caa3fe1e45a8adc"
+ integrity sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==
+
+are-we-there-yet@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-2.0.0.tgz#372e0e7bd279d8e94c653aaa1f67200884bf3e1c"
+ integrity sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw==
+ dependencies:
+ delegates "^1.0.0"
+ readable-stream "^3.6.0"
+
+argparse@^2.0.1:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38"
+ integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==
+
+argparse@~1.0.9:
+ version "1.0.10"
+ resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911"
+ integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==
+ dependencies:
+ sprintf-js "~1.0.2"
+
+aria-hidden@^1.1.1, aria-hidden@^1.2.3:
+ version "1.2.3"
+ resolved "https://registry.yarnpkg.com/aria-hidden/-/aria-hidden-1.2.3.tgz#14aeb7fb692bbb72d69bebfa47279c1fd725e954"
+ integrity sha512-xcLxITLe2HYa1cnYnwCjkOO1PqUHQpozB8x9AR0OgWN2woOBi5kSDVxKfd0b7sb1hw5qFeJhXm9H1nu3xSfLeQ==
+ dependencies:
+ tslib "^2.0.0"
+
+aria-query@5.1.3:
+ version "5.1.3"
+ resolved "https://registry.yarnpkg.com/aria-query/-/aria-query-5.1.3.tgz#19db27cd101152773631396f7a95a3b58c22c35e"
+ integrity sha512-R5iJ5lkuHybztUfuOAznmboyjWq8O6sqNqtK7CLOqdydi54VNbORp49mb14KbWgG1QD3JFO9hJdZ+y4KutfdOQ==
+ dependencies:
+ deep-equal "^2.0.5"
+
+aria-query@^5.0.0:
+ version "5.3.0"
+ resolved "https://registry.yarnpkg.com/aria-query/-/aria-query-5.3.0.tgz#650c569e41ad90b51b3d7df5e5eed1c7549c103e"
+ integrity sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==
+ dependencies:
+ dequal "^2.0.3"
+
+arr-diff@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-4.0.0.tgz#d6461074febfec71e7e15235761a329a5dc7c520"
+ integrity sha512-YVIQ82gZPGBebQV/a8dar4AitzCQs0jjXwMPZllpXMaGjXPYVUawSxQrRsjhjupyVxEvbHgUmIhKVlND+j02kA==
+
+arr-flatten@^1.1.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.1.0.tgz#36048bbff4e7b47e136644316c99669ea5ae91f1"
+ integrity sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==
+
+arr-union@^3.1.0:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/arr-union/-/arr-union-3.1.0.tgz#e39b09aea9def866a8f206e288af63919bae39c4"
+ integrity sha512-sKpyeERZ02v1FeCZT8lrfJq5u6goHCtpTAzPwJYe7c8SPFOboNjNg1vz2L4VTn9T4PQxEx13TbXLmYUcS6Ug7Q==
+
+array-buffer-byte-length@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/array-buffer-byte-length/-/array-buffer-byte-length-1.0.0.tgz#fabe8bc193fea865f317fe7807085ee0dee5aead"
+ integrity sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A==
+ dependencies:
+ call-bind "^1.0.2"
+ is-array-buffer "^3.0.1"
+
+array-each@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/array-each/-/array-each-1.0.1.tgz#a794af0c05ab1752846ee753a1f211a05ba0c44f"
+ integrity sha512-zHjL5SZa68hkKHBFBK6DJCTtr9sfTCPCaph/L7tMSLcTFgy+zX7E+6q5UArbtOtMBCtxdICpfTCspRse+ywyXA==
+
+array-slice@^1.0.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/array-slice/-/array-slice-1.1.0.tgz#e368ea15f89bc7069f7ffb89aec3a6c7d4ac22d4"
+ integrity sha512-B1qMD3RBP7O8o0H2KbrXDyB0IccejMF15+87Lvlor12ONPRHP6gTjXMNkt/d3ZuOGbAe66hFmaCfECI24Ufp6w==
+
+array-union@^2.1.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d"
+ integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==
+
+array-unique@^0.3.2:
+ version "0.3.2"
+ resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428"
+ integrity sha512-SleRWjh9JUud2wH1hPs9rZBZ33H6T9HOiL0uwGnGx9FpE6wKGyfWugmbkEOIs6qWrZhg0LWeLziLrEwQJhs5mQ==
+
+asn1.js@^5.3.0:
+ version "5.4.1"
+ resolved "https://registry.yarnpkg.com/asn1.js/-/asn1.js-5.4.1.tgz#11a980b84ebb91781ce35b0fdc2ee294e3783f07"
+ integrity sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA==
+ dependencies:
+ bn.js "^4.0.0"
+ inherits "^2.0.1"
+ minimalistic-assert "^1.0.0"
+ safer-buffer "^2.1.0"
+
+assign-symbols@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367"
+ integrity sha512-Q+JC7Whu8HhmTdBph/Tq59IoRtoy6KAm5zzPv00WdujX82lbAL8K7WVjne7vdCsAmbF4AYaDOPyO3k0kl8qIrw==
+
+async@^3.2.3:
+ version "3.2.5"
+ resolved "https://registry.yarnpkg.com/async/-/async-3.2.5.tgz#ebd52a8fdaf7a2289a24df399f8d8485c8a46b66"
+ integrity sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg==
+
+asynckit@^0.4.0:
+ version "0.4.0"
+ resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79"
+ integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==
+
+atob@^2.1.2:
+ version "2.1.2"
+ resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9"
+ integrity sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==
+
+available-typed-arrays@^1.0.5:
+ version "1.0.5"
+ resolved "https://registry.yarnpkg.com/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz#92f95616501069d07d10edb2fc37d3e1c65123b7"
+ integrity sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==
+
+aws-sdk@^2.1539.0:
+ version "2.1539.0"
+ resolved "https://registry.yarnpkg.com/aws-sdk/-/aws-sdk-2.1539.0.tgz#9bb095b23ffb6a23ee5102c0155e46a933a306bf"
+ integrity sha512-gqQgZPFWSfYFkkTDI0JEF9vs8ASYFm8z1+hH933sXMhnTqUB5jgaujcicpe3PJ3cy/SLAvNSzc6MhKoZiIU9+g==
+ dependencies:
+ buffer "4.9.2"
+ events "1.1.1"
+ ieee754 "1.1.13"
+ jmespath "0.16.0"
+ querystring "0.2.0"
+ sax "1.2.1"
+ url "0.10.3"
+ util "^0.12.4"
+ uuid "8.0.0"
+ xml2js "0.5.0"
+
+axios@1.6.0:
+ version "1.6.0"
+ resolved "https://registry.yarnpkg.com/axios/-/axios-1.6.0.tgz#f1e5292f26b2fd5c2e66876adc5b06cdbd7d2102"
+ integrity sha512-EZ1DYihju9pwVB+jg67ogm+Tmqc6JmhamRN6I4Zt8DfZu5lbcQGw3ozH9lFejSJgs/ibaef3A9PMXPLeefFGJg==
+ dependencies:
+ follow-redirects "^1.15.0"
+ form-data "^4.0.0"
+ proxy-from-env "^1.1.0"
+
+axios@^0.26.0:
+ version "0.26.1"
+ resolved "https://registry.yarnpkg.com/axios/-/axios-0.26.1.tgz#1ede41c51fcf51bbbd6fd43669caaa4f0495aaa9"
+ integrity sha512-fPwcX4EvnSHuInCMItEhAGnaSEXRBjtzh9fOtsE6E1G6p7vl7edEeZe11QHf18+6+9gR5PbKV/sGKNaD8YaMeA==
+ dependencies:
+ follow-redirects "^1.14.8"
+
+axios@^1.2.6:
+ version "1.6.5"
+ resolved "https://registry.yarnpkg.com/axios/-/axios-1.6.5.tgz#2c090da14aeeab3770ad30c3a1461bc970fb0cd8"
+ integrity sha512-Ii012v05KEVuUoFWmMW/UQv9aRIc3ZwkWDcM+h5Il8izZCtRVpDUfwpoFf7eOtajT3QiGR4yDUx7lPqHJULgbg==
+ dependencies:
+ follow-redirects "^1.15.4"
+ form-data "^4.0.0"
+ proxy-from-env "^1.1.0"
+
+b4a@^1.6.4:
+ version "1.6.4"
+ resolved "https://registry.yarnpkg.com/b4a/-/b4a-1.6.4.tgz#ef1c1422cae5ce6535ec191baeed7567443f36c9"
+ integrity sha512-fpWrvyVHEKyeEvbKZTVOeZF3VSKKWtJxFIxX/jaVPf+cLbGUSitjb49pHLqPV2BUNNZ0LcoeEGfE/YCpyDYHIw==
+
+babel-plugin-macros@^3.1.0:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/babel-plugin-macros/-/babel-plugin-macros-3.1.0.tgz#9ef6dc74deb934b4db344dc973ee851d148c50c1"
+ integrity sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==
+ dependencies:
+ "@babel/runtime" "^7.12.5"
+ cosmiconfig "^7.0.0"
+ resolve "^1.19.0"
+
+"babel-plugin-styled-components@>= 1.12.0":
+ version "2.1.4"
+ resolved "https://registry.yarnpkg.com/babel-plugin-styled-components/-/babel-plugin-styled-components-2.1.4.tgz#9a1f37c7f32ef927b4b008b529feb4a2c82b1092"
+ integrity sha512-Xgp9g+A/cG47sUyRwwYxGM4bR/jDRg5N6it/8+HxCnbT5XNKSKDT9xm4oag/osgqjC2It/vH0yXsomOG6k558g==
+ dependencies:
+ "@babel/helper-annotate-as-pure" "^7.22.5"
+ "@babel/helper-module-imports" "^7.22.5"
+ "@babel/plugin-syntax-jsx" "^7.22.5"
+ lodash "^4.17.21"
+ picomatch "^2.3.1"
+
+balanced-match@^1.0.0:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee"
+ integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==
+
+base64-js@^1.0.2, base64-js@^1.3.1:
+ version "1.5.1"
+ resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a"
+ integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==
+
+base@^0.11.1:
+ version "0.11.2"
+ resolved "https://registry.yarnpkg.com/base/-/base-0.11.2.tgz#7bde5ced145b6d551a90db87f83c558b4eb48a8f"
+ integrity sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==
+ dependencies:
+ cache-base "^1.0.1"
+ class-utils "^0.3.5"
+ component-emitter "^1.2.1"
+ define-property "^1.0.0"
+ isobject "^3.0.1"
+ mixin-deep "^1.2.0"
+ pascalcase "^0.1.1"
+
+bcryptjs@2.4.3:
+ version "2.4.3"
+ resolved "https://registry.yarnpkg.com/bcryptjs/-/bcryptjs-2.4.3.tgz#9ab5627b93e60621ff7cdac5da9733027df1d0cb"
+ integrity sha512-V/Hy/X9Vt7f3BbPJEi8BdVFMByHi+jNXrYkW3huaybV/kQ0KJg0Y6PkEMbn+zeT+i+SiKZ/HMqJGIIt4LZDqNQ==
+
+better-sqlite3@8.0.1:
+ version "8.0.1"
+ resolved "https://registry.yarnpkg.com/better-sqlite3/-/better-sqlite3-8.0.1.tgz#3a596d21fbcefadf36f94e126c5cf24d5697d0b8"
+ integrity sha512-JhTZjpyapA1icCEjIZB4TSSgkGdFgpWZA2Wszg7Cf4JwJwKQmbvuNnJBeR+EYG/Z29OXvR4G//Rbg31BW/Z7Yg==
+ dependencies:
+ bindings "^1.5.0"
+ prebuild-install "^7.1.0"
+
+big-integer@^1.6.16, big-integer@^1.6.44:
+ version "1.6.52"
+ resolved "https://registry.yarnpkg.com/big-integer/-/big-integer-1.6.52.tgz#60a887f3047614a8e1bffe5d7173490a97dc8c85"
+ integrity sha512-QxD8cf2eVqJOOz63z6JIN9BzvVs/dlySa5HGSBH5xtR8dPteIRQnBxxKqkNTiT6jbDTF6jAfrd4oMcND9RGbQg==
+
+big.js@^5.2.2:
+ version "5.2.2"
+ resolved "https://registry.yarnpkg.com/big.js/-/big.js-5.2.2.tgz#65f0af382f578bcdc742bd9c281e9cb2d7768328"
+ integrity sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==
+
+binary-extensions@^2.0.0:
+ version "2.2.0"
+ resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d"
+ integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==
+
+bindings@^1.5.0:
+ version "1.5.0"
+ resolved "https://registry.yarnpkg.com/bindings/-/bindings-1.5.0.tgz#10353c9e945334bc0511a6d90b38fbc7c9c504df"
+ integrity sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==
+ dependencies:
+ file-uri-to-path "1.0.0"
+
+bl@^4.0.3, bl@^4.1.0:
+ version "4.1.0"
+ resolved "https://registry.yarnpkg.com/bl/-/bl-4.1.0.tgz#451535264182bec2fbbc83a62ab98cf11d9f7b3a"
+ integrity sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==
+ dependencies:
+ buffer "^5.5.0"
+ inherits "^2.0.4"
+ readable-stream "^3.4.0"
+
+bn.js@^4.0.0, bn.js@^4.11.9:
+ version "4.12.0"
+ resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.12.0.tgz#775b3f278efbb9718eec7361f483fb36fbbfea88"
+ integrity sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==
+
+boolbase@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/boolbase/-/boolbase-1.0.0.tgz#68dff5fbe60c51eb37725ea9e3ed310dcc1e776e"
+ integrity sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==
+
+bowser@^2.11.0:
+ version "2.11.0"
+ resolved "https://registry.yarnpkg.com/bowser/-/bowser-2.11.0.tgz#5ca3c35757a7aa5771500c70a73a9f91ef420a8f"
+ integrity sha512-AlcaJBi/pqqJBIQ8U9Mcpc9i8Aqxn88Skv5d+xBX006BY5u8N3mGLHa5Lgppa7L/HfwgwLgZ6NYs+Ag6uUmJRA==
+
+boxen@5.1.2:
+ version "5.1.2"
+ resolved "https://registry.yarnpkg.com/boxen/-/boxen-5.1.2.tgz#788cb686fc83c1f486dfa8a40c68fc2b831d2b50"
+ integrity sha512-9gYgQKXx+1nP8mP7CzFyaUARhg7D3n1dF/FnErWmu9l6JvGpNUN278h0aSb+QjoiKSWG+iZ3uHrcqk0qrY9RQQ==
+ dependencies:
+ ansi-align "^3.0.0"
+ camelcase "^6.2.0"
+ chalk "^4.1.0"
+ cli-boxes "^2.2.1"
+ string-width "^4.2.2"
+ type-fest "^0.20.2"
+ widest-line "^3.1.0"
+ wrap-ansi "^7.0.0"
+
+bplist-parser@^0.2.0:
+ version "0.2.0"
+ resolved "https://registry.yarnpkg.com/bplist-parser/-/bplist-parser-0.2.0.tgz#43a9d183e5bf9d545200ceac3e712f79ebbe8d0e"
+ integrity sha512-z0M+byMThzQmD9NILRniCUXYsYpjwnlO8N5uCFaCqIOpqRsJCrQL9NK3JsD67CN5a08nF5oIL2bD6loTdHOuKw==
+ dependencies:
+ big-integer "^1.6.44"
+
+brace-expansion@^1.1.7:
+ version "1.1.11"
+ resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd"
+ integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==
+ dependencies:
+ balanced-match "^1.0.0"
+ concat-map "0.0.1"
+
+brace-expansion@^2.0.1:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-2.0.1.tgz#1edc459e0f0c548486ecf9fc99f2221364b9a0ae"
+ integrity sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==
+ dependencies:
+ balanced-match "^1.0.0"
+
+braces@^2.3.1:
+ version "2.3.2"
+ resolved "https://registry.yarnpkg.com/braces/-/braces-2.3.2.tgz#5979fd3f14cd531565e5fa2df1abfff1dfaee729"
+ integrity sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==
+ dependencies:
+ arr-flatten "^1.1.0"
+ array-unique "^0.3.2"
+ extend-shallow "^2.0.1"
+ fill-range "^4.0.0"
+ isobject "^3.0.1"
+ repeat-element "^1.1.2"
+ snapdragon "^0.8.1"
+ snapdragon-node "^2.0.1"
+ split-string "^3.0.2"
+ to-regex "^3.0.1"
+
+braces@^3.0.2, braces@~3.0.2:
+ version "3.0.2"
+ resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107"
+ integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==
+ dependencies:
+ fill-range "^7.0.1"
+
+broadcast-channel@^3.4.1:
+ version "3.7.0"
+ resolved "https://registry.yarnpkg.com/broadcast-channel/-/broadcast-channel-3.7.0.tgz#2dfa5c7b4289547ac3f6705f9c00af8723889937"
+ integrity sha512-cIAKJXAxGJceNZGTZSBzMxzyOn72cVgPnKx4dc6LRjQgbaJUQqhy5rzL3zbMxkMWsGKkv2hSFkPRMEXfoMZ2Mg==
+ dependencies:
+ "@babel/runtime" "^7.7.2"
+ detect-node "^2.1.0"
+ js-sha3 "0.8.0"
+ microseconds "0.2.0"
+ nano-time "1.0.0"
+ oblivious-set "1.0.0"
+ rimraf "3.0.2"
+ unload "2.2.0"
+
+brorand@^1.1.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f"
+ integrity sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==
+
+browserslist-to-esbuild@1.2.0:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/browserslist-to-esbuild/-/browserslist-to-esbuild-1.2.0.tgz#5c5b9ca73106da02e0168007396c4ec4c1e6d643"
+ integrity sha512-ftrrbI/VHBgEnmnSyhkqvQVMp6jAKybfs0qMIlm7SLBrQTGMsdCIP4q3BoKeLsZTBQllIQtY9kbxgRYV2WU47g==
+ dependencies:
+ browserslist "^4.17.3"
+
+browserslist@^4.14.5, browserslist@^4.17.3, browserslist@^4.22.1, browserslist@^4.22.2:
+ version "4.22.2"
+ resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.22.2.tgz#704c4943072bd81ea18997f3bd2180e89c77874b"
+ integrity sha512-0UgcrvQmBDvZHFGdYUehrCNIazki7/lUP3kkoi/r3YB2amZbFM9J43ZRkJTXBUZK4gmx56+Sqk9+Vs9mwZx9+A==
+ dependencies:
+ caniuse-lite "^1.0.30001565"
+ electron-to-chromium "^1.4.601"
+ node-releases "^2.0.14"
+ update-browserslist-db "^1.0.13"
+
+buffer-equal-constant-time@1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz#f8e71132f7ffe6e01a5c9697a4c6f3e48d5cc819"
+ integrity sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==
+
+buffer-from@^1.0.0:
+ version "1.1.2"
+ resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5"
+ integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==
+
+buffer-writer@2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/buffer-writer/-/buffer-writer-2.0.0.tgz#ce7eb81a38f7829db09c873f2fbb792c0c98ec04"
+ integrity sha512-a7ZpuTZU1TRtnwyCNW3I5dc0wWNC3VR9S++Ewyk2HHZdrO3CQJqSpd+95Us590V6AL7JqUAH2IwZ/398PmNFgw==
+
+buffer@4.9.2:
+ version "4.9.2"
+ resolved "https://registry.yarnpkg.com/buffer/-/buffer-4.9.2.tgz#230ead344002988644841ab0244af8c44bbe3ef8"
+ integrity sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg==
+ dependencies:
+ base64-js "^1.0.2"
+ ieee754 "^1.1.4"
+ isarray "^1.0.0"
+
+buffer@^5.1.0, buffer@^5.5.0:
+ version "5.7.1"
+ resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.7.1.tgz#ba62e7c13133053582197160851a8f648e99eed0"
+ integrity sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==
+ dependencies:
+ base64-js "^1.3.1"
+ ieee754 "^1.1.13"
+
+buildmail@3.10.0:
+ version "3.10.0"
+ resolved "https://registry.yarnpkg.com/buildmail/-/buildmail-3.10.0.tgz#c6826d716e7945bb6f6b1434b53985e029a03159"
+ integrity sha512-6e5sDN/pl3en5Klqdfyir7LEIBiFr9oqZuvYaEyVwjxpIbBZN+98e0j87Fz2Ukl8ud32rbk9VGOZAnsOZ7pkaA==
+ dependencies:
+ addressparser "1.0.1"
+ libbase64 "0.1.0"
+ libmime "2.1.0"
+ libqp "1.1.0"
+ nodemailer-fetch "1.6.0"
+ nodemailer-shared "1.1.0"
+
+bundle-name@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/bundle-name/-/bundle-name-3.0.0.tgz#ba59bcc9ac785fb67ccdbf104a2bf60c099f0e1a"
+ integrity sha512-PKA4BeSvBpQKQ8iPOGCSiell+N8P+Tf1DlwqmYhpe2gAhKPHn8EYOxVT+ShuGmhg8lN8XiSlS80yiExKXrURlw==
+ dependencies:
+ run-applescript "^5.0.0"
+
+byte-size@7.0.1:
+ version "7.0.1"
+ resolved "https://registry.yarnpkg.com/byte-size/-/byte-size-7.0.1.tgz#b1daf3386de7ab9d706b941a748dbfc71130dee3"
+ integrity sha512-crQdqyCwhokxwV1UyDzLZanhkugAgft7vt0qbbdt60C6Zf3CAiGmtUCylbtYwrU6loOUw3euGrNtW1J651ot1A==
+
+bytes@3.1.2, bytes@^3.0.0:
+ version "3.1.2"
+ resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.2.tgz#8b0beeb98605adf1b128fa4386403c009e0221a5"
+ integrity sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==
+
+cache-base@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/cache-base/-/cache-base-1.0.1.tgz#0a7f46416831c8b662ee36fe4e7c59d76f666ab2"
+ integrity sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==
+ dependencies:
+ collection-visit "^1.0.0"
+ component-emitter "^1.2.1"
+ get-value "^2.0.6"
+ has-value "^1.0.0"
+ isobject "^3.0.1"
+ set-value "^2.0.0"
+ to-object-path "^0.3.0"
+ union-value "^1.0.0"
+ unset-value "^1.0.0"
+
+cache-content-type@^1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/cache-content-type/-/cache-content-type-1.0.1.tgz#035cde2b08ee2129f4a8315ea8f00a00dba1453c"
+ integrity sha512-IKufZ1o4Ut42YUrZSo8+qnMTrFuKkvyoLXUywKz9GJ5BrhOFGhLdkx9sG4KAnVvbY6kEcSFjLQul+DVmBm2bgA==
+ dependencies:
+ mime-types "^2.1.18"
+ ylru "^1.2.0"
+
+cacheable-lookup@^5.0.3:
+ version "5.0.4"
+ resolved "https://registry.yarnpkg.com/cacheable-lookup/-/cacheable-lookup-5.0.4.tgz#5a6b865b2c44357be3d5ebc2a467b032719a7005"
+ integrity sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA==
+
+cacheable-request@^7.0.2:
+ version "7.0.4"
+ resolved "https://registry.yarnpkg.com/cacheable-request/-/cacheable-request-7.0.4.tgz#7a33ebf08613178b403635be7b899d3e69bbe817"
+ integrity sha512-v+p6ongsrp0yTGbJXjgxPow2+DL93DASP4kXCDKb8/bwRtt9OEF3whggkkDkGNzgcWy2XaF4a8nZglC7uElscg==
+ dependencies:
+ clone-response "^1.0.2"
+ get-stream "^5.1.0"
+ http-cache-semantics "^4.0.0"
+ keyv "^4.0.0"
+ lowercase-keys "^2.0.0"
+ normalize-url "^6.0.1"
+ responselike "^2.0.0"
+
+call-bind@^1.0.0, call-bind@^1.0.2, call-bind@^1.0.4, call-bind@^1.0.5:
+ version "1.0.5"
+ resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.5.tgz#6fa2b7845ce0ea49bf4d8b9ef64727a2c2e2e513"
+ integrity sha512-C3nQxfFZxFRVoJoGKKI8y3MOEo129NQ+FgQ08iye+Mk4zNZZGdjfs06bVTr+DBSlA66Q2VEcMki/cUCP4SercQ==
+ dependencies:
+ function-bind "^1.1.2"
+ get-intrinsic "^1.2.1"
+ set-function-length "^1.1.1"
+
+callsites@^3.0.0:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73"
+ integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==
+
+camel-case@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/camel-case/-/camel-case-3.0.0.tgz#ca3c3688a4e9cf3a4cda777dc4dcbc713249cf73"
+ integrity sha512-+MbKztAYHXPr1jNTSKQF52VpcFjwY5RkR7fxksV8Doo4KAYc5Fl4UJRgthBbTmEx8C54DqahhbLJkDwjI3PI/w==
+ dependencies:
+ no-case "^2.2.0"
+ upper-case "^1.1.1"
+
+camel-case@^4.1.2:
+ version "4.1.2"
+ resolved "https://registry.yarnpkg.com/camel-case/-/camel-case-4.1.2.tgz#9728072a954f805228225a6deea6b38461e1bd5a"
+ integrity sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw==
+ dependencies:
+ pascal-case "^3.1.2"
+ tslib "^2.0.3"
+
+camelcase@^6.2.0:
+ version "6.3.0"
+ resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.3.0.tgz#5685b95eb209ac9c0c177467778c9c84df58ba9a"
+ integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==
+
+camelize@^1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/camelize/-/camelize-1.0.1.tgz#89b7e16884056331a35d6b5ad064332c91daa6c3"
+ integrity sha512-dU+Tx2fsypxTgtLoE36npi3UqcjSSMNYfkqgmoEhtZrraP5VWq0K7FkWVTYa8eMPtnU/G2txVsfdCJTn9uzpuQ==
+
+caniuse-lite@^1.0.30001565:
+ version "1.0.30001576"
+ resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001576.tgz#893be772cf8ee6056d6c1e2d07df365b9ec0a5c4"
+ integrity sha512-ff5BdakGe2P3SQsMsiqmt1Lc8221NR1VzHj5jXN5vBny9A6fpze94HiVV/n7XRosOlsShJcvMv5mdnpjOGCEgg==
+
+canvas@^2.11.2:
+ version "2.11.2"
+ resolved "https://registry.yarnpkg.com/canvas/-/canvas-2.11.2.tgz#553d87b1e0228c7ac0fc72887c3adbac4abbd860"
+ integrity sha512-ItanGBMrmRV7Py2Z+Xhs7cT+FNt5K0vPL4p9EZ/UX/Mu7hFbkxSjKF2KVtPwX7UYWp7dRKnrTvReflgrItJbdw==
+ dependencies:
+ "@mapbox/node-pre-gyp" "^1.0.0"
+ nan "^2.17.0"
+ simple-get "^3.0.3"
+
+chalk@4.1.1:
+ version "4.1.1"
+ resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.1.tgz#c80b3fab28bf6371e6863325eee67e618b77e6ad"
+ integrity sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==
+ dependencies:
+ ansi-styles "^4.1.0"
+ supports-color "^7.1.0"
+
+chalk@4.1.2, chalk@^4.1.0, chalk@^4.1.1, chalk@^4.1.2:
+ version "4.1.2"
+ resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01"
+ integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==
+ dependencies:
+ ansi-styles "^4.1.0"
+ supports-color "^7.1.0"
+
+chalk@^1.1.3:
+ version "1.1.3"
+ resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98"
+ integrity sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A==
+ dependencies:
+ ansi-styles "^2.2.1"
+ escape-string-regexp "^1.0.2"
+ has-ansi "^2.0.0"
+ strip-ansi "^3.0.0"
+ supports-color "^2.0.0"
+
+chalk@^2.0.1, chalk@^2.4.2:
+ version "2.4.2"
+ resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424"
+ integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==
+ dependencies:
+ ansi-styles "^3.2.1"
+ escape-string-regexp "^1.0.5"
+ supports-color "^5.3.0"
+
+change-case@^3.1.0:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/change-case/-/change-case-3.1.0.tgz#0e611b7edc9952df2e8513b27b42de72647dd17e"
+ integrity sha512-2AZp7uJZbYEzRPsFoa+ijKdvp9zsrnnt6+yFokfwEpeJm0xuJDVoxiRCAaTzyJND8GJkofo2IcKWaUZ/OECVzw==
+ dependencies:
+ camel-case "^3.0.0"
+ constant-case "^2.0.0"
+ dot-case "^2.1.0"
+ header-case "^1.0.0"
+ is-lower-case "^1.1.0"
+ is-upper-case "^1.1.0"
+ lower-case "^1.1.1"
+ lower-case-first "^1.0.0"
+ no-case "^2.3.2"
+ param-case "^2.1.0"
+ pascal-case "^2.0.0"
+ path-case "^2.1.0"
+ sentence-case "^2.1.0"
+ snake-case "^2.1.0"
+ swap-case "^1.1.0"
+ title-case "^2.1.0"
+ upper-case "^1.1.1"
+ upper-case-first "^1.1.0"
+
+chardet@^0.7.0:
+ version "0.7.0"
+ resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e"
+ integrity sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==
+
+chokidar@3.5.3, chokidar@^3.4.2, chokidar@^3.5.3:
+ version "3.5.3"
+ resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.3.tgz#1cf37c8707b932bd1af1ae22c0432e2acd1903bd"
+ integrity sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==
+ dependencies:
+ anymatch "~3.1.2"
+ braces "~3.0.2"
+ glob-parent "~5.1.2"
+ is-binary-path "~2.1.0"
+ is-glob "~4.0.1"
+ normalize-path "~3.0.0"
+ readdirp "~3.6.0"
+ optionalDependencies:
+ fsevents "~2.3.2"
+
+chownr@^1.1.1:
+ version "1.1.4"
+ resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.4.tgz#6fc9d7b42d32a583596337666e7d08084da2cc6b"
+ integrity sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==
+
+chownr@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/chownr/-/chownr-2.0.0.tgz#15bfbe53d2eab4cf70f18a8cd68ebe5b3cb1dece"
+ integrity sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==
+
+chrome-trace-event@^1.0.2:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz#1015eced4741e15d06664a957dbbf50d041e26ac"
+ integrity sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==
+
+ci-info@3.8.0:
+ version "3.8.0"
+ resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-3.8.0.tgz#81408265a5380c929f0bc665d62256628ce9ef91"
+ integrity sha512-eXTggHWSooYhq49F2opQhuHWgzucfF2YgODK4e1566GQs5BIfP30B0oenwBJHfWxAs2fyPB1s7Mg949zLf61Yw==
+
+class-utils@^0.3.5:
+ version "0.3.6"
+ resolved "https://registry.yarnpkg.com/class-utils/-/class-utils-0.3.6.tgz#f93369ae8b9a7ce02fd41faad0ca83033190c463"
+ integrity sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==
+ dependencies:
+ arr-union "^3.1.0"
+ define-property "^0.2.5"
+ isobject "^3.0.0"
+ static-extend "^0.1.1"
+
+clean-css@^5.2.2:
+ version "5.3.3"
+ resolved "https://registry.yarnpkg.com/clean-css/-/clean-css-5.3.3.tgz#b330653cd3bd6b75009cc25c714cae7b93351ccd"
+ integrity sha512-D5J+kHaVb/wKSFcyyV75uCn8fiY4sV38XJoe4CUyGQ+mOU/fMVYUdH1hJC+CJQ5uY3EnW27SbJYS4X8BiLrAFg==
+ dependencies:
+ source-map "~0.6.0"
+
+clean-stack@^2.0.0:
+ version "2.2.0"
+ resolved "https://registry.yarnpkg.com/clean-stack/-/clean-stack-2.2.0.tgz#ee8472dbb129e727b31e8a10a427dee9dfe4008b"
+ integrity sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==
+
+cli-boxes@^2.2.1:
+ version "2.2.1"
+ resolved "https://registry.yarnpkg.com/cli-boxes/-/cli-boxes-2.2.1.tgz#ddd5035d25094fce220e9cab40a45840a440318f"
+ integrity sha512-y4coMcylgSCdVinjiDBuR8PCC2bLjyGTwEmPb9NHR/QaNU6EUOXcTY/s6VjGMD6ENSEaeQYHCY0GNGS5jfMwPw==
+
+cli-cursor@^2.1.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-2.1.0.tgz#b35dac376479facc3e94747d41d0d0f5238ffcb5"
+ integrity sha512-8lgKz8LmCRYZZQDpRyT2m5rKJ08TnU4tR9FFFW2rxpxR1FzWi4PQ/NfyODchAatHaUgnSPVcx/R5w6NuTBzFiw==
+ dependencies:
+ restore-cursor "^2.0.0"
+
+cli-cursor@^3.1.0:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-3.1.0.tgz#264305a7ae490d1d03bf0c9ba7c925d1753af307"
+ integrity sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==
+ dependencies:
+ restore-cursor "^3.1.0"
+
+cli-spinners@^2.0.0, cli-spinners@^2.5.0:
+ version "2.9.2"
+ resolved "https://registry.yarnpkg.com/cli-spinners/-/cli-spinners-2.9.2.tgz#1773a8f4b9c4d6ac31563df53b3fc1d79462fe41"
+ integrity sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==
+
+cli-table3@0.6.2:
+ version "0.6.2"
+ resolved "https://registry.yarnpkg.com/cli-table3/-/cli-table3-0.6.2.tgz#aaf5df9d8b5bf12634dc8b3040806a0c07120d2a"
+ integrity sha512-QyavHCaIC80cMivimWu4aWHilIpiDpfm3hGmqAmXVL1UsnbLuBSMd21hTX6VY4ZSDSM73ESLeF8TOYId3rBTbw==
+ dependencies:
+ string-width "^4.2.0"
+ optionalDependencies:
+ "@colors/colors" "1.5.0"
+
+cli-width@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-3.0.0.tgz#a2f48437a2caa9a22436e794bf071ec9e61cedf6"
+ integrity sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==
+
+cliui@^7.0.2:
+ version "7.0.4"
+ resolved "https://registry.yarnpkg.com/cliui/-/cliui-7.0.4.tgz#a0265ee655476fc807aea9df3df8df7783808b4f"
+ integrity sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==
+ dependencies:
+ string-width "^4.2.0"
+ strip-ansi "^6.0.0"
+ wrap-ansi "^7.0.0"
+
+cliui@^8.0.1:
+ version "8.0.1"
+ resolved "https://registry.yarnpkg.com/cliui/-/cliui-8.0.1.tgz#0c04b075db02cbfe60dc8e6cf2f5486b1a3608aa"
+ integrity sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==
+ dependencies:
+ string-width "^4.2.0"
+ strip-ansi "^6.0.1"
+ wrap-ansi "^7.0.0"
+
+clone-response@^1.0.2:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/clone-response/-/clone-response-1.0.3.tgz#af2032aa47816399cf5f0a1d0db902f517abb8c3"
+ integrity sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA==
+ dependencies:
+ mimic-response "^1.0.0"
+
+clone@^1.0.2:
+ version "1.0.4"
+ resolved "https://registry.yarnpkg.com/clone/-/clone-1.0.4.tgz#da309cc263df15994c688ca902179ca3c7cd7c7e"
+ integrity sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==
+
+cloudinary-core@^2.13.0:
+ version "2.13.0"
+ resolved "https://registry.yarnpkg.com/cloudinary-core/-/cloudinary-core-2.13.0.tgz#b59f90871b6c708c3d0735b9be47ac08181c57fb"
+ integrity sha512-Nt0Q5I2FtenmJghtC4YZ3MZZbGg1wLm84SsxcuVwZ83OyJqG9CNIGp86CiI6iDv3QobaqBUpOT7vg+HqY5HxEA==
+
+cloudinary@^1.41.0:
+ version "1.41.2"
+ resolved "https://registry.yarnpkg.com/cloudinary/-/cloudinary-1.41.2.tgz#29b567f6f320dd39a981e69d3787b559047aa34f"
+ integrity sha512-9gH6ofz+N8AzfjqtmTgB9lVxwWcroHFfMOOM6iiX/g1H+KYz+sArClXWtd0prRE6m/IoBBBbbaJ12yRdJNnMxA==
+ dependencies:
+ cloudinary-core "^2.13.0"
+ core-js "^3.30.1"
+ lodash "^4.17.21"
+ q "^1.5.1"
+
+co-body@^5.1.1:
+ version "5.2.0"
+ resolved "https://registry.yarnpkg.com/co-body/-/co-body-5.2.0.tgz#5a0a658c46029131e0e3a306f67647302f71c124"
+ integrity sha512-sX/LQ7LqUhgyaxzbe7IqwPeTr2yfpfUIQ/dgpKo6ZI4y4lpQA0YxAomWIY+7I7rHWcG02PG+OuPREzMW/5tszQ==
+ dependencies:
+ inflation "^2.0.0"
+ qs "^6.4.0"
+ raw-body "^2.2.0"
+ type-is "^1.6.14"
+
+co-body@^6.0.0:
+ version "6.1.0"
+ resolved "https://registry.yarnpkg.com/co-body/-/co-body-6.1.0.tgz#d87a8efc3564f9bfe3aced8ef5cd04c7a8766547"
+ integrity sha512-m7pOT6CdLN7FuXUcpuz/8lfQ/L77x8SchHCF4G0RBTJO20Wzmhn5Sp4/5WsKy8OSpifBSUrmg83qEqaDHdyFuQ==
+ dependencies:
+ inflation "^2.0.0"
+ qs "^6.5.2"
+ raw-body "^2.3.3"
+ type-is "^1.6.16"
+
+co@^4.6.0:
+ version "4.6.0"
+ resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184"
+ integrity sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==
+
+"codemirror5@npm:codemirror@^5.65.11":
+ version "5.65.16"
+ resolved "https://registry.yarnpkg.com/codemirror/-/codemirror-5.65.16.tgz#efc0661be6bf4988a6a1c2fe6893294638cdb334"
+ integrity sha512-br21LjYmSlVL0vFCPWPfhzUCT34FM/pAdK7rRIZwa0rrtrIdotvP4Oh4GUHsu2E3IrQMCfRkL/fN3ytMNxVQvg==
+
+codemirror@^6.0.0, codemirror@^6.0.1:
+ version "6.0.1"
+ resolved "https://registry.yarnpkg.com/codemirror/-/codemirror-6.0.1.tgz#62b91142d45904547ee3e0e0e4c1a79158035a29"
+ integrity sha512-J8j+nZ+CdWmIeFIGXEFbFPtpiYacFMDR8GlHK3IyHQJMCaVRfGx9NT+Hxivv1ckLWPvNdZqndbr/7lVhrf/Svg==
+ dependencies:
+ "@codemirror/autocomplete" "^6.0.0"
+ "@codemirror/commands" "^6.0.0"
+ "@codemirror/language" "^6.0.0"
+ "@codemirror/lint" "^6.0.0"
+ "@codemirror/search" "^6.0.0"
+ "@codemirror/state" "^6.0.0"
+ "@codemirror/view" "^6.0.0"
+
+collection-visit@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/collection-visit/-/collection-visit-1.0.0.tgz#4bc0373c164bc3291b4d368c829cf1a80a59dca0"
+ integrity sha512-lNkKvzEeMBBjUGHZ+q6z9pSJla0KWAQPvtzhEV9+iGyQYG+pBpl7xKDhxoNSOZH2hhv0v5k0y2yAM4o4SjoSkw==
+ dependencies:
+ map-visit "^1.0.0"
+ object-visit "^1.0.0"
+
+color-convert@^1.9.0, color-convert@^1.9.3:
+ version "1.9.3"
+ resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8"
+ integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==
+ dependencies:
+ color-name "1.1.3"
+
+color-convert@^2.0.1:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3"
+ integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==
+ dependencies:
+ color-name "~1.1.4"
+
+color-name@1.1.3:
+ version "1.1.3"
+ resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25"
+ integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==
+
+color-name@^1.0.0, color-name@~1.1.4:
+ version "1.1.4"
+ resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2"
+ integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==
+
+color-string@^1.6.0, color-string@^1.9.0:
+ version "1.9.1"
+ resolved "https://registry.yarnpkg.com/color-string/-/color-string-1.9.1.tgz#4467f9146f036f855b764dfb5bf8582bf342c7a4"
+ integrity sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==
+ dependencies:
+ color-name "^1.0.0"
+ simple-swizzle "^0.2.2"
+
+color-support@^1.1.2:
+ version "1.1.3"
+ resolved "https://registry.yarnpkg.com/color-support/-/color-support-1.1.3.tgz#93834379a1cc9a0c61f82f52f0d04322251bd5a2"
+ integrity sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==
+
+color@^3.1.3:
+ version "3.2.1"
+ resolved "https://registry.yarnpkg.com/color/-/color-3.2.1.tgz#3544dc198caf4490c3ecc9a790b54fe9ff45e164"
+ integrity sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA==
+ dependencies:
+ color-convert "^1.9.3"
+ color-string "^1.6.0"
+
+color@^4.2.3:
+ version "4.2.3"
+ resolved "https://registry.yarnpkg.com/color/-/color-4.2.3.tgz#d781ecb5e57224ee43ea9627560107c0e0c6463a"
+ integrity sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==
+ dependencies:
+ color-convert "^2.0.1"
+ color-string "^1.9.0"
+
+colorette@2.0.19:
+ version "2.0.19"
+ resolved "https://registry.yarnpkg.com/colorette/-/colorette-2.0.19.tgz#cdf044f47ad41a0f4b56b3a0d5b4e6e1a2d5a798"
+ integrity sha512-3tlv/dIP7FWvj3BsbHrGLJ6l/oKh1O3TcgBqMn+yyCagOxc23fyzDS6HypQbgxWbkpDnf52p1LuR4eWDQ/K9WQ==
+
+colorette@^2.0.10:
+ version "2.0.20"
+ resolved "https://registry.yarnpkg.com/colorette/-/colorette-2.0.20.tgz#9eb793e6833067f7235902fcd3b09917a000a95a"
+ integrity sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==
+
+colors@~1.2.1:
+ version "1.2.5"
+ resolved "https://registry.yarnpkg.com/colors/-/colors-1.2.5.tgz#89c7ad9a374bc030df8013241f68136ed8835afc"
+ integrity sha512-erNRLao/Y3Fv54qUa0LBB+//Uf3YwMUmdJinN20yMXm9zdKKqH9wt7R9IIVZ+K7ShzfpLV/Zg8+VyrBJYB4lpg==
+
+colorspace@1.1.x:
+ version "1.1.4"
+ resolved "https://registry.yarnpkg.com/colorspace/-/colorspace-1.1.4.tgz#8d442d1186152f60453bf8070cd66eb364e59243"
+ integrity sha512-BgvKJiuVu1igBUF2kEjRCZXol6wiiGbY5ipL/oVPwm0BL9sIpMIzM8IK7vwuxIIzOXMV3Ey5w+vxhm0rR/TN8w==
+ dependencies:
+ color "^3.1.3"
+ text-hex "1.0.x"
+
+combined-stream@^1.0.8:
+ version "1.0.8"
+ resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f"
+ integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==
+ dependencies:
+ delayed-stream "~1.0.0"
+
+commander@8.3.0, commander@^8.3.0:
+ version "8.3.0"
+ resolved "https://registry.yarnpkg.com/commander/-/commander-8.3.0.tgz#4837ea1b2da67b9c616a67afbb0fafee567bca66"
+ integrity sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==
+
+commander@^10.0.0:
+ version "10.0.1"
+ resolved "https://registry.yarnpkg.com/commander/-/commander-10.0.1.tgz#881ee46b4f77d1c1dccc5823433aa39b022cbe06"
+ integrity sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==
+
+commander@^2.20.0:
+ version "2.20.3"
+ resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33"
+ integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==
+
+commander@^7.2.0:
+ version "7.2.0"
+ resolved "https://registry.yarnpkg.com/commander/-/commander-7.2.0.tgz#a36cb57d0b501ce108e4d20559a150a391d97ab7"
+ integrity sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==
+
+common-path-prefix@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/common-path-prefix/-/common-path-prefix-3.0.0.tgz#7d007a7e07c58c4b4d5f433131a19141b29f11e0"
+ integrity sha512-QE33hToZseCH3jS0qN96O/bSh3kaw/h+Tq7ngyY9eWDUnTlTNUyqfqvCXioLe5Na5jFsL78ra/wuBU4iuEgd4w==
+
+component-emitter@^1.2.1:
+ version "1.3.1"
+ resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.3.1.tgz#ef1d5796f7d93f135ee6fb684340b26403c97d17"
+ integrity sha512-T0+barUSQRTUQASh8bx02dl+DhF54GtIDY13Y3m9oWTklKbb3Wv974meRpeZ3lp1JpLVECWWNHC4vaG2XHXouQ==
+
+compressible@^2.0.0:
+ version "2.0.18"
+ resolved "https://registry.yarnpkg.com/compressible/-/compressible-2.0.18.tgz#af53cca6b070d4c3c0750fbd77286a6d7cc46fba"
+ integrity sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==
+ dependencies:
+ mime-db ">= 1.43.0 < 2"
+
+compute-scroll-into-view@^1.0.20:
+ version "1.0.20"
+ resolved "https://registry.yarnpkg.com/compute-scroll-into-view/-/compute-scroll-into-view-1.0.20.tgz#1768b5522d1172754f5d0c9b02de3af6be506a43"
+ integrity sha512-UCB0ioiyj8CRjtrvaceBLqqhZCVP+1B8+NWQhmdsm0VXOJtobBCf1dBQmebCCo34qZmUwZfIH2MZLqNHazrfjg==
+
+compute-scroll-into-view@^3.1.0:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/compute-scroll-into-view/-/compute-scroll-into-view-3.1.0.tgz#753f11d972596558d8fe7c6bcbc8497690ab4c87"
+ integrity sha512-rj8l8pD4bJ1nx+dAkMhV1xB5RuZEyVysfxJqB1pRchh1KVvwOv9b7CGB8ZfjTImVv2oF+sYMUkMZq6Na5Ftmbg==
+
+concat-map@0.0.1:
+ version "0.0.1"
+ resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
+ integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==
+
+concurrently@^8.2.2:
+ version "8.2.2"
+ resolved "https://registry.yarnpkg.com/concurrently/-/concurrently-8.2.2.tgz#353141985c198cfa5e4a3ef90082c336b5851784"
+ integrity sha512-1dP4gpXFhei8IOtlXRE/T/4H88ElHgTiUzh71YUmtjTEHMSRS2Z/fgOxHSxxusGHogsRfxNq1vyAwxSC+EVyDg==
+ dependencies:
+ chalk "^4.1.2"
+ date-fns "^2.30.0"
+ lodash "^4.17.21"
+ rxjs "^7.8.1"
+ shell-quote "^1.8.1"
+ spawn-command "0.0.2"
+ supports-color "^8.1.1"
+ tree-kill "^1.2.2"
+ yargs "^17.7.2"
+
+config-chain@^1.1.11:
+ version "1.1.13"
+ resolved "https://registry.yarnpkg.com/config-chain/-/config-chain-1.1.13.tgz#fad0795aa6a6cdaff9ed1b68e9dff94372c232f4"
+ integrity sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==
+ dependencies:
+ ini "^1.3.4"
+ proto-list "~1.2.1"
+
+configstore@5.0.1:
+ version "5.0.1"
+ resolved "https://registry.yarnpkg.com/configstore/-/configstore-5.0.1.tgz#d365021b5df4b98cdd187d6a3b0e3f6a7cc5ed96"
+ integrity sha512-aMKprgk5YhBNyH25hj8wGt2+D52Sw1DRRIzqBwLp2Ya9mFmY8KPvvtvmna8SxVR9JMZ4kzMD68N22vlaRpkeFA==
+ dependencies:
+ dot-prop "^5.2.0"
+ graceful-fs "^4.1.2"
+ make-dir "^3.0.0"
+ unique-string "^2.0.0"
+ write-file-atomic "^3.0.0"
+ xdg-basedir "^4.0.0"
+
+console-control-strings@^1.0.0, console-control-strings@^1.1.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e"
+ integrity sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==
+
+constant-case@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/constant-case/-/constant-case-2.0.0.tgz#4175764d389d3fa9c8ecd29186ed6005243b6a46"
+ integrity sha512-eS0N9WwmjTqrOmR3o83F5vW8Z+9R1HnVz3xmzT2PMFug9ly+Au/fxRWlEBSb6LcZwspSsEn9Xs1uw9YgzAg1EQ==
+ dependencies:
+ snake-case "^2.1.0"
+ upper-case "^1.1.1"
+
+content-disposition@~0.5.2:
+ version "0.5.4"
+ resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.4.tgz#8b82b4efac82512a02bb0b1dcec9d2c5e8eb5bfe"
+ integrity sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==
+ dependencies:
+ safe-buffer "5.2.1"
+
+content-type@^1.0.4:
+ version "1.0.5"
+ resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.5.tgz#8b773162656d1d1086784c8f23a54ce6d73d7918"
+ integrity sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==
+
+convert-source-map@^1.5.0:
+ version "1.9.0"
+ resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.9.0.tgz#7faae62353fb4213366d0ca98358d22e8368b05f"
+ integrity sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==
+
+convert-source-map@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-2.0.0.tgz#4b560f649fc4e918dd0ab75cf4961e8bc882d82a"
+ integrity sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==
+
+cookie-signature@^1.2.1:
+ version "1.2.1"
+ resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.2.1.tgz#790dea2cce64638c7ae04d9fabed193bd7ccf3b4"
+ integrity sha512-78KWk9T26NhzXtuL26cIJ8/qNHANyJ/ZYrmEXFzUmhZdjpBv+DlWlOANRTGBt48YcyslsLrj0bMLFTmXvLRCOw==
+
+cookie@^0.4.1, cookie@^0.4.2:
+ version "0.4.2"
+ resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.2.tgz#0e41f24de5ecf317947c82fc789e06a884824432"
+ integrity sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==
+
+cookie@^0.5.0:
+ version "0.5.0"
+ resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.5.0.tgz#d1f5d71adec6558c58f389987c366aa47e994f8b"
+ integrity sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==
+
+cookies@~0.8.0:
+ version "0.8.0"
+ resolved "https://registry.yarnpkg.com/cookies/-/cookies-0.8.0.tgz#1293ce4b391740a8406e3c9870e828c4b54f3f90"
+ integrity sha512-8aPsApQfebXnuI+537McwYsDtjVxGm8gTIzQI3FDW6t5t/DAhERxtnbEPN/8RX+uZthoz4eCOgloXaE5cYyNow==
+ dependencies:
+ depd "~2.0.0"
+ keygrip "~1.1.0"
+
+cookies@~0.9.0:
+ version "0.9.1"
+ resolved "https://registry.yarnpkg.com/cookies/-/cookies-0.9.1.tgz#3ffed6f60bb4fb5f146feeedba50acc418af67e3"
+ integrity sha512-TG2hpqe4ELx54QER/S3HQ9SRVnQnGBtKUz5bLQWtYAQ+o6GpgMs6sYUvaiJjVxb+UXwhRhAEP3m7LbsIZ77Hmw==
+ dependencies:
+ depd "~2.0.0"
+ keygrip "~1.1.0"
+
+copy-descriptor@^0.1.0:
+ version "0.1.1"
+ resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d"
+ integrity sha512-XgZ0pFcakEUlbwQEVNg3+QAis1FyTL3Qel9FYy8pSkQqoG3PNoT0bOCQtOXcOkur21r2Eq2kI+IE+gsmAEVlYw==
+
+copy-to@^2.0.1:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/copy-to/-/copy-to-2.0.1.tgz#2680fbb8068a48d08656b6098092bdafc906f4a5"
+ integrity sha512-3DdaFaU/Zf1AnpLiFDeNCD4TOWe3Zl2RZaTzUvWiIk5ERzcCodOE20Vqq4fzCbNoHURFHT4/us/Lfq+S2zyY4w==
+
+copyfiles@2.4.1:
+ version "2.4.1"
+ resolved "https://registry.yarnpkg.com/copyfiles/-/copyfiles-2.4.1.tgz#d2dcff60aaad1015f09d0b66e7f0f1c5cd3c5da5"
+ integrity sha512-fereAvAvxDrQDOXybk3Qu3dPbOoKoysFMWtkY3mv5BsL8//OSZVL5DCLYqgRfY5cWirgRzlC+WSrxp6Bo3eNZg==
+ dependencies:
+ glob "^7.0.5"
+ minimatch "^3.0.3"
+ mkdirp "^1.0.4"
+ noms "0.0.0"
+ through2 "^2.0.1"
+ untildify "^4.0.0"
+ yargs "^16.1.0"
+
+core-js-pure@^3.23.3, core-js-pure@^3.30.2:
+ version "3.35.0"
+ resolved "https://registry.yarnpkg.com/core-js-pure/-/core-js-pure-3.35.0.tgz#4660033304a050215ae82e476bd2513a419fbb34"
+ integrity sha512-f+eRYmkou59uh7BPcyJ8MC76DiGhspj1KMxVIcF24tzP8NA9HVa1uC7BTW2tgx7E1QVCzDzsgp7kArrzhlz8Ew==
+
+core-js@^3.30.1:
+ version "3.35.0"
+ resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.35.0.tgz#58e651688484f83c34196ca13f099574ee53d6b4"
+ integrity sha512-ntakECeqg81KqMueeGJ79Q5ZgQNR+6eaE8sxGCx62zMbAIj65q+uYvatToew3m6eAGdU4gNZwpZ34NMe4GYswg==
+
+core-util-is@^1.0.2, core-util-is@~1.0.0:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.3.tgz#a6042d3634c2b27e9328f837b965fac83808db85"
+ integrity sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==
+
+cosmiconfig@^7.0.0, cosmiconfig@^7.0.1:
+ version "7.1.0"
+ resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-7.1.0.tgz#1443b9afa596b670082ea46cbd8f6a62b84635f6"
+ integrity sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==
+ dependencies:
+ "@types/parse-json" "^4.0.0"
+ import-fresh "^3.2.1"
+ parse-json "^5.0.0"
+ path-type "^4.0.0"
+ yaml "^1.10.0"
+
+crc@^3.8.0:
+ version "3.8.0"
+ resolved "https://registry.yarnpkg.com/crc/-/crc-3.8.0.tgz#ad60269c2c856f8c299e2c4cc0de4556914056c6"
+ integrity sha512-iX3mfgcTMIq3ZKLIsVFAbv7+Mc10kxabAGQb8HvjA1o3T1PIYprbakQ65d3I+2HGHt6nSKkM9PYjgoJO2KcFBQ==
+ dependencies:
+ buffer "^5.1.0"
+
+crelt@^1.0.5:
+ version "1.0.6"
+ resolved "https://registry.yarnpkg.com/crelt/-/crelt-1.0.6.tgz#7cc898ea74e190fb6ef9dae57f8f81cf7302df72"
+ integrity sha512-VQ2MBenTq1fWZUH9DJNGti7kKv6EeAuYr3cLwxUWhIu1baTaXh4Ib5W2CqHVqib4/MqbYGJqiL3Zb8GJZr3l4g==
+
+cron-parser@^3.5.0:
+ version "3.5.0"
+ resolved "https://registry.yarnpkg.com/cron-parser/-/cron-parser-3.5.0.tgz#b1a9da9514c0310aa7ef99c2f3f1d0f8c235257c"
+ integrity sha512-wyVZtbRs6qDfFd8ap457w3XVntdvqcwBGxBoTvJQH9KGVKL/fB+h2k3C8AqiVxvUQKN1Ps/Ns46CNViOpVDhfQ==
+ dependencies:
+ is-nan "^1.3.2"
+ luxon "^1.26.0"
+
+cropperjs@1.6.0:
+ version "1.6.0"
+ resolved "https://registry.yarnpkg.com/cropperjs/-/cropperjs-1.6.0.tgz#de9f23b7e397a53fd0dc10cc0d6fe31fe1e2019a"
+ integrity sha512-BzLU/ecrfsbflwxgu+o7sQTrTlo52pVRZkTVrugEK5uyj6n8qKwAHP4s6+DWHqlXLqQ5B9+cM2MKeXiNfAsF6Q==
+
+cross-env@^7.0.3:
+ version "7.0.3"
+ resolved "https://registry.yarnpkg.com/cross-env/-/cross-env-7.0.3.tgz#865264b29677dc015ba8418918965dd232fc54cf"
+ integrity sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==
+ dependencies:
+ cross-spawn "^7.0.1"
+
+cross-spawn@^7.0.1, cross-spawn@^7.0.3:
+ version "7.0.3"
+ resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6"
+ integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==
+ dependencies:
+ path-key "^3.1.0"
+ shebang-command "^2.0.0"
+ which "^2.0.1"
+
+crypto-random-string@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/crypto-random-string/-/crypto-random-string-2.0.0.tgz#ef2a7a966ec11083388369baa02ebead229b30d5"
+ integrity sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==
+
+css-color-keywords@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/css-color-keywords/-/css-color-keywords-1.0.0.tgz#fea2616dc676b2962686b3af8dbdbe180b244e05"
+ integrity sha512-FyyrDHZKEjXDpNJYvVsV960FiqQyXc/LlYmsxl2BcdMb2WPx0OGRVgTg55rPSyLSNMqP52R9r8geSp7apN3Ofg==
+
+css-loader@^6.8.1:
+ version "6.9.0"
+ resolved "https://registry.yarnpkg.com/css-loader/-/css-loader-6.9.0.tgz#0cc2f14df94ed97c526c5ae42b6b13916d1d8d0e"
+ integrity sha512-3I5Nu4ytWlHvOP6zItjiHlefBNtrH+oehq8tnQa2kO305qpVyx9XNIT1CXIj5bgCJs7qICBCkgCYxQLKPANoLA==
+ dependencies:
+ icss-utils "^5.1.0"
+ postcss "^8.4.31"
+ postcss-modules-extract-imports "^3.0.0"
+ postcss-modules-local-by-default "^4.0.3"
+ postcss-modules-scope "^3.1.0"
+ postcss-modules-values "^4.0.0"
+ postcss-value-parser "^4.2.0"
+ semver "^7.5.4"
+
+css-select@^4.1.3:
+ version "4.3.0"
+ resolved "https://registry.yarnpkg.com/css-select/-/css-select-4.3.0.tgz#db7129b2846662fd8628cfc496abb2b59e41529b"
+ integrity sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==
+ dependencies:
+ boolbase "^1.0.0"
+ css-what "^6.0.1"
+ domhandler "^4.3.1"
+ domutils "^2.8.0"
+ nth-check "^2.0.1"
+
+css-to-react-native@^3.0.0:
+ version "3.2.0"
+ resolved "https://registry.yarnpkg.com/css-to-react-native/-/css-to-react-native-3.2.0.tgz#cdd8099f71024e149e4f6fe17a7d46ecd55f1e32"
+ integrity sha512-e8RKaLXMOFii+02mOlqwjbD00KSEKqblnpO9e++1aXS1fPQOpS1YoqdVHBqPjHNoxeF2mimzVqawm2KCbEdtHQ==
+ dependencies:
+ camelize "^1.0.0"
+ css-color-keywords "^1.0.0"
+ postcss-value-parser "^4.0.2"
+
+css-what@^6.0.1:
+ version "6.1.0"
+ resolved "https://registry.yarnpkg.com/css-what/-/css-what-6.1.0.tgz#fb5effcf76f1ddea2c81bdfaa4de44e79bac70f4"
+ integrity sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==
+
+cssesc@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-3.0.0.tgz#37741919903b868565e1c09ea747445cd18983ee"
+ integrity sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==
+
+csstype@^3.0.2:
+ version "3.1.3"
+ resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.1.3.tgz#d80ff294d114fb0e6ac500fbf85b60137d7eff81"
+ integrity sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==
+
+cuid@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/cuid/-/cuid-3.0.0.tgz#8cef32136e3c48e4a94aec42025996b888cbae82"
+ integrity sha512-WZYYkHdIDnaxdeP8Misq3Lah5vFjJwGuItJuV+tvMafosMzw0nF297T7mrm8IOWiPJkV6gc7sa8pzx27+w25Zg==
+
+date-fns@2.30.0, date-fns@^2.30.0:
+ version "2.30.0"
+ resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-2.30.0.tgz#f367e644839ff57894ec6ac480de40cae4b0f4d0"
+ integrity sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw==
+ dependencies:
+ "@babel/runtime" "^7.21.0"
+
+date-fns@^3.1.0:
+ version "3.2.0"
+ resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-3.2.0.tgz#c97cf685b62c829aa4ecba554e4a51768cf0bffc"
+ integrity sha512-E4KWKavANzeuusPi0jUjpuI22SURAznGkx7eZV+4i6x2A+IZxAMcajgkvuDAU1bg40+xuhW1zRdVIIM/4khuIg==
+
+debounce@^1.2.1:
+ version "1.2.1"
+ resolved "https://registry.yarnpkg.com/debounce/-/debounce-1.2.1.tgz#38881d8f4166a5c5848020c11827b834bcb3e0a5"
+ integrity sha512-XRRe6Glud4rd/ZGQfiV1ruXSfbvfJedlV9Y6zOlP+2K04vBYiJEte6stfFkCP03aMnY5tsipamumUjL14fofug==
+
+debug@4, debug@4.3.4, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.3, debug@^4.3.4:
+ version "4.3.4"
+ resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865"
+ integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==
+ dependencies:
+ ms "2.1.2"
+
+debug@^2.2.0, debug@^2.3.3:
+ version "2.6.9"
+ resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f"
+ integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==
+ dependencies:
+ ms "2.0.0"
+
+debug@^3.1.0:
+ version "3.2.7"
+ resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.7.tgz#72580b7e9145fb39b6676f9c5e5fb100b934179a"
+ integrity sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==
+ dependencies:
+ ms "^2.1.1"
+
+decode-uri-component@^0.2.0:
+ version "0.2.2"
+ resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.2.tgz#e69dbe25d37941171dd540e024c444cd5188e1e9"
+ integrity sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==
+
+decompress-response@^4.2.0:
+ version "4.2.1"
+ resolved "https://registry.yarnpkg.com/decompress-response/-/decompress-response-4.2.1.tgz#414023cc7a302da25ce2ec82d0d5238ccafd8986"
+ integrity sha512-jOSne2qbyE+/r8G1VU+G/82LBs2Fs4LAsTiLSHOCOMZQl2OKZ6i8i4IyHemTe+/yIXOtTcRQMzPcgyhoFlqPkw==
+ dependencies:
+ mimic-response "^2.0.0"
+
+decompress-response@^6.0.0:
+ version "6.0.0"
+ resolved "https://registry.yarnpkg.com/decompress-response/-/decompress-response-6.0.0.tgz#ca387612ddb7e104bd16d85aab00d5ecf09c66fc"
+ integrity sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==
+ dependencies:
+ mimic-response "^3.1.0"
+
+decompress-response@^7.0.0:
+ version "7.0.0"
+ resolved "https://registry.yarnpkg.com/decompress-response/-/decompress-response-7.0.0.tgz#dc42107cc29a258aa8983fddc81c92351810f6fb"
+ integrity sha512-6IvPrADQyyPGLpMnUh6kfKiqy7SrbXbjoUuZ90WMBJKErzv2pCiwlGEXjRX9/54OnTq+XFVnkOnOMzclLI5aEA==
+ dependencies:
+ mimic-response "^3.1.0"
+
+deep-equal@^2.0.5:
+ version "2.2.3"
+ resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-2.2.3.tgz#af89dafb23a396c7da3e862abc0be27cf51d56e1"
+ integrity sha512-ZIwpnevOurS8bpT4192sqAowWM76JDKSHYzMLty3BZGSswgq6pBaH3DhCSW5xVAZICZyKdOBPjwww5wfgT/6PA==
+ dependencies:
+ array-buffer-byte-length "^1.0.0"
+ call-bind "^1.0.5"
+ es-get-iterator "^1.1.3"
+ get-intrinsic "^1.2.2"
+ is-arguments "^1.1.1"
+ is-array-buffer "^3.0.2"
+ is-date-object "^1.0.5"
+ is-regex "^1.1.4"
+ is-shared-array-buffer "^1.0.2"
+ isarray "^2.0.5"
+ object-is "^1.1.5"
+ object-keys "^1.1.1"
+ object.assign "^4.1.4"
+ regexp.prototype.flags "^1.5.1"
+ side-channel "^1.0.4"
+ which-boxed-primitive "^1.0.2"
+ which-collection "^1.0.1"
+ which-typed-array "^1.1.13"
+
+deep-equal@~1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-1.0.1.tgz#f5d260292b660e084eff4cdbc9f08ad3247448b5"
+ integrity sha512-bHtC0iYvWhyaTzvV3CZgPeZQqCOBGyGsVV7v4eevpdkLHfiSrXUdBG+qAuSz4RI70sszvjQ1QSZ98An1yNwpSw==
+
+deep-extend@^0.6.0:
+ version "0.6.0"
+ resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac"
+ integrity sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==
+
+deepmerge@^2.1.1:
+ version "2.2.1"
+ resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-2.2.1.tgz#5d3ff22a01c00f645405a2fbc17d0778a1801170"
+ integrity sha512-R9hc1Xa/NOBi9WRVUWg19rl1UB7Tt4kuPd+thNJgFZoxXsTz7ncaPaeIm+40oSGuP33DfMb4sZt1QIGiJzC4EA==
+
+deepmerge@^4.2.2:
+ version "4.3.1"
+ resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.3.1.tgz#44b5f2147cd3b00d4b56137685966f26fd25dd4a"
+ integrity sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==
+
+default-browser-id@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/default-browser-id/-/default-browser-id-3.0.0.tgz#bee7bbbef1f4e75d31f98f4d3f1556a14cea790c"
+ integrity sha512-OZ1y3y0SqSICtE8DE4S8YOE9UZOJ8wO16fKWVP5J1Qz42kV9jcnMVFrEE/noXb/ss3Q4pZIH79kxofzyNNtUNA==
+ dependencies:
+ bplist-parser "^0.2.0"
+ untildify "^4.0.0"
+
+default-browser@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/default-browser/-/default-browser-4.0.0.tgz#53c9894f8810bf86696de117a6ce9085a3cbc7da"
+ integrity sha512-wX5pXO1+BrhMkSbROFsyxUm0i/cJEScyNhA4PPxc41ICuv05ZZB/MX28s8aZx6xjmatvebIapF6hLEKEcpneUA==
+ dependencies:
+ bundle-name "^3.0.0"
+ default-browser-id "^3.0.0"
+ execa "^7.1.1"
+ titleize "^3.0.0"
+
+defaults@^1.0.3:
+ version "1.0.4"
+ resolved "https://registry.yarnpkg.com/defaults/-/defaults-1.0.4.tgz#b0b02062c1e2aa62ff5d9528f0f98baa90978d7a"
+ integrity sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==
+ dependencies:
+ clone "^1.0.2"
+
+defer-to-connect@^2.0.0:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/defer-to-connect/-/defer-to-connect-2.0.1.tgz#8016bdb4143e4632b77a3449c6236277de520587"
+ integrity sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==
+
+define-data-property@^1.0.1, define-data-property@^1.1.1:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/define-data-property/-/define-data-property-1.1.1.tgz#c35f7cd0ab09883480d12ac5cb213715587800b3"
+ integrity sha512-E7uGkTzkk1d0ByLeSc6ZsFS79Axg+m1P/VsgYsxHgiuc3tFSj+MjMIwe90FC4lOAZzNBdY7kkO2P2wKdsQ1vgQ==
+ dependencies:
+ get-intrinsic "^1.2.1"
+ gopd "^1.0.1"
+ has-property-descriptors "^1.0.0"
+
+define-lazy-prop@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz#3f7ae421129bcaaac9bc74905c98a0009ec9ee7f"
+ integrity sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==
+
+define-lazy-prop@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz#dbb19adfb746d7fc6d734a06b72f4a00d021255f"
+ integrity sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==
+
+define-properties@^1.1.3, define-properties@^1.2.0, define-properties@^1.2.1:
+ version "1.2.1"
+ resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.2.1.tgz#10781cc616eb951a80a034bafcaa7377f6af2b6c"
+ integrity sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==
+ dependencies:
+ define-data-property "^1.0.1"
+ has-property-descriptors "^1.0.0"
+ object-keys "^1.1.1"
+
+define-property@^0.2.5:
+ version "0.2.5"
+ resolved "https://registry.yarnpkg.com/define-property/-/define-property-0.2.5.tgz#c35b1ef918ec3c990f9a5bc57be04aacec5c8116"
+ integrity sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==
+ dependencies:
+ is-descriptor "^0.1.0"
+
+define-property@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/define-property/-/define-property-1.0.0.tgz#769ebaaf3f4a63aad3af9e8d304c9bbe79bfb0e6"
+ integrity sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA==
+ dependencies:
+ is-descriptor "^1.0.0"
+
+define-property@^2.0.2:
+ version "2.0.2"
+ resolved "https://registry.yarnpkg.com/define-property/-/define-property-2.0.2.tgz#d459689e8d654ba77e02a817f8710d702cb16e9d"
+ integrity sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==
+ dependencies:
+ is-descriptor "^1.0.2"
+ isobject "^3.0.1"
+
+del@^5.1.0:
+ version "5.1.0"
+ resolved "https://registry.yarnpkg.com/del/-/del-5.1.0.tgz#d9487c94e367410e6eff2925ee58c0c84a75b3a7"
+ integrity sha512-wH9xOVHnczo9jN2IW68BabcecVPxacIA3g/7z6vhSU/4stOKQzeCRK0yD0A24WiAAUJmmVpWqrERcTxnLo3AnA==
+ dependencies:
+ globby "^10.0.1"
+ graceful-fs "^4.2.2"
+ is-glob "^4.0.1"
+ is-path-cwd "^2.2.0"
+ is-path-inside "^3.0.1"
+ p-map "^3.0.0"
+ rimraf "^3.0.0"
+ slash "^3.0.0"
+
+delayed-stream@~1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619"
+ integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==
+
+delegates@1.0.0, delegates@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a"
+ integrity sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==
+
+depd@2.0.0, depd@^2.0.0, depd@~2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/depd/-/depd-2.0.0.tgz#b696163cc757560d09cf22cc8fad1571b79e76df"
+ integrity sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==
+
+depd@~1.1.2:
+ version "1.1.2"
+ resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9"
+ integrity sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==
+
+dequal@^2.0.3:
+ version "2.0.3"
+ resolved "https://registry.yarnpkg.com/dequal/-/dequal-2.0.3.tgz#2644214f1997d39ed0ee0ece72335490a7ac67be"
+ integrity sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==
+
+destroy@^1.0.4:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.2.0.tgz#4803735509ad8be552934c67df614f94e66fa015"
+ integrity sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==
+
+detect-file@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/detect-file/-/detect-file-1.0.0.tgz#f0d66d03672a825cb1b73bdb3fe62310c8e552b7"
+ integrity sha512-DtCOLG98P007x7wiiOmfI0fi3eIKyWiLTGJ2MDnVi/E04lWGbf+JzrRHMm0rgIIZJGtHpKpbVgLWHrv8xXpc3Q==
+
+detect-indent@^7.0.1:
+ version "7.0.1"
+ resolved "https://registry.yarnpkg.com/detect-indent/-/detect-indent-7.0.1.tgz#cbb060a12842b9c4d333f1cac4aa4da1bb66bc25"
+ integrity sha512-Mc7QhQ8s+cLrnUfU/Ji94vG/r8M26m8f++vyres4ZoojaRDpZ1eSIh/EpzLNwlWuvzSZ3UbDFspjFvTDXe6e/g==
+
+detect-libc@^2.0.0, detect-libc@^2.0.2:
+ version "2.0.2"
+ resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-2.0.2.tgz#8ccf2ba9315350e1241b88d0ac3b0e1fbd99605d"
+ integrity sha512-UX6sGumvvqSaXgdKGUsgZWqcUyIXZ/vZTrlRT/iobiKhGL0zL4d3osHj3uqllWJK+i+sixDS/3COVEOFbupFyw==
+
+detect-newline@^4.0.0:
+ version "4.0.1"
+ resolved "https://registry.yarnpkg.com/detect-newline/-/detect-newline-4.0.1.tgz#fcefdb5713e1fb8cb2839b8b6ee22e6716ab8f23"
+ integrity sha512-qE3Veg1YXzGHQhlA6jzebZN2qVf6NX+A7m7qlhCGG30dJixrAQhYOsJjsnBjJkCSmuOPpCk30145fr8FV0bzog==
+
+detect-node-es@^1.1.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/detect-node-es/-/detect-node-es-1.1.0.tgz#163acdf643330caa0b4cd7c21e7ee7755d6fa493"
+ integrity sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==
+
+detect-node@^2.0.4, detect-node@^2.1.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/detect-node/-/detect-node-2.1.0.tgz#c9c70775a49c3d03bc2c06d9a73be550f978f8b1"
+ integrity sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==
+
+dir-glob@^3.0.1:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f"
+ integrity sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==
+ dependencies:
+ path-type "^4.0.0"
+
+direction@^1.0.3:
+ version "1.0.4"
+ resolved "https://registry.yarnpkg.com/direction/-/direction-1.0.4.tgz#2b86fb686967e987088caf8b89059370d4837442"
+ integrity sha512-GYqKi1aH7PJXxdhTeZBFrg8vUBeKXi+cNprXsC1kpJcbcVnV9wBsrOu1cQEdG0WeQwlfHiy3XvnKfIrJ2R0NzQ==
+
+dkim-signer@0.2.2:
+ version "0.2.2"
+ resolved "https://registry.yarnpkg.com/dkim-signer/-/dkim-signer-0.2.2.tgz#aa81ec071eeed3622781baa922044d7800e5f308"
+ integrity sha512-24OZ3cCA30UTRz+Plpg+ibfPq3h7tDtsJRg75Bo0pGakZePXcPBddY80bKi1Bi7Jsz7tL5Cw527mhCRDvNFgfg==
+ dependencies:
+ libmime "^2.0.3"
+
+dnd-core@15.1.2:
+ version "15.1.2"
+ resolved "https://registry.yarnpkg.com/dnd-core/-/dnd-core-15.1.2.tgz#0983bce555c4985f58b731ffe1faed31e1ea7f6f"
+ integrity sha512-EOec1LyJUuGRFg0LDa55rSRAUe97uNVKVkUo8iyvzQlcECYTuPblVQfRWXWj1OyPseFIeebWpNmKFy0h6BcF1A==
+ dependencies:
+ "@react-dnd/asap" "4.0.1"
+ "@react-dnd/invariant" "3.0.1"
+ redux "^4.1.2"
+
+dom-accessibility-api@^0.5.9:
+ version "0.5.16"
+ resolved "https://registry.yarnpkg.com/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz#5a7429e6066eb3664d911e33fb0e45de8eb08453"
+ integrity sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==
+
+dom-converter@^0.2.0:
+ version "0.2.0"
+ resolved "https://registry.yarnpkg.com/dom-converter/-/dom-converter-0.2.0.tgz#6721a9daee2e293682955b6afe416771627bb768"
+ integrity sha512-gd3ypIPfOMr9h5jIKq8E3sHOTCjeirnl0WK5ZdS1AW0Odt0b1PaWaHdJ4Qk4klv+YB9aJBS7mESXjFoDQPu6DA==
+ dependencies:
+ utila "~0.4"
+
+dom-helpers@^5.0.1:
+ version "5.2.1"
+ resolved "https://registry.yarnpkg.com/dom-helpers/-/dom-helpers-5.2.1.tgz#d9400536b2bf8225ad98fe052e029451ac40e902"
+ integrity sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==
+ dependencies:
+ "@babel/runtime" "^7.8.7"
+ csstype "^3.0.2"
+
+dom-serializer@^1.0.1:
+ version "1.4.1"
+ resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-1.4.1.tgz#de5d41b1aea290215dc45a6dae8adcf1d32e2d30"
+ integrity sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==
+ dependencies:
+ domelementtype "^2.0.1"
+ domhandler "^4.2.0"
+ entities "^2.0.0"
+
+dom-serializer@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-2.0.0.tgz#e41b802e1eedf9f6cae183ce5e622d789d7d8e53"
+ integrity sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==
+ dependencies:
+ domelementtype "^2.3.0"
+ domhandler "^5.0.2"
+ entities "^4.2.0"
+
+domelementtype@^2.0.1, domelementtype@^2.2.0, domelementtype@^2.3.0:
+ version "2.3.0"
+ resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-2.3.0.tgz#5c45e8e869952626331d7aab326d01daf65d589d"
+ integrity sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==
+
+domhandler@^4.0.0, domhandler@^4.2.0, domhandler@^4.3.1:
+ version "4.3.1"
+ resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-4.3.1.tgz#8d792033416f59d68bc03a5aa7b018c1ca89279c"
+ integrity sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==
+ dependencies:
+ domelementtype "^2.2.0"
+
+domhandler@^5.0.2, domhandler@^5.0.3:
+ version "5.0.3"
+ resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-5.0.3.tgz#cc385f7f751f1d1fc650c21374804254538c7d31"
+ integrity sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==
+ dependencies:
+ domelementtype "^2.3.0"
+
+domutils@^2.5.2, domutils@^2.8.0:
+ version "2.8.0"
+ resolved "https://registry.yarnpkg.com/domutils/-/domutils-2.8.0.tgz#4437def5db6e2d1f5d6ee859bd95ca7d02048135"
+ integrity sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==
+ dependencies:
+ dom-serializer "^1.0.1"
+ domelementtype "^2.2.0"
+ domhandler "^4.2.0"
+
+domutils@^3.0.1:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/domutils/-/domutils-3.1.0.tgz#c47f551278d3dc4b0b1ab8cbb42d751a6f0d824e"
+ integrity sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==
+ dependencies:
+ dom-serializer "^2.0.0"
+ domelementtype "^2.3.0"
+ domhandler "^5.0.3"
+
+dot-case@^2.1.0:
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/dot-case/-/dot-case-2.1.1.tgz#34dcf37f50a8e93c2b3bca8bb7fb9155c7da3bee"
+ integrity sha512-HnM6ZlFqcajLsyudHq7LeeLDr2rFAVYtDv/hV5qchQEidSck8j9OPUsXY9KwJv/lHMtYlX4DjRQqwFYa+0r8Ug==
+ dependencies:
+ no-case "^2.2.0"
+
+dot-case@^3.0.4:
+ version "3.0.4"
+ resolved "https://registry.yarnpkg.com/dot-case/-/dot-case-3.0.4.tgz#9b2b670d00a431667a8a75ba29cd1b98809ce751"
+ integrity sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==
+ dependencies:
+ no-case "^3.0.4"
+ tslib "^2.0.3"
+
+dot-prop@^5.2.0:
+ version "5.3.0"
+ resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-5.3.0.tgz#90ccce708cd9cd82cc4dc8c3ddd9abdd55b20e88"
+ integrity sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==
+ dependencies:
+ is-obj "^2.0.0"
+
+dotenv@14.2.0:
+ version "14.2.0"
+ resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-14.2.0.tgz#7e77fd5dd6cff5942c4496e1acf2d0f37a9e67aa"
+ integrity sha512-05POuPJyPpO6jqzTNweQFfAyMSD4qa4lvsMOWyTRTdpHKy6nnnN+IYWaXF+lHivhBH/ufDKlR4IWCAN3oPnHuw==
+
+duplexer@^0.1.2:
+ version "0.1.2"
+ resolved "https://registry.yarnpkg.com/duplexer/-/duplexer-0.1.2.tgz#3abe43aef3835f8ae077d136ddce0f276b0400e6"
+ integrity sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==
+
+ecdsa-sig-formatter@1.0.11:
+ version "1.0.11"
+ resolved "https://registry.yarnpkg.com/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz#ae0f0fa2d85045ef14a817daa3ce9acd0489e5bf"
+ integrity sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==
+ dependencies:
+ safe-buffer "^5.0.1"
+
+ee-first@1.1.1:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d"
+ integrity sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==
+
+electron-to-chromium@^1.4.601:
+ version "1.4.628"
+ resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.628.tgz#97cefa4b2356d981875f19639885e4fc50ce6e82"
+ integrity sha512-2k7t5PHvLsufpP6Zwk0nof62yLOsCf032wZx7/q0mv8gwlXjhcxI3lz6f0jBr0GrnWKcm3burXzI3t5IrcdUxw==
+
+elliptic@^6.5.4:
+ version "6.5.4"
+ resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.4.tgz#da37cebd31e79a1367e941b592ed1fbebd58abbb"
+ integrity sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==
+ dependencies:
+ bn.js "^4.11.9"
+ brorand "^1.1.0"
+ hash.js "^1.0.0"
+ hmac-drbg "^1.0.1"
+ inherits "^2.0.4"
+ minimalistic-assert "^1.0.1"
+ minimalistic-crypto-utils "^1.0.1"
+
+emittery@^0.12.1:
+ version "0.12.1"
+ resolved "https://registry.yarnpkg.com/emittery/-/emittery-0.12.1.tgz#cb9a4a18745816f7a1fa03a8953e7eaededb45f2"
+ integrity sha512-pYyW59MIZo0HxPFf+Vb3+gacUu0gxVS3TZwB2ClwkEZywgF9f9OJDoVmNLojTn0vKX3tO9LC+pdQEcLP4Oz/bQ==
+
+emoji-regex@^8.0.0:
+ version "8.0.0"
+ resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37"
+ integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==
+
+emojis-list@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-3.0.0.tgz#5570662046ad29e2e916e71aae260abdff4f6a78"
+ integrity sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==
+
+enabled@2.0.x:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/enabled/-/enabled-2.0.0.tgz#f9dd92ec2d6f4bbc0d5d1e64e21d61cd4665e7c2"
+ integrity sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ==
+
+encodeurl@^1.0.2:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59"
+ integrity sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==
+
+end-of-stream@^1.1.0, end-of-stream@^1.4.1:
+ version "1.4.4"
+ resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0"
+ integrity sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==
+ dependencies:
+ once "^1.4.0"
+
+enhanced-resolve@^5.15.0:
+ version "5.15.0"
+ resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.15.0.tgz#1af946c7d93603eb88e9896cee4904dc012e9c35"
+ integrity sha512-LXYT42KJ7lpIKECr2mAXIaMldcNCh/7E0KBKOu4KSfkHmP+mZmSs+8V5gBAqisWBy0OO4W5Oyys0GO1Y8KtdKg==
+ dependencies:
+ graceful-fs "^4.2.4"
+ tapable "^2.2.0"
+
+entities@^2.0.0:
+ version "2.2.0"
+ resolved "https://registry.yarnpkg.com/entities/-/entities-2.2.0.tgz#098dc90ebb83d8dffa089d55256b351d34c4da55"
+ integrity sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==
+
+entities@^4.2.0, entities@^4.4.0:
+ version "4.5.0"
+ resolved "https://registry.yarnpkg.com/entities/-/entities-4.5.0.tgz#5d268ea5e7113ec74c4d033b79ea5a35a488fb48"
+ integrity sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==
+
+entities@~2.1.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/entities/-/entities-2.1.0.tgz#992d3129cf7df6870b96c57858c249a120f8b8b5"
+ integrity sha512-hCx1oky9PFrJ611mf0ifBLBRW8lUUVRlFolb5gWRfIELabBlbp9xZvrqZLZAs+NxFnbfQoeGd8wDkygjg7U85w==
+
+error-ex@^1.3.1:
+ version "1.3.2"
+ resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf"
+ integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==
+ dependencies:
+ is-arrayish "^0.2.1"
+
+error-stack-parser@^2.0.6:
+ version "2.1.4"
+ resolved "https://registry.yarnpkg.com/error-stack-parser/-/error-stack-parser-2.1.4.tgz#229cb01cdbfa84440bfa91876285b94680188286"
+ integrity sha512-Sk5V6wVazPhq5MhpO+AUxJn5x7XSXGl1R93Vn7i+zS15KDVxQijejNCrz8340/2bgLBjR9GtEG8ZVKONDjcqGQ==
+ dependencies:
+ stackframe "^1.3.4"
+
+es-get-iterator@^1.1.3:
+ version "1.1.3"
+ resolved "https://registry.yarnpkg.com/es-get-iterator/-/es-get-iterator-1.1.3.tgz#3ef87523c5d464d41084b2c3c9c214f1199763d6"
+ integrity sha512-sPZmqHBe6JIiTfN5q2pEi//TwxmAFHwj/XEuYjTuse78i8KxaqMTTzxPoFKuzRpDpTJ+0NAbpfenkmH2rePtuw==
+ dependencies:
+ call-bind "^1.0.2"
+ get-intrinsic "^1.1.3"
+ has-symbols "^1.0.3"
+ is-arguments "^1.1.1"
+ is-map "^2.0.2"
+ is-set "^2.0.2"
+ is-string "^1.0.7"
+ isarray "^2.0.5"
+ stop-iteration-iterator "^1.0.0"
+
+es-module-lexer@^1.2.1:
+ version "1.4.1"
+ resolved "https://registry.yarnpkg.com/es-module-lexer/-/es-module-lexer-1.4.1.tgz#41ea21b43908fe6a287ffcbe4300f790555331f5"
+ integrity sha512-cXLGjP0c4T3flZJKQSuziYoq7MlT+rnvfZjfp7h+I7K9BNX54kP9nyWvdbwjQ4u1iWbOL4u96fgeZLToQlZC7w==
+
+esbuild-loader@^2.21.0:
+ version "2.21.0"
+ resolved "https://registry.yarnpkg.com/esbuild-loader/-/esbuild-loader-2.21.0.tgz#2698a3e565b0db2bb19a3dd91c2b6c9aad526c80"
+ integrity sha512-k7ijTkCT43YBSZ6+fBCW1Gin7s46RrJ0VQaM8qA7lq7W+OLsGgtLyFV8470FzYi/4TeDexniTBTPTwZUnXXR5g==
+ dependencies:
+ esbuild "^0.16.17"
+ joycon "^3.0.1"
+ json5 "^2.2.0"
+ loader-utils "^2.0.0"
+ tapable "^2.2.0"
+ webpack-sources "^1.4.3"
+
+esbuild-register@3.5.0:
+ version "3.5.0"
+ resolved "https://registry.yarnpkg.com/esbuild-register/-/esbuild-register-3.5.0.tgz#449613fb29ab94325c722f560f800dd946dc8ea8"
+ integrity sha512-+4G/XmakeBAsvJuDugJvtyF1x+XJT4FMocynNpxrvEBViirpfUn2PgNpCHedfWhF4WokNsO/OvMKrmJOIJsI5A==
+ dependencies:
+ debug "^4.3.4"
+
+esbuild@0.19.2:
+ version "0.19.2"
+ resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.19.2.tgz#b1541828a89dfb6f840d38538767c6130dca2aac"
+ integrity sha512-G6hPax8UbFakEj3hWO0Vs52LQ8k3lnBhxZWomUJDxfz3rZTLqF5k/FCzuNdLx2RbpBiQQF9H9onlDDH1lZsnjg==
+ optionalDependencies:
+ "@esbuild/android-arm" "0.19.2"
+ "@esbuild/android-arm64" "0.19.2"
+ "@esbuild/android-x64" "0.19.2"
+ "@esbuild/darwin-arm64" "0.19.2"
+ "@esbuild/darwin-x64" "0.19.2"
+ "@esbuild/freebsd-arm64" "0.19.2"
+ "@esbuild/freebsd-x64" "0.19.2"
+ "@esbuild/linux-arm" "0.19.2"
+ "@esbuild/linux-arm64" "0.19.2"
+ "@esbuild/linux-ia32" "0.19.2"
+ "@esbuild/linux-loong64" "0.19.2"
+ "@esbuild/linux-mips64el" "0.19.2"
+ "@esbuild/linux-ppc64" "0.19.2"
+ "@esbuild/linux-riscv64" "0.19.2"
+ "@esbuild/linux-s390x" "0.19.2"
+ "@esbuild/linux-x64" "0.19.2"
+ "@esbuild/netbsd-x64" "0.19.2"
+ "@esbuild/openbsd-x64" "0.19.2"
+ "@esbuild/sunos-x64" "0.19.2"
+ "@esbuild/win32-arm64" "0.19.2"
+ "@esbuild/win32-ia32" "0.19.2"
+ "@esbuild/win32-x64" "0.19.2"
+
+esbuild@^0.16.17:
+ version "0.16.17"
+ resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.16.17.tgz#fc2c3914c57ee750635fee71b89f615f25065259"
+ integrity sha512-G8LEkV0XzDMNwXKgM0Jwu3nY3lSTwSGY6XbxM9cr9+s0T/qSV1q1JVPBGzm3dcjhCic9+emZDmMffkwgPeOeLg==
+ optionalDependencies:
+ "@esbuild/android-arm" "0.16.17"
+ "@esbuild/android-arm64" "0.16.17"
+ "@esbuild/android-x64" "0.16.17"
+ "@esbuild/darwin-arm64" "0.16.17"
+ "@esbuild/darwin-x64" "0.16.17"
+ "@esbuild/freebsd-arm64" "0.16.17"
+ "@esbuild/freebsd-x64" "0.16.17"
+ "@esbuild/linux-arm" "0.16.17"
+ "@esbuild/linux-arm64" "0.16.17"
+ "@esbuild/linux-ia32" "0.16.17"
+ "@esbuild/linux-loong64" "0.16.17"
+ "@esbuild/linux-mips64el" "0.16.17"
+ "@esbuild/linux-ppc64" "0.16.17"
+ "@esbuild/linux-riscv64" "0.16.17"
+ "@esbuild/linux-s390x" "0.16.17"
+ "@esbuild/linux-x64" "0.16.17"
+ "@esbuild/netbsd-x64" "0.16.17"
+ "@esbuild/openbsd-x64" "0.16.17"
+ "@esbuild/sunos-x64" "0.16.17"
+ "@esbuild/win32-arm64" "0.16.17"
+ "@esbuild/win32-ia32" "0.16.17"
+ "@esbuild/win32-x64" "0.16.17"
+
+esbuild@^0.18.10:
+ version "0.18.20"
+ resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.18.20.tgz#4709f5a34801b43b799ab7d6d82f7284a9b7a7a6"
+ integrity sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA==
+ optionalDependencies:
+ "@esbuild/android-arm" "0.18.20"
+ "@esbuild/android-arm64" "0.18.20"
+ "@esbuild/android-x64" "0.18.20"
+ "@esbuild/darwin-arm64" "0.18.20"
+ "@esbuild/darwin-x64" "0.18.20"
+ "@esbuild/freebsd-arm64" "0.18.20"
+ "@esbuild/freebsd-x64" "0.18.20"
+ "@esbuild/linux-arm" "0.18.20"
+ "@esbuild/linux-arm64" "0.18.20"
+ "@esbuild/linux-ia32" "0.18.20"
+ "@esbuild/linux-loong64" "0.18.20"
+ "@esbuild/linux-mips64el" "0.18.20"
+ "@esbuild/linux-ppc64" "0.18.20"
+ "@esbuild/linux-riscv64" "0.18.20"
+ "@esbuild/linux-s390x" "0.18.20"
+ "@esbuild/linux-x64" "0.18.20"
+ "@esbuild/netbsd-x64" "0.18.20"
+ "@esbuild/openbsd-x64" "0.18.20"
+ "@esbuild/sunos-x64" "0.18.20"
+ "@esbuild/win32-arm64" "0.18.20"
+ "@esbuild/win32-ia32" "0.18.20"
+ "@esbuild/win32-x64" "0.18.20"
+
+escalade@^3.1.1:
+ version "3.1.1"
+ resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40"
+ integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==
+
+escape-html@^1.0.3:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988"
+ integrity sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==
+
+escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5:
+ version "1.0.5"
+ resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
+ integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==
+
+escape-string-regexp@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz#a30304e99daa32e23b2fd20f51babd07cffca344"
+ integrity sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==
+
+escape-string-regexp@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34"
+ integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==
+
+esdoc-ecmascript-proposal-plugin@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/esdoc-ecmascript-proposal-plugin/-/esdoc-ecmascript-proposal-plugin-1.0.0.tgz#390dc5656ba8a2830e39dba3570d79138df2ffd9"
+ integrity sha512-PuaU/O8d+Sb0J6qQdyhmy74h/2cp/2kqsvPuoCiK+50Rw54nlGqXxvWNaaNikS5qntE0FfssnwZtUPa6q4RiXg==
+
+eslint-scope@5.1.1:
+ version "5.1.1"
+ resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.1.tgz#e786e59a66cb92b3f6c1fb0d508aab174848f48c"
+ integrity sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==
+ dependencies:
+ esrecurse "^4.3.0"
+ estraverse "^4.1.1"
+
+esm@^3.2.25:
+ version "3.2.25"
+ resolved "https://registry.yarnpkg.com/esm/-/esm-3.2.25.tgz#342c18c29d56157688ba5ce31f8431fbb795cc10"
+ integrity sha512-U1suiZ2oDVWv4zPO56S0NcR5QriEahGtdN2OR6FiOG4WJvcjBVFB0qI4+eKoWFH483PKGuLuu6V8Z4T5g63UVA==
+
+esrecurse@^4.3.0:
+ version "4.3.0"
+ resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.3.0.tgz#7ad7964d679abb28bee72cec63758b1c5d2c9921"
+ integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==
+ dependencies:
+ estraverse "^5.2.0"
+
+estraverse@^4.1.1:
+ version "4.3.0"
+ resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d"
+ integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==
+
+estraverse@^5.2.0:
+ version "5.3.0"
+ resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123"
+ integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==
+
+eventemitter3@^4.0.4:
+ version "4.0.7"
+ resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.7.tgz#2de9b68f6528d5644ef5c59526a1b4a07306169f"
+ integrity sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==
+
+events@1.1.1:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/events/-/events-1.1.1.tgz#9ebdb7635ad099c70dcc4c2a1f5004288e8bd924"
+ integrity sha512-kEcvvCBByWXGnZy6JUlgAp2gBIUjfCAV6P6TgT1/aaQKcmuAEC4OZTV1I4EWQLz2gxZw76atuVyvHhTxvi0Flw==
+
+events@^3.2.0, events@^3.3.0:
+ version "3.3.0"
+ resolved "https://registry.yarnpkg.com/events/-/events-3.3.0.tgz#31a95ad0a924e2d2c419a813aeb2c4e878ea7400"
+ integrity sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==
+
+execa@5.1.1, execa@^5.0.0:
+ version "5.1.1"
+ resolved "https://registry.yarnpkg.com/execa/-/execa-5.1.1.tgz#f80ad9cbf4298f7bd1d4c9555c21e93741c411dd"
+ integrity sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==
+ dependencies:
+ cross-spawn "^7.0.3"
+ get-stream "^6.0.0"
+ human-signals "^2.1.0"
+ is-stream "^2.0.0"
+ merge-stream "^2.0.0"
+ npm-run-path "^4.0.1"
+ onetime "^5.1.2"
+ signal-exit "^3.0.3"
+ strip-final-newline "^2.0.0"
+
+execa@^7.1.1:
+ version "7.2.0"
+ resolved "https://registry.yarnpkg.com/execa/-/execa-7.2.0.tgz#657e75ba984f42a70f38928cedc87d6f2d4fe4e9"
+ integrity sha512-UduyVP7TLB5IcAQl+OzLyLcS/l32W/GLg+AhHJ+ow40FOk2U3SAllPwR44v4vmdFwIWqpdwxxpQbF1n5ta9seA==
+ dependencies:
+ cross-spawn "^7.0.3"
+ get-stream "^6.0.1"
+ human-signals "^4.3.0"
+ is-stream "^3.0.0"
+ merge-stream "^2.0.0"
+ npm-run-path "^5.1.0"
+ onetime "^6.0.0"
+ signal-exit "^3.0.7"
+ strip-final-newline "^3.0.0"
+
+expand-brackets@^2.1.4:
+ version "2.1.4"
+ resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-2.1.4.tgz#b77735e315ce30f6b6eff0f83b04151a22449622"
+ integrity sha512-w/ozOKR9Obk3qoWeY/WDi6MFta9AoMR+zud60mdnbniMcBxRuFJyDt2LdX/14A1UABeqk+Uk+LDfUpvoGKppZA==
+ dependencies:
+ debug "^2.3.3"
+ define-property "^0.2.5"
+ extend-shallow "^2.0.1"
+ posix-character-classes "^0.1.0"
+ regex-not "^1.0.0"
+ snapdragon "^0.8.1"
+ to-regex "^3.0.1"
+
+expand-template@^2.0.3:
+ version "2.0.3"
+ resolved "https://registry.yarnpkg.com/expand-template/-/expand-template-2.0.3.tgz#6e14b3fcee0f3a6340ecb57d2e8918692052a47c"
+ integrity sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==
+
+expand-tilde@^2.0.0, expand-tilde@^2.0.2:
+ version "2.0.2"
+ resolved "https://registry.yarnpkg.com/expand-tilde/-/expand-tilde-2.0.2.tgz#97e801aa052df02454de46b02bf621642cdc8502"
+ integrity sha512-A5EmesHW6rfnZ9ysHQjPdJRni0SRar0tjtG5MNtm9n5TUvsYU8oozprtRD4AqHxcZWWlVuAmQo2nWKfN9oyjTw==
+ dependencies:
+ homedir-polyfill "^1.0.1"
+
+extend-shallow@^2.0.1:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-2.0.1.tgz#51af7d614ad9a9f610ea1bafbb989d6b1c56890f"
+ integrity sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==
+ dependencies:
+ is-extendable "^0.1.0"
+
+extend-shallow@^3.0.0, extend-shallow@^3.0.2:
+ version "3.0.2"
+ resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-3.0.2.tgz#26a71aaf073b39fb2127172746131c2704028db8"
+ integrity sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==
+ dependencies:
+ assign-symbols "^1.0.0"
+ is-extendable "^1.0.1"
+
+extend@^3.0.0:
+ version "3.0.2"
+ resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa"
+ integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==
+
+external-editor@^3.0.3:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-3.1.0.tgz#cb03f740befae03ea4d283caed2741a83f335495"
+ integrity sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==
+ dependencies:
+ chardet "^0.7.0"
+ iconv-lite "^0.4.24"
+ tmp "^0.0.33"
+
+extglob@^2.0.4:
+ version "2.0.4"
+ resolved "https://registry.yarnpkg.com/extglob/-/extglob-2.0.4.tgz#ad00fe4dc612a9232e8718711dc5cb5ab0285543"
+ integrity sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==
+ dependencies:
+ array-unique "^0.3.2"
+ define-property "^1.0.0"
+ expand-brackets "^2.1.4"
+ extend-shallow "^2.0.1"
+ fragment-cache "^0.2.1"
+ regex-not "^1.0.0"
+ snapdragon "^0.8.1"
+ to-regex "^3.0.1"
+
+fast-deep-equal@3.1.3, fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3:
+ version "3.1.3"
+ resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525"
+ integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==
+
+fast-fifo@^1.1.0, fast-fifo@^1.2.0:
+ version "1.3.2"
+ resolved "https://registry.yarnpkg.com/fast-fifo/-/fast-fifo-1.3.2.tgz#286e31de96eb96d38a97899815740ba2a4f3640c"
+ integrity sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==
+
+fast-glob@^3.0.3, fast-glob@^3.3.0:
+ version "3.3.2"
+ resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.2.tgz#a904501e57cfdd2ffcded45e99a54fef55e46129"
+ integrity sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==
+ dependencies:
+ "@nodelib/fs.stat" "^2.0.2"
+ "@nodelib/fs.walk" "^1.2.3"
+ glob-parent "^5.1.2"
+ merge2 "^1.3.0"
+ micromatch "^4.0.4"
+
+fast-json-stable-stringify@^2.0.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633"
+ integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==
+
+fast-xml-parser@4.2.5:
+ version "4.2.5"
+ resolved "https://registry.yarnpkg.com/fast-xml-parser/-/fast-xml-parser-4.2.5.tgz#a6747a09296a6cb34f2ae634019bf1738f3b421f"
+ integrity sha512-B9/wizE4WngqQftFPmdaMYlXoJlJOYxGQOanC77fq9k8+Z0v5dDSVh+3glErdIROP//s/jgb7ZuxKfB8nVyo0g==
+ dependencies:
+ strnum "^1.0.5"
+
+fastq@^1.6.0:
+ version "1.16.0"
+ resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.16.0.tgz#83b9a9375692db77a822df081edb6a9cf6839320"
+ integrity sha512-ifCoaXsDrsdkWTtiNJX5uzHDsrck5TzfKKDcuFFTIrrc/BS076qgEIfoIy1VeZqViznfKiysPYTh/QeHtnIsYA==
+ dependencies:
+ reusify "^1.0.4"
+
+fecha@^4.2.0:
+ version "4.2.3"
+ resolved "https://registry.yarnpkg.com/fecha/-/fecha-4.2.3.tgz#4d9ccdbc61e8629b259fdca67e65891448d569fd"
+ integrity sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw==
+
+figures@^3.0.0:
+ version "3.2.0"
+ resolved "https://registry.yarnpkg.com/figures/-/figures-3.2.0.tgz#625c18bd293c604dc4a8ddb2febf0c88341746af"
+ integrity sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==
+ dependencies:
+ escape-string-regexp "^1.0.5"
+
+file-uri-to-path@1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz#553a7b8446ff6f684359c445f1e37a05dacc33dd"
+ integrity sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==
+
+fill-range@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-4.0.0.tgz#d544811d428f98eb06a63dc402d2403c328c38f7"
+ integrity sha512-VcpLTWqWDiTerugjj8e3+esbg+skS3M9e54UuR3iCeIDMXCLTsAH8hTSzDQU/X6/6t3eYkOKoZSef2PlU6U1XQ==
+ dependencies:
+ extend-shallow "^2.0.1"
+ is-number "^3.0.0"
+ repeat-string "^1.6.1"
+ to-regex-range "^2.1.0"
+
+fill-range@^7.0.1:
+ version "7.0.1"
+ resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40"
+ integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==
+ dependencies:
+ to-regex-range "^5.0.1"
+
+find-root@1.1.0, find-root@^1.1.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/find-root/-/find-root-1.1.0.tgz#abcfc8ba76f708c42a97b3d685b7e9450bfb9ce4"
+ integrity sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==
+
+find-up@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/find-up/-/find-up-3.0.0.tgz#49169f1d7993430646da61ecc5ae355c21c97b73"
+ integrity sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==
+ dependencies:
+ locate-path "^3.0.0"
+
+find-up@^4.1.0:
+ version "4.1.0"
+ resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19"
+ integrity sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==
+ dependencies:
+ locate-path "^5.0.0"
+ path-exists "^4.0.0"
+
+find-up@^5.0.0:
+ version "5.0.0"
+ resolved "https://registry.yarnpkg.com/find-up/-/find-up-5.0.0.tgz#4c92819ecb7083561e4f4a240a86be5198f536fc"
+ integrity sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==
+ dependencies:
+ locate-path "^6.0.0"
+ path-exists "^4.0.0"
+
+findup-sync@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/findup-sync/-/findup-sync-2.0.0.tgz#9326b1488c22d1a6088650a86901b2d9a90a2cbc"
+ integrity sha512-vs+3unmJT45eczmcAZ6zMJtxN3l/QXeccaXQx5cu/MeJMhewVfoWZqibRkOxPnmoR59+Zy5hjabfQc6JLSah4g==
+ dependencies:
+ detect-file "^1.0.0"
+ is-glob "^3.1.0"
+ micromatch "^3.0.4"
+ resolve-dir "^1.0.1"
+
+fined@^1.0.1:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/fined/-/fined-1.2.0.tgz#d00beccf1aa2b475d16d423b0238b713a2c4a37b"
+ integrity sha512-ZYDqPLGxDkDhDZBjZBb+oD1+j0rA4E0pXY50eplAAOPg2N/gUBSSk5IM1/QhPfyVo19lJ+CvXpqfvk+b2p/8Ng==
+ dependencies:
+ expand-tilde "^2.0.2"
+ is-plain-object "^2.0.3"
+ object.defaults "^1.1.0"
+ object.pick "^1.2.0"
+ parse-filepath "^1.0.1"
+
+flagged-respawn@^1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/flagged-respawn/-/flagged-respawn-1.0.1.tgz#e7de6f1279ddd9ca9aac8a5971d618606b3aab41"
+ integrity sha512-lNaHNVymajmk0OJMBn8fVUAU1BtDeKIqKoVhk4xAALB57aALg6b4W0MfJ/cUE0g9YBXy5XhSlPIpYIJ7HaY/3Q==
+
+flat-cache@^3.0.4:
+ version "3.2.0"
+ resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-3.2.0.tgz#2c0c2d5040c99b1632771a9d105725c0115363ee"
+ integrity sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==
+ dependencies:
+ flatted "^3.2.9"
+ keyv "^4.5.3"
+ rimraf "^3.0.2"
+
+flatted@^3.2.9:
+ version "3.2.9"
+ resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.2.9.tgz#7eb4c67ca1ba34232ca9d2d93e9886e611ad7daf"
+ integrity sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ==
+
+fn.name@1.x.x:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/fn.name/-/fn.name-1.1.0.tgz#26cad8017967aea8731bc42961d04a3d5988accc"
+ integrity sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==
+
+follow-redirects@^1.14.8, follow-redirects@^1.15.0, follow-redirects@^1.15.2, follow-redirects@^1.15.4:
+ version "1.15.4"
+ resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.4.tgz#cdc7d308bf6493126b17ea2191ea0ccf3e535adf"
+ integrity sha512-Cr4D/5wlrb0z9dgERpUL3LrmPKVDsETIJhaCMeDfuFYcqa5bldGV6wBsAN6X/vxlXQtFBMrXdXxdL8CbDTGniw==
+
+for-each@^0.3.3:
+ version "0.3.3"
+ resolved "https://registry.yarnpkg.com/for-each/-/for-each-0.3.3.tgz#69b447e88a0a5d32c3e7084f3f1710034b21376e"
+ integrity sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==
+ dependencies:
+ is-callable "^1.1.3"
+
+for-in@^1.0.1, for-in@^1.0.2:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80"
+ integrity sha512-7EwmXrOjyL+ChxMhmG5lnW9MPt1aIeZEwKhQzoBUdTV0N3zuwWDZYVJatDvZ2OyzPUvdIAZDsCetk3coyMfcnQ==
+
+for-own@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/for-own/-/for-own-1.0.0.tgz#c63332f415cedc4b04dbfe70cf836494c53cb44b"
+ integrity sha512-0OABksIGrxKK8K4kynWkQ7y1zounQxP+CWnyclVwj81KW3vlLlGUx57DKGcP/LH216GzqnstnPocF16Nxs0Ycg==
+ dependencies:
+ for-in "^1.0.1"
+
+fork-ts-checker-webpack-plugin@8.0.0:
+ version "8.0.0"
+ resolved "https://registry.yarnpkg.com/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-8.0.0.tgz#dae45dfe7298aa5d553e2580096ced79b6179504"
+ integrity sha512-mX3qW3idpueT2klaQXBzrIM/pHw+T0B/V9KHEvNrqijTq9NFnMZU6oreVxDYcf33P8a5cW+67PjodNHthGnNVg==
+ dependencies:
+ "@babel/code-frame" "^7.16.7"
+ chalk "^4.1.2"
+ chokidar "^3.5.3"
+ cosmiconfig "^7.0.1"
+ deepmerge "^4.2.2"
+ fs-extra "^10.0.0"
+ memfs "^3.4.1"
+ minimatch "^3.0.4"
+ node-abort-controller "^3.0.1"
+ schema-utils "^3.1.1"
+ semver "^7.3.5"
+ tapable "^2.2.1"
+
+form-data@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.0.tgz#93919daeaf361ee529584b9b31664dc12c9fa452"
+ integrity sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==
+ dependencies:
+ asynckit "^0.4.0"
+ combined-stream "^1.0.8"
+ mime-types "^2.1.12"
+
+formidable@^1.1.1:
+ version "1.2.6"
+ resolved "https://registry.yarnpkg.com/formidable/-/formidable-1.2.6.tgz#d2a51d60162bbc9b4a055d8457a7c75315d1a168"
+ integrity sha512-KcpbcpuLNOwrEjnbpMC0gS+X8ciDoZE1kkqzat4a8vrprf+s9pKNQ/QIwWfbfs4ltgmFl3MD177SNTkve3BwGQ==
+
+formik@2.2.9:
+ version "2.2.9"
+ resolved "https://registry.yarnpkg.com/formik/-/formik-2.2.9.tgz#8594ba9c5e2e5cf1f42c5704128e119fc46232d0"
+ integrity sha512-LQLcISMmf1r5at4/gyJigGn0gOwFbeEAlji+N9InZF6LIMXnFNkO42sCI8Jt84YZggpD4cPWObAZaxpEFtSzNA==
+ dependencies:
+ deepmerge "^2.1.1"
+ hoist-non-react-statics "^3.3.0"
+ lodash "^4.17.21"
+ lodash-es "^4.17.21"
+ react-fast-compare "^2.0.1"
+ tiny-warning "^1.0.2"
+ tslib "^1.10.0"
+
+formik@2.4.0:
+ version "2.4.0"
+ resolved "https://registry.yarnpkg.com/formik/-/formik-2.4.0.tgz#8243e42a89e1c9fbe9aefbd48bc8d1f10ae2950d"
+ integrity sha512-QZiWztt9fD84EYcF7Bmr431ZhIm1xUVgBACbTuJ6azPrUpVp7o6q+t9HJaIQsFZrMfcBPNBotYtDgyDpzQ3z0Q==
+ dependencies:
+ deepmerge "^2.1.1"
+ hoist-non-react-statics "^3.3.0"
+ lodash "^4.17.21"
+ lodash-es "^4.17.21"
+ react-fast-compare "^2.0.1"
+ tiny-warning "^1.0.2"
+ tslib "^1.10.0"
+
+fractional-indexing@3.2.0:
+ version "3.2.0"
+ resolved "https://registry.yarnpkg.com/fractional-indexing/-/fractional-indexing-3.2.0.tgz#1193e63d54ff4e0cbe0c79a9ed6cfbab25d91628"
+ integrity sha512-PcOxmqwYCW7O2ovKRU8OoQQj2yqTfEB/yeTYk4gPid6dN5ODRfU1hXd9tTVZzax/0NkO7AxpHykvZnT1aYp/BQ==
+
+fragment-cache@^0.2.1:
+ version "0.2.1"
+ resolved "https://registry.yarnpkg.com/fragment-cache/-/fragment-cache-0.2.1.tgz#4290fad27f13e89be7f33799c6bc5a0abfff0d19"
+ integrity sha512-GMBAbW9antB8iZRHLoGw0b3HANt57diZYFO/HL1JGIC1MjKrdmhxvrJbupnVvpys0zsz7yBApXdQyfepKly2kA==
+ dependencies:
+ map-cache "^0.2.2"
+
+fresh@~0.5.2:
+ version "0.5.2"
+ resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7"
+ integrity sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==
+
+from2@^2.3.0:
+ version "2.3.0"
+ resolved "https://registry.yarnpkg.com/from2/-/from2-2.3.0.tgz#8bfb5502bde4a4d36cfdeea007fcca21d7e382af"
+ integrity sha512-OMcX/4IC/uqEPVgGeyfN22LJk6AZrMkRZHxcHBMBvHScDGgwTm2GT2Wkgtocyd3JfZffjj2kYUDXXII0Fk9W0g==
+ dependencies:
+ inherits "^2.0.1"
+ readable-stream "^2.0.0"
+
+fs-constants@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/fs-constants/-/fs-constants-1.0.0.tgz#6be0de9be998ce16af8afc24497b9ee9b7ccd9ad"
+ integrity sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==
+
+fs-extra@10.0.0:
+ version "10.0.0"
+ resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-10.0.0.tgz#9ff61b655dde53fb34a82df84bb214ce802e17c1"
+ integrity sha512-C5owb14u9eJwizKGdchcDUQeFtlSHHthBk8pbX9Vc1PFZrLombudjDnNns88aYslCyF6IY5SUw3Roz6xShcEIQ==
+ dependencies:
+ graceful-fs "^4.2.0"
+ jsonfile "^6.0.1"
+ universalify "^2.0.0"
+
+fs-extra@^10.0.0:
+ version "10.1.0"
+ resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-10.1.0.tgz#02873cfbc4084dde127eaa5f9905eef2325d1abf"
+ integrity sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==
+ dependencies:
+ graceful-fs "^4.2.0"
+ jsonfile "^6.0.1"
+ universalify "^2.0.0"
+
+fs-jetpack@^4.3.1:
+ version "4.3.1"
+ resolved "https://registry.yarnpkg.com/fs-jetpack/-/fs-jetpack-4.3.1.tgz#cdfd4b64e6bfdec7c7dc55c76b39efaa7853bb20"
+ integrity sha512-dbeOK84F6BiQzk2yqqCVwCPWTxAvVGJ3fMQc6E2wuEohS28mR6yHngbrKuVCK1KHRx/ccByDylqu4H5PCP2urQ==
+ dependencies:
+ minimatch "^3.0.2"
+ rimraf "^2.6.3"
+
+fs-minipass@^2.0.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-2.1.0.tgz#7f5036fdbf12c63c169190cbe4199c852271f9fb"
+ integrity sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==
+ dependencies:
+ minipass "^3.0.0"
+
+fs-monkey@^1.0.4:
+ version "1.0.5"
+ resolved "https://registry.yarnpkg.com/fs-monkey/-/fs-monkey-1.0.5.tgz#fe450175f0db0d7ea758102e1d84096acb925788"
+ integrity sha512-8uMbBjrhzW76TYgEV27Y5E//W2f/lTFmx78P2w19FZSxarhI/798APGQyuGCwmkNxgwGRhrLfvWyLBvNtuOmew==
+
+fs.realpath@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"
+ integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==
+
+fsevents@~2.3.2:
+ version "2.3.3"
+ resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6"
+ integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==
+
+function-bind@^1.1.2:
+ version "1.1.2"
+ resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c"
+ integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==
+
+functions-have-names@^1.2.3:
+ version "1.2.3"
+ resolved "https://registry.yarnpkg.com/functions-have-names/-/functions-have-names-1.2.3.tgz#0404fe4ee2ba2f607f0e0ec3c80bae994133b834"
+ integrity sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==
+
+fuzzy-search@^3.2.1:
+ version "3.2.1"
+ resolved "https://registry.yarnpkg.com/fuzzy-search/-/fuzzy-search-3.2.1.tgz#65d5faad6bc633aee86f1898b7788dfe312ac6c9"
+ integrity sha512-vAcPiyomt1ioKAsAL2uxSABHJ4Ju/e4UeDM+g1OlR0vV4YhLGMNsdLNvZTpEDY4JCSt0E4hASCNM5t2ETtsbyg==
+
+fuzzysort@2.0.4:
+ version "2.0.4"
+ resolved "https://registry.yarnpkg.com/fuzzysort/-/fuzzysort-2.0.4.tgz#a21d1ce8947eaf2797dc3b7c28c36db9d1165f84"
+ integrity sha512-Api1mJL+Ad7W7vnDZnWq5pGaXJjyencT+iKGia2PlHUcSsSzWwIQ3S1isiMpwpavjYtGd2FzhUIhnnhOULZgDw==
+
+gauge@^3.0.0:
+ version "3.0.2"
+ resolved "https://registry.yarnpkg.com/gauge/-/gauge-3.0.2.tgz#03bf4441c044383908bcfa0656ad91803259b395"
+ integrity sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q==
+ dependencies:
+ aproba "^1.0.3 || ^2.0.0"
+ color-support "^1.1.2"
+ console-control-strings "^1.0.0"
+ has-unicode "^2.0.1"
+ object-assign "^4.1.1"
+ signal-exit "^3.0.0"
+ string-width "^4.2.3"
+ strip-ansi "^6.0.1"
+ wide-align "^1.1.2"
+
+gensync@^1.0.0-beta.2:
+ version "1.0.0-beta.2"
+ resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0"
+ integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==
+
+get-caller-file@^2.0.5:
+ version "2.0.5"
+ resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e"
+ integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==
+
+get-intrinsic@^1.0.2, get-intrinsic@^1.1.1, get-intrinsic@^1.1.3, get-intrinsic@^1.2.0, get-intrinsic@^1.2.1, get-intrinsic@^1.2.2:
+ version "1.2.2"
+ resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.2.tgz#281b7622971123e1ef4b3c90fd7539306da93f3b"
+ integrity sha512-0gSo4ml/0j98Y3lngkFEot/zhiCeWsbYIlZ+uZOVgzLyLaUw7wxUL+nCTP0XJvJg1AXulJRI3UJi8GsbDuxdGA==
+ dependencies:
+ function-bind "^1.1.2"
+ has-proto "^1.0.1"
+ has-symbols "^1.0.3"
+ hasown "^2.0.0"
+
+get-it@^8.0.9:
+ version "8.4.4"
+ resolved "https://registry.yarnpkg.com/get-it/-/get-it-8.4.4.tgz#8c1c4b16f6f2da4120c00fffa66c5afe2d454e23"
+ integrity sha512-Pu3pnJfnYuLEhwJgMlFqk19ugvtazzTxh7rg8wATaBL4c5Fy4ahM5B+bGdluiNSNYYK89F5vSa+N3sTa/qqtlg==
+ dependencies:
+ debug "^4.3.4"
+ decompress-response "^7.0.0"
+ follow-redirects "^1.15.2"
+ into-stream "^6.0.0"
+ is-plain-object "^5.0.0"
+ is-retry-allowed "^2.2.0"
+ is-stream "^2.0.1"
+ parse-headers "^2.0.5"
+ progress-stream "^2.0.0"
+ tunnel-agent "^0.6.0"
+
+get-latest-version@5.1.0:
+ version "5.1.0"
+ resolved "https://registry.yarnpkg.com/get-latest-version/-/get-latest-version-5.1.0.tgz#928f7fda59a9a34d7c7cf3664a2006dfd9af6aa7"
+ integrity sha512-Q6IBWr/zzw57zIkJmNhI23eRTw3nZ4BWWK034meLwOYU9L3J3IpXiyM73u2pYUwN6U7ahkerCwg2T0jlxiLwsw==
+ dependencies:
+ get-it "^8.0.9"
+ registry-auth-token "^5.0.2"
+ registry-url "^5.1.0"
+ semver "^7.3.8"
+
+get-nonce@^1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/get-nonce/-/get-nonce-1.0.1.tgz#fdf3f0278073820d2ce9426c18f07481b1e0cdf3"
+ integrity sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==
+
+get-package-type@^0.1.0:
+ version "0.1.0"
+ resolved "https://registry.yarnpkg.com/get-package-type/-/get-package-type-0.1.0.tgz#8de2d803cff44df3bc6c456e6668b36c3926e11a"
+ integrity sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==
+
+get-stdin@^9.0.0:
+ version "9.0.0"
+ resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-9.0.0.tgz#3983ff82e03d56f1b2ea0d3e60325f39d703a575"
+ integrity sha512-dVKBjfWisLAicarI2Sf+JuBE/DghV4UzNAVe9yhEJuzeREd3JhOTE9cUaJTeSa77fsbQUK3pcOpJfM59+VKZaA==
+
+get-stream@^5.1.0:
+ version "5.2.0"
+ resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-5.2.0.tgz#4966a1795ee5ace65e706c4b7beb71257d6e22d3"
+ integrity sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==
+ dependencies:
+ pump "^3.0.0"
+
+get-stream@^6.0.0, get-stream@^6.0.1:
+ version "6.0.1"
+ resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7"
+ integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==
+
+get-value@^2.0.3, get-value@^2.0.6:
+ version "2.0.6"
+ resolved "https://registry.yarnpkg.com/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28"
+ integrity sha512-Ln0UQDlxH1BapMu3GPtf7CuYNwRZf2gwCuPqbyG6pB8WfmFpzqcy4xtAaAMUhnNqjMKTiCPZG2oMT3YSx8U2NA==
+
+getopts@2.3.0:
+ version "2.3.0"
+ resolved "https://registry.yarnpkg.com/getopts/-/getopts-2.3.0.tgz#71e5593284807e03e2427449d4f6712a268666f4"
+ integrity sha512-5eDf9fuSXwxBL6q5HX+dhDj+dslFGWzU5thZ9kNKUkcPtaPdatmUFKwHFrLb/uf/WpA4BHET+AX3Scl56cAjpA==
+
+git-hooks-list@^3.0.0:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/git-hooks-list/-/git-hooks-list-3.1.0.tgz#386dc531dcc17474cf094743ff30987a3d3e70fc"
+ integrity sha512-LF8VeHeR7v+wAbXqfgRlTSX/1BJR9Q1vEMR8JAz1cEg6GX07+zyj3sAdDvYjj/xnlIfVuGgj4qBei1K3hKH+PA==
+
+git-up@^7.0.0:
+ version "7.0.0"
+ resolved "https://registry.yarnpkg.com/git-up/-/git-up-7.0.0.tgz#bace30786e36f56ea341b6f69adfd83286337467"
+ integrity sha512-ONdIrbBCFusq1Oy0sC71F5azx8bVkvtZtMJAsv+a6lz5YAmbNnLD6HAB4gptHZVLPR8S2/kVN6Gab7lryq5+lQ==
+ dependencies:
+ is-ssh "^1.4.0"
+ parse-url "^8.1.0"
+
+git-url-parse@13.1.0:
+ version "13.1.0"
+ resolved "https://registry.yarnpkg.com/git-url-parse/-/git-url-parse-13.1.0.tgz#07e136b5baa08d59fabdf0e33170de425adf07b4"
+ integrity sha512-5FvPJP/70WkIprlUZ33bm4UAaFdjcLkJLpWft1BeZKqwR0uhhNGoKwlUaPtVb4LxCSQ++erHapRak9kWGj+FCA==
+ dependencies:
+ git-up "^7.0.0"
+
+github-from-package@0.0.0:
+ version "0.0.0"
+ resolved "https://registry.yarnpkg.com/github-from-package/-/github-from-package-0.0.0.tgz#97fb5d96bfde8973313f20e8288ef9a167fa64ce"
+ integrity sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==
+
+glob-parent@^5.1.2, glob-parent@~5.1.2:
+ version "5.1.2"
+ resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4"
+ integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==
+ dependencies:
+ is-glob "^4.0.1"
+
+glob-to-regexp@^0.4.1:
+ version "0.4.1"
+ resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz#c75297087c851b9a578bd217dd59a92f59fe546e"
+ integrity sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==
+
+glob@7.2.3, glob@^7.0.5, glob@^7.1.3:
+ version "7.2.3"
+ resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b"
+ integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==
+ dependencies:
+ fs.realpath "^1.0.0"
+ inflight "^1.0.4"
+ inherits "2"
+ minimatch "^3.1.1"
+ once "^1.3.0"
+ path-is-absolute "^1.0.0"
+
+glob@^8.0.3:
+ version "8.1.0"
+ resolved "https://registry.yarnpkg.com/glob/-/glob-8.1.0.tgz#d388f656593ef708ee3e34640fdfb99a9fd1c33e"
+ integrity sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==
+ dependencies:
+ fs.realpath "^1.0.0"
+ inflight "^1.0.4"
+ inherits "2"
+ minimatch "^5.0.1"
+ once "^1.3.0"
+
+global-modules@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/global-modules/-/global-modules-1.0.0.tgz#6d770f0eb523ac78164d72b5e71a8877265cc3ea"
+ integrity sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==
+ dependencies:
+ global-prefix "^1.0.1"
+ is-windows "^1.0.1"
+ resolve-dir "^1.0.0"
+
+global-prefix@^1.0.1:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/global-prefix/-/global-prefix-1.0.2.tgz#dbf743c6c14992593c655568cb66ed32c0122ebe"
+ integrity sha512-5lsx1NUDHtSjfg0eHlmYvZKv8/nVqX4ckFbM+FrGcQ+04KWcWFo9P5MxPZYSzUvyzmdTbI7Eix8Q4IbELDqzKg==
+ dependencies:
+ expand-tilde "^2.0.2"
+ homedir-polyfill "^1.0.1"
+ ini "^1.3.4"
+ is-windows "^1.0.1"
+ which "^1.2.14"
+
+globals@^11.1.0:
+ version "11.12.0"
+ resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e"
+ integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==
+
+globby@^10.0.1:
+ version "10.0.2"
+ resolved "https://registry.yarnpkg.com/globby/-/globby-10.0.2.tgz#277593e745acaa4646c3ab411289ec47a0392543"
+ integrity sha512-7dUi7RvCoT/xast/o/dLN53oqND4yk0nsHkhRgn9w65C4PofCLOoJ39iSOg+qVDdWQPIEj+eszMHQ+aLVwwQSg==
+ dependencies:
+ "@types/glob" "^7.1.1"
+ array-union "^2.1.0"
+ dir-glob "^3.0.1"
+ fast-glob "^3.0.3"
+ glob "^7.1.3"
+ ignore "^5.1.1"
+ merge2 "^1.2.3"
+ slash "^3.0.0"
+
+globby@^13.1.2:
+ version "13.2.2"
+ resolved "https://registry.yarnpkg.com/globby/-/globby-13.2.2.tgz#63b90b1bf68619c2135475cbd4e71e66aa090592"
+ integrity sha512-Y1zNGV+pzQdh7H39l9zgB4PJqjRNqydvdYCDG4HFXM4XuvSaQQlEc91IU1yALL8gUTDomgBAfz3XJdmUS+oo0w==
+ dependencies:
+ dir-glob "^3.0.1"
+ fast-glob "^3.3.0"
+ ignore "^5.2.4"
+ merge2 "^1.4.1"
+ slash "^4.0.0"
+
+gopd@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/gopd/-/gopd-1.0.1.tgz#29ff76de69dac7489b7c0918a5788e56477c332c"
+ integrity sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==
+ dependencies:
+ get-intrinsic "^1.1.3"
+
+got@^11.8.2:
+ version "11.8.6"
+ resolved "https://registry.yarnpkg.com/got/-/got-11.8.6.tgz#276e827ead8772eddbcfc97170590b841823233a"
+ integrity sha512-6tfZ91bOr7bOXnK7PRDCGBLa1H4U080YHNaAQ2KsMGlLEzRbk44nsZF2E1IeRc3vtJHPVbKCYgdFbaGO2ljd8g==
+ dependencies:
+ "@sindresorhus/is" "^4.0.0"
+ "@szmarczak/http-timer" "^4.0.5"
+ "@types/cacheable-request" "^6.0.1"
+ "@types/responselike" "^1.0.0"
+ cacheable-lookup "^5.0.3"
+ cacheable-request "^7.0.2"
+ decompress-response "^6.0.0"
+ http2-wrapper "^1.0.0-beta.5.2"
+ lowercase-keys "^2.0.0"
+ p-cancelable "^2.0.0"
+ responselike "^2.0.0"
+
+graceful-fs@4.2.10:
+ version "4.2.10"
+ resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.10.tgz#147d3a006da4ca3ce14728c7aefc287c367d7a6c"
+ integrity sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==
+
+graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.2, graceful-fs@^4.2.4, graceful-fs@^4.2.9:
+ version "4.2.11"
+ resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3"
+ integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==
+
+grant-koa@5.4.8:
+ version "5.4.8"
+ resolved "https://registry.yarnpkg.com/grant-koa/-/grant-koa-5.4.8.tgz#2fc49ad91007588fff58559cffa44dca9f06835d"
+ integrity sha512-Kw8np9AL3Z3mZuvoSUklHJpTe3xx7iLBDauRyIwwbDLRr/5Ll6APmOFHixXj+Vw+LGEnreTxO35CyhAf9oBUMA==
+ dependencies:
+ grant "^5.4.8"
+
+grant@^5.4.8:
+ version "5.4.22"
+ resolved "https://registry.yarnpkg.com/grant/-/grant-5.4.22.tgz#b4756e7bb51a6a0091387467b4058ec6a750d69e"
+ integrity sha512-DEi+/JjXT84mmFYhSmv+SX14v+3Z7vuCIYAMwtdPCTXHMSLhWqSYqWAMXDUQZuV7yaJv2d84AYnkCFNooLKBsA==
+ dependencies:
+ qs "^6.11.2"
+ request-compose "^2.1.6"
+ request-oauth "^1.0.1"
+ optionalDependencies:
+ cookie "^0.5.0"
+ cookie-signature "^1.2.1"
+ jwk-to-pem "^2.0.5"
+ jws "^4.0.0"
+
+"graphql@^15.0.0 || ^16.0.0":
+ version "16.8.1"
+ resolved "https://registry.yarnpkg.com/graphql/-/graphql-16.8.1.tgz#1930a965bef1170603702acdb68aedd3f3cf6f07"
+ integrity sha512-59LZHPdGZVh695Ud9lRzPBVTtlX9ZCV150Er2W43ro37wVof0ctenSaskPPjN7lVTIN8mSZt8PHUNKZuNQUuxw==
+
+gzip-size@^6.0.0:
+ version "6.0.0"
+ resolved "https://registry.yarnpkg.com/gzip-size/-/gzip-size-6.0.0.tgz#065367fd50c239c0671cbcbad5be3e2eeb10e462"
+ integrity sha512-ax7ZYomf6jqPTQ4+XCpUGyXKHk5WweS+e05MBO4/y3WJ5RkmPXNKvX+bx1behVILVwr6JSQvZAku021CHPXG3Q==
+ dependencies:
+ duplexer "^0.1.2"
+
+handlebars@^4.4.3:
+ version "4.7.8"
+ resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.7.8.tgz#41c42c18b1be2365439188c77c6afae71c0cd9e9"
+ integrity sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ==
+ dependencies:
+ minimist "^1.2.5"
+ neo-async "^2.6.2"
+ source-map "^0.6.1"
+ wordwrap "^1.0.0"
+ optionalDependencies:
+ uglify-js "^3.1.4"
+
+has-ansi@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91"
+ integrity sha512-C8vBJ8DwUCx19vhm7urhTuUsr4/IyP6l4VzNQDv+ryHQObW3TTTp9yB68WpYgRe2bbaGuZ/se74IqFeVnMnLZg==
+ dependencies:
+ ansi-regex "^2.0.0"
+
+has-bigints@^1.0.1:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/has-bigints/-/has-bigints-1.0.2.tgz#0871bd3e3d51626f6ca0966668ba35d5602d6eaa"
+ integrity sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==
+
+has-flag@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd"
+ integrity sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==
+
+has-flag@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b"
+ integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==
+
+has-property-descriptors@^1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/has-property-descriptors/-/has-property-descriptors-1.0.1.tgz#52ba30b6c5ec87fd89fa574bc1c39125c6f65340"
+ integrity sha512-VsX8eaIewvas0xnvinAe9bw4WfIeODpGYikiWYLH+dma0Jw6KHYqWiWfhQlgOVK8D6PvjubK5Uc4P0iIhIcNVg==
+ dependencies:
+ get-intrinsic "^1.2.2"
+
+has-proto@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/has-proto/-/has-proto-1.0.1.tgz#1885c1305538958aff469fef37937c22795408e0"
+ integrity sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==
+
+has-symbols@^1.0.2, has-symbols@^1.0.3:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8"
+ integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==
+
+has-tostringtag@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/has-tostringtag/-/has-tostringtag-1.0.0.tgz#7e133818a7d394734f941e73c3d3f9291e658b25"
+ integrity sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==
+ dependencies:
+ has-symbols "^1.0.2"
+
+has-unicode@^2.0.1:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9"
+ integrity sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==
+
+has-value@^0.3.1:
+ version "0.3.1"
+ resolved "https://registry.yarnpkg.com/has-value/-/has-value-0.3.1.tgz#7b1f58bada62ca827ec0a2078025654845995e1f"
+ integrity sha512-gpG936j8/MzaeID5Yif+577c17TxaDmhuyVgSwtnL/q8UUTySg8Mecb+8Cf1otgLoD7DDH75axp86ER7LFsf3Q==
+ dependencies:
+ get-value "^2.0.3"
+ has-values "^0.1.4"
+ isobject "^2.0.0"
+
+has-value@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/has-value/-/has-value-1.0.0.tgz#18b281da585b1c5c51def24c930ed29a0be6b177"
+ integrity sha512-IBXk4GTsLYdQ7Rvt+GRBrFSVEkmuOUy4re0Xjd9kJSUQpnTrWR4/y9RpfexN9vkAPMFuQoeWKwqzPozRTlasGw==
+ dependencies:
+ get-value "^2.0.6"
+ has-values "^1.0.0"
+ isobject "^3.0.0"
+
+has-values@^0.1.4:
+ version "0.1.4"
+ resolved "https://registry.yarnpkg.com/has-values/-/has-values-0.1.4.tgz#6d61de95d91dfca9b9a02089ad384bff8f62b771"
+ integrity sha512-J8S0cEdWuQbqD9//tlZxiMuMNmxB8PlEwvYwuxsTmR1G5RXUePEX/SJn7aD0GMLieuZYSwNH0cQuJGwnYunXRQ==
+
+has-values@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/has-values/-/has-values-1.0.0.tgz#95b0b63fec2146619a6fe57fe75628d5a39efe4f"
+ integrity sha512-ODYZC64uqzmtfGMEAX/FvZiRyWLpAC3vYnNunURUnkGVTS+mI0smVsWaPydRBsE3g+ok7h960jChO8mFcWlHaQ==
+ dependencies:
+ is-number "^3.0.0"
+ kind-of "^4.0.0"
+
+hash.js@^1.0.0, hash.js@^1.0.3:
+ version "1.1.7"
+ resolved "https://registry.yarnpkg.com/hash.js/-/hash.js-1.1.7.tgz#0babca538e8d4ee4a0f8988d68866537a003cf42"
+ integrity sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==
+ dependencies:
+ inherits "^2.0.3"
+ minimalistic-assert "^1.0.1"
+
+hasown@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.0.tgz#f4c513d454a57b7c7e1650778de226b11700546c"
+ integrity sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==
+ dependencies:
+ function-bind "^1.1.2"
+
+he@^1.2.0:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f"
+ integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==
+
+header-case@^1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/header-case/-/header-case-1.0.1.tgz#9535973197c144b09613cd65d317ef19963bd02d"
+ integrity sha512-i0q9mkOeSuhXw6bGgiQCCBgY/jlZuV/7dZXyZ9c6LcBrqwvT8eT719E9uxE5LiZftdl+z81Ugbg/VvXV4OJOeQ==
+ dependencies:
+ no-case "^2.2.0"
+ upper-case "^1.1.3"
+
+headers-polyfill@3.2.5:
+ version "3.2.5"
+ resolved "https://registry.yarnpkg.com/headers-polyfill/-/headers-polyfill-3.2.5.tgz#6e67d392c9d113d37448fe45014e0afdd168faed"
+ integrity sha512-tUCGvt191vNSQgttSyJoibR+VO+I6+iCHIUdhzEMJKE+EAL8BwCN7fUOZlY4ofOelNHsK+gEjxB/B+9N3EWtdA==
+
+headers-polyfill@^3.1.0:
+ version "3.3.0"
+ resolved "https://registry.yarnpkg.com/headers-polyfill/-/headers-polyfill-3.3.0.tgz#67c6ef7b72d4c8cac832ad5936f5b3a56e7b705a"
+ integrity sha512-5e57etwBpNcDc0b6KCVWEh/Ro063OxPvzVimUdM0/tsYM/T7Hfy3kknIGj78SFTOhNd8AZY41U8mOHoO4LzmIQ==
+
+helmet@^6.0.1:
+ version "6.2.0"
+ resolved "https://registry.yarnpkg.com/helmet/-/helmet-6.2.0.tgz#c29d62014be4c70b8ef092c9c5e54c8c26b8e16e"
+ integrity sha512-DWlwuXLLqbrIOltR6tFQXShj/+7Cyp0gLi6uAb8qMdFh/YBBFbKSgQ6nbXmScYd8emMctuthmgIa7tUfo9Rtyg==
+
+highlight.js@^10.4.1:
+ version "10.7.3"
+ resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-10.7.3.tgz#697272e3991356e40c3cac566a74eef681756531"
+ integrity sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A==
+
+history@^4.10.1, history@^4.9.0:
+ version "4.10.1"
+ resolved "https://registry.yarnpkg.com/history/-/history-4.10.1.tgz#33371a65e3a83b267434e2b3f3b1b4c58aad4cf3"
+ integrity sha512-36nwAD620w12kuzPAsyINPWJqlNbij+hpK1k9XRloDtym8mxzGYl2c17LnV6IAGB2Dmg4tEa7G7DlawS0+qjew==
+ dependencies:
+ "@babel/runtime" "^7.1.2"
+ loose-envify "^1.2.0"
+ resolve-pathname "^3.0.0"
+ tiny-invariant "^1.0.2"
+ tiny-warning "^1.0.0"
+ value-equal "^1.0.1"
+
+hmac-drbg@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1"
+ integrity sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==
+ dependencies:
+ hash.js "^1.0.3"
+ minimalistic-assert "^1.0.0"
+ minimalistic-crypto-utils "^1.0.1"
+
+hoist-non-react-statics@^3.0.0, hoist-non-react-statics@^3.1.0, hoist-non-react-statics@^3.3.0, hoist-non-react-statics@^3.3.1, hoist-non-react-statics@^3.3.2:
+ version "3.3.2"
+ resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz#ece0acaf71d62c2969c2ec59feff42a4b1a85b45"
+ integrity sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==
+ dependencies:
+ react-is "^16.7.0"
+
+homedir-polyfill@^1.0.1:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz#743298cef4e5af3e194161fbadcc2151d3a058e8"
+ integrity sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==
+ dependencies:
+ parse-passwd "^1.0.0"
+
+hosted-git-info@^2.1.4:
+ version "2.8.9"
+ resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.8.9.tgz#dffc0bf9a21c02209090f2aa69429e1414daf3f9"
+ integrity sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==
+
+html-entities@^2.1.0:
+ version "2.4.0"
+ resolved "https://registry.yarnpkg.com/html-entities/-/html-entities-2.4.0.tgz#edd0cee70402584c8c76cc2c0556db09d1f45061"
+ integrity sha512-igBTJcNNNhvZFRtm8uA6xMY6xYleeDwn3PeBCkDz7tHttv4F2hsDI2aPgNERWzvRcNYHNT3ymRaQzllmXj4YsQ==
+
+html-escaper@^2.0.2:
+ version "2.0.2"
+ resolved "https://registry.yarnpkg.com/html-escaper/-/html-escaper-2.0.2.tgz#dfd60027da36a36dfcbe236262c00a5822681453"
+ integrity sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==
+
+html-minifier-terser@^6.0.2:
+ version "6.1.0"
+ resolved "https://registry.yarnpkg.com/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz#bfc818934cc07918f6b3669f5774ecdfd48f32ab"
+ integrity sha512-YXxSlJBZTP7RS3tWnQw74ooKa6L9b9i9QYXY21eUEvhZ3u9XLfv6OnFsQq6RxkhHygsaUMvYsZRV5rU/OVNZxw==
+ dependencies:
+ camel-case "^4.1.2"
+ clean-css "^5.2.2"
+ commander "^8.3.0"
+ he "^1.2.0"
+ param-case "^3.0.4"
+ relateurl "^0.2.7"
+ terser "^5.10.0"
+
+html-webpack-plugin@5.5.0:
+ version "5.5.0"
+ resolved "https://registry.yarnpkg.com/html-webpack-plugin/-/html-webpack-plugin-5.5.0.tgz#c3911936f57681c1f9f4d8b68c158cd9dfe52f50"
+ integrity sha512-sy88PC2cRTVxvETRgUHFrL4No3UxvcH8G1NepGhqaTT+GXN2kTamqasot0inS5hXeg1cMbFDt27zzo9p35lZVw==
+ dependencies:
+ "@types/html-minifier-terser" "^6.0.0"
+ html-minifier-terser "^6.0.2"
+ lodash "^4.17.21"
+ pretty-error "^4.0.0"
+ tapable "^2.0.0"
+
+htmlparser2@^6.1.0:
+ version "6.1.0"
+ resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-6.1.0.tgz#c4d762b6c3371a05dbe65e94ae43a9f845fb8fb7"
+ integrity sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==
+ dependencies:
+ domelementtype "^2.0.1"
+ domhandler "^4.0.0"
+ domutils "^2.5.2"
+ entities "^2.0.0"
+
+htmlparser2@^8.0.0:
+ version "8.0.2"
+ resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-8.0.2.tgz#f002151705b383e62433b5cf466f5b716edaec21"
+ integrity sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==
+ dependencies:
+ domelementtype "^2.3.0"
+ domhandler "^5.0.3"
+ domutils "^3.0.1"
+ entities "^4.4.0"
+
+http-assert@^1.3.0:
+ version "1.5.0"
+ resolved "https://registry.yarnpkg.com/http-assert/-/http-assert-1.5.0.tgz#c389ccd87ac16ed2dfa6246fd73b926aa00e6b8f"
+ integrity sha512-uPpH7OKX4H25hBmU6G1jWNaqJGpTXxey+YOUizJUAgu0AjLUeC8D73hTrhvDS5D+GJN1DN1+hhc/eF/wpxtp0w==
+ dependencies:
+ deep-equal "~1.0.1"
+ http-errors "~1.8.0"
+
+http-cache-semantics@^4.0.0:
+ version "4.1.1"
+ resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz#abe02fcb2985460bf0323be664436ec3476a6d5a"
+ integrity sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==
+
+http-errors@1.8.1, http-errors@^1.6.3, http-errors@^1.7.3, http-errors@^1.8.0, http-errors@~1.8.0:
+ version "1.8.1"
+ resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.8.1.tgz#7c3f28577cbc8a207388455dbd62295ed07bd68c"
+ integrity sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g==
+ dependencies:
+ depd "~1.1.2"
+ inherits "2.0.4"
+ setprototypeof "1.2.0"
+ statuses ">= 1.5.0 < 2"
+ toidentifier "1.0.1"
+
+http-errors@2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-2.0.0.tgz#b7774a1486ef73cf7667ac9ae0858c012c57b9d3"
+ integrity sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==
+ dependencies:
+ depd "2.0.0"
+ inherits "2.0.4"
+ setprototypeof "1.2.0"
+ statuses "2.0.1"
+ toidentifier "1.0.1"
+
+http-errors@~1.6.2:
+ version "1.6.3"
+ resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.6.3.tgz#8b55680bb4be283a0b5bf4ea2e38580be1d9320d"
+ integrity sha512-lks+lVC8dgGyh97jxvxeYTWQFvh4uw4yC12gVl63Cg30sjPX4wuGcdkICVXDAESr6OJGjqGA8Iz5mkeN6zlD7A==
+ dependencies:
+ depd "~1.1.2"
+ inherits "2.0.3"
+ setprototypeof "1.1.0"
+ statuses ">= 1.4.0 < 2"
+
+http2-wrapper@^1.0.0-beta.5.2:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/http2-wrapper/-/http2-wrapper-1.0.3.tgz#b8f55e0c1f25d4ebd08b3b0c2c079f9590800b3d"
+ integrity sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg==
+ dependencies:
+ quick-lru "^5.1.1"
+ resolve-alpn "^1.0.0"
+
+https-proxy-agent@5.0.1, https-proxy-agent@^5.0.0:
+ version "5.0.1"
+ resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz#c59ef224a04fe8b754f3db0063a25ea30d0005d6"
+ integrity sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==
+ dependencies:
+ agent-base "6"
+ debug "4"
+
+human-signals@^2.1.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-2.1.0.tgz#dc91fcba42e4d06e4abaed33b3e7a3c02f514ea0"
+ integrity sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==
+
+human-signals@^4.3.0:
+ version "4.3.1"
+ resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-4.3.1.tgz#ab7f811e851fca97ffbd2c1fe9a958964de321b2"
+ integrity sha512-nZXjEF2nbo7lIw3mgYjItAfgQXog3OjJogSbKa2CQIIvSGWcKgeJnQlNXip6NglNzYH45nSRiEVimMvYL8DDqQ==
+
+iconv-lite@0.4.13:
+ version "0.4.13"
+ resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.13.tgz#1f88aba4ab0b1508e8312acc39345f36e992e2f2"
+ integrity sha512-QwVuTNQv7tXC5mMWFX5N5wGjmybjNBBD8P3BReTkPmipoxTUFgWM2gXNvldHQr6T14DH0Dh6qBVg98iJt7u4mQ==
+
+iconv-lite@0.4.15:
+ version "0.4.15"
+ resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.15.tgz#fe265a218ac6a57cfe854927e9d04c19825eddeb"
+ integrity sha512-RGR+c9Lm+tLsvU57FTJJtdbv2hQw42Yl2n26tVIBaYmZzLN+EGfroUugN/z9nJf9kOXd49hBmpoGr4FEm+A4pw==
+
+iconv-lite@0.4.24, iconv-lite@^0.4.24:
+ version "0.4.24"
+ resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b"
+ integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==
+ dependencies:
+ safer-buffer ">= 2.1.2 < 3"
+
+icss-utils@^5.0.0, icss-utils@^5.1.0:
+ version "5.1.0"
+ resolved "https://registry.yarnpkg.com/icss-utils/-/icss-utils-5.1.0.tgz#c6be6858abd013d768e98366ae47e25d5887b1ae"
+ integrity sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==
+
+ieee754@1.1.13:
+ version "1.1.13"
+ resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.13.tgz#ec168558e95aa181fd87d37f55c32bbcb6708b84"
+ integrity sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==
+
+ieee754@^1.1.13, ieee754@^1.1.4:
+ version "1.2.1"
+ resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352"
+ integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==
+
+ignore@^5.1.1, ignore@^5.2.4:
+ version "5.3.0"
+ resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.3.0.tgz#67418ae40d34d6999c95ff56016759c718c82f78"
+ integrity sha512-g7dmpshy+gD7mh88OC9NwSGTKoc3kyLAZQRU1mt53Aw/vnvfXnbC+F/7F7QoYVKbV+KNvJx8wArewKy1vXMtlg==
+
+immer@9.0.19:
+ version "9.0.19"
+ resolved "https://registry.yarnpkg.com/immer/-/immer-9.0.19.tgz#67fb97310555690b5f9cd8380d38fc0aabb6b38b"
+ integrity sha512-eY+Y0qcsB4TZKwgQzLaE/lqYMlKhv5J9dyd2RhhtGhNo2njPXDqU9XPfcNfa3MIDsdtZt5KlkIsirlo4dHsWdQ==
+
+immer@^9.0.21, immer@^9.0.6:
+ version "9.0.21"
+ resolved "https://registry.yarnpkg.com/immer/-/immer-9.0.21.tgz#1e025ea31a40f24fb064f1fef23e931496330176"
+ integrity sha512-bc4NBHqOqSfRW7POMkHd51LvClaeMXpm8dx0e8oE2GORbq5aRK7Bxl4FyzVLdGtLmvLKL7BTDBG5ACQm4HWjTA==
+
+import-fresh@^3.2.1:
+ version "3.3.0"
+ resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b"
+ integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==
+ dependencies:
+ parent-module "^1.0.0"
+ resolve-from "^4.0.0"
+
+imurmurhash@^0.1.4:
+ version "0.1.4"
+ resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea"
+ integrity sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==
+
+indent-string@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-4.0.0.tgz#624f8f4497d619b2d9768531d58f4122854d7251"
+ integrity sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==
+
+inflation@^2.0.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/inflation/-/inflation-2.1.0.tgz#9214db11a47e6f756d111c4f9df96971c60f886c"
+ integrity sha512-t54PPJHG1Pp7VQvxyVCJ9mBbjG3Hqryges9bXoOO6GExCPa+//i/d5GSuFtpx3ALLd7lgIAur6zrIlBQyJuMlQ==
+
+inflight@^1.0.4:
+ version "1.0.6"
+ resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9"
+ integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==
+ dependencies:
+ once "^1.3.0"
+ wrappy "1"
+
+inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.1, inherits@~2.0.3:
+ version "2.0.4"
+ resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c"
+ integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
+
+inherits@2.0.3:
+ version "2.0.3"
+ resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de"
+ integrity sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==
+
+ini@4.1.1:
+ version "4.1.1"
+ resolved "https://registry.yarnpkg.com/ini/-/ini-4.1.1.tgz#d95b3d843b1e906e56d6747d5447904ff50ce7a1"
+ integrity sha512-QQnnxNyfvmHFIsj7gkPcYymR8Jdw/o7mp5ZFihxn6h8Ci6fh3Dx4E1gPjpQEpIuPo9XVNY/ZUwh4BPMjGyL01g==
+
+ini@^1.3.4, ini@~1.3.0:
+ version "1.3.8"
+ resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.8.tgz#a29da425b48806f34767a4efce397269af28432c"
+ integrity sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==
+
+inquirer@8.2.5:
+ version "8.2.5"
+ resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-8.2.5.tgz#d8654a7542c35a9b9e069d27e2df4858784d54f8"
+ integrity sha512-QAgPDQMEgrDssk1XiwwHoOGYF9BAbUcc1+j+FhEvaOt8/cKRqyLn0U5qA6F74fGhTMGxf92pOvPBeh29jQJDTQ==
+ dependencies:
+ ansi-escapes "^4.2.1"
+ chalk "^4.1.1"
+ cli-cursor "^3.1.0"
+ cli-width "^3.0.0"
+ external-editor "^3.0.3"
+ figures "^3.0.0"
+ lodash "^4.17.21"
+ mute-stream "0.0.8"
+ ora "^5.4.1"
+ run-async "^2.4.0"
+ rxjs "^7.5.5"
+ string-width "^4.1.0"
+ strip-ansi "^6.0.0"
+ through "^2.3.6"
+ wrap-ansi "^7.0.0"
+
+inquirer@^7.1.0:
+ version "7.3.3"
+ resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-7.3.3.tgz#04d176b2af04afc157a83fd7c100e98ee0aad003"
+ integrity sha512-JG3eIAj5V9CwcGvuOmoo6LB9kbAYT8HXffUl6memuszlwDC/qvFAJw49XJ5NROSFNPxp3iQg1GqkFhaY/CR0IA==
+ dependencies:
+ ansi-escapes "^4.2.1"
+ chalk "^4.1.0"
+ cli-cursor "^3.1.0"
+ cli-width "^3.0.0"
+ external-editor "^3.0.3"
+ figures "^3.0.0"
+ lodash "^4.17.19"
+ mute-stream "0.0.8"
+ run-async "^2.4.0"
+ rxjs "^6.6.0"
+ string-width "^4.1.0"
+ strip-ansi "^6.0.0"
+ through "^2.3.6"
+
+inquirer@^8.2.0:
+ version "8.2.6"
+ resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-8.2.6.tgz#733b74888195d8d400a67ac332011b5fae5ea562"
+ integrity sha512-M1WuAmb7pn9zdFRtQYk26ZBoY043Sse0wVDdk4Bppr+JOXyQYybdtvK+l9wUibhtjdjvtoiNy8tk+EgsYIUqKg==
+ dependencies:
+ ansi-escapes "^4.2.1"
+ chalk "^4.1.1"
+ cli-cursor "^3.1.0"
+ cli-width "^3.0.0"
+ external-editor "^3.0.3"
+ figures "^3.0.0"
+ lodash "^4.17.21"
+ mute-stream "0.0.8"
+ ora "^5.4.1"
+ run-async "^2.4.0"
+ rxjs "^7.5.5"
+ string-width "^4.1.0"
+ strip-ansi "^6.0.0"
+ through "^2.3.6"
+ wrap-ansi "^6.0.1"
+
+internal-slot@^1.0.4:
+ version "1.0.6"
+ resolved "https://registry.yarnpkg.com/internal-slot/-/internal-slot-1.0.6.tgz#37e756098c4911c5e912b8edbf71ed3aa116f930"
+ integrity sha512-Xj6dv+PsbtwyPpEflsejS+oIZxmMlV44zAhG479uYu89MsjcYOhCFnNyKrkJrihbsiasQyY0afoCl/9BLR65bg==
+ dependencies:
+ get-intrinsic "^1.2.2"
+ hasown "^2.0.0"
+ side-channel "^1.0.4"
+
+interpret@^1.2.0:
+ version "1.4.0"
+ resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.4.0.tgz#665ab8bc4da27a774a40584e812e3e0fa45b1a1e"
+ integrity sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==
+
+interpret@^2.2.0:
+ version "2.2.0"
+ resolved "https://registry.yarnpkg.com/interpret/-/interpret-2.2.0.tgz#1a78a0b5965c40a5416d007ad6f50ad27c417df9"
+ integrity sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw==
+
+intl-messageformat@10.3.3:
+ version "10.3.3"
+ resolved "https://registry.yarnpkg.com/intl-messageformat/-/intl-messageformat-10.3.3.tgz#576798d31c9f8d90f9beadaa5a3878b8d30177a2"
+ integrity sha512-un/f07/g2e/3Q8e1ghDKET+el22Bi49M7O/rHxd597R+oLpPOMykSv5s51cABVfu3FZW+fea4hrzf2MHu1W4hw==
+ dependencies:
+ "@formatjs/ecma402-abstract" "1.14.3"
+ "@formatjs/fast-memoize" "2.0.1"
+ "@formatjs/icu-messageformat-parser" "2.3.0"
+ tslib "^2.4.0"
+
+intl-messageformat@10.3.4:
+ version "10.3.4"
+ resolved "https://registry.yarnpkg.com/intl-messageformat/-/intl-messageformat-10.3.4.tgz#20f064c28b46fa6d352a4c4ba5e9bfc597af3eba"
+ integrity sha512-/FxUIrlbPtuykSNX85CB5sp2FjLVeTmdD7TfRkVFPft2n4FgcSlAcilFytYiFAEmPHc+0PvpLCIPXeaGFzIvOg==
+ dependencies:
+ "@formatjs/ecma402-abstract" "1.14.3"
+ "@formatjs/fast-memoize" "2.0.1"
+ "@formatjs/icu-messageformat-parser" "2.3.1"
+ tslib "^2.4.0"
+
+into-stream@^5.1.0:
+ version "5.1.1"
+ resolved "https://registry.yarnpkg.com/into-stream/-/into-stream-5.1.1.tgz#f9a20a348a11f3c13face22763f2d02e127f4db8"
+ integrity sha512-krrAJ7McQxGGmvaYbB7Q1mcA+cRwg9Ij2RfWIeVesNBgVDZmzY/Fa4IpZUT3bmdRzMzdf/mzltCG2Dq99IZGBA==
+ dependencies:
+ from2 "^2.3.0"
+ p-is-promise "^3.0.0"
+
+into-stream@^6.0.0:
+ version "6.0.0"
+ resolved "https://registry.yarnpkg.com/into-stream/-/into-stream-6.0.0.tgz#4bfc1244c0128224e18b8870e85b2de8e66c6702"
+ integrity sha512-XHbaOAvP+uFKUFsOgoNPRjLkwB+I22JFPFe5OjTkQ0nwgj6+pSjb4NmB6VMxaPshLiOf+zcpOCBQuLwC1KHhZA==
+ dependencies:
+ from2 "^2.3.0"
+ p-is-promise "^3.0.0"
+
+invariant@^2.2.4:
+ version "2.2.4"
+ resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6"
+ integrity sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==
+ dependencies:
+ loose-envify "^1.0.0"
+
+is-absolute@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/is-absolute/-/is-absolute-1.0.0.tgz#395e1ae84b11f26ad1795e73c17378e48a301576"
+ integrity sha512-dOWoqflvcydARa360Gvv18DZ/gRuHKi2NU/wU5X1ZFzdYfH29nkiNZsF3mp4OJ3H4yo9Mx8A/uAGNzpzPN3yBA==
+ dependencies:
+ is-relative "^1.0.0"
+ is-windows "^1.0.1"
+
+is-accessor-descriptor@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-1.0.1.tgz#3223b10628354644b86260db29b3e693f5ceedd4"
+ integrity sha512-YBUanLI8Yoihw923YeFUS5fs0fF2f5TSFTNiYAAzhhDscDa3lEqYuz1pDOEP5KvX94I9ey3vsqjJcLVFVU+3QA==
+ dependencies:
+ hasown "^2.0.0"
+
+is-arguments@^1.0.4, is-arguments@^1.1.1:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/is-arguments/-/is-arguments-1.1.1.tgz#15b3f88fda01f2a97fec84ca761a560f123efa9b"
+ integrity sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==
+ dependencies:
+ call-bind "^1.0.2"
+ has-tostringtag "^1.0.0"
+
+is-array-buffer@^3.0.1, is-array-buffer@^3.0.2:
+ version "3.0.2"
+ resolved "https://registry.yarnpkg.com/is-array-buffer/-/is-array-buffer-3.0.2.tgz#f2653ced8412081638ecb0ebbd0c41c6e0aecbbe"
+ integrity sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w==
+ dependencies:
+ call-bind "^1.0.2"
+ get-intrinsic "^1.2.0"
+ is-typed-array "^1.1.10"
+
+is-arrayish@^0.2.1:
+ version "0.2.1"
+ resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d"
+ integrity sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==
+
+is-arrayish@^0.3.1:
+ version "0.3.2"
+ resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.3.2.tgz#4574a2ae56f7ab206896fb431eaeed066fdf8f03"
+ integrity sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==
+
+is-bigint@^1.0.1:
+ version "1.0.4"
+ resolved "https://registry.yarnpkg.com/is-bigint/-/is-bigint-1.0.4.tgz#08147a1875bc2b32005d41ccd8291dffc6691df3"
+ integrity sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==
+ dependencies:
+ has-bigints "^1.0.1"
+
+is-binary-path@~2.1.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09"
+ integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==
+ dependencies:
+ binary-extensions "^2.0.0"
+
+is-boolean-object@^1.1.0:
+ version "1.1.2"
+ resolved "https://registry.yarnpkg.com/is-boolean-object/-/is-boolean-object-1.1.2.tgz#5c6dc200246dd9321ae4b885a114bb1f75f63719"
+ integrity sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==
+ dependencies:
+ call-bind "^1.0.2"
+ has-tostringtag "^1.0.0"
+
+is-buffer@^1.1.5:
+ version "1.1.6"
+ resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be"
+ integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==
+
+is-callable@^1.1.3:
+ version "1.2.7"
+ resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.7.tgz#3bc2a85ea742d9e36205dcacdd72ca1fdc51b055"
+ integrity sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==
+
+is-class-hotfix@~0.0.6:
+ version "0.0.6"
+ resolved "https://registry.yarnpkg.com/is-class-hotfix/-/is-class-hotfix-0.0.6.tgz#a527d31fb23279281dde5f385c77b5de70a72435"
+ integrity sha512-0n+pzCC6ICtVr/WXnN2f03TK/3BfXY7me4cjCAqT8TYXEl0+JBRoqBo94JJHXcyDSLUeWbNX8Fvy5g5RJdAstQ==
+
+is-core-module@^2.13.0:
+ version "2.13.1"
+ resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.13.1.tgz#ad0d7532c6fea9da1ebdc82742d74525c6273384"
+ integrity sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==
+ dependencies:
+ hasown "^2.0.0"
+
+is-data-descriptor@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-1.0.1.tgz#2109164426166d32ea38c405c1e0945d9e6a4eeb"
+ integrity sha512-bc4NlCDiCr28U4aEsQ3Qs2491gVq4V8G7MQyws968ImqjKuYtTJXrl7Vq7jsN7Ly/C3xj5KWFrY7sHNeDkAzXw==
+ dependencies:
+ hasown "^2.0.0"
+
+is-date-object@^1.0.5:
+ version "1.0.5"
+ resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.5.tgz#0841d5536e724c25597bf6ea62e1bd38298df31f"
+ integrity sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==
+ dependencies:
+ has-tostringtag "^1.0.0"
+
+is-descriptor@^0.1.0:
+ version "0.1.7"
+ resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-0.1.7.tgz#2727eb61fd789dcd5bdf0ed4569f551d2fe3be33"
+ integrity sha512-C3grZTvObeN1xud4cRWl366OMXZTj0+HGyk4hvfpx4ZHt1Pb60ANSXqCK7pdOTeUQpRzECBSTphqvD7U+l22Eg==
+ dependencies:
+ is-accessor-descriptor "^1.0.1"
+ is-data-descriptor "^1.0.1"
+
+is-descriptor@^1.0.0, is-descriptor@^1.0.2:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-1.0.3.tgz#92d27cb3cd311c4977a4db47df457234a13cb306"
+ integrity sha512-JCNNGbwWZEVaSPtS45mdtrneRWJFp07LLmykxeFV5F6oBvNF8vHSfJuJgoT472pSfk+Mf8VnlrspaFBHWM8JAw==
+ dependencies:
+ is-accessor-descriptor "^1.0.1"
+ is-data-descriptor "^1.0.1"
+
+is-docker@2.2.1, is-docker@^2.0.0, is-docker@^2.1.1:
+ version "2.2.1"
+ resolved "https://registry.yarnpkg.com/is-docker/-/is-docker-2.2.1.tgz#33eeabe23cfe86f14bde4408a02c0cfb853acdaa"
+ integrity sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==
+
+is-docker@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/is-docker/-/is-docker-3.0.0.tgz#90093aa3106277d8a77a5910dbae71747e15a200"
+ integrity sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==
+
+is-extendable@^0.1.0, is-extendable@^0.1.1:
+ version "0.1.1"
+ resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89"
+ integrity sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==
+
+is-extendable@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-1.0.1.tgz#a7470f9e426733d81bd81e1155264e3a3507cab4"
+ integrity sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==
+ dependencies:
+ is-plain-object "^2.0.4"
+
+is-extglob@^2.1.0, is-extglob@^2.1.1:
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2"
+ integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==
+
+is-fullwidth-code-point@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d"
+ integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==
+
+is-generator-function@^1.0.7:
+ version "1.0.10"
+ resolved "https://registry.yarnpkg.com/is-generator-function/-/is-generator-function-1.0.10.tgz#f1558baf1ac17e0deea7c0415c438351ff2b3c72"
+ integrity sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==
+ dependencies:
+ has-tostringtag "^1.0.0"
+
+is-glob@^3.1.0:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-3.1.0.tgz#7ba5ae24217804ac70707b96922567486cc3e84a"
+ integrity sha512-UFpDDrPgM6qpnFNI+rh/p3bUaq9hKLZN8bMUWzxmcnZVS3omf4IPK+BrewlnWjO1WmUsMYuSjKh4UJuV4+Lqmw==
+ dependencies:
+ is-extglob "^2.1.0"
+
+is-glob@^4.0.1, is-glob@^4.0.3, is-glob@~4.0.1:
+ version "4.0.3"
+ resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084"
+ integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==
+ dependencies:
+ is-extglob "^2.1.1"
+
+is-hotkey@^0.1.6:
+ version "0.1.8"
+ resolved "https://registry.yarnpkg.com/is-hotkey/-/is-hotkey-0.1.8.tgz#6b1f4b2d0e5639934e20c05ed24d623a21d36d25"
+ integrity sha512-qs3NZ1INIS+H+yeo7cD9pDfwYV/jqRh1JG9S9zYrNudkoUQg7OL7ziXqRKu+InFjUIDoP2o6HIkLYMh1pcWgyQ==
+
+is-inside-container@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/is-inside-container/-/is-inside-container-1.0.0.tgz#e81fba699662eb31dbdaf26766a61d4814717ea4"
+ integrity sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==
+ dependencies:
+ is-docker "^3.0.0"
+
+is-interactive@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/is-interactive/-/is-interactive-1.0.0.tgz#cea6e6ae5c870a7b0a0004070b7b587e0252912e"
+ integrity sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==
+
+is-lower-case@^1.1.0:
+ version "1.1.3"
+ resolved "https://registry.yarnpkg.com/is-lower-case/-/is-lower-case-1.1.3.tgz#7e147be4768dc466db3bfb21cc60b31e6ad69393"
+ integrity sha512-+5A1e/WJpLLXZEDlgz4G//WYSHyQBD32qa4Jd3Lw06qQlv3fJHnp3YIHjTQSGzHMgzmVKz2ZP3rBxTHkPw/lxA==
+ dependencies:
+ lower-case "^1.1.0"
+
+is-map@^2.0.1, is-map@^2.0.2:
+ version "2.0.2"
+ resolved "https://registry.yarnpkg.com/is-map/-/is-map-2.0.2.tgz#00922db8c9bf73e81b7a335827bc2a43f2b91127"
+ integrity sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg==
+
+is-nan@^1.3.2:
+ version "1.3.2"
+ resolved "https://registry.yarnpkg.com/is-nan/-/is-nan-1.3.2.tgz#043a54adea31748b55b6cd4e09aadafa69bd9e1d"
+ integrity sha512-E+zBKpQ2t6MEo1VsonYmluk9NxGrbzpeeLC2xIViuO2EjU2xsXsBPwTr3Ykv9l08UYEVEdWeRZNouaZqF6RN0w==
+ dependencies:
+ call-bind "^1.0.0"
+ define-properties "^1.1.3"
+
+is-node-process@^1.0.1:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/is-node-process/-/is-node-process-1.2.0.tgz#ea02a1b90ddb3934a19aea414e88edef7e11d134"
+ integrity sha512-Vg4o6/fqPxIjtxgUH5QLJhwZ7gW5diGCVlXpuUfELC62CuxM1iHcRe51f2W1FDy04Ai4KJkagKjx3XaqyfRKXw==
+
+is-number-object@^1.0.4:
+ version "1.0.7"
+ resolved "https://registry.yarnpkg.com/is-number-object/-/is-number-object-1.0.7.tgz#59d50ada4c45251784e9904f5246c742f07a42fc"
+ integrity sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==
+ dependencies:
+ has-tostringtag "^1.0.0"
+
+is-number@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/is-number/-/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195"
+ integrity sha512-4cboCqIpliH+mAvFNegjZQ4kgKc3ZUhQVr3HvWbSh5q3WH2v82ct+T2Y1hdU5Gdtorx/cLifQjqCbL7bpznLTg==
+ dependencies:
+ kind-of "^3.0.2"
+
+is-number@^7.0.0:
+ version "7.0.0"
+ resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b"
+ integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==
+
+is-obj@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-2.0.0.tgz#473fb05d973705e3fd9620545018ca8e22ef4982"
+ integrity sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==
+
+is-path-cwd@^2.2.0:
+ version "2.2.0"
+ resolved "https://registry.yarnpkg.com/is-path-cwd/-/is-path-cwd-2.2.0.tgz#67d43b82664a7b5191fd9119127eb300048a9fdb"
+ integrity sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ==
+
+is-path-inside@^3.0.1:
+ version "3.0.3"
+ resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-3.0.3.tgz#d231362e53a07ff2b0e0ea7fed049161ffd16283"
+ integrity sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==
+
+is-plain-obj@^4.1.0:
+ version "4.1.0"
+ resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-4.1.0.tgz#d65025edec3657ce032fd7db63c97883eaed71f0"
+ integrity sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==
+
+is-plain-object@^2.0.3, is-plain-object@^2.0.4:
+ version "2.0.4"
+ resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677"
+ integrity sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==
+ dependencies:
+ isobject "^3.0.1"
+
+is-plain-object@^5.0.0:
+ version "5.0.0"
+ resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-5.0.0.tgz#4427f50ab3429e9025ea7d52e9043a9ef4159344"
+ integrity sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==
+
+is-regex@^1.1.4:
+ version "1.1.4"
+ resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.4.tgz#eef5663cd59fa4c0ae339505323df6854bb15958"
+ integrity sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==
+ dependencies:
+ call-bind "^1.0.2"
+ has-tostringtag "^1.0.0"
+
+is-relative@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/is-relative/-/is-relative-1.0.0.tgz#a1bb6935ce8c5dba1e8b9754b9b2dcc020e2260d"
+ integrity sha512-Kw/ReK0iqwKeu0MITLFuj0jbPAmEiOsIwyIXvvbfa6QfmN9pkD1M+8pdk7Rl/dTKbH34/XBFMbgD4iMJhLQbGA==
+ dependencies:
+ is-unc-path "^1.0.0"
+
+is-retry-allowed@^2.2.0:
+ version "2.2.0"
+ resolved "https://registry.yarnpkg.com/is-retry-allowed/-/is-retry-allowed-2.2.0.tgz#88f34cbd236e043e71b6932d09b0c65fb7b4d71d"
+ integrity sha512-XVm7LOeLpTW4jV19QSH38vkswxoLud8sQ57YwJVTPWdiaI9I8keEhGFpBlslyVsgdQy4Opg8QOLb8YRgsyZiQg==
+
+is-set@^2.0.1, is-set@^2.0.2:
+ version "2.0.2"
+ resolved "https://registry.yarnpkg.com/is-set/-/is-set-2.0.2.tgz#90755fa4c2562dc1c5d4024760d6119b94ca18ec"
+ integrity sha512-+2cnTEZeY5z/iXGbLhPrOAaK/Mau5k5eXq9j14CpRTftq0pAJu2MwVRSZhyZWBzx3o6X795Lz6Bpb6R0GKf37g==
+
+is-shared-array-buffer@^1.0.2:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz#8f259c573b60b6a32d4058a1a07430c0a7344c79"
+ integrity sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==
+ dependencies:
+ call-bind "^1.0.2"
+
+is-ssh@^1.4.0:
+ version "1.4.0"
+ resolved "https://registry.yarnpkg.com/is-ssh/-/is-ssh-1.4.0.tgz#4f8220601d2839d8fa624b3106f8e8884f01b8b2"
+ integrity sha512-x7+VxdxOdlV3CYpjvRLBv5Lo9OJerlYanjwFrPR9fuGPjCiNiCzFgAWpiLAohSbsnH4ZAys3SBh+hq5rJosxUQ==
+ dependencies:
+ protocols "^2.0.1"
+
+is-stream@^2.0.0, is-stream@^2.0.1:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.1.tgz#fac1e3d53b97ad5a9d0ae9cef2389f5810a5c077"
+ integrity sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==
+
+is-stream@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-3.0.0.tgz#e6bfd7aa6bef69f4f472ce9bb681e3e57b4319ac"
+ integrity sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==
+
+is-string@^1.0.5, is-string@^1.0.7:
+ version "1.0.7"
+ resolved "https://registry.yarnpkg.com/is-string/-/is-string-1.0.7.tgz#0dd12bf2006f255bb58f695110eff7491eebc0fd"
+ integrity sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==
+ dependencies:
+ has-tostringtag "^1.0.0"
+
+is-symbol@^1.0.3:
+ version "1.0.4"
+ resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.4.tgz#a6dac93b635b063ca6872236de88910a57af139c"
+ integrity sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==
+ dependencies:
+ has-symbols "^1.0.2"
+
+is-type-of@^1.2.1:
+ version "1.4.0"
+ resolved "https://registry.yarnpkg.com/is-type-of/-/is-type-of-1.4.0.tgz#3ed175a0eee888b1da4983332e7714feb8a8fb2b"
+ integrity sha512-EddYllaovi5ysMLMEN7yzHEKh8A850cZ7pykrY1aNRQGn/CDjRDE9qEWbIdt7xGEVJmjBXzU/fNnC4ABTm8tEQ==
+ dependencies:
+ core-util-is "^1.0.2"
+ is-class-hotfix "~0.0.6"
+ isstream "~0.1.2"
+
+is-typed-array@^1.1.10, is-typed-array@^1.1.3:
+ version "1.1.12"
+ resolved "https://registry.yarnpkg.com/is-typed-array/-/is-typed-array-1.1.12.tgz#d0bab5686ef4a76f7a73097b95470ab199c57d4a"
+ integrity sha512-Z14TF2JNG8Lss5/HMqt0//T9JeHXttXy5pH/DBU4vi98ozO2btxzq9MwYDZYnKwU8nRsz/+GVFVRDq3DkVuSPg==
+ dependencies:
+ which-typed-array "^1.1.11"
+
+is-typedarray@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a"
+ integrity sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==
+
+is-unc-path@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/is-unc-path/-/is-unc-path-1.0.0.tgz#d731e8898ed090a12c352ad2eaed5095ad322c9d"
+ integrity sha512-mrGpVd0fs7WWLfVsStvgF6iEJnbjDFZh9/emhRDcGWTduTfNHd9CHeUwH3gYIjdbwo4On6hunkztwOaAw0yllQ==
+ dependencies:
+ unc-path-regex "^0.1.2"
+
+is-unicode-supported@^0.1.0:
+ version "0.1.0"
+ resolved "https://registry.yarnpkg.com/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz#3f26c76a809593b52bfa2ecb5710ed2779b522a7"
+ integrity sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==
+
+is-upper-case@^1.1.0:
+ version "1.1.2"
+ resolved "https://registry.yarnpkg.com/is-upper-case/-/is-upper-case-1.1.2.tgz#8d0b1fa7e7933a1e58483600ec7d9661cbaf756f"
+ integrity sha512-GQYSJMgfeAmVwh9ixyk888l7OIhNAGKtY6QA+IrWlu9MDTCaXmeozOZ2S9Knj7bQwBO/H6J2kb+pbyTUiMNbsw==
+ dependencies:
+ upper-case "^1.1.0"
+
+is-weakmap@^2.0.1:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/is-weakmap/-/is-weakmap-2.0.1.tgz#5008b59bdc43b698201d18f62b37b2ca243e8cf2"
+ integrity sha512-NSBR4kH5oVj1Uwvv970ruUkCV7O1mzgVFO4/rev2cLRda9Tm9HrL70ZPut4rOHgY0FNrUu9BCbXA2sdQ+x0chA==
+
+is-weakset@^2.0.1:
+ version "2.0.2"
+ resolved "https://registry.yarnpkg.com/is-weakset/-/is-weakset-2.0.2.tgz#4569d67a747a1ce5a994dfd4ef6dcea76e7c0a1d"
+ integrity sha512-t2yVvttHkQktwnNNmBQ98AhENLdPUTDTE21uPqAQ0ARwQfGeQKRVS0NNurH7bTf7RrvcVn1OOge45CnBeHCSmg==
+ dependencies:
+ call-bind "^1.0.2"
+ get-intrinsic "^1.1.1"
+
+is-windows@^1.0.1, is-windows@^1.0.2:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d"
+ integrity sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==
+
+is-wsl@^2.2.0:
+ version "2.2.0"
+ resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-2.2.0.tgz#74a4c76e77ca9fd3f932f290c17ea326cd157271"
+ integrity sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==
+ dependencies:
+ is-docker "^2.0.0"
+
+isarray@0.0.1:
+ version "0.0.1"
+ resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf"
+ integrity sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==
+
+isarray@1.0.0, isarray@^1.0.0, isarray@~1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11"
+ integrity sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==
+
+isarray@^2.0.5:
+ version "2.0.5"
+ resolved "https://registry.yarnpkg.com/isarray/-/isarray-2.0.5.tgz#8af1e4c1221244cc62459faf38940d4e644a5723"
+ integrity sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==
+
+isbinaryfile@^4.0.2:
+ version "4.0.10"
+ resolved "https://registry.yarnpkg.com/isbinaryfile/-/isbinaryfile-4.0.10.tgz#0c5b5e30c2557a2f06febd37b7322946aaee42b3"
+ integrity sha512-iHrqe5shvBUcFbmZq9zOQHBoeOhZJu6RQGrDpBgenUm/Am+F3JM2MgQj+rK3Z601fzrL5gLZWtAPH2OBaSVcyw==
+
+isexe@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10"
+ integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==
+
+isobject@^2.0.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89"
+ integrity sha512-+OUdGJlgjOBZDfxnDjYYG6zp487z0JGNQq3cYQYg5f5hKR+syHMsaztzGeml/4kGG55CSpKSpWTY+jYGgsHLgA==
+ dependencies:
+ isarray "1.0.0"
+
+isobject@^3.0.0, isobject@^3.0.1:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df"
+ integrity sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==
+
+isstream@^0.1.2, isstream@~0.1.2:
+ version "0.1.2"
+ resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a"
+ integrity sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==
+
+jest-worker@^27.4.5:
+ version "27.5.1"
+ resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-27.5.1.tgz#8d146f0900e8973b106b6f73cc1e9a8cb86f8db0"
+ integrity sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==
+ dependencies:
+ "@types/node" "*"
+ merge-stream "^2.0.0"
+ supports-color "^8.0.0"
+
+jmespath@0.16.0:
+ version "0.16.0"
+ resolved "https://registry.yarnpkg.com/jmespath/-/jmespath-0.16.0.tgz#b15b0a85dfd4d930d43e69ed605943c802785076"
+ integrity sha512-9FzQjJ7MATs1tSpnco1K6ayiYE3figslrXA72G2HQ/n76RzvYlofyi5QM+iX4YRs/pu3yzxlVQSST23+dMDknw==
+
+joycon@^3.0.1:
+ version "3.1.1"
+ resolved "https://registry.yarnpkg.com/joycon/-/joycon-3.1.1.tgz#bce8596d6ae808f8b68168f5fc69280996894f03"
+ integrity sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==
+
+js-cookie@2.2.1:
+ version "2.2.1"
+ resolved "https://registry.yarnpkg.com/js-cookie/-/js-cookie-2.2.1.tgz#69e106dc5d5806894562902aa5baec3744e9b2b8"
+ integrity sha512-HvdH2LzI/EAZcUwA8+0nKNtWHqS+ZmijLA30RwZA0bo7ToCckjK5MkGhjED9KoRcXO6BaGI3I9UIzSA1FKFPOQ==
+
+js-levenshtein@^1.1.6:
+ version "1.1.6"
+ resolved "https://registry.yarnpkg.com/js-levenshtein/-/js-levenshtein-1.1.6.tgz#c6cee58eb3550372df8deb85fad5ce66ce01d59d"
+ integrity sha512-X2BB11YZtrRqY4EnQcLX5Rh373zbK4alC1FW7D7MBhL2gtcC17cTnr6DmfHZeS0s2rTHjUTMMHfG7gO8SSdw+g==
+
+js-sha3@0.8.0:
+ version "0.8.0"
+ resolved "https://registry.yarnpkg.com/js-sha3/-/js-sha3-0.8.0.tgz#b9b7a5da73afad7dedd0f8c463954cbde6818840"
+ integrity sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q==
+
+"js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499"
+ integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==
+
+jsesc@^2.5.1:
+ version "2.5.2"
+ resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4"
+ integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==
+
+json-buffer@3.0.1:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.1.tgz#9338802a30d3b6605fbe0613e094008ca8c05a13"
+ integrity sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==
+
+json-parse-even-better-errors@^2.3.0, json-parse-even-better-errors@^2.3.1:
+ version "2.3.1"
+ resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d"
+ integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==
+
+json-schema-traverse@^0.4.1:
+ version "0.4.1"
+ resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660"
+ integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==
+
+json-schema-traverse@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz#ae7bcb3656ab77a73ba5c49bf654f38e6b6860e2"
+ integrity sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==
+
+json5@^2.1.2, json5@^2.2.0, json5@^2.2.3:
+ version "2.2.3"
+ resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.3.tgz#78cd6f1a19bdc12b73db5ad0c61efd66c1e29283"
+ integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==
+
+jsonfile@^6.0.1:
+ version "6.1.0"
+ resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-6.1.0.tgz#bc55b2634793c679ec6403094eb13698a6ec0aae"
+ integrity sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==
+ dependencies:
+ universalify "^2.0.0"
+ optionalDependencies:
+ graceful-fs "^4.1.6"
+
+jsonwebtoken@9.0.0:
+ version "9.0.0"
+ resolved "https://registry.yarnpkg.com/jsonwebtoken/-/jsonwebtoken-9.0.0.tgz#d0faf9ba1cc3a56255fe49c0961a67e520c1926d"
+ integrity sha512-tuGfYXxkQGDPnLJ7SibiQgVgeDgfbPq2k2ICcbgqW8WxWLBAxKQM/ZCu/IT8SOSwmaYl4dpTFCW5xZv7YbbWUw==
+ dependencies:
+ jws "^3.2.2"
+ lodash "^4.17.21"
+ ms "^2.1.1"
+ semver "^7.3.8"
+
+jsonwebtoken@^9.0.0:
+ version "9.0.2"
+ resolved "https://registry.yarnpkg.com/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz#65ff91f4abef1784697d40952bb1998c504caaf3"
+ integrity sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ==
+ dependencies:
+ jws "^3.2.2"
+ lodash.includes "^4.3.0"
+ lodash.isboolean "^3.0.3"
+ lodash.isinteger "^4.0.4"
+ lodash.isnumber "^3.0.3"
+ lodash.isplainobject "^4.0.6"
+ lodash.isstring "^4.0.1"
+ lodash.once "^4.0.0"
+ ms "^2.1.1"
+ semver "^7.5.4"
+
+jwa@^1.4.1:
+ version "1.4.1"
+ resolved "https://registry.yarnpkg.com/jwa/-/jwa-1.4.1.tgz#743c32985cb9e98655530d53641b66c8645b039a"
+ integrity sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==
+ dependencies:
+ buffer-equal-constant-time "1.0.1"
+ ecdsa-sig-formatter "1.0.11"
+ safe-buffer "^5.0.1"
+
+jwa@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/jwa/-/jwa-2.0.0.tgz#a7e9c3f29dae94027ebcaf49975c9345593410fc"
+ integrity sha512-jrZ2Qx916EA+fq9cEAeCROWPTfCwi1IVHqT2tapuqLEVVDKFDENFw1oL+MwrTvH6msKxsd1YTDVw6uKEcsrLEA==
+ dependencies:
+ buffer-equal-constant-time "1.0.1"
+ ecdsa-sig-formatter "1.0.11"
+ safe-buffer "^5.0.1"
+
+jwk-to-pem@2.0.5, jwk-to-pem@^2.0.5:
+ version "2.0.5"
+ resolved "https://registry.yarnpkg.com/jwk-to-pem/-/jwk-to-pem-2.0.5.tgz#151310bcfbcf731adc5ad9f379cbc8b395742906"
+ integrity sha512-L90jwellhO8jRKYwbssU9ifaMVqajzj3fpRjDKcsDzrslU9syRbFqfkXtT4B89HYAap+xsxNcxgBSB09ig+a7A==
+ dependencies:
+ asn1.js "^5.3.0"
+ elliptic "^6.5.4"
+ safe-buffer "^5.0.1"
+
+jws@^3.2.2:
+ version "3.2.2"
+ resolved "https://registry.yarnpkg.com/jws/-/jws-3.2.2.tgz#001099f3639468c9414000e99995fa52fb478304"
+ integrity sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==
+ dependencies:
+ jwa "^1.4.1"
+ safe-buffer "^5.0.1"
+
+jws@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/jws/-/jws-4.0.0.tgz#2d4e8cf6a318ffaa12615e9dec7e86e6c97310f4"
+ integrity sha512-KDncfTmOZoOMTFG4mBlG0qUIOlc03fmzH+ru6RgYVZhPkyiy/92Owlt/8UEN+a4TXR1FQetfIpJE8ApdvdVxTg==
+ dependencies:
+ jwa "^2.0.0"
+ safe-buffer "^5.0.1"
+
+keygrip@~1.1.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/keygrip/-/keygrip-1.1.0.tgz#871b1681d5e159c62a445b0c74b615e0917e7226"
+ integrity sha512-iYSchDJ+liQ8iwbSI2QqsQOvqv58eJCEanyJPJi+Khyu8smkcKSFUCbPwzFcL7YVtZ6eONjqRX/38caJ7QjRAQ==
+ dependencies:
+ tsscmp "1.0.6"
+
+keyv@^4.0.0, keyv@^4.5.3:
+ version "4.5.4"
+ resolved "https://registry.yarnpkg.com/keyv/-/keyv-4.5.4.tgz#a879a99e29452f942439f2a405e3af8b31d4de93"
+ integrity sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==
+ dependencies:
+ json-buffer "3.0.1"
+
+kind-of@^3.0.2, kind-of@^3.0.3, kind-of@^3.2.0:
+ version "3.2.2"
+ resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64"
+ integrity sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==
+ dependencies:
+ is-buffer "^1.1.5"
+
+kind-of@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-4.0.0.tgz#20813df3d712928b207378691a45066fae72dd57"
+ integrity sha512-24XsCxmEbRwEDbz/qz3stgin8TTzZ1ESR56OMCN0ujYg+vRutNSiOj9bHH9u85DKgXguraugV5sFuvbD4FW/hw==
+ dependencies:
+ is-buffer "^1.1.5"
+
+kind-of@^6.0.2:
+ version "6.0.3"
+ resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd"
+ integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==
+
+kleur@^3.0.3:
+ version "3.0.3"
+ resolved "https://registry.yarnpkg.com/kleur/-/kleur-3.0.3.tgz#a79c9ecc86ee1ce3fa6206d1216c501f147fc07e"
+ integrity sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==
+
+knex@2.5.0:
+ version "2.5.0"
+ resolved "https://registry.yarnpkg.com/knex/-/knex-2.5.0.tgz#5c99245e9c7e6a9d1a8b7fcf48b457ccb471dec3"
+ integrity sha512-h6Ru3PJmZjCDUEqLgwQ/RJUu06Bz7MTzY6sD90udLIa9qwtC7Rnicr7TBiWSaswZmDqk4EZ8xysdg1fkvhYM6w==
+ dependencies:
+ colorette "2.0.19"
+ commander "^10.0.0"
+ debug "4.3.4"
+ escalade "^3.1.1"
+ esm "^3.2.25"
+ get-package-type "^0.1.0"
+ getopts "2.3.0"
+ interpret "^2.2.0"
+ lodash "^4.17.21"
+ pg-connection-string "2.6.1"
+ rechoir "^0.8.0"
+ resolve-from "^5.0.0"
+ tarn "^3.0.2"
+ tildify "2.0.0"
+
+koa-body@4.2.0:
+ version "4.2.0"
+ resolved "https://registry.yarnpkg.com/koa-body/-/koa-body-4.2.0.tgz#37229208b820761aca5822d14c5fc55cee31b26f"
+ integrity sha512-wdGu7b9amk4Fnk/ytH8GuWwfs4fsB5iNkY8kZPpgQVb04QZSv85T0M8reb+cJmvLE8cjPYvBzRikD3s6qz8OoA==
+ dependencies:
+ "@types/formidable" "^1.0.31"
+ co-body "^5.1.1"
+ formidable "^1.1.1"
+
+koa-bodyparser@4.4.1:
+ version "4.4.1"
+ resolved "https://registry.yarnpkg.com/koa-bodyparser/-/koa-bodyparser-4.4.1.tgz#a908d848e142cc57d9eece478e932bf00dce3029"
+ integrity sha512-kBH3IYPMb+iAXnrxIhXnW+gXV8OTzCu8VPDqvcDHW9SQrbkHmqPQtiZwrltNmSq6/lpipHnT7k7PsjlVD7kK0w==
+ dependencies:
+ co-body "^6.0.0"
+ copy-to "^2.0.1"
+ type-is "^1.6.18"
+
+koa-compose@4.1.0, koa-compose@^4.1.0:
+ version "4.1.0"
+ resolved "https://registry.yarnpkg.com/koa-compose/-/koa-compose-4.1.0.tgz#507306b9371901db41121c812e923d0d67d3e877"
+ integrity sha512-8ODW8TrDuMYvXRwra/Kh7/rJo9BtOfPc6qO8eAfC80CnCvSjSl0bkRM24X6/XBBEyj0v1nRUQ1LyOy3dbqOWXw==
+
+koa-compress@5.1.0:
+ version "5.1.0"
+ resolved "https://registry.yarnpkg.com/koa-compress/-/koa-compress-5.1.0.tgz#7b9fe24f4c1b28d9cae90864597da472c2fcf701"
+ integrity sha512-G3Ppo9jrUwlchp6qdoRgQNMiGZtM0TAHkxRZQ7EoVvIG8E47J4nAsMJxXHAUQ+0oc7t0MDxSdONWTFcbzX7/Bg==
+ dependencies:
+ bytes "^3.0.0"
+ compressible "^2.0.0"
+ http-errors "^1.8.0"
+ koa-is-json "^1.0.0"
+ statuses "^2.0.1"
+
+koa-convert@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/koa-convert/-/koa-convert-2.0.0.tgz#86a0c44d81d40551bae22fee6709904573eea4f5"
+ integrity sha512-asOvN6bFlSnxewce2e/DK3p4tltyfC4VM7ZwuTuepI7dEQVcvpyFuBcEARu1+Hxg8DIwytce2n7jrZtRlPrARA==
+ dependencies:
+ co "^4.6.0"
+ koa-compose "^4.1.0"
+
+koa-favicon@2.1.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/koa-favicon/-/koa-favicon-2.1.0.tgz#c430cc594614fb494adcb5ee1196a2f7f53ea442"
+ integrity sha512-LvukcooYjxKtnZq0RXdBup+JDhaHwLgnLlDHB/xvjwQEjbc4rbp/0WkmOzpOvaHujc+fIwPear0dpKX1V+dHVg==
+ dependencies:
+ mz "^2.7.0"
+
+koa-helmet@7.0.2:
+ version "7.0.2"
+ resolved "https://registry.yarnpkg.com/koa-helmet/-/koa-helmet-7.0.2.tgz#2077e60cc69fa550802931ccdb85f948aa6bd054"
+ integrity sha512-AvzS6VuEfFgbAm0mTUnkk/BpMarMcs5A56g+f0sfrJ6m63wII48d2GDrnUQGp0Nj+RR950vNtgqXm9UJSe7GOg==
+ dependencies:
+ helmet "^6.0.1"
+
+koa-ip@^2.1.2:
+ version "2.1.3"
+ resolved "https://registry.yarnpkg.com/koa-ip/-/koa-ip-2.1.3.tgz#b7318bb30fd1e06d03a96beb704ee72cc6ecade0"
+ integrity sha512-QLVBByImwDq9enZXVOD3Astk876B7N0IYta7Kik4iyNB462rVzBB1/LD0Ek1F+v9nGUTHBFyhh8043EIlskK9Q==
+ dependencies:
+ debug "4.3.4"
+ lodash.isplainobject "4.0.6"
+ request-ip "3.3.0"
+
+koa-is-json@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/koa-is-json/-/koa-is-json-1.0.0.tgz#273c07edcdcb8df6a2c1ab7d59ee76491451ec14"
+ integrity sha512-+97CtHAlWDx0ndt0J8y3P12EWLwTLMXIfMnYDev3wOTwH/RpBGMlfn4bDXlMEg1u73K6XRE9BbUp+5ZAYoRYWw==
+
+koa-passport@5.0.0:
+ version "5.0.0"
+ resolved "https://registry.yarnpkg.com/koa-passport/-/koa-passport-5.0.0.tgz#66c8e91b06358969ab6129d90368fa07a06fafc0"
+ integrity sha512-eNGg3TGgZ4ydm9DYCOqaa0ySSA/44BS6X+v4CKjP/nHOoXlADRonHsZvS3QWok6EV0ZL0V7FhfWxRYfD2B5kTQ==
+ dependencies:
+ passport "^0.6.0"
+
+koa-range@0.3.0:
+ version "0.3.0"
+ resolved "https://registry.yarnpkg.com/koa-range/-/koa-range-0.3.0.tgz#3588e3496473a839a1bd264d2a42b1d85bd7feac"
+ integrity sha512-Ich3pCz6RhtbajYXRWjIl6O5wtrLs6kE3nkXc9XmaWe+MysJyZO7K4L3oce1Jpg/iMgCbj+5UCiMm/rqVtcDIg==
+ dependencies:
+ stream-slice "^0.1.2"
+
+koa-send@^5.0.0:
+ version "5.0.1"
+ resolved "https://registry.yarnpkg.com/koa-send/-/koa-send-5.0.1.tgz#39dceebfafb395d0d60beaffba3a70b4f543fe79"
+ integrity sha512-tmcyQ/wXXuxpDxyNXv5yNNkdAMdFRqwtegBXUaowiQzUKqJehttS0x2j0eOZDQAyloAth5w6wwBImnFzkUz3pQ==
+ dependencies:
+ debug "^4.1.1"
+ http-errors "^1.7.3"
+ resolve-path "^1.4.0"
+
+koa-session@6.4.0:
+ version "6.4.0"
+ resolved "https://registry.yarnpkg.com/koa-session/-/koa-session-6.4.0.tgz#f17c6f1844b37114192aa23a0ccf4f58c3042e96"
+ integrity sha512-h/dxmSOvNEXpHQPRs4TV03TZVFyZIjmYQiTAW5JBFTYBOZ0VdpZ8QEE6Dud75g8z9JNGXi3m++VqRmqToB+c2A==
+ dependencies:
+ crc "^3.8.0"
+ debug "^4.3.3"
+ is-type-of "^1.2.1"
+ uuid "^8.3.2"
+
+koa-static@5.0.0:
+ version "5.0.0"
+ resolved "https://registry.yarnpkg.com/koa-static/-/koa-static-5.0.0.tgz#5e92fc96b537ad5219f425319c95b64772776943"
+ integrity sha512-UqyYyH5YEXaJrf9S8E23GoJFQZXkBVJ9zYYMPGz919MSX1KuvAcycIuS0ci150HCoPf4XQVhQ84Qf8xRPWxFaQ==
+ dependencies:
+ debug "^3.1.0"
+ koa-send "^5.0.0"
+
+koa2-ratelimit@^1.1.2, koa2-ratelimit@^1.1.3:
+ version "1.1.3"
+ resolved "https://registry.yarnpkg.com/koa2-ratelimit/-/koa2-ratelimit-1.1.3.tgz#9f839c4f5533151aa4d5b8d11381a9a07854f0ff"
+ integrity sha512-gdrIw6m/D7pmScScL4dz50qLbRR3UGqvO1Vuy2dc7hVIuFAl1OVTnu6WFyEJ5GbfyLZFaCMWzRw6t4krvzvUTg==
+
+koa@2.13.4:
+ version "2.13.4"
+ resolved "https://registry.yarnpkg.com/koa/-/koa-2.13.4.tgz#ee5b0cb39e0b8069c38d115139c774833d32462e"
+ integrity sha512-43zkIKubNbnrULWlHdN5h1g3SEKXOEzoAlRsHOTFpnlDu8JlAOZSMJBLULusuXRequboiwJcj5vtYXKB3k7+2g==
+ dependencies:
+ accepts "^1.3.5"
+ cache-content-type "^1.0.0"
+ content-disposition "~0.5.2"
+ content-type "^1.0.4"
+ cookies "~0.8.0"
+ debug "^4.3.2"
+ delegates "^1.0.0"
+ depd "^2.0.0"
+ destroy "^1.0.4"
+ encodeurl "^1.0.2"
+ escape-html "^1.0.3"
+ fresh "~0.5.2"
+ http-assert "^1.3.0"
+ http-errors "^1.6.3"
+ is-generator-function "^1.0.7"
+ koa-compose "^4.1.0"
+ koa-convert "^2.0.0"
+ on-finished "^2.3.0"
+ only "~0.0.2"
+ parseurl "^1.3.2"
+ statuses "^1.5.0"
+ type-is "^1.6.16"
+ vary "^1.1.2"
+
+koa@^2.15.0:
+ version "2.15.0"
+ resolved "https://registry.yarnpkg.com/koa/-/koa-2.15.0.tgz#d24ae1b0ff378bf12eb3df584ab4204e4c12ac2b"
+ integrity sha512-KEL/vU1knsoUvfP4MC4/GthpQrY/p6dzwaaGI6Rt4NQuFqkw3qrvsdYF5pz3wOfi7IGTvMPHC9aZIcUKYFNxsw==
+ dependencies:
+ accepts "^1.3.5"
+ cache-content-type "^1.0.0"
+ content-disposition "~0.5.2"
+ content-type "^1.0.4"
+ cookies "~0.9.0"
+ debug "^4.3.2"
+ delegates "^1.0.0"
+ depd "^2.0.0"
+ destroy "^1.0.4"
+ encodeurl "^1.0.2"
+ escape-html "^1.0.3"
+ fresh "~0.5.2"
+ http-assert "^1.3.0"
+ http-errors "^1.6.3"
+ is-generator-function "^1.0.7"
+ koa-compose "^4.1.0"
+ koa-convert "^2.0.0"
+ on-finished "^2.3.0"
+ only "~0.0.2"
+ parseurl "^1.3.2"
+ statuses "^1.5.0"
+ type-is "^1.6.16"
+ vary "^1.1.2"
+
+kuler@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/kuler/-/kuler-2.0.0.tgz#e2c570a3800388fb44407e851531c1d670b061b3"
+ integrity sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A==
+
+libbase64@0.1.0:
+ version "0.1.0"
+ resolved "https://registry.yarnpkg.com/libbase64/-/libbase64-0.1.0.tgz#62351a839563ac5ff5bd26f12f60e9830bb751e6"
+ integrity sha512-B91jifmFw1DKEqEWstSpg1PbtUbBzR4yQAPT86kCQXBtud1AJVA+Z6RSklSrqmKe4q2eiEufgnhqJKPgozzfIQ==
+
+libmime@2.1.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/libmime/-/libmime-2.1.0.tgz#51bc76de2283161eb9051c4bc80aed713e4fd1cd"
+ integrity sha512-4be2R6/jOasyPTw0BkpIZBVk2cElqjdIdS0PRPhbOCV4wWuL/ZcYYpN1BCTVB+6eIQ0uuAwp5hQTHFrM5Joa8w==
+ dependencies:
+ iconv-lite "0.4.13"
+ libbase64 "0.1.0"
+ libqp "1.1.0"
+
+libmime@^2.0.3:
+ version "2.1.3"
+ resolved "https://registry.yarnpkg.com/libmime/-/libmime-2.1.3.tgz#25017ca5ab5a1e98aadbe2725017cf1d48a42a0c"
+ integrity sha512-ABr2f4O+K99sypmkF/yPz2aXxUFHEZzv+iUkxItCeKZWHHXdQPpDXd6rV1kBBwL4PserzLU09EIzJ2lxC9hPfQ==
+ dependencies:
+ iconv-lite "0.4.15"
+ libbase64 "0.1.0"
+ libqp "1.1.0"
+
+libqp@1.1.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/libqp/-/libqp-1.1.0.tgz#f5e6e06ad74b794fb5b5b66988bf728ef1dedbe8"
+ integrity sha512-4Rgfa0hZpG++t1Vi2IiqXG9Ad1ig4QTmtuZF946QJP4bPqOYC78ixUXgz5TW/wE7lNaNKlplSYTxQ+fR2KZ0EA==
+
+liftoff@^2.5.0:
+ version "2.5.0"
+ resolved "https://registry.yarnpkg.com/liftoff/-/liftoff-2.5.0.tgz#2009291bb31cea861bbf10a7c15a28caf75c31ec"
+ integrity sha512-01zfGFqfORP1CGmZZP2Zn51zsqz4RltDi0RDOhbGoLYdUT5Lw+I2gX6QdwXhPITF6hPOHEOp+At6/L24hIg9WQ==
+ dependencies:
+ extend "^3.0.0"
+ findup-sync "^2.0.0"
+ fined "^1.0.1"
+ flagged-respawn "^1.0.0"
+ is-plain-object "^2.0.4"
+ object.map "^1.0.0"
+ rechoir "^0.6.2"
+ resolve "^1.1.7"
+
+lines-and-columns@^1.1.6:
+ version "1.2.4"
+ resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632"
+ integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==
+
+linkify-it@^3.0.1:
+ version "3.0.3"
+ resolved "https://registry.yarnpkg.com/linkify-it/-/linkify-it-3.0.3.tgz#a98baf44ce45a550efb4d49c769d07524cc2fa2e"
+ integrity sha512-ynTsyrFSdE5oZ/O9GEf00kPngmOfVwazR5GKDq6EYfhlpFug3J2zybX56a2PRRpc9P+FuSoGNAwjlbDs9jJBPQ==
+ dependencies:
+ uc.micro "^1.0.1"
+
+loader-runner@^4.2.0:
+ version "4.3.0"
+ resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-4.3.0.tgz#c1b4a163b99f614830353b16755e7149ac2314e1"
+ integrity sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==
+
+loader-utils@^2.0.0, loader-utils@^2.0.4:
+ version "2.0.4"
+ resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-2.0.4.tgz#8b5cb38b5c34a9a018ee1fc0e6a066d1dfcc528c"
+ integrity sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==
+ dependencies:
+ big.js "^5.2.2"
+ emojis-list "^3.0.0"
+ json5 "^2.1.2"
+
+locate-path@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-3.0.0.tgz#dbec3b3ab759758071b58fe59fc41871af21400e"
+ integrity sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==
+ dependencies:
+ p-locate "^3.0.0"
+ path-exists "^3.0.0"
+
+locate-path@^5.0.0:
+ version "5.0.0"
+ resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-5.0.0.tgz#1afba396afd676a6d42504d0a67a3a7eb9f62aa0"
+ integrity sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==
+ dependencies:
+ p-locate "^4.1.0"
+
+locate-path@^6.0.0:
+ version "6.0.0"
+ resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-6.0.0.tgz#55321eb309febbc59c4801d931a72452a681d286"
+ integrity sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==
+ dependencies:
+ p-locate "^5.0.0"
+
+lodash-es@^4.17.15, lodash-es@^4.17.21:
+ version "4.17.21"
+ resolved "https://registry.yarnpkg.com/lodash-es/-/lodash-es-4.17.21.tgz#43e626c46e6591b7750beb2b50117390c609e3ee"
+ integrity sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==
+
+lodash.deburr@^4.1.0:
+ version "4.1.0"
+ resolved "https://registry.yarnpkg.com/lodash.deburr/-/lodash.deburr-4.1.0.tgz#ddb1bbb3ef07458c0177ba07de14422cb033ff9b"
+ integrity sha512-m/M1U1f3ddMCs6Hq2tAsYThTBDaAKFDX3dwDo97GEYzamXi9SqUpjWi/Rrj/gf3X2n8ktwgZrlP1z6E3v/IExQ==
+
+lodash.get@^4.4.2:
+ version "4.4.2"
+ resolved "https://registry.yarnpkg.com/lodash.get/-/lodash.get-4.4.2.tgz#2d177f652fa31e939b4438d5341499dfa3825e99"
+ integrity sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==
+
+lodash.includes@^4.3.0:
+ version "4.3.0"
+ resolved "https://registry.yarnpkg.com/lodash.includes/-/lodash.includes-4.3.0.tgz#60bb98a87cb923c68ca1e51325483314849f553f"
+ integrity sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==
+
+lodash.isboolean@^3.0.3:
+ version "3.0.3"
+ resolved "https://registry.yarnpkg.com/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz#6c2e171db2a257cd96802fd43b01b20d5f5870f6"
+ integrity sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==
+
+lodash.isinteger@^4.0.4:
+ version "4.0.4"
+ resolved "https://registry.yarnpkg.com/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz#619c0af3d03f8b04c31f5882840b77b11cd68343"
+ integrity sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==
+
+lodash.isnumber@^3.0.3:
+ version "3.0.3"
+ resolved "https://registry.yarnpkg.com/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz#3ce76810c5928d03352301ac287317f11c0b1ffc"
+ integrity sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==
+
+lodash.isplainobject@4.0.6, lodash.isplainobject@^4.0.6:
+ version "4.0.6"
+ resolved "https://registry.yarnpkg.com/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz#7c526a52d89b45c45cc690b88163be0497f550cb"
+ integrity sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==
+
+lodash.isstring@^4.0.1:
+ version "4.0.1"
+ resolved "https://registry.yarnpkg.com/lodash.isstring/-/lodash.isstring-4.0.1.tgz#d527dfb5456eca7cc9bb95d5daeaf88ba54a5451"
+ integrity sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==
+
+lodash.once@^4.0.0:
+ version "4.1.1"
+ resolved "https://registry.yarnpkg.com/lodash.once/-/lodash.once-4.1.1.tgz#0dd3971213c7c56df880977d504c88fb471a97ac"
+ integrity sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==
+
+lodash@4.17.21, lodash@^4.17.19, lodash@^4.17.20, lodash@^4.17.21, lodash@^4.17.4:
+ version "4.17.21"
+ resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c"
+ integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==
+
+log-symbols@^2.2.0:
+ version "2.2.0"
+ resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-2.2.0.tgz#5740e1c5d6f0dfda4ad9323b5332107ef6b4c40a"
+ integrity sha512-VeIAFslyIerEJLXHziedo2basKbMKtTw3vfn5IzG0XTjhAVEJyNHnL2p7vc+wBDSdQuUpNw3M2u6xb9QsAY5Eg==
+ dependencies:
+ chalk "^2.0.1"
+
+log-symbols@^4.1.0:
+ version "4.1.0"
+ resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-4.1.0.tgz#3fbdbb95b4683ac9fc785111e792e558d4abd503"
+ integrity sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==
+ dependencies:
+ chalk "^4.1.0"
+ is-unicode-supported "^0.1.0"
+
+logform@^2.3.2, logform@^2.4.0:
+ version "2.6.0"
+ resolved "https://registry.yarnpkg.com/logform/-/logform-2.6.0.tgz#8c82a983f05d6eaeb2d75e3decae7a768b2bf9b5"
+ integrity sha512-1ulHeNPp6k/LD8H91o7VYFBng5i1BDE7HoKxVbZiGFidS1Rj65qcywLxX+pVfAPoQJEjRdvKcusKwOupHCVOVQ==
+ dependencies:
+ "@colors/colors" "1.6.0"
+ "@types/triple-beam" "^1.3.2"
+ fecha "^4.2.0"
+ ms "^2.1.1"
+ safe-stable-stringify "^2.3.1"
+ triple-beam "^1.3.0"
+
+long-timeout@0.1.1:
+ version "0.1.1"
+ resolved "https://registry.yarnpkg.com/long-timeout/-/long-timeout-0.1.1.tgz#9721d788b47e0bcb5a24c2e2bee1a0da55dab514"
+ integrity sha512-BFRuQUqc7x2NWxfJBCyUrN8iYUYznzL9JROmRz1gZ6KlOIgmoD+njPVbb+VNn2nGMKggMsK79iUNErillsrx7w==
+
+loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.2.0, loose-envify@^1.3.1, loose-envify@^1.4.0:
+ version "1.4.0"
+ resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf"
+ integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==
+ dependencies:
+ js-tokens "^3.0.0 || ^4.0.0"
+
+lower-case-first@^1.0.0:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/lower-case-first/-/lower-case-first-1.0.2.tgz#e5da7c26f29a7073be02d52bac9980e5922adfa1"
+ integrity sha512-UuxaYakO7XeONbKrZf5FEgkantPf5DUqDayzP5VXZrtRPdH86s4kN47I8B3TW10S4QKiE3ziHNf3kRN//okHjA==
+ dependencies:
+ lower-case "^1.1.2"
+
+lower-case@^1.1.0, lower-case@^1.1.1, lower-case@^1.1.2:
+ version "1.1.4"
+ resolved "https://registry.yarnpkg.com/lower-case/-/lower-case-1.1.4.tgz#9a2cabd1b9e8e0ae993a4bf7d5875c39c42e8eac"
+ integrity sha512-2Fgx1Ycm599x+WGpIYwJOvsjmXFzTSc34IwDWALRA/8AopUKAVPwfJ+h5+f85BCp0PWmmJcWzEpxOpoXycMpdA==
+
+lower-case@^2.0.2:
+ version "2.0.2"
+ resolved "https://registry.yarnpkg.com/lower-case/-/lower-case-2.0.2.tgz#6fa237c63dbdc4a82ca0fd882e4722dc5e634e28"
+ integrity sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==
+ dependencies:
+ tslib "^2.0.3"
+
+lowercase-keys@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-2.0.0.tgz#2603e78b7b4b0006cbca2fbcc8a3202558ac9479"
+ integrity sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==
+
+lru-cache@^5.1.1:
+ version "5.1.1"
+ resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920"
+ integrity sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==
+ dependencies:
+ yallist "^3.0.2"
+
+lru-cache@^6.0.0:
+ version "6.0.0"
+ resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94"
+ integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==
+ dependencies:
+ yallist "^4.0.0"
+
+lru_map@^0.3.3:
+ version "0.3.3"
+ resolved "https://registry.yarnpkg.com/lru_map/-/lru_map-0.3.3.tgz#b5c8351b9464cbd750335a79650a0ec0e56118dd"
+ integrity sha512-Pn9cox5CsMYngeDbmChANltQl+5pi6XmTrraMSzhPmMBbmgcxmqWry0U3PGapCU1yB4/LqCcom7qhHZiF/jGfQ==
+
+luxon@^1.26.0:
+ version "1.28.1"
+ resolved "https://registry.yarnpkg.com/luxon/-/luxon-1.28.1.tgz#528cdf3624a54506d710290a2341aa8e6e6c61b0"
+ integrity sha512-gYHAa180mKrNIUJCbwpmD0aTu9kV0dREDrwNnuyFAsO1Wt0EVYSZelPnJlbj9HplzXX/YWXHFTL45kvZ53M0pw==
+
+lz-string@^1.4.4, lz-string@^1.5.0:
+ version "1.5.0"
+ resolved "https://registry.yarnpkg.com/lz-string/-/lz-string-1.5.0.tgz#c1ab50f77887b712621201ba9fd4e3a6ed099941"
+ integrity sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==
+
+mailcomposer@3.12.0:
+ version "3.12.0"
+ resolved "https://registry.yarnpkg.com/mailcomposer/-/mailcomposer-3.12.0.tgz#9c5e1188aa8e1c62ec8b86bd43468102b639e8f9"
+ integrity sha512-zBeDoKUTNI8IAsazoMQFt3eVSVRtDtgrvBjBVdBjxDEX+5KLlKtEFCrBXnxPhs8aTYufUS1SmbFnGpjHS53deg==
+ dependencies:
+ buildmail "3.10.0"
+ libmime "2.1.0"
+
+make-dir@^3.0.0, make-dir@^3.1.0:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-3.1.0.tgz#415e967046b3a7f1d185277d84aa58203726a13f"
+ integrity sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==
+ dependencies:
+ semver "^6.0.0"
+
+make-iterator@^1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/make-iterator/-/make-iterator-1.0.1.tgz#29b33f312aa8f547c4a5e490f56afcec99133ad6"
+ integrity sha512-pxiuXh0iVEq7VM7KMIhs5gxsfxCux2URptUQaXo4iZZJxBAzTPOLE2BumO5dbfVYq/hBJFBR/a1mFDmOx5AGmw==
+ dependencies:
+ kind-of "^6.0.2"
+
+map-cache@^0.2.0, map-cache@^0.2.2:
+ version "0.2.2"
+ resolved "https://registry.yarnpkg.com/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf"
+ integrity sha512-8y/eV9QQZCiyn1SprXSrCmqJN0yNRATe+PO8ztwqrvrbdRLA3eYJF0yaR0YayLWkMbsQSKWS9N2gPcGEc4UsZg==
+
+map-visit@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/map-visit/-/map-visit-1.0.0.tgz#ecdca8f13144e660f1b5bd41f12f3479d98dfb8f"
+ integrity sha512-4y7uGv8bd2WdM9vpQsiQNo41Ln1NvhvDRuVt0k2JZQ+ezN2uaQes7lZeZ+QQUHOLQAtDaBJ+7wCbi+ab/KFs+w==
+ dependencies:
+ object-visit "^1.0.0"
+
+markdown-it-abbr@^1.0.4:
+ version "1.0.4"
+ resolved "https://registry.yarnpkg.com/markdown-it-abbr/-/markdown-it-abbr-1.0.4.tgz#d66b5364521cbb3dd8aa59dadfba2fb6865c8fd8"
+ integrity sha512-ZeA4Z4SaBbYysZap5iZcxKmlPL6bYA8grqhzJIHB1ikn7njnzaP8uwbtuXc4YXD5LicI4/2Xmc0VwmSiFV04gg==
+
+markdown-it-container@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/markdown-it-container/-/markdown-it-container-3.0.0.tgz#1d19b06040a020f9a827577bb7dbf67aa5de9a5b"
+ integrity sha512-y6oKTq4BB9OQuY/KLfk/O3ysFhB3IMYoIWhGJEidXt1NQFocFK2sA2t0NYZAMyMShAGL6x5OPIbrmXPIqaN9rw==
+
+markdown-it-deflist@^2.1.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/markdown-it-deflist/-/markdown-it-deflist-2.1.0.tgz#50d7a56b9544cd81252f7623bd785e28a8dcef5c"
+ integrity sha512-3OuqoRUlSxJiuQYu0cWTLHNhhq2xtoSFqsZK8plANg91+RJQU1ziQ6lA2LzmFAEes18uPBsHZpcX6We5l76Nzg==
+
+markdown-it-emoji@^2.0.0:
+ version "2.0.2"
+ resolved "https://registry.yarnpkg.com/markdown-it-emoji/-/markdown-it-emoji-2.0.2.tgz#cd42421c2fda1537d9cc12b9923f5c8aeb9029c8"
+ integrity sha512-zLftSaNrKuYl0kR5zm4gxXjHaOI3FAOEaloKmRA5hijmJZvSjmxcokOLlzycb/HXlUFWzXqpIEoyEMCE4i9MvQ==
+
+markdown-it-footnote@^3.0.3:
+ version "3.0.3"
+ resolved "https://registry.yarnpkg.com/markdown-it-footnote/-/markdown-it-footnote-3.0.3.tgz#e0e4c0d67390a4c5f0c75f73be605c7c190ca4d8"
+ integrity sha512-YZMSuCGVZAjzKMn+xqIco9d1cLGxbELHZ9do/TSYVzraooV8ypsppKNmUJ0fVH5ljkCInQAtFpm8Rb3eXSrt5w==
+
+markdown-it-ins@^3.0.1:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/markdown-it-ins/-/markdown-it-ins-3.0.1.tgz#c09356b917cf1dbf73add0b275d67ab8c73d4b4d"
+ integrity sha512-32SSfZqSzqyAmmQ4SHvhxbFqSzPDqsZgMHDwxqPzp+v+t8RsmqsBZRG+RfRQskJko9PfKC2/oxyOs4Yg/CfiRw==
+
+markdown-it-mark@^3.0.1:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/markdown-it-mark/-/markdown-it-mark-3.0.1.tgz#51257db58787d78aaf46dc13418d99a9f3f0ebd3"
+ integrity sha512-HyxjAu6BRsdt6Xcv6TKVQnkz/E70TdGXEFHRYBGLncRE9lBFwDNLVtFojKxjJWgJ+5XxUwLaHXy+2sGBbDn+4A==
+
+markdown-it-sub@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/markdown-it-sub/-/markdown-it-sub-1.0.0.tgz#375fd6026eae7ddcb012497f6411195ea1e3afe8"
+ integrity sha512-z2Rm/LzEE1wzwTSDrI+FlPEveAAbgdAdPhdWarq/ZGJrGW/uCQbKAnhoCsE4hAbc3SEym26+W2z/VQB0cQiA9Q==
+
+markdown-it-sup@1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/markdown-it-sup/-/markdown-it-sup-1.0.0.tgz#cb9c9ff91a5255ac08f3fd3d63286e15df0a1fc3"
+ integrity sha512-E32m0nV9iyhRR7CrhnzL5msqic7rL1juWre6TQNxsnApg7Uf+F97JOKxUijg5YwXz86lZ0mqfOnutoryyNdntQ==
+
+markdown-it@^12.3.2:
+ version "12.3.2"
+ resolved "https://registry.yarnpkg.com/markdown-it/-/markdown-it-12.3.2.tgz#bf92ac92283fe983fe4de8ff8abfb5ad72cd0c90"
+ integrity sha512-TchMembfxfNVpHkbtriWltGWc+m3xszaRD0CZup7GFFhzIgQqxIfn3eGj1yZpfuflzPvfkt611B2Q/Bsk1YnGg==
+ dependencies:
+ argparse "^2.0.1"
+ entities "~2.1.0"
+ linkify-it "^3.0.1"
+ mdurl "^1.0.1"
+ uc.micro "^1.0.5"
+
+match-sorter@^4.2.1:
+ version "4.2.1"
+ resolved "https://registry.yarnpkg.com/match-sorter/-/match-sorter-4.2.1.tgz#575b4b3737185ba9518b67612b66877ea0b37358"
+ integrity sha512-s+3h9TiZU9U1pWhIERHf8/f4LmBN6IXaRgo2CI17+XGByGS1GvG5VvXK9pcGyCjGe3WM3mSYRC3ipGrd5UEVgw==
+ dependencies:
+ "@babel/runtime" "^7.10.5"
+ remove-accents "0.4.2"
+
+match-sorter@^6.0.2:
+ version "6.3.1"
+ resolved "https://registry.yarnpkg.com/match-sorter/-/match-sorter-6.3.1.tgz#98cc37fda756093424ddf3cbc62bfe9c75b92bda"
+ integrity sha512-mxybbo3pPNuA+ZuCUhm5bwNkXrJTbsk5VWbR5wiwz/GC6LIiegBGn2w3O08UG/jdbYLinw51fSQ5xNU1U3MgBw==
+ dependencies:
+ "@babel/runtime" "^7.12.5"
+ remove-accents "0.4.2"
+
+mdurl@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/mdurl/-/mdurl-1.0.1.tgz#fe85b2ec75a59037f2adfec100fd6c601761152e"
+ integrity sha512-/sKlQJCBYVY9Ers9hqzKou4H6V5UWc/M59TH2dvkt+84itfnq7uFOMLpOiOS4ujvHP4etln18fmIxA5R5fll0g==
+
+media-typer@0.3.0:
+ version "0.3.0"
+ resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748"
+ integrity sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==
+
+memfs@^3.4.1, memfs@^3.4.12:
+ version "3.6.0"
+ resolved "https://registry.yarnpkg.com/memfs/-/memfs-3.6.0.tgz#d7a2110f86f79dd950a8b6df6d57bc984aa185f6"
+ integrity sha512-EGowvkkgbMcIChjMTMkESFDbZeSh8xZ7kNSF0hAiAN4Jh6jgHCRS0Ga/+C8y6Au+oqpezRHCfPsmJ2+DwAgiwQ==
+ dependencies:
+ fs-monkey "^1.0.4"
+
+"memoize-one@>=3.1.1 <6":
+ version "5.2.1"
+ resolved "https://registry.yarnpkg.com/memoize-one/-/memoize-one-5.2.1.tgz#8337aa3c4335581839ec01c3d594090cebe8f00e"
+ integrity sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q==
+
+memoize-one@^6.0.0:
+ version "6.0.0"
+ resolved "https://registry.yarnpkg.com/memoize-one/-/memoize-one-6.0.0.tgz#b2591b871ed82948aee4727dc6abceeeac8c1045"
+ integrity sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw==
+
+merge-stream@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60"
+ integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==
+
+merge2@^1.2.3, merge2@^1.3.0, merge2@^1.4.1:
+ version "1.4.1"
+ resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae"
+ integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==
+
+methods@^1.1.2:
+ version "1.1.2"
+ resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee"
+ integrity sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==
+
+micromatch@^3.0.4:
+ version "3.1.10"
+ resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23"
+ integrity sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==
+ dependencies:
+ arr-diff "^4.0.0"
+ array-unique "^0.3.2"
+ braces "^2.3.1"
+ define-property "^2.0.2"
+ extend-shallow "^3.0.2"
+ extglob "^2.0.4"
+ fragment-cache "^0.2.1"
+ kind-of "^6.0.2"
+ nanomatch "^1.2.9"
+ object.pick "^1.3.0"
+ regex-not "^1.0.0"
+ snapdragon "^0.8.1"
+ to-regex "^3.0.2"
+
+micromatch@^4.0.4:
+ version "4.0.5"
+ resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.5.tgz#bc8999a7cbbf77cdc89f132f6e467051b49090c6"
+ integrity sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==
+ dependencies:
+ braces "^3.0.2"
+ picomatch "^2.3.1"
+
+microseconds@0.2.0:
+ version "0.2.0"
+ resolved "https://registry.yarnpkg.com/microseconds/-/microseconds-0.2.0.tgz#233b25f50c62a65d861f978a4a4f8ec18797dc39"
+ integrity sha512-n7DHHMjR1avBbSpsTBj6fmMGh2AGrifVV4e+WYc3Q9lO+xnSZ3NyhcBND3vzzatt05LFhoKFRxrIyklmLlUtyA==
+
+mime-db@1.52.0, "mime-db@>= 1.43.0 < 2":
+ version "1.52.0"
+ resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70"
+ integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==
+
+mime-types@2.1.35, mime-types@^2.1.12, mime-types@^2.1.18, mime-types@^2.1.27, mime-types@^2.1.28, mime-types@^2.1.31, mime-types@~2.1.24, mime-types@~2.1.34:
+ version "2.1.35"
+ resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a"
+ integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==
+ dependencies:
+ mime-db "1.52.0"
+
+mimic-fn@^1.0.0:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.2.0.tgz#820c86a39334640e99516928bd03fca88057d022"
+ integrity sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==
+
+mimic-fn@^2.1.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b"
+ integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==
+
+mimic-fn@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-4.0.0.tgz#60a90550d5cb0b239cca65d893b1a53b29871ecc"
+ integrity sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==
+
+mimic-response@^1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-1.0.1.tgz#4923538878eef42063cb8a3e3b0798781487ab1b"
+ integrity sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==
+
+mimic-response@^2.0.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-2.1.0.tgz#d13763d35f613d09ec37ebb30bac0469c0ee8f43"
+ integrity sha512-wXqjST+SLt7R009ySCglWBCFpjUygmCIfD790/kVbiGmUgfYGuB14PiTd5DwVxSV4NcYHjzMkoj5LjQZwTQLEA==
+
+mimic-response@^3.1.0:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-3.1.0.tgz#2d1d59af9c1b129815accc2c46a022a5ce1fa3c9"
+ integrity sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==
+
+mini-css-extract-plugin@2.7.6:
+ version "2.7.6"
+ resolved "https://registry.yarnpkg.com/mini-css-extract-plugin/-/mini-css-extract-plugin-2.7.6.tgz#282a3d38863fddcd2e0c220aaed5b90bc156564d"
+ integrity sha512-Qk7HcgaPkGG6eD77mLvZS1nmxlao3j+9PkrT9Uc7HAE1id3F41+DdBRYRYkbyfNRGzm8/YWtzhw7nVPmwhqTQw==
+ dependencies:
+ schema-utils "^4.0.0"
+
+minimalistic-assert@^1.0.0, minimalistic-assert@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7"
+ integrity sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==
+
+minimalistic-crypto-utils@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a"
+ integrity sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==
+
+minimatch@^3.0.2, minimatch@^3.0.3, minimatch@^3.0.4, minimatch@^3.1.1:
+ version "3.1.2"
+ resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b"
+ integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==
+ dependencies:
+ brace-expansion "^1.1.7"
+
+minimatch@^5.0.1:
+ version "5.1.6"
+ resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-5.1.6.tgz#1cfcb8cf5522ea69952cd2af95ae09477f122a96"
+ integrity sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==
+ dependencies:
+ brace-expansion "^2.0.1"
+
+minimist@^1.2.0, minimist@^1.2.3, minimist@^1.2.5, minimist@^1.2.6:
+ version "1.2.8"
+ resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c"
+ integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==
+
+minipass@^3.0.0:
+ version "3.3.6"
+ resolved "https://registry.yarnpkg.com/minipass/-/minipass-3.3.6.tgz#7bba384db3a1520d18c9c0e5251c3444e95dd94a"
+ integrity sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==
+ dependencies:
+ yallist "^4.0.0"
+
+minipass@^4.0.0:
+ version "4.2.8"
+ resolved "https://registry.yarnpkg.com/minipass/-/minipass-4.2.8.tgz#f0010f64393ecfc1d1ccb5f582bcaf45f48e1a3a"
+ integrity sha512-fNzuVyifolSLFL4NzpF+wEF4qrgqaaKX0haXPQEdQ7NKAN+WecoKMHV09YcuL/DHxrUsYQOK3MiuDf7Ip2OXfQ==
+
+minipass@^5.0.0:
+ version "5.0.0"
+ resolved "https://registry.yarnpkg.com/minipass/-/minipass-5.0.0.tgz#3e9788ffb90b694a5d0ec94479a45b5d8738133d"
+ integrity sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==
+
+minizlib@^2.1.1:
+ version "2.1.2"
+ resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-2.1.2.tgz#e90d3466ba209b932451508a11ce3d3632145931"
+ integrity sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==
+ dependencies:
+ minipass "^3.0.0"
+ yallist "^4.0.0"
+
+mixin-deep@^1.2.0:
+ version "1.3.2"
+ resolved "https://registry.yarnpkg.com/mixin-deep/-/mixin-deep-1.3.2.tgz#1120b43dc359a785dce65b55b82e257ccf479566"
+ integrity sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==
+ dependencies:
+ for-in "^1.0.2"
+ is-extendable "^1.0.1"
+
+mkdirp-classic@^0.5.2, mkdirp-classic@^0.5.3:
+ version "0.5.3"
+ resolved "https://registry.yarnpkg.com/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz#fa10c9115cc6d8865be221ba47ee9bed78601113"
+ integrity sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==
+
+mkdirp@^0.5.1:
+ version "0.5.6"
+ resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.6.tgz#7def03d2432dcae4ba1d611445c48396062255f6"
+ integrity sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==
+ dependencies:
+ minimist "^1.2.6"
+
+mkdirp@^1.0.3, mkdirp@^1.0.4:
+ version "1.0.4"
+ resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e"
+ integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==
+
+mrmime@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/mrmime/-/mrmime-2.0.0.tgz#151082a6e06e59a9a39b46b3e14d5cfe92b3abb4"
+ integrity sha512-eu38+hdgojoyq63s+yTpN4XMBdt5l8HhMhc4VKLO9KM5caLIBvUm4thi7fFaxyTmCKeNnXZ5pAlBwCUnhA09uw==
+
+ms@2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"
+ integrity sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==
+
+ms@2.1.2:
+ version "2.1.2"
+ resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009"
+ integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==
+
+ms@^2.1.1:
+ version "2.1.3"
+ resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2"
+ integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==
+
+msw@1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/msw/-/msw-1.0.1.tgz#f55b36b3d7e911ee75a73d6346585e01af3fbcfb"
+ integrity sha512-fBwQRCmf+jh0zlGlasBfpCaxLqb4QLMsY1Q+nkXkO0nnUYopl50NcNRvP4V+TAiqOwJSd0LrQ5NcJqwbrnTBqw==
+ dependencies:
+ "@mswjs/cookies" "^0.2.2"
+ "@mswjs/interceptors" "^0.17.5"
+ "@open-draft/until" "^1.0.3"
+ "@types/cookie" "^0.4.1"
+ "@types/js-levenshtein" "^1.1.1"
+ chalk "4.1.1"
+ chokidar "^3.4.2"
+ cookie "^0.4.2"
+ graphql "^15.0.0 || ^16.0.0"
+ headers-polyfill "^3.1.0"
+ inquirer "^8.2.0"
+ is-node-process "^1.0.1"
+ js-levenshtein "^1.1.6"
+ node-fetch "^2.6.7"
+ outvariant "^1.3.0"
+ path-to-regexp "^6.2.0"
+ strict-event-emitter "^0.4.3"
+ type-fest "^2.19.0"
+ yargs "^17.3.1"
+
+multistream@^4.0.1:
+ version "4.1.0"
+ resolved "https://registry.yarnpkg.com/multistream/-/multistream-4.1.0.tgz#7bf00dfd119556fbc153cff3de4c6d477909f5a8"
+ integrity sha512-J1XDiAmmNpRCBfIWJv+n0ymC4ABcf/Pl+5YvC5B/D2f/2+8PtHvCNxMPKiQcZyi922Hq69J2YOpb1pTywfifyw==
+ dependencies:
+ once "^1.4.0"
+ readable-stream "^3.6.0"
+
+mute-stream@0.0.8:
+ version "0.0.8"
+ resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.8.tgz#1630c42b2251ff81e2a283de96a5497ea92e5e0d"
+ integrity sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==
+
+mz@^2.7.0:
+ version "2.7.0"
+ resolved "https://registry.yarnpkg.com/mz/-/mz-2.7.0.tgz#95008057a56cafadc2bc63dde7f9ff6955948e32"
+ integrity sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==
+ dependencies:
+ any-promise "^1.0.0"
+ object-assign "^4.0.1"
+ thenify-all "^1.0.0"
+
+nan@^2.17.0:
+ version "2.18.0"
+ resolved "https://registry.yarnpkg.com/nan/-/nan-2.18.0.tgz#26a6faae7ffbeb293a39660e88a76b82e30b7554"
+ integrity sha512-W7tfG7vMOGtD30sHoZSSc/JVYiyDPEyQVso/Zz+/uQd0B0L46gtC+pHha5FFMRpil6fm/AoEcRWyOVi4+E/f8w==
+
+nano-time@1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/nano-time/-/nano-time-1.0.0.tgz#b0554f69ad89e22d0907f7a12b0993a5d96137ef"
+ integrity sha512-flnngywOoQ0lLQOTRNexn2gGSNuM9bKj9RZAWSzhQ+UJYaAFG9bac4DW9VHjUAzrOaIcajHybCTHe/bkvozQqA==
+ dependencies:
+ big-integer "^1.6.16"
+
+nanoclone@^0.2.1:
+ version "0.2.1"
+ resolved "https://registry.yarnpkg.com/nanoclone/-/nanoclone-0.2.1.tgz#dd4090f8f1a110d26bb32c49ed2f5b9235209ed4"
+ integrity sha512-wynEP02LmIbLpcYw8uBKpcfF6dmg2vcpKqxeH5UcoKEYdExslsdUA4ugFauuaeYdTB76ez6gJW8XAZ6CgkXYxA==
+
+nanoid@^3.3.7:
+ version "3.3.7"
+ resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.7.tgz#d0c301a691bc8d54efa0a2226ccf3fe2fd656bd8"
+ integrity sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==
+
+nanomatch@^1.2.9:
+ version "1.2.13"
+ resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119"
+ integrity sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==
+ dependencies:
+ arr-diff "^4.0.0"
+ array-unique "^0.3.2"
+ define-property "^2.0.2"
+ extend-shallow "^3.0.2"
+ fragment-cache "^0.2.1"
+ is-windows "^1.0.2"
+ kind-of "^6.0.2"
+ object.pick "^1.3.0"
+ regex-not "^1.0.0"
+ snapdragon "^0.8.1"
+ to-regex "^3.0.1"
+
+napi-build-utils@^1.0.1:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/napi-build-utils/-/napi-build-utils-1.0.2.tgz#b1fddc0b2c46e380a0b7a76f984dd47c41a13806"
+ integrity sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==
+
+negotiator@0.6.3:
+ version "0.6.3"
+ resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.3.tgz#58e323a72fedc0d6f9cd4d31fe49f51479590ccd"
+ integrity sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==
+
+neo-async@^2.6.2:
+ version "2.6.2"
+ resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.2.tgz#b4aafb93e3aeb2d8174ca53cf163ab7d7308305f"
+ integrity sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==
+
+no-case@^2.2.0, no-case@^2.3.2:
+ version "2.3.2"
+ resolved "https://registry.yarnpkg.com/no-case/-/no-case-2.3.2.tgz#60b813396be39b3f1288a4c1ed5d1e7d28b464ac"
+ integrity sha512-rmTZ9kz+f3rCvK2TD1Ue/oZlns7OGoIWP4fc3llxxRXlOkHKoWPPWJOfFYpITabSow43QJbRIoHQXtt10VldyQ==
+ dependencies:
+ lower-case "^1.1.1"
+
+no-case@^3.0.4:
+ version "3.0.4"
+ resolved "https://registry.yarnpkg.com/no-case/-/no-case-3.0.4.tgz#d361fd5c9800f558551a8369fc0dcd4662b6124d"
+ integrity sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==
+ dependencies:
+ lower-case "^2.0.2"
+ tslib "^2.0.3"
+
+node-abi@^3.3.0:
+ version "3.54.0"
+ resolved "https://registry.yarnpkg.com/node-abi/-/node-abi-3.54.0.tgz#f6386f7548817acac6434c6cba02999c9aebcc69"
+ integrity sha512-p7eGEiQil0YUV3ItH4/tBb781L5impVmmx2E9FRKF7d18XXzp4PGT2tdYMFY6wQqgxD0IwNZOiSJ0/K0fSi/OA==
+ dependencies:
+ semver "^7.3.5"
+
+node-abort-controller@^3.0.1, node-abort-controller@^3.1.1:
+ version "3.1.1"
+ resolved "https://registry.yarnpkg.com/node-abort-controller/-/node-abort-controller-3.1.1.tgz#a94377e964a9a37ac3976d848cb5c765833b8548"
+ integrity sha512-AGK2yQKIjRuqnc6VkX2Xj5d+QW8xZ87pa1UK6yA6ouUyuxfHuMP6umE5QK7UmTeOAymo+Zx1Fxiuw9rVx8taHQ==
+
+node-addon-api@^6.1.0:
+ version "6.1.0"
+ resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-6.1.0.tgz#ac8470034e58e67d0c6f1204a18ae6995d9c0d76"
+ integrity sha512-+eawOlIgy680F0kBzPUNFhMZGtJ1YmqM6l4+Crf4IkImjYrO/mqPwRMh352g23uIaQKFItcQ64I7KMaJxHgAVA==
+
+node-fetch@2.7.0, node-fetch@^2.6.7:
+ version "2.7.0"
+ resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.7.0.tgz#d0f0fa6e3e2dc1d27efcd8ad99d550bda94d187d"
+ integrity sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==
+ dependencies:
+ whatwg-url "^5.0.0"
+
+node-machine-id@1.1.12, node-machine-id@^1.1.10:
+ version "1.1.12"
+ resolved "https://registry.yarnpkg.com/node-machine-id/-/node-machine-id-1.1.12.tgz#37904eee1e59b320bb9c5d6c0a59f3b469cb6267"
+ integrity sha512-QNABxbrPa3qEIfrE6GOJ7BYIuignnJw7iQ2YPbc3Nla1HzRJjXzZOiikfF8m7eAMfichLt3M4VgLOetqgDmgGQ==
+
+node-plop@0.26.3, node-plop@^0.26.3:
+ version "0.26.3"
+ resolved "https://registry.yarnpkg.com/node-plop/-/node-plop-0.26.3.tgz#d6fa7e71393c8b940513ba8c4868f8aaa6dea9df"
+ integrity sha512-Cov028YhBZ5aB7MdMWJEmwyBig43aGL5WT4vdoB28Oitau1zZAcHUn8Sgfk9HM33TqhtLJ9PlM/O0Mv+QpV/4Q==
+ dependencies:
+ "@babel/runtime-corejs3" "^7.9.2"
+ "@types/inquirer" "^6.5.0"
+ change-case "^3.1.0"
+ del "^5.1.0"
+ globby "^10.0.1"
+ handlebars "^4.4.3"
+ inquirer "^7.1.0"
+ isbinaryfile "^4.0.2"
+ lodash.get "^4.4.2"
+ mkdirp "^0.5.1"
+ resolve "^1.12.0"
+
+node-releases@^2.0.14:
+ version "2.0.14"
+ resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.14.tgz#2ffb053bceb8b2be8495ece1ab6ce600c4461b0b"
+ integrity sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==
+
+node-schedule@2.1.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/node-schedule/-/node-schedule-2.1.0.tgz#068ae38d7351c330616f7fe7cdb05036f977cbaf"
+ integrity sha512-nl4JTiZ7ZQDc97MmpTq9BQjYhq7gOtoh7SiPH069gBFBj0PzD8HI7zyFs6rzqL8Y5tTiEEYLxgtbx034YPrbyQ==
+ dependencies:
+ cron-parser "^3.5.0"
+ long-timeout "0.1.1"
+ sorted-array-functions "^1.3.0"
+
+nodemailer-fetch@1.6.0:
+ version "1.6.0"
+ resolved "https://registry.yarnpkg.com/nodemailer-fetch/-/nodemailer-fetch-1.6.0.tgz#79c4908a1c0f5f375b73fe888da9828f6dc963a4"
+ integrity sha512-P7S5CEVGAmDrrpn351aXOLYs1R/7fD5NamfMCHyi6WIkbjS2eeZUB/TkuvpOQr0bvRZicVqo59+8wbhR3yrJbQ==
+
+nodemailer-shared@1.1.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/nodemailer-shared/-/nodemailer-shared-1.1.0.tgz#cf5994e2fd268d00f5cf0fa767a08169edb07ec0"
+ integrity sha512-68xW5LSyPWv8R0GLm6veAvm7E+XFXkVgvE3FW0FGxNMMZqMkPFeGDVALfR1DPdSfcoO36PnW7q5AAOgFImEZGg==
+ dependencies:
+ nodemailer-fetch "1.6.0"
+
+noms@0.0.0:
+ version "0.0.0"
+ resolved "https://registry.yarnpkg.com/noms/-/noms-0.0.0.tgz#da8ebd9f3af9d6760919b27d9cdc8092a7332859"
+ integrity sha512-lNDU9VJaOPxUmXcLb+HQFeUgQQPtMI24Gt6hgfuMHRJgMRHMF/qZ4HJD3GDru4sSw9IQl2jPjAYnQrdIeLbwow==
+ dependencies:
+ inherits "^2.0.1"
+ readable-stream "~1.0.31"
+
+nopt@^5.0.0:
+ version "5.0.0"
+ resolved "https://registry.yarnpkg.com/nopt/-/nopt-5.0.0.tgz#530942bb58a512fccafe53fe210f13a25355dc88"
+ integrity sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==
+ dependencies:
+ abbrev "1"
+
+normalize-package-data@^2.5.0:
+ version "2.5.0"
+ resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.5.0.tgz#e66db1838b200c1dfc233225d12cb36520e234a8"
+ integrity sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==
+ dependencies:
+ hosted-git-info "^2.1.4"
+ resolve "^1.10.0"
+ semver "2 || 3 || 4 || 5"
+ validate-npm-package-license "^3.0.1"
+
+normalize-path@^3.0.0, normalize-path@~3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65"
+ integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==
+
+normalize-url@^6.0.1:
+ version "6.1.0"
+ resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-6.1.0.tgz#40d0885b535deffe3f3147bec877d05fe4c5668a"
+ integrity sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==
+
+npm-run-path@^4.0.1:
+ version "4.0.1"
+ resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-4.0.1.tgz#b7ecd1e5ed53da8e37a55e1c2269e0b97ed748ea"
+ integrity sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==
+ dependencies:
+ path-key "^3.0.0"
+
+npm-run-path@^5.1.0:
+ version "5.2.0"
+ resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-5.2.0.tgz#224cdd22c755560253dd71b83a1ef2f758b2e955"
+ integrity sha512-W4/tgAXFqFA0iL7fk0+uQ3g7wkL8xJmx3XdK0VGb4cHW//eZTtKGvFBBoRKVTpY7n6ze4NL9ly7rgXcHufqXKg==
+ dependencies:
+ path-key "^4.0.0"
+
+npmlog@^5.0.1:
+ version "5.0.1"
+ resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-5.0.1.tgz#f06678e80e29419ad67ab964e0fa69959c1eb8b0"
+ integrity sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw==
+ dependencies:
+ are-we-there-yet "^2.0.0"
+ console-control-strings "^1.1.0"
+ gauge "^3.0.0"
+ set-blocking "^2.0.0"
+
+nth-check@^2.0.1:
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/nth-check/-/nth-check-2.1.1.tgz#c9eab428effce36cd6b92c924bdb000ef1f1ed1d"
+ integrity sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==
+ dependencies:
+ boolbase "^1.0.0"
+
+oauth-sign@^0.9.0:
+ version "0.9.0"
+ resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455"
+ integrity sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==
+
+object-assign@^4.0.1, object-assign@^4.1.1:
+ version "4.1.1"
+ resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
+ integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==
+
+object-copy@^0.1.0:
+ version "0.1.0"
+ resolved "https://registry.yarnpkg.com/object-copy/-/object-copy-0.1.0.tgz#7e7d858b781bd7c991a41ba975ed3812754e998c"
+ integrity sha512-79LYn6VAb63zgtmAteVOWo9Vdj71ZVBy3Pbse+VqxDpEP83XuujMrGqHIwAXJ5I/aM0zU7dIyIAhifVTPrNItQ==
+ dependencies:
+ copy-descriptor "^0.1.0"
+ define-property "^0.2.5"
+ kind-of "^3.0.3"
+
+object-inspect@^1.9.0:
+ version "1.13.1"
+ resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.13.1.tgz#b96c6109324ccfef6b12216a956ca4dc2ff94bc2"
+ integrity sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==
+
+object-is@^1.1.5:
+ version "1.1.5"
+ resolved "https://registry.yarnpkg.com/object-is/-/object-is-1.1.5.tgz#b9deeaa5fc7f1846a0faecdceec138e5778f53ac"
+ integrity sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw==
+ dependencies:
+ call-bind "^1.0.2"
+ define-properties "^1.1.3"
+
+object-keys@^1.1.1:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e"
+ integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==
+
+object-visit@^1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/object-visit/-/object-visit-1.0.1.tgz#f79c4493af0c5377b59fe39d395e41042dd045bb"
+ integrity sha512-GBaMwwAVK9qbQN3Scdo0OyvgPW7l3lnaVMj84uTOZlswkX0KpF6fyDBJhtTthf7pymztoN36/KEr1DyhF96zEA==
+ dependencies:
+ isobject "^3.0.0"
+
+object.assign@^4.1.4:
+ version "4.1.5"
+ resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.5.tgz#3a833f9ab7fdb80fc9e8d2300c803d216d8fdbb0"
+ integrity sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==
+ dependencies:
+ call-bind "^1.0.5"
+ define-properties "^1.2.1"
+ has-symbols "^1.0.3"
+ object-keys "^1.1.1"
+
+object.defaults@^1.1.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/object.defaults/-/object.defaults-1.1.0.tgz#3a7f868334b407dea06da16d88d5cd29e435fecf"
+ integrity sha512-c/K0mw/F11k4dEUBMW8naXUuBuhxRCfG7W+yFy8EcijU/rSmazOUd1XAEEe6bC0OuXY4HUKjTJv7xbxIMqdxrA==
+ dependencies:
+ array-each "^1.0.1"
+ array-slice "^1.0.0"
+ for-own "^1.0.0"
+ isobject "^3.0.0"
+
+object.map@^1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/object.map/-/object.map-1.0.1.tgz#cf83e59dc8fcc0ad5f4250e1f78b3b81bd801d37"
+ integrity sha512-3+mAJu2PLfnSVGHwIWubpOFLscJANBKuB/6A4CxBstc4aqwQY0FWcsppuy4jU5GSB95yES5JHSI+33AWuS4k6w==
+ dependencies:
+ for-own "^1.0.0"
+ make-iterator "^1.0.0"
+
+object.pick@^1.2.0, object.pick@^1.3.0:
+ version "1.3.0"
+ resolved "https://registry.yarnpkg.com/object.pick/-/object.pick-1.3.0.tgz#87a10ac4c1694bd2e1cbf53591a66141fb5dd747"
+ integrity sha512-tqa/UMy/CCoYmj+H5qc07qvSL9dqcs/WZENZ1JbtWBlATP+iVOe778gE6MSijnyCnORzDuX6hU+LA4SZ09YjFQ==
+ dependencies:
+ isobject "^3.0.1"
+
+oblivious-set@1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/oblivious-set/-/oblivious-set-1.0.0.tgz#c8316f2c2fb6ff7b11b6158db3234c49f733c566"
+ integrity sha512-z+pI07qxo4c2CulUHCDf9lcqDlMSo72N/4rLUpRXf6fu+q8vjt8y0xS+Tlf8NTJDdTXHbdeO1n3MlbctwEoXZw==
+
+on-finished@^2.3.0:
+ version "2.4.1"
+ resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.4.1.tgz#58c8c44116e54845ad57f14ab10b03533184ac3f"
+ integrity sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==
+ dependencies:
+ ee-first "1.1.1"
+
+once@^1.3.0, once@^1.3.1, once@^1.4.0:
+ version "1.4.0"
+ resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
+ integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==
+ dependencies:
+ wrappy "1"
+
+one-time@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/one-time/-/one-time-1.0.0.tgz#e06bc174aed214ed58edede573b433bbf827cb45"
+ integrity sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g==
+ dependencies:
+ fn.name "1.x.x"
+
+onetime@^2.0.0:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/onetime/-/onetime-2.0.1.tgz#067428230fd67443b2794b22bba528b6867962d4"
+ integrity sha512-oyyPpiMaKARvvcgip+JV+7zci5L8D1W9RZIz2l1o08AM3pfspitVWnPt3mzHcBPp12oYMTy0pqrFs/C+m3EwsQ==
+ dependencies:
+ mimic-fn "^1.0.0"
+
+onetime@^5.1.0, onetime@^5.1.2:
+ version "5.1.2"
+ resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.2.tgz#d0e96ebb56b07476df1dd9c4806e5237985ca45e"
+ integrity sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==
+ dependencies:
+ mimic-fn "^2.1.0"
+
+onetime@^6.0.0:
+ version "6.0.0"
+ resolved "https://registry.yarnpkg.com/onetime/-/onetime-6.0.0.tgz#7c24c18ed1fd2e9bca4bd26806a33613c77d34b4"
+ integrity sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==
+ dependencies:
+ mimic-fn "^4.0.0"
+
+only@~0.0.2:
+ version "0.0.2"
+ resolved "https://registry.yarnpkg.com/only/-/only-0.0.2.tgz#2afde84d03e50b9a8edc444e30610a70295edfb4"
+ integrity sha512-Fvw+Jemq5fjjyWz6CpKx6w9s7xxqo3+JCyM0WXWeCSOboZ8ABkyvP8ID4CZuChA/wxSx+XSJmdOm8rGVyJ1hdQ==
+
+open@8.4.0:
+ version "8.4.0"
+ resolved "https://registry.yarnpkg.com/open/-/open-8.4.0.tgz#345321ae18f8138f82565a910fdc6b39e8c244f8"
+ integrity sha512-XgFPPM+B28FtCCgSb9I+s9szOC1vZRSwgWsRUA5ylIxRTgKozqjOCrVOqGsYABPYK5qnfqClxZTFBa8PKt2v6Q==
+ dependencies:
+ define-lazy-prop "^2.0.0"
+ is-docker "^2.1.1"
+ is-wsl "^2.2.0"
+
+open@^9.1.0:
+ version "9.1.0"
+ resolved "https://registry.yarnpkg.com/open/-/open-9.1.0.tgz#684934359c90ad25742f5a26151970ff8c6c80b6"
+ integrity sha512-OS+QTnw1/4vrf+9hh1jc1jnYjzSG4ttTBB8UxOwAnInG3Uo4ssetzC1ihqaIHjLJnA5GGlRl6QlZXOTQhRBUvg==
+ dependencies:
+ default-browser "^4.0.0"
+ define-lazy-prop "^3.0.0"
+ is-inside-container "^1.0.0"
+ is-wsl "^2.2.0"
+
+opener@^1.5.2:
+ version "1.5.2"
+ resolved "https://registry.yarnpkg.com/opener/-/opener-1.5.2.tgz#5d37e1f35077b9dcac4301372271afdeb2a13598"
+ integrity sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A==
+
+ora@5.4.1, ora@^5.4.1:
+ version "5.4.1"
+ resolved "https://registry.yarnpkg.com/ora/-/ora-5.4.1.tgz#1b2678426af4ac4a509008e5e4ac9e9959db9e18"
+ integrity sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==
+ dependencies:
+ bl "^4.1.0"
+ chalk "^4.1.0"
+ cli-cursor "^3.1.0"
+ cli-spinners "^2.5.0"
+ is-interactive "^1.0.0"
+ is-unicode-supported "^0.1.0"
+ log-symbols "^4.1.0"
+ strip-ansi "^6.0.0"
+ wcwidth "^1.0.1"
+
+ora@^3.4.0:
+ version "3.4.0"
+ resolved "https://registry.yarnpkg.com/ora/-/ora-3.4.0.tgz#bf0752491059a3ef3ed4c85097531de9fdbcd318"
+ integrity sha512-eNwHudNbO1folBP3JsZ19v9azXWtQZjICdr3Q0TDPIaeBQ3mXLrh54wM+er0+hSp+dWKf+Z8KM58CYzEyIYxYg==
+ dependencies:
+ chalk "^2.4.2"
+ cli-cursor "^2.1.0"
+ cli-spinners "^2.0.0"
+ log-symbols "^2.2.0"
+ strip-ansi "^5.2.0"
+ wcwidth "^1.0.1"
+
+os-tmpdir@~1.0.2:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274"
+ integrity sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==
+
+outdent@0.8.0:
+ version "0.8.0"
+ resolved "https://registry.yarnpkg.com/outdent/-/outdent-0.8.0.tgz#2ebc3e77bf49912543f1008100ff8e7f44428eb0"
+ integrity sha512-KiOAIsdpUTcAXuykya5fnVVT+/5uS0Q1mrkRHcF89tpieSmY33O/tmc54CqwA+bfhbtEfZUNLHaPUiB9X3jt1A==
+
+outvariant@^1.2.1, outvariant@^1.3.0:
+ version "1.4.2"
+ resolved "https://registry.yarnpkg.com/outvariant/-/outvariant-1.4.2.tgz#f54f19240eeb7f15b28263d5147405752d8e2066"
+ integrity sha512-Ou3dJ6bA/UJ5GVHxah4LnqDwZRwAmWxrG3wtrHrbGnP4RnLCtA64A4F+ae7Y8ww660JaddSoArUR5HjipWSHAQ==
+
+p-cancelable@^2.0.0:
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-2.1.1.tgz#aab7fbd416582fa32a3db49859c122487c5ed2cf"
+ integrity sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg==
+
+p-finally@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae"
+ integrity sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==
+
+p-is-promise@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/p-is-promise/-/p-is-promise-3.0.0.tgz#58e78c7dfe2e163cf2a04ff869e7c1dba64a5971"
+ integrity sha512-Wo8VsW4IRQSKVXsJCn7TomUaVtyfjVDn3nUP7kE967BQk0CwFpdbZs0X0uk5sW9mkBa9eNM7hCMaG93WUAwxYQ==
+
+p-limit@^2.0.0, p-limit@^2.2.0:
+ version "2.3.0"
+ resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1"
+ integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==
+ dependencies:
+ p-try "^2.0.0"
+
+p-limit@^3.0.2:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b"
+ integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==
+ dependencies:
+ yocto-queue "^0.1.0"
+
+p-locate@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-3.0.0.tgz#322d69a05c0264b25997d9f40cd8a891ab0064a4"
+ integrity sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==
+ dependencies:
+ p-limit "^2.0.0"
+
+p-locate@^4.1.0:
+ version "4.1.0"
+ resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-4.1.0.tgz#a3428bb7088b3a60292f66919278b7c297ad4f07"
+ integrity sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==
+ dependencies:
+ p-limit "^2.2.0"
+
+p-locate@^5.0.0:
+ version "5.0.0"
+ resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-5.0.0.tgz#83c8315c6785005e3bd021839411c9e110e6d834"
+ integrity sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==
+ dependencies:
+ p-limit "^3.0.2"
+
+p-map@4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/p-map/-/p-map-4.0.0.tgz#bb2f95a5eda2ec168ec9274e06a747c3e2904d2b"
+ integrity sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==
+ dependencies:
+ aggregate-error "^3.0.0"
+
+p-map@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/p-map/-/p-map-3.0.0.tgz#d704d9af8a2ba684e2600d9a215983d4141a979d"
+ integrity sha512-d3qXVTF/s+W+CdJ5A29wywV2n8CQQYahlgz2bFiA+4eVNJbHJodPZ+/gXwPGh0bOqA+j8S+6+ckmvLGPk1QpxQ==
+ dependencies:
+ aggregate-error "^3.0.0"
+
+p-queue@^6.6.2:
+ version "6.6.2"
+ resolved "https://registry.yarnpkg.com/p-queue/-/p-queue-6.6.2.tgz#2068a9dcf8e67dd0ec3e7a2bcb76810faa85e426"
+ integrity sha512-RwFpb72c/BhQLEXIZ5K2e+AhgNVmIejGlTgiB9MzZ0e93GRvqZ7uSi0dvRF7/XIXDeNkra2fNHBxTyPDGySpjQ==
+ dependencies:
+ eventemitter3 "^4.0.4"
+ p-timeout "^3.2.0"
+
+p-timeout@^3.2.0:
+ version "3.2.0"
+ resolved "https://registry.yarnpkg.com/p-timeout/-/p-timeout-3.2.0.tgz#c7e17abc971d2a7962ef83626b35d635acf23dfe"
+ integrity sha512-rhIwUycgwwKcP9yTOOFK/AKsAopjjCakVqLHePO3CC6Mir1Z99xT+R63jZxAT5lFZLa2inS5h+ZS2GvR99/FBg==
+ dependencies:
+ p-finally "^1.0.0"
+
+p-try@^2.0.0:
+ version "2.2.0"
+ resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6"
+ integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==
+
+package-json@7.0.0:
+ version "7.0.0"
+ resolved "https://registry.yarnpkg.com/package-json/-/package-json-7.0.0.tgz#1355416e50a5c1b8f1a6f471197a3650d21186bf"
+ integrity sha512-CHJqc94AA8YfSLHGQT3DbvSIuE12NLFekpM4n7LRrAd3dOJtA911+4xe9q6nC3/jcKraq7nNS9VxgtT0KC+diA==
+ dependencies:
+ got "^11.8.2"
+ registry-auth-token "^4.0.0"
+ registry-url "^5.0.0"
+ semver "^7.3.5"
+
+packet-reader@1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/packet-reader/-/packet-reader-1.0.0.tgz#9238e5480dedabacfe1fe3f2771063f164157d74"
+ integrity sha512-HAKu/fG3HpHFO0AA8WE8q2g+gBJaZ9MG7fcKk+IJPLTGAD6Psw4443l+9DGRbOIh3/aXr7Phy0TjilYivJo5XQ==
+
+param-case@^2.1.0:
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/param-case/-/param-case-2.1.1.tgz#df94fd8cf6531ecf75e6bef9a0858fbc72be2247"
+ integrity sha512-eQE845L6ot89sk2N8liD8HAuH4ca6Vvr7VWAWwt7+kvvG5aBcPmmphQ68JsEG2qa9n1TykS2DLeMt363AAH8/w==
+ dependencies:
+ no-case "^2.2.0"
+
+param-case@^3.0.4:
+ version "3.0.4"
+ resolved "https://registry.yarnpkg.com/param-case/-/param-case-3.0.4.tgz#7d17fe4aa12bde34d4a77d91acfb6219caad01c5"
+ integrity sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A==
+ dependencies:
+ dot-case "^3.0.4"
+ tslib "^2.0.3"
+
+parent-module@^1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2"
+ integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==
+ dependencies:
+ callsites "^3.0.0"
+
+parse-filepath@^1.0.1:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/parse-filepath/-/parse-filepath-1.0.2.tgz#a632127f53aaf3d15876f5872f3ffac763d6c891"
+ integrity sha512-FwdRXKCohSVeXqwtYonZTXtbGJKrn+HNyWDYVcp5yuJlesTwNH4rsmRZ+GrKAPJ5bLpRxESMeS+Rl0VCHRvB2Q==
+ dependencies:
+ is-absolute "^1.0.0"
+ map-cache "^0.2.0"
+ path-root "^0.1.1"
+
+parse-headers@^2.0.5:
+ version "2.0.5"
+ resolved "https://registry.yarnpkg.com/parse-headers/-/parse-headers-2.0.5.tgz#069793f9356a54008571eb7f9761153e6c770da9"
+ integrity sha512-ft3iAoLOB/MlwbNXgzy43SWGP6sQki2jQvAyBg/zDFAgr9bfNWZIUj42Kw2eJIl8kEi4PbgE6U1Zau/HwI75HA==
+
+parse-json@^5.0.0:
+ version "5.2.0"
+ resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-5.2.0.tgz#c76fc66dee54231c962b22bcc8a72cf2f99753cd"
+ integrity sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==
+ dependencies:
+ "@babel/code-frame" "^7.0.0"
+ error-ex "^1.3.1"
+ json-parse-even-better-errors "^2.3.0"
+ lines-and-columns "^1.1.6"
+
+parse-passwd@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/parse-passwd/-/parse-passwd-1.0.0.tgz#6d5b934a456993b23d37f40a382d6f1666a8e5c6"
+ integrity sha512-1Y1A//QUXEZK7YKz+rD9WydcE1+EuPr6ZBgKecAB8tmoW6UFv0NREVJe1p+jRxtThkcbbKkfwIbWJe/IeE6m2Q==
+
+parse-path@^7.0.0:
+ version "7.0.0"
+ resolved "https://registry.yarnpkg.com/parse-path/-/parse-path-7.0.0.tgz#605a2d58d0a749c8594405d8cc3a2bf76d16099b"
+ integrity sha512-Euf9GG8WT9CdqwuWJGdf3RkUcTBArppHABkO7Lm8IzRQp0e2r/kkFnmhu4TSK30Wcu5rVAZLmfPKSBBi9tWFog==
+ dependencies:
+ protocols "^2.0.0"
+
+parse-srcset@^1.0.2:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/parse-srcset/-/parse-srcset-1.0.2.tgz#f2bd221f6cc970a938d88556abc589caaaa2bde1"
+ integrity sha512-/2qh0lav6CmI15FzA3i/2Bzk2zCgQhGMkvhOhKNcBVQ1ldgpbfiNTVslmooUmWJcADi1f1kIeynbDRVzNlfR6Q==
+
+parse-url@^8.1.0:
+ version "8.1.0"
+ resolved "https://registry.yarnpkg.com/parse-url/-/parse-url-8.1.0.tgz#972e0827ed4b57fc85f0ea6b0d839f0d8a57a57d"
+ integrity sha512-xDvOoLU5XRrcOZvnI6b8zA6n9O9ejNk/GExuz1yBuWUGn9KA97GI6HTs6u02wKara1CeVmZhH+0TZFdWScR89w==
+ dependencies:
+ parse-path "^7.0.0"
+
+parseurl@^1.3.2:
+ version "1.3.3"
+ resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4"
+ integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==
+
+pascal-case@^2.0.0:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/pascal-case/-/pascal-case-2.0.1.tgz#2d578d3455f660da65eca18ef95b4e0de912761e"
+ integrity sha512-qjS4s8rBOJa2Xm0jmxXiyh1+OFf6ekCWOvUaRgAQSktzlTbMotS0nmG9gyYAybCWBcuP4fsBeRCKNwGBnMe2OQ==
+ dependencies:
+ camel-case "^3.0.0"
+ upper-case-first "^1.1.0"
+
+pascal-case@^3.1.2:
+ version "3.1.2"
+ resolved "https://registry.yarnpkg.com/pascal-case/-/pascal-case-3.1.2.tgz#b48e0ef2b98e205e7c1dae747d0b1508237660eb"
+ integrity sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==
+ dependencies:
+ no-case "^3.0.4"
+ tslib "^2.0.3"
+
+pascalcase@^0.1.1:
+ version "0.1.1"
+ resolved "https://registry.yarnpkg.com/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14"
+ integrity sha512-XHXfu/yOQRy9vYOtUDVMN60OEJjW013GoObG1o+xwQTpB9eYJX/BjXMsdW13ZDPruFhYYn0AG22w0xgQMwl3Nw==
+
+passport-local@1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/passport-local/-/passport-local-1.0.0.tgz#1fe63268c92e75606626437e3b906662c15ba6ee"
+ integrity sha512-9wCE6qKznvf9mQYYbgJ3sVOHmCWoUNMVFoZzNoznmISbhnNNPhN9xfY3sLmScHMetEJeoY7CXwfhCe7argfQow==
+ dependencies:
+ passport-strategy "1.x.x"
+
+passport-strategy@1.x.x:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/passport-strategy/-/passport-strategy-1.0.0.tgz#b5539aa8fc225a3d1ad179476ddf236b440f52e4"
+ integrity sha512-CB97UUvDKJde2V0KDWWB3lyf6PC3FaZP7YxZ2G8OAtn9p4HI9j9JLP9qjOGZFvyl8uwNT8qM+hGnz/n16NI7oA==
+
+passport@^0.6.0:
+ version "0.6.0"
+ resolved "https://registry.yarnpkg.com/passport/-/passport-0.6.0.tgz#e869579fab465b5c0b291e841e6cc95c005fac9d"
+ integrity sha512-0fe+p3ZnrWRW74fe8+SvCyf4a3Pb2/h7gFkQ8yTJpAO50gDzlfjZUZTO1k5Eg9kUct22OxHLqDZoKUWRHOh9ug==
+ dependencies:
+ passport-strategy "1.x.x"
+ pause "0.0.1"
+ utils-merge "^1.0.1"
+
+path-case@^2.1.0:
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/path-case/-/path-case-2.1.1.tgz#94b8037c372d3fe2906e465bb45e25d226e8eea5"
+ integrity sha512-Ou0N05MioItesaLr9q8TtHVWmJ6fxWdqKB2RohFmNWVyJ+2zeKIeDNWAN6B/Pe7wpzWChhZX6nONYmOnMeJQ/Q==
+ dependencies:
+ no-case "^2.2.0"
+
+path-exists@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515"
+ integrity sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==
+
+path-exists@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3"
+ integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==
+
+path-is-absolute@1.0.1, path-is-absolute@^1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f"
+ integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==
+
+path-key@^3.0.0, path-key@^3.1.0:
+ version "3.1.1"
+ resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375"
+ integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==
+
+path-key@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/path-key/-/path-key-4.0.0.tgz#295588dc3aee64154f877adb9d780b81c554bf18"
+ integrity sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==
+
+path-parse@^1.0.7:
+ version "1.0.7"
+ resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735"
+ integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==
+
+path-root-regex@^0.1.0:
+ version "0.1.2"
+ resolved "https://registry.yarnpkg.com/path-root-regex/-/path-root-regex-0.1.2.tgz#bfccdc8df5b12dc52c8b43ec38d18d72c04ba96d"
+ integrity sha512-4GlJ6rZDhQZFE0DPVKh0e9jmZ5egZfxTkp7bcRDuPlJXbAwhxcl2dINPUAsjLdejqaLsCeg8axcLjIbvBjN4pQ==
+
+path-root@^0.1.1:
+ version "0.1.1"
+ resolved "https://registry.yarnpkg.com/path-root/-/path-root-0.1.1.tgz#9a4a6814cac1c0cd73360a95f32083c8ea4745b7"
+ integrity sha512-QLcPegTHF11axjfojBIoDygmS2E3Lf+8+jI6wOVmNVenrKSo3mFdSGiIgdSHenczw3wPtlVMQaFVwGmM7BJdtg==
+ dependencies:
+ path-root-regex "^0.1.0"
+
+path-to-regexp@^1.7.0:
+ version "1.8.0"
+ resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-1.8.0.tgz#887b3ba9d84393e87a0a0b9f4cb756198b53548a"
+ integrity sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA==
+ dependencies:
+ isarray "0.0.1"
+
+path-to-regexp@^6.1.0, path-to-regexp@^6.2.0:
+ version "6.2.1"
+ resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-6.2.1.tgz#d54934d6798eb9e5ef14e7af7962c945906918e5"
+ integrity sha512-JLyh7xT1kizaEvcaXOQwOc2/Yhw6KZOvPf1S8401UyLk86CU79LN3vl7ztXGm/pZ+YjoyAJ4rxmHwbkBXJX+yw==
+
+path-type@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b"
+ integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==
+
+pause@0.0.1:
+ version "0.0.1"
+ resolved "https://registry.yarnpkg.com/pause/-/pause-0.0.1.tgz#1d408b3fdb76923b9543d96fb4c9dfd535d9cb5d"
+ integrity sha512-KG8UEiEVkR3wGEb4m5yZkVCzigAD+cVEJck2CzYZO37ZGJfctvVptVO192MwrtPhzONn6go8ylnOdMhKqi4nfg==
+
+pg-cloudflare@^1.1.1:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/pg-cloudflare/-/pg-cloudflare-1.1.1.tgz#e6d5833015b170e23ae819e8c5d7eaedb472ca98"
+ integrity sha512-xWPagP/4B6BgFO+EKz3JONXv3YDgvkbVrGw2mTo3D6tVDQRh1e7cqVGvyR3BE+eQgAvx1XhW/iEASj4/jCWl3Q==
+
+pg-connection-string@2.6.1:
+ version "2.6.1"
+ resolved "https://registry.yarnpkg.com/pg-connection-string/-/pg-connection-string-2.6.1.tgz#78c23c21a35dd116f48e12e23c0965e8d9e2cbfb"
+ integrity sha512-w6ZzNu6oMmIzEAYVw+RLK0+nqHPt8K3ZnknKi+g48Ak2pr3dtljJW3o+D/n2zzCG07Zoe9VOX3aiKpj+BN0pjg==
+
+pg-connection-string@^2.6.2:
+ version "2.6.2"
+ resolved "https://registry.yarnpkg.com/pg-connection-string/-/pg-connection-string-2.6.2.tgz#713d82053de4e2bd166fab70cd4f26ad36aab475"
+ integrity sha512-ch6OwaeaPYcova4kKZ15sbJ2hKb/VP48ZD2gE7i1J+L4MspCtBMAx8nMgz7bksc7IojCIIWuEhHibSMFH8m8oA==
+
+pg-int8@1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/pg-int8/-/pg-int8-1.0.1.tgz#943bd463bf5b71b4170115f80f8efc9a0c0eb78c"
+ integrity sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==
+
+pg-pool@^3.6.1:
+ version "3.6.1"
+ resolved "https://registry.yarnpkg.com/pg-pool/-/pg-pool-3.6.1.tgz#5a902eda79a8d7e3c928b77abf776b3cb7d351f7"
+ integrity sha512-jizsIzhkIitxCGfPRzJn1ZdcosIt3pz9Sh3V01fm1vZnbnCMgmGl5wvGGdNN2EL9Rmb0EcFoCkixH4Pu+sP9Og==
+
+pg-protocol@^1.6.0:
+ version "1.6.0"
+ resolved "https://registry.yarnpkg.com/pg-protocol/-/pg-protocol-1.6.0.tgz#4c91613c0315349363af2084608db843502f8833"
+ integrity sha512-M+PDm637OY5WM307051+bsDia5Xej6d9IR4GwJse1qA1DIhiKlksvrneZOYQq42OM+spubpcNYEo2FcKQrDk+Q==
+
+pg-types@^2.1.0:
+ version "2.2.0"
+ resolved "https://registry.yarnpkg.com/pg-types/-/pg-types-2.2.0.tgz#2d0250d636454f7cfa3b6ae0382fdfa8063254a3"
+ integrity sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==
+ dependencies:
+ pg-int8 "1.0.1"
+ postgres-array "~2.0.0"
+ postgres-bytea "~1.0.0"
+ postgres-date "~1.0.4"
+ postgres-interval "^1.1.0"
+
+pg@^8.11.3:
+ version "8.11.3"
+ resolved "https://registry.yarnpkg.com/pg/-/pg-8.11.3.tgz#d7db6e3fe268fcedd65b8e4599cda0b8b4bf76cb"
+ integrity sha512-+9iuvG8QfaaUrrph+kpF24cXkH1YOOUeArRNYIxq1viYHZagBxrTno7cecY1Fa44tJeZvaoG+Djpkc3JwehN5g==
+ dependencies:
+ buffer-writer "2.0.0"
+ packet-reader "1.0.0"
+ pg-connection-string "^2.6.2"
+ pg-pool "^3.6.1"
+ pg-protocol "^1.6.0"
+ pg-types "^2.1.0"
+ pgpass "1.x"
+ optionalDependencies:
+ pg-cloudflare "^1.1.1"
+
+pgpass@1.x:
+ version "1.0.5"
+ resolved "https://registry.yarnpkg.com/pgpass/-/pgpass-1.0.5.tgz#9b873e4a564bb10fa7a7dbd55312728d422a223d"
+ integrity sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==
+ dependencies:
+ split2 "^4.1.0"
+
+picocolors@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c"
+ integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==
+
+picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.3.1:
+ version "2.3.1"
+ resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42"
+ integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==
+
+pkg-up@3.1.0:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/pkg-up/-/pkg-up-3.1.0.tgz#100ec235cc150e4fd42519412596a28512a0def5"
+ integrity sha512-nDywThFk1i4BQK4twPQ6TA4RT8bDY96yeuCVBWL3ePARCiEKDRSrNGbFIgUJpLp+XeIR65v8ra7WuJOFUBtkMA==
+ dependencies:
+ find-up "^3.0.0"
+
+plop@2.7.6:
+ version "2.7.6"
+ resolved "https://registry.yarnpkg.com/plop/-/plop-2.7.6.tgz#1fa5360cd5b04e9932ce677bb6bd44750d97ae67"
+ integrity sha512-IgnYAsC3Ni7t1cDU7wH2151CD22YhMxH8PFh+iPzCf+WuGEWXslJ5t1Tpr0N/gjL23CAV/HbLAWug2IPM2YrHg==
+ dependencies:
+ "@types/liftoff" "^2.5.1"
+ chalk "^1.1.3"
+ interpret "^1.2.0"
+ liftoff "^2.5.0"
+ minimist "^1.2.5"
+ node-plop "^0.26.3"
+ ora "^3.4.0"
+ v8flags "^2.0.10"
+
+pluralize@8.0.0:
+ version "8.0.0"
+ resolved "https://registry.yarnpkg.com/pluralize/-/pluralize-8.0.0.tgz#1a6fa16a38d12a1901e0320fa017051c539ce3b1"
+ integrity sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==
+
+pony-cause@^2.1.2:
+ version "2.1.10"
+ resolved "https://registry.yarnpkg.com/pony-cause/-/pony-cause-2.1.10.tgz#828457ad6f13be401a075dbf14107a9057945174"
+ integrity sha512-3IKLNXclQgkU++2fSi93sQ6BznFuxSLB11HdvZQ6JW/spahf/P1pAHBQEahr20rs0htZW0UDkM1HmA+nZkXKsw==
+
+posix-character-classes@^0.1.0:
+ version "0.1.1"
+ resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab"
+ integrity sha512-xTgYBc3fuo7Yt7JbiuFxSYGToMoz8fLoE6TC9Wx1P/u+LfeThMOAqmuyECnlBaaJb+u1m9hHiXUEtwW4OzfUJg==
+
+postcss-modules-extract-imports@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.0.0.tgz#cda1f047c0ae80c97dbe28c3e76a43b88025741d"
+ integrity sha512-bdHleFnP3kZ4NYDhuGlVK+CMrQ/pqUm8bx/oGL93K6gVwiclvX5x0n76fYMKuIGKzlABOy13zsvqjb0f92TEXw==
+
+postcss-modules-local-by-default@^4.0.3:
+ version "4.0.3"
+ resolved "https://registry.yarnpkg.com/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.0.3.tgz#b08eb4f083050708998ba2c6061b50c2870ca524"
+ integrity sha512-2/u2zraspoACtrbFRnTijMiQtb4GW4BvatjaG/bCjYQo8kLTdevCUlwuBHx2sCnSyrI3x3qj4ZK1j5LQBgzmwA==
+ dependencies:
+ icss-utils "^5.0.0"
+ postcss-selector-parser "^6.0.2"
+ postcss-value-parser "^4.1.0"
+
+postcss-modules-scope@^3.1.0:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/postcss-modules-scope/-/postcss-modules-scope-3.1.0.tgz#fbfddfda93a31f310f1d152c2bb4d3f3c5592ee0"
+ integrity sha512-SaIbK8XW+MZbd0xHPf7kdfA/3eOt7vxJ72IRecn3EzuZVLr1r0orzf0MX/pN8m+NMDoo6X/SQd8oeKqGZd8PXg==
+ dependencies:
+ postcss-selector-parser "^6.0.4"
+
+postcss-modules-values@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/postcss-modules-values/-/postcss-modules-values-4.0.0.tgz#d7c5e7e68c3bb3c9b27cbf48ca0bb3ffb4602c9c"
+ integrity sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ==
+ dependencies:
+ icss-utils "^5.0.0"
+
+postcss-selector-parser@^6.0.2, postcss-selector-parser@^6.0.4:
+ version "6.0.15"
+ resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-6.0.15.tgz#11cc2b21eebc0b99ea374ffb9887174855a01535"
+ integrity sha512-rEYkQOMUCEMhsKbK66tbEU9QVIxbhN18YiniAwA7XQYTVBqrBy+P2p5JcdqsHgKM2zWylp8d7J6eszocfds5Sw==
+ dependencies:
+ cssesc "^3.0.0"
+ util-deprecate "^1.0.2"
+
+postcss-value-parser@^4.0.2, postcss-value-parser@^4.1.0, postcss-value-parser@^4.2.0:
+ version "4.2.0"
+ resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz#723c09920836ba6d3e5af019f92bc0971c02e514"
+ integrity sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==
+
+postcss@^8.3.11, postcss@^8.4.27, postcss@^8.4.31:
+ version "8.4.33"
+ resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.33.tgz#1378e859c9f69bf6f638b990a0212f43e2aaa742"
+ integrity sha512-Kkpbhhdjw2qQs2O2DGX+8m5OVqEcbB9HRBvuYM9pgrjEFUg30A9LmXNlTAUj4S9kgtGyrMbTzVjH7E+s5Re2yg==
+ dependencies:
+ nanoid "^3.3.7"
+ picocolors "^1.0.0"
+ source-map-js "^1.0.2"
+
+postgres-array@~2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/postgres-array/-/postgres-array-2.0.0.tgz#48f8fce054fbc69671999329b8834b772652d82e"
+ integrity sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==
+
+postgres-bytea@~1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/postgres-bytea/-/postgres-bytea-1.0.0.tgz#027b533c0aa890e26d172d47cf9ccecc521acd35"
+ integrity sha512-xy3pmLuQqRBZBXDULy7KbaitYqLcmxigw14Q5sj8QBVLqEwXfeybIKVWiqAXTlcvdvb0+xkOtDbfQMOf4lST1w==
+
+postgres-date@~1.0.4:
+ version "1.0.7"
+ resolved "https://registry.yarnpkg.com/postgres-date/-/postgres-date-1.0.7.tgz#51bc086006005e5061c591cee727f2531bf641a8"
+ integrity sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==
+
+postgres-interval@^1.1.0:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/postgres-interval/-/postgres-interval-1.2.0.tgz#b460c82cb1587507788819a06aa0fffdb3544695"
+ integrity sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==
+ dependencies:
+ xtend "^4.0.0"
+
+prebuild-install@^7.1.0, prebuild-install@^7.1.1:
+ version "7.1.1"
+ resolved "https://registry.yarnpkg.com/prebuild-install/-/prebuild-install-7.1.1.tgz#de97d5b34a70a0c81334fd24641f2a1702352e45"
+ integrity sha512-jAXscXWMcCK8GgCoHOfIr0ODh5ai8mj63L2nWrjuAgXE6tDyYGnx4/8o/rCgU+B4JSyZBKbeZqzhtwtC3ovxjw==
+ dependencies:
+ detect-libc "^2.0.0"
+ expand-template "^2.0.3"
+ github-from-package "0.0.0"
+ minimist "^1.2.3"
+ mkdirp-classic "^0.5.3"
+ napi-build-utils "^1.0.1"
+ node-abi "^3.3.0"
+ pump "^3.0.0"
+ rc "^1.2.7"
+ simple-get "^4.0.0"
+ tar-fs "^2.0.0"
+ tunnel-agent "^0.6.0"
+
+prettier-plugin-packagejson@2.4.5:
+ version "2.4.5"
+ resolved "https://registry.yarnpkg.com/prettier-plugin-packagejson/-/prettier-plugin-packagejson-2.4.5.tgz#20cc396e5654b5736657bd2dfb7ac859afc618cc"
+ integrity sha512-glG71jE1gO3y5+JNAhC8X+4yrlN28rub6Aj461SKbaPie9RgMiHKcInH2Moi2VGOfkTXaEHBhg4uVMBqa+kBUA==
+ dependencies:
+ sort-package-json "2.5.1"
+ synckit "0.8.5"
+
+prettier@2.8.4:
+ version "2.8.4"
+ resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.8.4.tgz#34dd2595629bfbb79d344ac4a91ff948694463c3"
+ integrity sha512-vIS4Rlc2FNh0BySk3Wkd6xmwxB0FpOndW5fisM5H8hsZSxU2VWVB5CWIkIjWvrHjIhxk2g3bfMKM87zNTrZddw==
+
+pretty-error@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/pretty-error/-/pretty-error-4.0.0.tgz#90a703f46dd7234adb46d0f84823e9d1cb8f10d6"
+ integrity sha512-AoJ5YMAcXKYxKhuJGdcvse+Voc6v1RgnsR3nWcYU7q4t6z0Q6T86sv5Zq8VIRbOWWFpvdGE83LtdSMNd+6Y0xw==
+ dependencies:
+ lodash "^4.17.20"
+ renderkid "^3.0.0"
+
+pretty-format@^27.0.2:
+ version "27.5.1"
+ resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-27.5.1.tgz#2181879fdea51a7a5851fb39d920faa63f01d88e"
+ integrity sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==
+ dependencies:
+ ansi-regex "^5.0.1"
+ ansi-styles "^5.0.0"
+ react-is "^17.0.1"
+
+process-nextick-args@~2.0.0:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2"
+ integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==
+
+progress-stream@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/progress-stream/-/progress-stream-2.0.0.tgz#fac63a0b3d11deacbb0969abcc93b214bce19ed5"
+ integrity sha512-xJwOWR46jcXUq6EH9yYyqp+I52skPySOeHfkxOZ2IY1AiBi/sFJhbhAKHoV3OTw/omQ45KTio9215dRJ2Yxd3Q==
+ dependencies:
+ speedometer "~1.0.0"
+ through2 "~2.0.3"
+
+prompts@2.4.2:
+ version "2.4.2"
+ resolved "https://registry.yarnpkg.com/prompts/-/prompts-2.4.2.tgz#7b57e73b3a48029ad10ebd44f74b01722a4cb069"
+ integrity sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==
+ dependencies:
+ kleur "^3.0.3"
+ sisteransi "^1.0.5"
+
+prop-types@^15.6.0, prop-types@^15.6.2, prop-types@^15.7.2, prop-types@^15.8.1:
+ version "15.8.1"
+ resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.8.1.tgz#67d87bf1a694f48435cf332c24af10214a3140b5"
+ integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==
+ dependencies:
+ loose-envify "^1.4.0"
+ object-assign "^4.1.1"
+ react-is "^16.13.1"
+
+property-expr@^2.0.4:
+ version "2.0.6"
+ resolved "https://registry.yarnpkg.com/property-expr/-/property-expr-2.0.6.tgz#f77bc00d5928a6c748414ad12882e83f24aec1e8"
+ integrity sha512-SVtmxhRE/CGkn3eZY1T6pC8Nln6Fr/lu1mKSgRud0eC73whjGfoAogbn78LkD8aFL0zz3bAFerKSnOl7NlErBA==
+
+proto-list@~1.2.1:
+ version "1.2.4"
+ resolved "https://registry.yarnpkg.com/proto-list/-/proto-list-1.2.4.tgz#212d5bfe1318306a420f6402b8e26ff39647a849"
+ integrity sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==
+
+protocols@^2.0.0, protocols@^2.0.1:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/protocols/-/protocols-2.0.1.tgz#8f155da3fc0f32644e83c5782c8e8212ccf70a86"
+ integrity sha512-/XJ368cyBJ7fzLMwLKv1e4vLxOju2MNAIokcr7meSaNcVbWz/CPcW22cP04mwxOErdA5mwjA8Q6w/cdAQxVn7Q==
+
+proxy-from-env@^1.1.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz#e102f16ca355424865755d2c9e8ea4f24d58c3e2"
+ integrity sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==
+
+pump@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64"
+ integrity sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==
+ dependencies:
+ end-of-stream "^1.1.0"
+ once "^1.3.1"
+
+punycode@1.3.2:
+ version "1.3.2"
+ resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.3.2.tgz#9653a036fb7c1ee42342f2325cceefea3926c48d"
+ integrity sha512-RofWgt/7fL5wP1Y7fxE7/EmTLzQVnB0ycyibJ0OOHIlJqTNzglYFxVwETOcIoJqJmpDXJ9xImDv+Fq34F/d4Dw==
+
+punycode@^2.1.0:
+ version "2.3.1"
+ resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.1.tgz#027422e2faec0b25e1549c3e1bd8309b9133b6e5"
+ integrity sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==
+
+purest@4.0.2:
+ version "4.0.2"
+ resolved "https://registry.yarnpkg.com/purest/-/purest-4.0.2.tgz#6d60403f00731bbe3c508955c96d56e8c0f30098"
+ integrity sha512-Uq6kdia8zGVHOb/0zAOb7FvKFMKeyeTZTLEwpO0JR3cIFEkpH6asv3ls9M9URDjHiYIdgAPmht5ecSbvPacfyg==
+ dependencies:
+ "@simov/deep-extend" "^1.0.0"
+ qs "^6.10.3"
+ request-compose "^2.1.4"
+ request-multipart "^1.0.0"
+ request-oauth "^1.0.1"
+
+q@^1.5.1:
+ version "1.5.1"
+ resolved "https://registry.yarnpkg.com/q/-/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7"
+ integrity sha512-kV/CThkXo6xyFEZUugw/+pIOywXcDbFYgSct5cT3gqlbkBE1SJdwy6UQoZvodiWF/ckQLZyDE/Bu1M6gVu5lVw==
+
+qs@6.11.1:
+ version "6.11.1"
+ resolved "https://registry.yarnpkg.com/qs/-/qs-6.11.1.tgz#6c29dff97f0c0060765911ba65cbc9764186109f"
+ integrity sha512-0wsrzgTz/kAVIeuxSjnpGC56rzYtr6JT/2BwEvMaPhFIoYa1aGO8LbzuU1R0uUYQkLpWBTOj0l/CLAJB64J6nQ==
+ dependencies:
+ side-channel "^1.0.4"
+
+qs@^6.10.3, qs@^6.11.2, qs@^6.4.0, qs@^6.5.2, qs@^6.9.6:
+ version "6.11.2"
+ resolved "https://registry.yarnpkg.com/qs/-/qs-6.11.2.tgz#64bea51f12c1f5da1bc01496f48ffcff7c69d7d9"
+ integrity sha512-tDNIz22aBzCDxLtVH++VnTfzxlfeK5CbqohpSqpJgj1Wg/cQbStNAz3NuqCs5vV+pjBsK4x4pN9HlVh7rcYRiA==
+ dependencies:
+ side-channel "^1.0.4"
+
+querystring@0.2.0:
+ version "0.2.0"
+ resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620"
+ integrity sha512-X/xY82scca2tau62i9mDyU9K+I+djTMUsvwf7xnUX5GLvVzgJybOJf4Y6o9Zx3oJK/LSXg5tTZBjwzqVPaPO2g==
+
+queue-microtask@^1.2.2:
+ version "1.2.3"
+ resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243"
+ integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==
+
+queue-tick@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/queue-tick/-/queue-tick-1.0.1.tgz#f6f07ac82c1fd60f82e098b417a80e52f1f4c142"
+ integrity sha512-kJt5qhMxoszgU/62PLP1CJytzd2NKetjSRnyuj31fDd3Rlcz3fzlFdFLD1SItunPwyqEOkca6GbV612BWfaBag==
+
+quick-lru@^5.1.1:
+ version "5.1.1"
+ resolved "https://registry.yarnpkg.com/quick-lru/-/quick-lru-5.1.1.tgz#366493e6b3e42a3a6885e2e99d18f80fb7a8c932"
+ integrity sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==
+
+randombytes@^2.1.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a"
+ integrity sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==
+ dependencies:
+ safe-buffer "^5.1.0"
+
+range-parser@^1.2.1:
+ version "1.2.1"
+ resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031"
+ integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==
+
+raw-body@^2.2.0, raw-body@^2.3.3:
+ version "2.5.2"
+ resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.5.2.tgz#99febd83b90e08975087e8f1f9419a149366b68a"
+ integrity sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==
+ dependencies:
+ bytes "3.1.2"
+ http-errors "2.0.0"
+ iconv-lite "0.4.24"
+ unpipe "1.0.0"
+
+rc@1.2.8, rc@^1.2.7, rc@^1.2.8:
+ version "1.2.8"
+ resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed"
+ integrity sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==
+ dependencies:
+ deep-extend "^0.6.0"
+ ini "~1.3.0"
+ minimist "^1.2.0"
+ strip-json-comments "~2.0.1"
+
+react-dnd-html5-backend@15.1.3:
+ version "15.1.3"
+ resolved "https://registry.yarnpkg.com/react-dnd-html5-backend/-/react-dnd-html5-backend-15.1.3.tgz#57b4f47e0f23923e7c243d2d0eefe490069115a9"
+ integrity sha512-HH/8nOEmrrcRGHMqJR91FOwhnLlx5SRLXmsQwZT3IPcBjx88WT+0pWC5A4tDOYDdoooh9k+KMPvWfxooR5TcOA==
+ dependencies:
+ dnd-core "15.1.2"
+
+react-dnd@15.1.2:
+ version "15.1.2"
+ resolved "https://registry.yarnpkg.com/react-dnd/-/react-dnd-15.1.2.tgz#211b30fd842326209c63f26f1bdf1bc52eef4f64"
+ integrity sha512-EaSbMD9iFJDY/o48T3c8wn3uWU+2uxfFojhesZN3LhigJoAIvH2iOjxofSA9KbqhAKP6V9P853G6XG8JngKVtA==
+ dependencies:
+ "@react-dnd/invariant" "3.0.1"
+ "@react-dnd/shallowequal" "3.0.1"
+ dnd-core "15.1.2"
+ fast-deep-equal "^3.1.3"
+ hoist-non-react-statics "^3.3.2"
+
+react-dom@^18.2.0:
+ version "18.2.0"
+ resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-18.2.0.tgz#22aaf38708db2674ed9ada224ca4aa708d821e3d"
+ integrity sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==
+ dependencies:
+ loose-envify "^1.1.0"
+ scheduler "^0.23.0"
+
+react-error-boundary@3.1.4, react-error-boundary@^3.1.0:
+ version "3.1.4"
+ resolved "https://registry.yarnpkg.com/react-error-boundary/-/react-error-boundary-3.1.4.tgz#255db92b23197108757a888b01e5b729919abde0"
+ integrity sha512-uM9uPzZJTF6wRQORmSrvOIgt4lJ9MC1sNgEOj2XGsDTRE4kmpWxg7ENK9EWNKJRMAOY9z0MuF4yIfl6gp4sotA==
+ dependencies:
+ "@babel/runtime" "^7.12.5"
+
+react-fast-compare@^2.0.1:
+ version "2.0.4"
+ resolved "https://registry.yarnpkg.com/react-fast-compare/-/react-fast-compare-2.0.4.tgz#e84b4d455b0fec113e0402c329352715196f81f9"
+ integrity sha512-suNP+J1VU1MWFKcyt7RtjiSWUjvidmQSlqu+eHslq+342xCbGTYmC0mEhPCOHxlW0CywylOC1u2DFAT+bv4dBw==
+
+react-fast-compare@^3.1.1:
+ version "3.2.2"
+ resolved "https://registry.yarnpkg.com/react-fast-compare/-/react-fast-compare-3.2.2.tgz#929a97a532304ce9fee4bcae44234f1ce2c21d49"
+ integrity sha512-nsO+KSNgo1SbJqJEYRE9ERzo7YtYbou/OqjSQKxV7jcKox7+usiUVZOAC+XnDOABXggQTno0Y1CpVnuWEc1boQ==
+
+react-helmet@6.1.0, react-helmet@^6.1.0:
+ version "6.1.0"
+ resolved "https://registry.yarnpkg.com/react-helmet/-/react-helmet-6.1.0.tgz#a750d5165cb13cf213e44747502652e794468726"
+ integrity sha512-4uMzEY9nlDlgxr61NL3XbKRy1hEkXmKNXhjbAIOVw5vcFrsdYbH2FEwcNyWvWinl103nXgzYNlns9ca+8kFiWw==
+ dependencies:
+ object-assign "^4.1.1"
+ prop-types "^15.7.2"
+ react-fast-compare "^3.1.1"
+ react-side-effect "^2.1.0"
+
+react-intl@6.3.2:
+ version "6.3.2"
+ resolved "https://registry.yarnpkg.com/react-intl/-/react-intl-6.3.2.tgz#0816f0943690dbc6186ab1a2968eb378ba9c99f7"
+ integrity sha512-NT03zOHRAFGcZdTx4cXcVKZtnWBOM6RfLPK8Q67eA+Ba+pHdYb+cmrahncqAnevZKgO1r/nEauiVFKwQeudLIw==
+ dependencies:
+ "@formatjs/ecma402-abstract" "1.14.3"
+ "@formatjs/icu-messageformat-parser" "2.3.0"
+ "@formatjs/intl" "2.6.9"
+ "@formatjs/intl-displaynames" "6.2.6"
+ "@formatjs/intl-listformat" "7.1.9"
+ "@types/hoist-non-react-statics" "^3.3.1"
+ "@types/react" "16 || 17 || 18"
+ hoist-non-react-statics "^3.3.2"
+ intl-messageformat "10.3.3"
+ tslib "^2.4.0"
+
+react-intl@6.4.1:
+ version "6.4.1"
+ resolved "https://registry.yarnpkg.com/react-intl/-/react-intl-6.4.1.tgz#01e4bd5497cb93d87146e966d8eda25851d4d9b6"
+ integrity sha512-/aT5595AEMZ+Pjmt8W2R5/ZkYJmyyd6jTzHzqhJ1LnfeG36+N5huBtykxYhHqLc1BrIRQ1fTX1orYC0Ej5ojtg==
+ dependencies:
+ "@formatjs/ecma402-abstract" "1.14.3"
+ "@formatjs/icu-messageformat-parser" "2.3.1"
+ "@formatjs/intl" "2.7.1"
+ "@formatjs/intl-displaynames" "6.3.1"
+ "@formatjs/intl-listformat" "7.2.1"
+ "@types/hoist-non-react-statics" "^3.3.1"
+ "@types/react" "16 || 17 || 18"
+ hoist-non-react-statics "^3.3.2"
+ intl-messageformat "10.3.4"
+ tslib "^2.4.0"
+
+"react-is@^16.12.0 || ^17.0.0 || ^18.0.0", react-is@^18.0.0, react-is@^18.2.0:
+ version "18.2.0"
+ resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.2.0.tgz#199431eeaaa2e09f86427efbb4f1473edb47609b"
+ integrity sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==
+
+react-is@^16.13.1, react-is@^16.6.0, react-is@^16.7.0:
+ version "16.13.1"
+ resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4"
+ integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==
+
+react-is@^17.0.1, react-is@^17.0.2:
+ version "17.0.2"
+ resolved "https://registry.yarnpkg.com/react-is/-/react-is-17.0.2.tgz#e691d4a8e9c789365655539ab372762b0efb54f0"
+ integrity sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==
+
+react-query@3.24.3:
+ version "3.24.3"
+ resolved "https://registry.yarnpkg.com/react-query/-/react-query-3.24.3.tgz#58c538fb55386fa947bda88acbe616e02cb5b2bb"
+ integrity sha512-JipKpn7XoDVvRWwXWXKSJU5SbNJKqspx9IRBntaQt1EQOBXe9314Z/8cV9YXXbZIhzrHAetT3X7tRClZaYk98g==
+ dependencies:
+ "@babel/runtime" "^7.5.5"
+ broadcast-channel "^3.4.1"
+ match-sorter "^6.0.2"
+
+react-query@3.39.3:
+ version "3.39.3"
+ resolved "https://registry.yarnpkg.com/react-query/-/react-query-3.39.3.tgz#4cea7127c6c26bdea2de5fb63e51044330b03f35"
+ integrity sha512-nLfLz7GiohKTJDuT4us4X3h/8unOh+00MLb2yJoGTPjxKs2bc1iDhkNx2bd5MKklXnOD3NrVZ+J2UXujA5In4g==
+ dependencies:
+ "@babel/runtime" "^7.5.5"
+ broadcast-channel "^3.4.1"
+ match-sorter "^6.0.2"
+
+react-redux@8.0.5:
+ version "8.0.5"
+ resolved "https://registry.yarnpkg.com/react-redux/-/react-redux-8.0.5.tgz#e5fb8331993a019b8aaf2e167a93d10af469c7bd"
+ integrity sha512-Q2f6fCKxPFpkXt1qNRZdEDLlScsDWyrgSj0mliK59qU6W5gvBiKkdMEG2lJzhd1rCctf0hb6EtePPLZ2e0m1uw==
+ dependencies:
+ "@babel/runtime" "^7.12.1"
+ "@types/hoist-non-react-statics" "^3.3.1"
+ "@types/use-sync-external-store" "^0.0.3"
+ hoist-non-react-statics "^3.3.2"
+ react-is "^18.0.0"
+ use-sync-external-store "^1.0.0"
+
+react-redux@8.1.1:
+ version "8.1.1"
+ resolved "https://registry.yarnpkg.com/react-redux/-/react-redux-8.1.1.tgz#8e740f3fd864a4cd0de5ba9cdc8ad39cc9e7c81a"
+ integrity sha512-5W0QaKtEhj+3bC0Nj0NkqkhIv8gLADH/2kYFMTHxCVqQILiWzLv6MaLuV5wJU3BQEdHKzTfcvPN0WMS6SC1oyA==
+ dependencies:
+ "@babel/runtime" "^7.12.1"
+ "@types/hoist-non-react-statics" "^3.3.1"
+ "@types/use-sync-external-store" "^0.0.3"
+ hoist-non-react-statics "^3.3.2"
+ react-is "^18.0.0"
+ use-sync-external-store "^1.0.0"
+
+react-refresh@0.14.0, react-refresh@^0.14.0:
+ version "0.14.0"
+ resolved "https://registry.yarnpkg.com/react-refresh/-/react-refresh-0.14.0.tgz#4e02825378a5f227079554d4284889354e5f553e"
+ integrity sha512-wViHqhAd8OHeLS/IRMJjTSDHF3U9eWi62F/MledQGPdJGDhodXJ9PBLNGr6WWL7qlH12Mt3TyTpbS+hGXMjCzQ==
+
+react-remove-scroll-bar@^2.3.3, react-remove-scroll-bar@^2.3.4:
+ version "2.3.4"
+ resolved "https://registry.yarnpkg.com/react-remove-scroll-bar/-/react-remove-scroll-bar-2.3.4.tgz#53e272d7a5cb8242990c7f144c44d8bd8ab5afd9"
+ integrity sha512-63C4YQBUt0m6ALadE9XV56hV8BgJWDmmTPY758iIJjfQKt2nYwoUrPk0LXRXcB/yIj82T1/Ixfdpdk68LwIB0A==
+ dependencies:
+ react-style-singleton "^2.2.1"
+ tslib "^2.0.0"
+
+react-remove-scroll@2.5.5:
+ version "2.5.5"
+ resolved "https://registry.yarnpkg.com/react-remove-scroll/-/react-remove-scroll-2.5.5.tgz#1e31a1260df08887a8a0e46d09271b52b3a37e77"
+ integrity sha512-ImKhrzJJsyXJfBZ4bzu8Bwpka14c/fQt0k+cyFp/PBhTfyDnU5hjOtM4AG/0AMyy8oKzOTR0lDgJIM7pYXI0kw==
+ dependencies:
+ react-remove-scroll-bar "^2.3.3"
+ react-style-singleton "^2.2.1"
+ tslib "^2.1.0"
+ use-callback-ref "^1.3.0"
+ use-sidecar "^1.1.2"
+
+react-remove-scroll@^2.5.7:
+ version "2.5.7"
+ resolved "https://registry.yarnpkg.com/react-remove-scroll/-/react-remove-scroll-2.5.7.tgz#15a1fd038e8497f65a695bf26a4a57970cac1ccb"
+ integrity sha512-FnrTWO4L7/Bhhf3CYBNArEG/yROV0tKmTv7/3h9QCFvH6sndeFf1wPqOcbFVu5VAulS5dV1wGT3GZZ/1GawqiA==
+ dependencies:
+ react-remove-scroll-bar "^2.3.4"
+ react-style-singleton "^2.2.1"
+ tslib "^2.1.0"
+ use-callback-ref "^1.3.0"
+ use-sidecar "^1.1.2"
+
+react-router-dom@5.3.4:
+ version "5.3.4"
+ resolved "https://registry.yarnpkg.com/react-router-dom/-/react-router-dom-5.3.4.tgz#2ed62ffd88cae6db134445f4a0c0ae8b91d2e5e6"
+ integrity sha512-m4EqFMHv/Ih4kpcBCONHbkT68KoAeHN4p3lAGoNryfHi0dMy0kCzEZakiKRsvg5wHZ/JLrLW8o8KomWiz/qbYQ==
+ dependencies:
+ "@babel/runtime" "^7.12.13"
+ history "^4.9.0"
+ loose-envify "^1.3.1"
+ prop-types "^15.6.2"
+ react-router "5.3.4"
+ tiny-invariant "^1.0.2"
+ tiny-warning "^1.0.0"
+
+react-router@5.3.4:
+ version "5.3.4"
+ resolved "https://registry.yarnpkg.com/react-router/-/react-router-5.3.4.tgz#8ca252d70fcc37841e31473c7a151cf777887bb5"
+ integrity sha512-Ys9K+ppnJah3QuaRiLxk+jDWOR1MekYQrlytiXxC1RyfbdsZkS5pvKAzCCr031xHixZwpnsYNT5xysdFHQaYsA==
+ dependencies:
+ "@babel/runtime" "^7.12.13"
+ history "^4.9.0"
+ hoist-non-react-statics "^3.1.0"
+ loose-envify "^1.3.1"
+ path-to-regexp "^1.7.0"
+ prop-types "^15.6.2"
+ react-is "^16.6.0"
+ tiny-invariant "^1.0.2"
+ tiny-warning "^1.0.0"
+
+react-select@5.7.0:
+ version "5.7.0"
+ resolved "https://registry.yarnpkg.com/react-select/-/react-select-5.7.0.tgz#82921b38f1fcf1471a0b62304da01f2896cd8ce6"
+ integrity sha512-lJGiMxCa3cqnUr2Jjtg9YHsaytiZqeNOKeibv6WF5zbK/fPegZ1hg3y/9P1RZVLhqBTs0PfqQLKuAACednYGhQ==
+ dependencies:
+ "@babel/runtime" "^7.12.0"
+ "@emotion/cache" "^11.4.0"
+ "@emotion/react" "^11.8.1"
+ "@floating-ui/dom" "^1.0.1"
+ "@types/react-transition-group" "^4.4.0"
+ memoize-one "^6.0.0"
+ prop-types "^15.6.0"
+ react-transition-group "^4.3.0"
+ use-isomorphic-layout-effect "^1.1.2"
+
+react-shallow-renderer@^16.13.1:
+ version "16.15.0"
+ resolved "https://registry.yarnpkg.com/react-shallow-renderer/-/react-shallow-renderer-16.15.0.tgz#48fb2cf9b23d23cde96708fe5273a7d3446f4457"
+ integrity sha512-oScf2FqQ9LFVQgA73vr86xl2NaOIX73rh+YFqcOp68CWj56tSfgtGKrEbyhCj0rSijyG9M1CYprTh39fBi5hzA==
+ dependencies:
+ object-assign "^4.1.1"
+ react-is "^16.12.0 || ^17.0.0 || ^18.0.0"
+
+react-side-effect@^2.1.0:
+ version "2.1.2"
+ resolved "https://registry.yarnpkg.com/react-side-effect/-/react-side-effect-2.1.2.tgz#dc6345b9e8f9906dc2eeb68700b615e0b4fe752a"
+ integrity sha512-PVjOcvVOyIILrYoyGEpDN3vmYNLdy1CajSFNt4TDsVQC5KpTijDvWVoR+/7Rz2xT978D8/ZtFceXxzsPwZEDvw==
+
+react-style-singleton@^2.2.1:
+ version "2.2.1"
+ resolved "https://registry.yarnpkg.com/react-style-singleton/-/react-style-singleton-2.2.1.tgz#f99e420492b2d8f34d38308ff660b60d0b1205b4"
+ integrity sha512-ZWj0fHEMyWkHzKYUr2Bs/4zU6XLmq9HsgBURm7g5pAVfyn49DgUiNgY2d4lXRlYSiCif9YBGpQleewkcqddc7g==
+ dependencies:
+ get-nonce "^1.0.0"
+ invariant "^2.2.4"
+ tslib "^2.0.0"
+
+react-test-renderer@^17.0.2:
+ version "17.0.2"
+ resolved "https://registry.yarnpkg.com/react-test-renderer/-/react-test-renderer-17.0.2.tgz#4cd4ae5ef1ad5670fc0ef776e8cc7e1231d9866c"
+ integrity sha512-yaQ9cB89c17PUb0x6UfWRs7kQCorVdHlutU1boVPEsB8IDZH6n9tHxMacc3y0JoXOJUsZb/t/Mb8FUWMKaM7iQ==
+ dependencies:
+ object-assign "^4.1.1"
+ react-is "^17.0.2"
+ react-shallow-renderer "^16.13.1"
+ scheduler "^0.20.2"
+
+react-transition-group@^4.3.0:
+ version "4.4.5"
+ resolved "https://registry.yarnpkg.com/react-transition-group/-/react-transition-group-4.4.5.tgz#e53d4e3f3344da8521489fbef8f2581d42becdd1"
+ integrity sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==
+ dependencies:
+ "@babel/runtime" "^7.5.5"
+ dom-helpers "^5.0.1"
+ loose-envify "^1.4.0"
+ prop-types "^15.6.2"
+
+react-window@1.8.8:
+ version "1.8.8"
+ resolved "https://registry.yarnpkg.com/react-window/-/react-window-1.8.8.tgz#1b52919f009ddf91970cbdb2050a6c7be44df243"
+ integrity sha512-D4IiBeRtGXziZ1n0XklnFGu7h9gU684zepqyKzgPNzrsrk7xOCxni+TCckjg2Nr/DiaEEGVVmnhYSlT2rB47dQ==
+ dependencies:
+ "@babel/runtime" "^7.0.0"
+ memoize-one ">=3.1.1 <6"
+
+react@^18.2.0:
+ version "18.2.0"
+ resolved "https://registry.yarnpkg.com/react/-/react-18.2.0.tgz#555bd98592883255fa00de14f1151a917b5d77d5"
+ integrity sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==
+ dependencies:
+ loose-envify "^1.1.0"
+
+read-pkg-up@7.0.1:
+ version "7.0.1"
+ resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-7.0.1.tgz#f3a6135758459733ae2b95638056e1854e7ef507"
+ integrity sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==
+ dependencies:
+ find-up "^4.1.0"
+ read-pkg "^5.2.0"
+ type-fest "^0.8.1"
+
+read-pkg@^5.2.0:
+ version "5.2.0"
+ resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-5.2.0.tgz#7bf295438ca5a33e56cd30e053b34ee7250c93cc"
+ integrity sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==
+ dependencies:
+ "@types/normalize-package-data" "^2.4.0"
+ normalize-package-data "^2.5.0"
+ parse-json "^5.0.0"
+ type-fest "^0.6.0"
+
+readable-stream@^2.0.0, readable-stream@~2.3.6:
+ version "2.3.8"
+ resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.8.tgz#91125e8042bba1b9887f49345f6277027ce8be9b"
+ integrity sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==
+ dependencies:
+ core-util-is "~1.0.0"
+ inherits "~2.0.3"
+ isarray "~1.0.0"
+ process-nextick-args "~2.0.0"
+ safe-buffer "~5.1.1"
+ string_decoder "~1.1.1"
+ util-deprecate "~1.0.1"
+
+readable-stream@^3.1.1, readable-stream@^3.4.0, readable-stream@^3.6.0:
+ version "3.6.2"
+ resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.2.tgz#56a9b36ea965c00c5a93ef31eb111a0f11056967"
+ integrity sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==
+ dependencies:
+ inherits "^2.0.3"
+ string_decoder "^1.1.1"
+ util-deprecate "^1.0.1"
+
+readable-stream@~1.0.31:
+ version "1.0.34"
+ resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.0.34.tgz#125820e34bc842d2f2aaafafe4c2916ee32c157c"
+ integrity sha512-ok1qVCJuRkNmvebYikljxJA/UEsKwLl2nI1OmaqAu4/UE+h0wKCHok4XkL/gvi39OacXvw59RJUOFUkDib2rHg==
+ dependencies:
+ core-util-is "~1.0.0"
+ inherits "~2.0.1"
+ isarray "0.0.1"
+ string_decoder "~0.10.x"
+
+readdirp@~3.6.0:
+ version "3.6.0"
+ resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7"
+ integrity sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==
+ dependencies:
+ picomatch "^2.2.1"
+
+rechoir@^0.6.2:
+ version "0.6.2"
+ resolved "https://registry.yarnpkg.com/rechoir/-/rechoir-0.6.2.tgz#85204b54dba82d5742e28c96756ef43af50e3384"
+ integrity sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw==
+ dependencies:
+ resolve "^1.1.6"
+
+rechoir@^0.8.0:
+ version "0.8.0"
+ resolved "https://registry.yarnpkg.com/rechoir/-/rechoir-0.8.0.tgz#49f866e0d32146142da3ad8f0eff352b3215ff22"
+ integrity sha512-/vxpCXddiX8NGfGO/mTafwjq4aFa/71pvamip0++IQk3zG8cbCj0fifNPrjjF1XMXUne91jL9OoxmdykoEtifQ==
+ dependencies:
+ resolve "^1.20.0"
+
+redux-thunk@^2.4.2:
+ version "2.4.2"
+ resolved "https://registry.yarnpkg.com/redux-thunk/-/redux-thunk-2.4.2.tgz#b9d05d11994b99f7a91ea223e8b04cf0afa5ef3b"
+ integrity sha512-+P3TjtnP0k/FEjcBL5FZpoovtvrTNT/UXd4/sluaSyrURlSlhLSzEdfsTBW7WsKB6yPvgd7q/iZPICFjW4o57Q==
+
+redux@^4.1.2, redux@^4.2.1:
+ version "4.2.1"
+ resolved "https://registry.yarnpkg.com/redux/-/redux-4.2.1.tgz#c08f4306826c49b5e9dc901dee0452ea8fce6197"
+ integrity sha512-LAUYz4lc+Do8/g7aeRa8JkyDErK6ekstQaqWQrNRW//MY1TvCEpMtpTWvlQ+FPbWCx+Xixu/6SHt5N0HR+SB4w==
+ dependencies:
+ "@babel/runtime" "^7.9.2"
+
+regenerator-runtime@^0.14.0:
+ version "0.14.1"
+ resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz#356ade10263f685dda125100cd862c1db895327f"
+ integrity sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==
+
+regex-not@^1.0.0, regex-not@^1.0.2:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/regex-not/-/regex-not-1.0.2.tgz#1f4ece27e00b0b65e0247a6810e6a85d83a5752c"
+ integrity sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==
+ dependencies:
+ extend-shallow "^3.0.2"
+ safe-regex "^1.1.0"
+
+regexp.prototype.flags@^1.5.1:
+ version "1.5.1"
+ resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.5.1.tgz#90ce989138db209f81492edd734183ce99f9677e"
+ integrity sha512-sy6TXMN+hnP/wMy+ISxg3krXx7BAtWVO4UouuCN/ziM9UEne0euamVNafDfvC83bRNr95y0V5iijeDQFUNpvrg==
+ dependencies:
+ call-bind "^1.0.2"
+ define-properties "^1.2.0"
+ set-function-name "^2.0.0"
+
+registry-auth-token@^4.0.0:
+ version "4.2.2"
+ resolved "https://registry.yarnpkg.com/registry-auth-token/-/registry-auth-token-4.2.2.tgz#f02d49c3668884612ca031419491a13539e21fac"
+ integrity sha512-PC5ZysNb42zpFME6D/XlIgtNGdTl8bBOCw90xQLVMpzuuubJKYDWFAEuUNc+Cn8Z8724tg2SDhDRrkVEsqfDMg==
+ dependencies:
+ rc "1.2.8"
+
+registry-auth-token@^5.0.2:
+ version "5.0.2"
+ resolved "https://registry.yarnpkg.com/registry-auth-token/-/registry-auth-token-5.0.2.tgz#8b026cc507c8552ebbe06724136267e63302f756"
+ integrity sha512-o/3ikDxtXaA59BmZuZrJZDJv8NMDGSj+6j6XaeBmHw8eY1i1qd9+6H+LjVvQXx3HN6aRCGa1cUdJ9RaJZUugnQ==
+ dependencies:
+ "@pnpm/npm-conf" "^2.1.0"
+
+registry-url@^5.0.0, registry-url@^5.1.0:
+ version "5.1.0"
+ resolved "https://registry.yarnpkg.com/registry-url/-/registry-url-5.1.0.tgz#e98334b50d5434b81136b44ec638d9c2009c5009"
+ integrity sha512-8acYXXTI0AkQv6RAOjE3vOaIXZkT9wo4LOFbBKYQEEnnMNBpKqdUrI6S4NT0KPIo/WVvJ5tE/X5LF/TQUf0ekw==
+ dependencies:
+ rc "^1.2.8"
+
+relateurl@^0.2.7:
+ version "0.2.7"
+ resolved "https://registry.yarnpkg.com/relateurl/-/relateurl-0.2.7.tgz#54dbf377e51440aca90a4cd274600d3ff2d888a9"
+ integrity sha512-G08Dxvm4iDN3MLM0EsP62EDV9IuhXPR6blNz6Utcp7zyV3tr4HVNINt6MpaRWbxoOHT3Q7YN2P+jaHX8vUbgog==
+
+remove-accents@0.4.2:
+ version "0.4.2"
+ resolved "https://registry.yarnpkg.com/remove-accents/-/remove-accents-0.4.2.tgz#0a43d3aaae1e80db919e07ae254b285d9e1c7bb5"
+ integrity sha512-7pXIJqJOq5tFgG1A2Zxti3Ht8jJF337m4sowbuHsW30ZnkQFnDzy9qBNhgzX8ZLW4+UBcXiiR7SwR6pokHsxiA==
+
+renderkid@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/renderkid/-/renderkid-3.0.0.tgz#5fd823e4d6951d37358ecc9a58b1f06836b6268a"
+ integrity sha512-q/7VIQA8lmM1hF+jn+sFSPWGlMkSAeNYcPLmDQx2zzuiDfaLrOmumR8iaUKlenFgh0XRPIUeSPlH3A+AW3Z5pg==
+ dependencies:
+ css-select "^4.1.3"
+ dom-converter "^0.2.0"
+ htmlparser2 "^6.1.0"
+ lodash "^4.17.21"
+ strip-ansi "^6.0.1"
+
+repeat-element@^1.1.2:
+ version "1.1.4"
+ resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.4.tgz#be681520847ab58c7568ac75fbfad28ed42d39e9"
+ integrity sha512-LFiNfRcSu7KK3evMyYOuCzv3L10TW7yC1G2/+StMjK8Y6Vqd2MG7r/Qjw4ghtuCOjFvlnms/iMmLqpvW/ES/WQ==
+
+repeat-string@^1.6.1:
+ version "1.6.1"
+ resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637"
+ integrity sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==
+
+request-compose@^2.1.4, request-compose@^2.1.6:
+ version "2.1.6"
+ resolved "https://registry.yarnpkg.com/request-compose/-/request-compose-2.1.6.tgz#f498d6afd4ce983066432446d4b1e3d3d51fbd0f"
+ integrity sha512-S07L+2VbJB32WddD/o/PnYGKym63zLVbymygVWXvt8L79VAngcjAxhHaGuFOICLxEV90EasEPzqPKKHPspXP8w==
+
+request-ip@3.3.0:
+ version "3.3.0"
+ resolved "https://registry.yarnpkg.com/request-ip/-/request-ip-3.3.0.tgz#863451e8fec03847d44f223e30a5d63e369fa611"
+ integrity sha512-cA6Xh6e0fDBBBwH77SLJaJPBmD3nWVAcF9/XAcsrIHdjhFzFiB5aNQFytdjCGPezU3ROwrR11IddKAM08vohxA==
+
+request-multipart@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/request-multipart/-/request-multipart-1.0.0.tgz#26fe57634e379a5686eb499788ecd8b4fd51deaf"
+ integrity sha512-dazx88T19dIKFNc0XdlZV8H46D2RmNFdR4mipcbrFOaN70PSSSMM3urVY+eVbrpraf/fHXccxFhLvG1wkSUtKQ==
+ dependencies:
+ bl "^4.0.3"
+ isstream "^0.1.2"
+ mime-types "^2.1.28"
+ multistream "^4.0.1"
+ uuid "^8.3.2"
+
+request-oauth@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/request-oauth/-/request-oauth-1.0.1.tgz#dedb0c4a37234d9e93f377ddb0aaab425f31239e"
+ integrity sha512-85THTg1RgOYtqQw42JON6AqvHLptlj1biw265Tsq4fD4cPdUvhDB2Qh9NTv17yCD322ROuO9aOmpc4GyayGVBA==
+ dependencies:
+ oauth-sign "^0.9.0"
+ qs "^6.9.6"
+ uuid "^8.3.2"
+
+require-directory@^2.1.1:
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42"
+ integrity sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==
+
+require-from-string@^2.0.2:
+ version "2.0.2"
+ resolved "https://registry.yarnpkg.com/require-from-string/-/require-from-string-2.0.2.tgz#89a7fdd938261267318eafe14f9c32e598c36909"
+ integrity sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==
+
+reselect@^4.1.8:
+ version "4.1.8"
+ resolved "https://registry.yarnpkg.com/reselect/-/reselect-4.1.8.tgz#3f5dc671ea168dccdeb3e141236f69f02eaec524"
+ integrity sha512-ab9EmR80F/zQTMNeneUr4cv+jSwPJgIlvEmVwLerwrWVbpLlBuls9XHzIeTFy4cegU2NHBp3va0LKOzU5qFEYQ==
+
+resolve-alpn@^1.0.0:
+ version "1.2.1"
+ resolved "https://registry.yarnpkg.com/resolve-alpn/-/resolve-alpn-1.2.1.tgz#b7adbdac3546aaaec20b45e7d8265927072726f9"
+ integrity sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==
+
+resolve-cwd@3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-3.0.0.tgz#0f0075f1bb2544766cf73ba6a6e2adfebcb13f2d"
+ integrity sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==
+ dependencies:
+ resolve-from "^5.0.0"
+
+resolve-dir@^1.0.0, resolve-dir@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/resolve-dir/-/resolve-dir-1.0.1.tgz#79a40644c362be82f26effe739c9bb5382046f43"
+ integrity sha512-R7uiTjECzvOsWSfdM0QKFNBVFcK27aHOUwdvK53BcW8zqnGdYp0Fbj82cy54+2A4P2tFM22J5kRfe1R+lM/1yg==
+ dependencies:
+ expand-tilde "^2.0.0"
+ global-modules "^1.0.0"
+
+resolve-from@5.0.0, resolve-from@^5.0.0:
+ version "5.0.0"
+ resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-5.0.0.tgz#c35225843df8f776df21c57557bc087e9dfdfc69"
+ integrity sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==
+
+resolve-from@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6"
+ integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==
+
+resolve-path@^1.4.0:
+ version "1.4.0"
+ resolved "https://registry.yarnpkg.com/resolve-path/-/resolve-path-1.4.0.tgz#c4bda9f5efb2fce65247873ab36bb4d834fe16f7"
+ integrity sha512-i1xevIst/Qa+nA9olDxLWnLk8YZbi8R/7JPbCMcgyWaFR6bKWaexgJgEB5oc2PKMjYdrHynyz0NY+if+H98t1w==
+ dependencies:
+ http-errors "~1.6.2"
+ path-is-absolute "1.0.1"
+
+resolve-pathname@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/resolve-pathname/-/resolve-pathname-3.0.0.tgz#99d02224d3cf263689becbb393bc560313025dcd"
+ integrity sha512-C7rARubxI8bXFNB/hqcp/4iUeIXJhJZvFPFPiSPRnhU5UPxzMFIl+2E6yY6c4k9giDJAhtV+enfA+G89N6Csng==
+
+resolve-url@^0.2.1:
+ version "0.2.1"
+ resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a"
+ integrity sha512-ZuF55hVUQaaczgOIwqWzkEcEidmlD/xl44x1UZnhOXcYuFN2S6+rcxpG+C1N3So0wvNI3DmJICUFfu2SxhBmvg==
+
+resolve@^1.1.6, resolve@^1.1.7, resolve@^1.10.0, resolve@^1.12.0, resolve@^1.19.0, resolve@^1.20.0:
+ version "1.22.8"
+ resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.8.tgz#b6c87a9f2aa06dfab52e3d70ac8cde321fa5a48d"
+ integrity sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==
+ dependencies:
+ is-core-module "^2.13.0"
+ path-parse "^1.0.7"
+ supports-preserve-symlinks-flag "^1.0.0"
+
+responselike@^2.0.0:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/responselike/-/responselike-2.0.1.tgz#9a0bc8fdc252f3fb1cca68b016591059ba1422bc"
+ integrity sha512-4gl03wn3hj1HP3yzgdI7d3lCkF95F21Pz4BPGvKHinyQzALR5CapwC8yIi0Rh58DEMQ/SguC03wFj2k0M/mHhw==
+ dependencies:
+ lowercase-keys "^2.0.0"
+
+restore-cursor@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-2.0.0.tgz#9f7ee287f82fd326d4fd162923d62129eee0dfaf"
+ integrity sha512-6IzJLuGi4+R14vwagDHX+JrXmPVtPpn4mffDJ1UdR7/Edm87fl6yi8mMBIVvFtJaNTUvjughmW4hwLhRG7gC1Q==
+ dependencies:
+ onetime "^2.0.0"
+ signal-exit "^3.0.2"
+
+restore-cursor@^3.1.0:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-3.1.0.tgz#39f67c54b3a7a58cea5236d95cf0034239631f7e"
+ integrity sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==
+ dependencies:
+ onetime "^5.1.0"
+ signal-exit "^3.0.2"
+
+ret@~0.1.10:
+ version "0.1.15"
+ resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc"
+ integrity sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==
+
+reusify@^1.0.4:
+ version "1.0.4"
+ resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76"
+ integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==
+
+rimraf@3.0.2, rimraf@^3.0.0, rimraf@^3.0.2:
+ version "3.0.2"
+ resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a"
+ integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==
+ dependencies:
+ glob "^7.1.3"
+
+rimraf@^2.6.3:
+ version "2.7.1"
+ resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec"
+ integrity sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==
+ dependencies:
+ glob "^7.1.3"
+
+rollup@^3.27.1:
+ version "3.29.4"
+ resolved "https://registry.yarnpkg.com/rollup/-/rollup-3.29.4.tgz#4d70c0f9834146df8705bfb69a9a19c9e1109981"
+ integrity sha512-oWzmBZwvYrU0iJHtDmhsm662rC15FRXmcjCk1xD771dFDx5jJ02ufAQQTn0etB2emNk4J9EZg/yWKpsn9BWGRw==
+ optionalDependencies:
+ fsevents "~2.3.2"
+
+run-applescript@^5.0.0:
+ version "5.0.0"
+ resolved "https://registry.yarnpkg.com/run-applescript/-/run-applescript-5.0.0.tgz#e11e1c932e055d5c6b40d98374e0268d9b11899c"
+ integrity sha512-XcT5rBksx1QdIhlFOCtgZkB99ZEouFZ1E2Kc2LHqNW13U3/74YGdkQRmThTwxy4QIyookibDKYZOPqX//6BlAg==
+ dependencies:
+ execa "^5.0.0"
+
+run-async@^2.4.0:
+ version "2.4.1"
+ resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.4.1.tgz#8440eccf99ea3e70bd409d49aab88e10c189a455"
+ integrity sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==
+
+run-parallel@^1.1.9:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee"
+ integrity sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==
+ dependencies:
+ queue-microtask "^1.2.2"
+
+rxjs@7.8.1, rxjs@^7.5.5, rxjs@^7.8.1:
+ version "7.8.1"
+ resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-7.8.1.tgz#6f6f3d99ea8044291efd92e7c7fcf562c4057543"
+ integrity sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==
+ dependencies:
+ tslib "^2.1.0"
+
+rxjs@^6.4.0, rxjs@^6.6.0:
+ version "6.6.7"
+ resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.6.7.tgz#90ac018acabf491bf65044235d5863c4dab804c9"
+ integrity sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==
+ dependencies:
+ tslib "^1.9.0"
+
+safe-buffer@5.2.1, safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@~5.2.0:
+ version "5.2.1"
+ resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6"
+ integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==
+
+safe-buffer@~5.1.0, safe-buffer@~5.1.1:
+ version "5.1.2"
+ resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d"
+ integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==
+
+safe-regex@^1.1.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/safe-regex/-/safe-regex-1.1.0.tgz#40a3669f3b077d1e943d44629e157dd48023bf2e"
+ integrity sha512-aJXcif4xnaNUzvUuC5gcb46oTS7zvg4jpMTnuqtrEPlR3vFr4pxtdTwaF1Qs3Enjn9HK+ZlwQui+a7z0SywIzg==
+ dependencies:
+ ret "~0.1.10"
+
+safe-stable-stringify@^2.3.1:
+ version "2.4.3"
+ resolved "https://registry.yarnpkg.com/safe-stable-stringify/-/safe-stable-stringify-2.4.3.tgz#138c84b6f6edb3db5f8ef3ef7115b8f55ccbf886"
+ integrity sha512-e2bDA2WJT0wxseVd4lsDP4+3ONX6HpMXQa1ZhFQ7SU+GjvORCmShbCMltrtIDfkYhVHrOcPtj+KhmDBdPdZD1g==
+
+"safer-buffer@>= 2.1.2 < 3", safer-buffer@^2.1.0:
+ version "2.1.2"
+ resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a"
+ integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==
+
+sanitize-html@2.11.0:
+ version "2.11.0"
+ resolved "https://registry.yarnpkg.com/sanitize-html/-/sanitize-html-2.11.0.tgz#9a6434ee8fcaeddc740d8ae7cd5dd71d3981f8f6"
+ integrity sha512-BG68EDHRaGKqlsNjJ2xUB7gpInPA8gVx/mvjO743hZaeMCZ2DwzW7xvsqZ+KNU4QKwj86HJ3uu2liISf2qBBUA==
+ dependencies:
+ deepmerge "^4.2.2"
+ escape-string-regexp "^4.0.0"
+ htmlparser2 "^8.0.0"
+ is-plain-object "^5.0.0"
+ parse-srcset "^1.0.2"
+ postcss "^8.3.11"
+
+sax@1.2.1:
+ version "1.2.1"
+ resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.1.tgz#7b8e656190b228e81a66aea748480d828cd2d37a"
+ integrity sha512-8I2a3LovHTOpm7NV5yOyO8IHqgVsfK4+UuySrXU8YXkSRX7k6hCV9b3HrkKCr3nMpgj+0bmocaJJWpvp1oc7ZA==
+
+sax@>=0.6.0:
+ version "1.3.0"
+ resolved "https://registry.yarnpkg.com/sax/-/sax-1.3.0.tgz#a5dbe77db3be05c9d1ee7785dbd3ea9de51593d0"
+ integrity sha512-0s+oAmw9zLl1V1cS9BtZN7JAd0cW5e0QH4W3LWEK6a4LaLEA2OTpGYWDY+6XasBLtz6wkm3u1xRw95mRuJ59WA==
+
+scheduler@^0.20.2:
+ version "0.20.2"
+ resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.20.2.tgz#4baee39436e34aa93b4874bddcbf0fe8b8b50e91"
+ integrity sha512-2eWfGgAqqWFGqtdMmcL5zCMK1U8KlXv8SQFGglL3CEtd0aDVDWgeF/YoCmvln55m5zSk3J/20hTaSBeSObsQDQ==
+ dependencies:
+ loose-envify "^1.1.0"
+ object-assign "^4.1.1"
+
+scheduler@^0.23.0:
+ version "0.23.0"
+ resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.23.0.tgz#ba8041afc3d30eb206a487b6b384002e4e61fdfe"
+ integrity sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==
+ dependencies:
+ loose-envify "^1.1.0"
+
+schema-utils@^3.0.0, schema-utils@^3.1.1, schema-utils@^3.2.0:
+ version "3.3.0"
+ resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-3.3.0.tgz#f50a88877c3c01652a15b622ae9e9795df7a60fe"
+ integrity sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==
+ dependencies:
+ "@types/json-schema" "^7.0.8"
+ ajv "^6.12.5"
+ ajv-keywords "^3.5.2"
+
+schema-utils@^4.0.0:
+ version "4.2.0"
+ resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-4.2.0.tgz#70d7c93e153a273a805801882ebd3bff20d89c8b"
+ integrity sha512-L0jRsrPpjdckP3oPug3/VxNKt2trR8TcabrM6FOAAlvC/9Phcmm+cuAgTlxBqdBR1WJx7Naj9WHw+aOmheSVbw==
+ dependencies:
+ "@types/json-schema" "^7.0.9"
+ ajv "^8.9.0"
+ ajv-formats "^2.1.1"
+ ajv-keywords "^5.1.0"
+
+scroll-into-view-if-needed@^2.2.20:
+ version "2.2.31"
+ resolved "https://registry.yarnpkg.com/scroll-into-view-if-needed/-/scroll-into-view-if-needed-2.2.31.tgz#d3c482959dc483e37962d1521254e3295d0d1587"
+ integrity sha512-dGCXy99wZQivjmjIqihaBQNjryrz5rueJY7eHfTdyWEiR4ttYpsajb14rn9s5d4DY4EcY6+4+U/maARBXJedkA==
+ dependencies:
+ compute-scroll-into-view "^1.0.20"
+
+"semver@2 || 3 || 4 || 5":
+ version "5.7.2"
+ resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.2.tgz#48d55db737c3287cd4835e17fa13feace1c41ef8"
+ integrity sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==
+
+semver@7.5.4, semver@^7.3.5, semver@^7.3.8, semver@^7.5.4:
+ version "7.5.4"
+ resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.4.tgz#483986ec4ed38e1c6c48c34894a9182dbff68a6e"
+ integrity sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==
+ dependencies:
+ lru-cache "^6.0.0"
+
+semver@^6.0.0, semver@^6.3.1:
+ version "6.3.1"
+ resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4"
+ integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==
+
+sendmail@^1.6.1:
+ version "1.6.1"
+ resolved "https://registry.yarnpkg.com/sendmail/-/sendmail-1.6.1.tgz#6be92fb4be70d1d9ad102030aeb1e737bd512159"
+ integrity sha512-lIhvnjSi5e5jL8wA1GPP6j2QVlx6JOEfmdn0QIfmuJdmXYGmJ375kcOU0NSm/34J+nypm4sa1AXrYE5w3uNIIA==
+ dependencies:
+ dkim-signer "0.2.2"
+ mailcomposer "3.12.0"
+
+sentence-case@^2.1.0:
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/sentence-case/-/sentence-case-2.1.1.tgz#1f6e2dda39c168bf92d13f86d4a918933f667ed4"
+ integrity sha512-ENl7cYHaK/Ktwk5OTD+aDbQ3uC8IByu/6Bkg+HDv8Mm+XnBnppVNalcfJTNsp1ibstKh030/JKQQWglDvtKwEQ==
+ dependencies:
+ no-case "^2.2.0"
+ upper-case-first "^1.1.2"
+
+serialize-javascript@^6.0.1:
+ version "6.0.2"
+ resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-6.0.2.tgz#defa1e055c83bf6d59ea805d8da862254eb6a6c2"
+ integrity sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==
+ dependencies:
+ randombytes "^2.1.0"
+
+set-blocking@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7"
+ integrity sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==
+
+set-cookie-parser@^2.4.6:
+ version "2.6.0"
+ resolved "https://registry.yarnpkg.com/set-cookie-parser/-/set-cookie-parser-2.6.0.tgz#131921e50f62ff1a66a461d7d62d7b21d5d15a51"
+ integrity sha512-RVnVQxTXuerk653XfuliOxBP81Sf0+qfQE73LIYKcyMYHG94AuH0kgrQpRDuTZnSmjpysHmzxJXKNfa6PjFhyQ==
+
+set-function-length@^1.1.1:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/set-function-length/-/set-function-length-1.1.1.tgz#4bc39fafb0307224a33e106a7d35ca1218d659ed"
+ integrity sha512-VoaqjbBJKiWtg4yRcKBQ7g7wnGnLV3M8oLvVWwOk2PdYY6PEFegR1vezXR0tw6fZGF9csVakIRjrJiy2veSBFQ==
+ dependencies:
+ define-data-property "^1.1.1"
+ get-intrinsic "^1.2.1"
+ gopd "^1.0.1"
+ has-property-descriptors "^1.0.0"
+
+set-function-name@^2.0.0:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/set-function-name/-/set-function-name-2.0.1.tgz#12ce38b7954310b9f61faa12701620a0c882793a"
+ integrity sha512-tMNCiqYVkXIZgc2Hnoy2IvC/f8ezc5koaRFkCjrpWzGpCd3qbZXPzVy9MAZzK1ch/X0jvSkojys3oqJN0qCmdA==
+ dependencies:
+ define-data-property "^1.0.1"
+ functions-have-names "^1.2.3"
+ has-property-descriptors "^1.0.0"
+
+set-value@^2.0.0, set-value@^2.0.1:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/set-value/-/set-value-2.0.1.tgz#a18d40530e6f07de4228c7defe4227af8cad005b"
+ integrity sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==
+ dependencies:
+ extend-shallow "^2.0.1"
+ is-extendable "^0.1.1"
+ is-plain-object "^2.0.3"
+ split-string "^3.0.1"
+
+setprototypeof@1.1.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.0.tgz#d0bd85536887b6fe7c0d818cb962d9d91c54e656"
+ integrity sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==
+
+setprototypeof@1.2.0:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.2.0.tgz#66c9a24a73f9fc28cbe66b09fed3d33dcaf1b424"
+ integrity sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==
+
+shallowequal@^1.1.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/shallowequal/-/shallowequal-1.1.0.tgz#188d521de95b9087404fd4dcb68b13df0ae4e7f8"
+ integrity sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ==
+
+sharp@0.32.6, sharp@^0.32.6:
+ version "0.32.6"
+ resolved "https://registry.yarnpkg.com/sharp/-/sharp-0.32.6.tgz#6ad30c0b7cd910df65d5f355f774aa4fce45732a"
+ integrity sha512-KyLTWwgcR9Oe4d9HwCwNM2l7+J0dUQwn/yf7S0EnTtb0eVS4RxO0eUSvxPtzT4F3SY+C4K6fqdv/DO27sJ/v/w==
+ dependencies:
+ color "^4.2.3"
+ detect-libc "^2.0.2"
+ node-addon-api "^6.1.0"
+ prebuild-install "^7.1.1"
+ semver "^7.5.4"
+ simple-get "^4.0.1"
+ tar-fs "^3.0.4"
+ tunnel-agent "^0.6.0"
+
+shebang-command@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea"
+ integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==
+ dependencies:
+ shebang-regex "^3.0.0"
+
+shebang-regex@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172"
+ integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==
+
+shell-quote@^1.8.1:
+ version "1.8.1"
+ resolved "https://registry.yarnpkg.com/shell-quote/-/shell-quote-1.8.1.tgz#6dbf4db75515ad5bac63b4f1894c3a154c766680"
+ integrity sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA==
+
+side-channel@^1.0.4:
+ version "1.0.4"
+ resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.4.tgz#efce5c8fdc104ee751b25c58d4290011fa5ea2cf"
+ integrity sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==
+ dependencies:
+ call-bind "^1.0.0"
+ get-intrinsic "^1.0.2"
+ object-inspect "^1.9.0"
+
+sift@16.0.1:
+ version "16.0.1"
+ resolved "https://registry.yarnpkg.com/sift/-/sift-16.0.1.tgz#e9c2ccc72191585008cf3e36fc447b2d2633a053"
+ integrity sha512-Wv6BjQ5zbhW7VFefWusVP33T/EM0vYikCaQ2qR8yULbsilAT8/wQaXvuQ3ptGLpoKx+lihJE3y2UTgKDyyNHZQ==
+
+signal-exit@^3.0.0, signal-exit@^3.0.2, signal-exit@^3.0.3, signal-exit@^3.0.7:
+ version "3.0.7"
+ resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9"
+ integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==
+
+simple-concat@^1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/simple-concat/-/simple-concat-1.0.1.tgz#f46976082ba35c2263f1c8ab5edfe26c41c9552f"
+ integrity sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==
+
+simple-get@^3.0.3:
+ version "3.1.1"
+ resolved "https://registry.yarnpkg.com/simple-get/-/simple-get-3.1.1.tgz#cc7ba77cfbe761036fbfce3d021af25fc5584d55"
+ integrity sha512-CQ5LTKGfCpvE1K0n2us+kuMPbk/q0EKl82s4aheV9oXjFEz6W/Y7oQFVJuU6QG77hRT4Ghb5RURteF5vnWjupA==
+ dependencies:
+ decompress-response "^4.2.0"
+ once "^1.3.1"
+ simple-concat "^1.0.0"
+
+simple-get@^4.0.0, simple-get@^4.0.1:
+ version "4.0.1"
+ resolved "https://registry.yarnpkg.com/simple-get/-/simple-get-4.0.1.tgz#4a39db549287c979d352112fa03fd99fd6bc3543"
+ integrity sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==
+ dependencies:
+ decompress-response "^6.0.0"
+ once "^1.3.1"
+ simple-concat "^1.0.0"
+
+simple-swizzle@^0.2.2:
+ version "0.2.2"
+ resolved "https://registry.yarnpkg.com/simple-swizzle/-/simple-swizzle-0.2.2.tgz#a4da6b635ffcccca33f70d17cb92592de95e557a"
+ integrity sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==
+ dependencies:
+ is-arrayish "^0.3.1"
+
+sirv@^2.0.3:
+ version "2.0.4"
+ resolved "https://registry.yarnpkg.com/sirv/-/sirv-2.0.4.tgz#5dd9a725c578e34e449f332703eb2a74e46a29b0"
+ integrity sha512-94Bdh3cC2PKrbgSOUqTiGPWVZeSiXfKOVZNJniWoqrWrRkB1CJzBU3NEbiTsPcYy1lDsANA/THzS+9WBiy5nfQ==
+ dependencies:
+ "@polka/url" "^1.0.0-next.24"
+ mrmime "^2.0.0"
+ totalist "^3.0.0"
+
+sisteransi@^1.0.5:
+ version "1.0.5"
+ resolved "https://registry.yarnpkg.com/sisteransi/-/sisteransi-1.0.5.tgz#134d681297756437cc05ca01370d3a7a571075ed"
+ integrity sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==
+
+slash@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634"
+ integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==
+
+slash@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/slash/-/slash-4.0.0.tgz#2422372176c4c6c5addb5e2ada885af984b396a7"
+ integrity sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==
+
+slate-history@0.93.0:
+ version "0.93.0"
+ resolved "https://registry.yarnpkg.com/slate-history/-/slate-history-0.93.0.tgz#d2fad47e4e8b262ab7c86b653f5dd6d9b6d85277"
+ integrity sha512-Gr1GMGPipRuxIz41jD2/rbvzPj8eyar56TVMyJBvBeIpQSSjNISssvGNDYfJlSWM8eaRqf6DAcxMKzsLCYeX6g==
+ dependencies:
+ is-plain-object "^5.0.0"
+
+slate-react@0.98.3:
+ version "0.98.3"
+ resolved "https://registry.yarnpkg.com/slate-react/-/slate-react-0.98.3.tgz#5090d269d69186f3ec2a6b5862d2645f01772eda"
+ integrity sha512-p1BnF9eRyRM0i5hkgOb11KgmpWLQm9Zyp6jVkOAj5fPdIGheKhg48Z7aWKrayeJ4nmRyi/NjRZz/io5hQcphmw==
+ dependencies:
+ "@juggle/resize-observer" "^3.4.0"
+ "@types/is-hotkey" "^0.1.1"
+ "@types/lodash" "^4.14.149"
+ direction "^1.0.3"
+ is-hotkey "^0.1.6"
+ is-plain-object "^5.0.0"
+ lodash "^4.17.4"
+ scroll-into-view-if-needed "^2.2.20"
+ tiny-invariant "1.0.6"
+
+slate@0.94.1:
+ version "0.94.1"
+ resolved "https://registry.yarnpkg.com/slate/-/slate-0.94.1.tgz#13b0ba7d0a7eeb0ec89a87598e9111cbbd685696"
+ integrity sha512-GH/yizXr1ceBoZ9P9uebIaHe3dC/g6Plpf9nlUwnvoyf6V1UOYrRwkabtOCd3ZfIGxomY4P7lfgLr7FPH8/BKA==
+ dependencies:
+ immer "^9.0.6"
+ is-plain-object "^5.0.0"
+ tiny-warning "^1.0.3"
+
+snake-case@^2.1.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/snake-case/-/snake-case-2.1.0.tgz#41bdb1b73f30ec66a04d4e2cad1b76387d4d6d9f"
+ integrity sha512-FMR5YoPFwOLuh4rRz92dywJjyKYZNLpMn1R5ujVpIYkbA9p01fq8RMg0FkO4M+Yobt4MjHeLTJVm5xFFBHSV2Q==
+ dependencies:
+ no-case "^2.2.0"
+
+snapdragon-node@^2.0.1:
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/snapdragon-node/-/snapdragon-node-2.1.1.tgz#6c175f86ff14bdb0724563e8f3c1b021a286853b"
+ integrity sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==
+ dependencies:
+ define-property "^1.0.0"
+ isobject "^3.0.0"
+ snapdragon-util "^3.0.1"
+
+snapdragon-util@^3.0.1:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/snapdragon-util/-/snapdragon-util-3.0.1.tgz#f956479486f2acd79700693f6f7b805e45ab56e2"
+ integrity sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==
+ dependencies:
+ kind-of "^3.2.0"
+
+snapdragon@^0.8.1:
+ version "0.8.2"
+ resolved "https://registry.yarnpkg.com/snapdragon/-/snapdragon-0.8.2.tgz#64922e7c565b0e14204ba1aa7d6964278d25182d"
+ integrity sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==
+ dependencies:
+ base "^0.11.1"
+ debug "^2.2.0"
+ define-property "^0.2.5"
+ extend-shallow "^2.0.1"
+ map-cache "^0.2.2"
+ source-map "^0.5.6"
+ source-map-resolve "^0.5.0"
+ use "^3.1.0"
+
+sort-object-keys@^1.1.3:
+ version "1.1.3"
+ resolved "https://registry.yarnpkg.com/sort-object-keys/-/sort-object-keys-1.1.3.tgz#bff833fe85cab147b34742e45863453c1e190b45"
+ integrity sha512-855pvK+VkU7PaKYPc+Jjnmt4EzejQHyhhF33q31qG8x7maDzkeFhAAThdCYay11CISO+qAMwjOBP+fPZe0IPyg==
+
+sort-package-json@2.5.1:
+ version "2.5.1"
+ resolved "https://registry.yarnpkg.com/sort-package-json/-/sort-package-json-2.5.1.tgz#5c0f2ce8cc8851988e5039f76b8978439439039d"
+ integrity sha512-vx/KoZxm8YNMUqdlw7SGTfqR5pqZ/sUfgOuRtDILiOy/3AvzhAibyUe2cY3OpLs3oRSow9up4yLVtQaM24rbDQ==
+ dependencies:
+ detect-indent "^7.0.1"
+ detect-newline "^4.0.0"
+ get-stdin "^9.0.0"
+ git-hooks-list "^3.0.0"
+ globby "^13.1.2"
+ is-plain-obj "^4.1.0"
+ sort-object-keys "^1.1.3"
+
+sorted-array-functions@^1.3.0:
+ version "1.3.0"
+ resolved "https://registry.yarnpkg.com/sorted-array-functions/-/sorted-array-functions-1.3.0.tgz#8605695563294dffb2c9796d602bd8459f7a0dd5"
+ integrity sha512-2sqgzeFlid6N4Z2fUQ1cvFmTOLRi/sEDzSQ0OKYchqgoPmQBVyM3959qYx3fpS6Esef80KjmpgPeEr028dP3OA==
+
+source-list-map@^2.0.0:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/source-list-map/-/source-list-map-2.0.1.tgz#3993bd873bfc48479cca9ea3a547835c7c154b34"
+ integrity sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw==
+
+source-map-js@^1.0.2:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.0.2.tgz#adbc361d9c62df380125e7f161f71c826f1e490c"
+ integrity sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==
+
+source-map-resolve@^0.5.0:
+ version "0.5.3"
+ resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.5.3.tgz#190866bece7553e1f8f267a2ee82c606b5509a1a"
+ integrity sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==
+ dependencies:
+ atob "^2.1.2"
+ decode-uri-component "^0.2.0"
+ resolve-url "^0.2.1"
+ source-map-url "^0.4.0"
+ urix "^0.1.0"
+
+source-map-support@~0.5.20:
+ version "0.5.21"
+ resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.21.tgz#04fe7c7f9e1ed2d662233c28cb2b35b9f63f6e4f"
+ integrity sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==
+ dependencies:
+ buffer-from "^1.0.0"
+ source-map "^0.6.0"
+
+source-map-url@^0.4.0:
+ version "0.4.1"
+ resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.1.tgz#0af66605a745a5a2f91cf1bbf8a7afbc283dec56"
+ integrity sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw==
+
+source-map@^0.5.6, source-map@^0.5.7:
+ version "0.5.7"
+ resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc"
+ integrity sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==
+
+source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.0, source-map@~0.6.1:
+ version "0.6.1"
+ resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263"
+ integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==
+
+source-map@^0.7.3:
+ version "0.7.4"
+ resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.4.tgz#a9bbe705c9d8846f4e08ff6765acf0f1b0898656"
+ integrity sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==
+
+spawn-command@0.0.2:
+ version "0.0.2"
+ resolved "https://registry.yarnpkg.com/spawn-command/-/spawn-command-0.0.2.tgz#9544e1a43ca045f8531aac1a48cb29bdae62338e"
+ integrity sha512-zC8zGoGkmc8J9ndvml8Xksr1Amk9qBujgbF0JAIWO7kXr43w0h/0GJNM/Vustixu+YE8N/MTrQ7N31FvHUACxQ==
+
+spdx-correct@^3.0.0:
+ version "3.2.0"
+ resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-3.2.0.tgz#4f5ab0668f0059e34f9c00dce331784a12de4e9c"
+ integrity sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==
+ dependencies:
+ spdx-expression-parse "^3.0.0"
+ spdx-license-ids "^3.0.0"
+
+spdx-exceptions@^2.1.0:
+ version "2.3.0"
+ resolved "https://registry.yarnpkg.com/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz#3f28ce1a77a00372683eade4a433183527a2163d"
+ integrity sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==
+
+spdx-expression-parse@^3.0.0:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz#cf70f50482eefdc98e3ce0a6833e4a53ceeba679"
+ integrity sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==
+ dependencies:
+ spdx-exceptions "^2.1.0"
+ spdx-license-ids "^3.0.0"
+
+spdx-license-ids@^3.0.0:
+ version "3.0.16"
+ resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.16.tgz#a14f64e0954f6e25cc6587bd4f392522db0d998f"
+ integrity sha512-eWN+LnM3GR6gPu35WxNgbGl8rmY1AEmoMDvL/QD6zYmPWgywxWqJWNdLGT+ke8dKNWrcYgYjPpG5gbTfghP8rw==
+
+speedometer@~1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/speedometer/-/speedometer-1.0.0.tgz#cd671cb06752c22bca3370e2f334440be4fc62e2"
+ integrity sha512-lgxErLl/7A5+vgIIXsh9MbeukOaCb2axgQ+bKCdIE+ibNT4XNYGNCR1qFEGq6F+YDASXK3Fh/c5FgtZchFolxw==
+
+split-string@^3.0.1, split-string@^3.0.2:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/split-string/-/split-string-3.1.0.tgz#7cb09dda3a86585705c64b39a6466038682e8fe2"
+ integrity sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==
+ dependencies:
+ extend-shallow "^3.0.0"
+
+split2@^4.1.0:
+ version "4.2.0"
+ resolved "https://registry.yarnpkg.com/split2/-/split2-4.2.0.tgz#c9c5920904d148bab0b9f67145f245a86aadbfa4"
+ integrity sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==
+
+sprintf-js@~1.0.2:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c"
+ integrity sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==
+
+stack-trace@0.0.x:
+ version "0.0.10"
+ resolved "https://registry.yarnpkg.com/stack-trace/-/stack-trace-0.0.10.tgz#547c70b347e8d32b4e108ea1a2a159e5fdde19c0"
+ integrity sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg==
+
+stackframe@^1.3.4:
+ version "1.3.4"
+ resolved "https://registry.yarnpkg.com/stackframe/-/stackframe-1.3.4.tgz#b881a004c8c149a5e8efef37d51b16e412943310"
+ integrity sha512-oeVtt7eWQS+Na6F//S4kJ2K2VbRlS9D43mAlMyVpVWovy9o+jfgH8O9agzANzaiLjclA0oYzUXEM4PurhSUChw==
+
+static-extend@^0.1.1:
+ version "0.1.2"
+ resolved "https://registry.yarnpkg.com/static-extend/-/static-extend-0.1.2.tgz#60809c39cbff55337226fd5e0b520f341f1fb5c6"
+ integrity sha512-72E9+uLc27Mt718pMHt9VMNiAL4LMsmDbBva8mxWUCkT07fSzEGMYUCk0XWY6lp0j6RBAG4cJ3mWuZv2OE3s0g==
+ dependencies:
+ define-property "^0.2.5"
+ object-copy "^0.1.0"
+
+statuses@2.0.1, statuses@^2.0.1:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/statuses/-/statuses-2.0.1.tgz#55cb000ccf1d48728bd23c685a063998cf1a1b63"
+ integrity sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==
+
+"statuses@>= 1.4.0 < 2", "statuses@>= 1.5.0 < 2", statuses@^1.5.0:
+ version "1.5.0"
+ resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c"
+ integrity sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==
+
+stop-iteration-iterator@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/stop-iteration-iterator/-/stop-iteration-iterator-1.0.0.tgz#6a60be0b4ee757d1ed5254858ec66b10c49285e4"
+ integrity sha512-iCGQj+0l0HOdZ2AEeBADlsRC+vsnDsZsbdSiH1yNSjcfKM7fdpCMfqAL/dwF5BLiw/XhRft/Wax6zQbhq2BcjQ==
+ dependencies:
+ internal-slot "^1.0.4"
+
+strapi-plugin-fuzzy-search@^2.2.0:
+ version "2.2.0"
+ resolved "https://registry.yarnpkg.com/strapi-plugin-fuzzy-search/-/strapi-plugin-fuzzy-search-2.2.0.tgz#258e848ef0a96219c29101b854a83f63105b4ef8"
+ integrity sha512-l85PozOja/B38otA+da7tylGz7/+xl1lgZkzLcvczw/hbBo+cq9pmz7I6Q8ZrZhWJdHM3W3U+7q6aXFdSynASA==
+ dependencies:
+ fuzzysort "2.0.4"
+ transliteration "2.3.5"
+
+stream-chain@2.2.5, stream-chain@^2.2.5:
+ version "2.2.5"
+ resolved "https://registry.yarnpkg.com/stream-chain/-/stream-chain-2.2.5.tgz#b30967e8f14ee033c5b9a19bbe8a2cba90ba0d09"
+ integrity sha512-1TJmBx6aSWqZ4tx7aTpBDXK0/e2hhcNSTV8+CbFJtDjbb+I1mZ8lHit0Grw9GRT+6JbIrrDd8esncgBi8aBXGA==
+
+stream-json@1.8.0:
+ version "1.8.0"
+ resolved "https://registry.yarnpkg.com/stream-json/-/stream-json-1.8.0.tgz#53f486b2e3b4496c506131f8d7260ba42def151c"
+ integrity sha512-HZfXngYHUAr1exT4fxlbc1IOce1RYxp2ldeaf97LYCOPSoOqY/1Psp7iGvpb+6JIOgkra9zDYnPX01hGAHzEPw==
+ dependencies:
+ stream-chain "^2.2.5"
+
+stream-slice@^0.1.2:
+ version "0.1.2"
+ resolved "https://registry.yarnpkg.com/stream-slice/-/stream-slice-0.1.2.tgz#2dc4f4e1b936fb13f3eb39a2def1932798d07a4b"
+ integrity sha512-QzQxpoacatkreL6jsxnVb7X5R/pGw9OUv2qWTYWnmLpg4NdN31snPy/f3TdQE1ZUXaThRvj1Zw4/OGg0ZkaLMA==
+
+streamx@^2.15.0:
+ version "2.15.6"
+ resolved "https://registry.yarnpkg.com/streamx/-/streamx-2.15.6.tgz#28bf36997ebc7bf6c08f9eba958735231b833887"
+ integrity sha512-q+vQL4AAz+FdfT137VF69Cc/APqUbxy+MDOImRrMvchJpigHj9GksgDU2LYbO9rx7RX6osWgxJB2WxhYv4SZAw==
+ dependencies:
+ fast-fifo "^1.1.0"
+ queue-tick "^1.0.1"
+
+strict-event-emitter@^0.2.4:
+ version "0.2.8"
+ resolved "https://registry.yarnpkg.com/strict-event-emitter/-/strict-event-emitter-0.2.8.tgz#b4e768927c67273c14c13d20e19d5e6c934b47ca"
+ integrity sha512-KDf/ujU8Zud3YaLtMCcTI4xkZlZVIYxTLr+XIULexP+77EEVWixeXroLUXQXiVtH4XH2W7jr/3PT1v3zBuvc3A==
+ dependencies:
+ events "^3.3.0"
+
+strict-event-emitter@^0.4.3:
+ version "0.4.6"
+ resolved "https://registry.yarnpkg.com/strict-event-emitter/-/strict-event-emitter-0.4.6.tgz#ff347c8162b3e931e3ff5f02cfce6772c3b07eb3"
+ integrity sha512-12KWeb+wixJohmnwNFerbyiBrAlq5qJLwIt38etRtKtmmHyDSoGlIqFE9wx+4IwG0aDjI7GV8tc8ZccjWZZtTg==
+
+string-argv@~0.3.1:
+ version "0.3.2"
+ resolved "https://registry.yarnpkg.com/string-argv/-/string-argv-0.3.2.tgz#2b6d0ef24b656274d957d54e0a4bbf6153dc02b6"
+ integrity sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==
+
+"string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.0.0, string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.2, string-width@^4.2.3:
+ version "4.2.3"
+ resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
+ integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
+ dependencies:
+ emoji-regex "^8.0.0"
+ is-fullwidth-code-point "^3.0.0"
+ strip-ansi "^6.0.1"
+
+string_decoder@^1.1.1:
+ version "1.3.0"
+ resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e"
+ integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==
+ dependencies:
+ safe-buffer "~5.2.0"
+
+string_decoder@~0.10.x:
+ version "0.10.31"
+ resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94"
+ integrity sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==
+
+string_decoder@~1.1.1:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8"
+ integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==
+ dependencies:
+ safe-buffer "~5.1.0"
+
+strip-ansi@^3.0.0:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf"
+ integrity sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==
+ dependencies:
+ ansi-regex "^2.0.0"
+
+strip-ansi@^5.2.0:
+ version "5.2.0"
+ resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-5.2.0.tgz#8c9a536feb6afc962bdfa5b104a5091c1ad9c0ae"
+ integrity sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==
+ dependencies:
+ ansi-regex "^4.1.0"
+
+strip-ansi@^6.0.0, strip-ansi@^6.0.1:
+ version "6.0.1"
+ resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
+ integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
+ dependencies:
+ ansi-regex "^5.0.1"
+
+strip-final-newline@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-2.0.0.tgz#89b852fb2fcbe936f6f4b3187afb0a12c1ab58ad"
+ integrity sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==
+
+strip-final-newline@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-3.0.0.tgz#52894c313fbff318835280aed60ff71ebf12b8fd"
+ integrity sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==
+
+strip-json-comments@~2.0.1:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a"
+ integrity sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==
+
+strnum@^1.0.5:
+ version "1.0.5"
+ resolved "https://registry.yarnpkg.com/strnum/-/strnum-1.0.5.tgz#5c4e829fe15ad4ff0d20c3db5ac97b73c9b072db"
+ integrity sha512-J8bbNyKKXl5qYcR36TIO8W3mVGVHrmmxsd5PAItGkmyzwJvybiw2IVq5nqd0i4LSNSkB/sx9VHllbfFdr9k1JA==
+
+style-loader@3.3.1:
+ version "3.3.1"
+ resolved "https://registry.yarnpkg.com/style-loader/-/style-loader-3.3.1.tgz#057dfa6b3d4d7c7064462830f9113ed417d38575"
+ integrity sha512-GPcQ+LDJbrcxHORTRes6Jy2sfvK2kS6hpSfI/fXhPt+spVzxF6LJ1dHLN9zIGmVaaP044YKaIatFaufENRiDoQ==
+
+style-mod@^4.0.0, style-mod@^4.1.0:
+ version "4.1.0"
+ resolved "https://registry.yarnpkg.com/style-mod/-/style-mod-4.1.0.tgz#a313a14f4ae8bb4d52878c0053c4327fb787ec09"
+ integrity sha512-Ca5ib8HrFn+f+0n4N4ScTIA9iTOQ7MaGS1ylHcoVqW9J7w2w8PzN6g9gKmTYgGEBH8e120+RCmhpje6jC5uGWA==
+
+styled-components@5.3.3:
+ version "5.3.3"
+ resolved "https://registry.yarnpkg.com/styled-components/-/styled-components-5.3.3.tgz#312a3d9a549f4708f0fb0edc829eb34bde032743"
+ integrity sha512-++4iHwBM7ZN+x6DtPPWkCI4vdtwumQ+inA/DdAsqYd4SVgUKJie5vXyzotA00ttcFdQkCng7zc6grwlfIfw+lw==
+ dependencies:
+ "@babel/helper-module-imports" "^7.0.0"
+ "@babel/traverse" "^7.4.5"
+ "@emotion/is-prop-valid" "^0.8.8"
+ "@emotion/stylis" "^0.8.4"
+ "@emotion/unitless" "^0.7.4"
+ babel-plugin-styled-components ">= 1.12.0"
+ css-to-react-native "^3.0.0"
+ hoist-non-react-statics "^3.0.0"
+ shallowequal "^1.1.0"
+ supports-color "^5.5.0"
+
+stylis@4.2.0:
+ version "4.2.0"
+ resolved "https://registry.yarnpkg.com/stylis/-/stylis-4.2.0.tgz#79daee0208964c8fe695a42fcffcac633a211a51"
+ integrity sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==
+
+supports-color@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7"
+ integrity sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g==
+
+supports-color@^5.3.0, supports-color@^5.5.0:
+ version "5.5.0"
+ resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f"
+ integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==
+ dependencies:
+ has-flag "^3.0.0"
+
+supports-color@^7.1.0:
+ version "7.2.0"
+ resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da"
+ integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==
+ dependencies:
+ has-flag "^4.0.0"
+
+supports-color@^8.0.0, supports-color@^8.1.1:
+ version "8.1.1"
+ resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c"
+ integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==
+ dependencies:
+ has-flag "^4.0.0"
+
+supports-preserve-symlinks-flag@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09"
+ integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==
+
+swap-case@^1.1.0:
+ version "1.1.2"
+ resolved "https://registry.yarnpkg.com/swap-case/-/swap-case-1.1.2.tgz#c39203a4587385fad3c850a0bd1bcafa081974e3"
+ integrity sha512-BAmWG6/bx8syfc6qXPprof3Mn5vQgf5dwdUNJhsNqU9WdPt5P+ES/wQ5bxfijy8zwZgZZHslC3iAsxsuQMCzJQ==
+ dependencies:
+ lower-case "^1.1.1"
+ upper-case "^1.1.1"
+
+synckit@0.8.5:
+ version "0.8.5"
+ resolved "https://registry.yarnpkg.com/synckit/-/synckit-0.8.5.tgz#b7f4358f9bb559437f9f167eb6bc46b3c9818fa3"
+ integrity sha512-L1dapNV6vu2s/4Sputv8xGsCdAVlb5nRDMFU/E27D44l5U6cw1g0dGd45uLc+OXjNMmF4ntiMdCimzcjFKQI8Q==
+ dependencies:
+ "@pkgr/utils" "^2.3.1"
+ tslib "^2.5.0"
+
+tapable@^2.0.0, tapable@^2.1.1, tapable@^2.2.0, tapable@^2.2.1:
+ version "2.2.1"
+ resolved "https://registry.yarnpkg.com/tapable/-/tapable-2.2.1.tgz#1967a73ef4060a82f12ab96af86d52fdb76eeca0"
+ integrity sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==
+
+tar-fs@^2.0.0:
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/tar-fs/-/tar-fs-2.1.1.tgz#489a15ab85f1f0befabb370b7de4f9eb5cbe8784"
+ integrity sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==
+ dependencies:
+ chownr "^1.1.1"
+ mkdirp-classic "^0.5.2"
+ pump "^3.0.0"
+ tar-stream "^2.1.4"
+
+tar-fs@^3.0.4:
+ version "3.0.4"
+ resolved "https://registry.yarnpkg.com/tar-fs/-/tar-fs-3.0.4.tgz#a21dc60a2d5d9f55e0089ccd78124f1d3771dbbf"
+ integrity sha512-5AFQU8b9qLfZCX9zp2duONhPmZv0hGYiBPJsyUdqMjzq/mqVpy/rEUSeHk1+YitmxugaptgBh5oDGU3VsAJq4w==
+ dependencies:
+ mkdirp-classic "^0.5.2"
+ pump "^3.0.0"
+ tar-stream "^3.1.5"
+
+tar-stream@2.2.0, tar-stream@^2.1.4:
+ version "2.2.0"
+ resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-2.2.0.tgz#acad84c284136b060dc3faa64474aa9aebd77287"
+ integrity sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==
+ dependencies:
+ bl "^4.0.3"
+ end-of-stream "^1.4.1"
+ fs-constants "^1.0.0"
+ inherits "^2.0.3"
+ readable-stream "^3.1.1"
+
+tar-stream@^3.1.5:
+ version "3.1.6"
+ resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-3.1.6.tgz#6520607b55a06f4a2e2e04db360ba7d338cc5bab"
+ integrity sha512-B/UyjYwPpMBv+PaFSWAmtYjwdrlEaZQEhMIBFNC5oEG8lpiW8XjcSdmEaClj28ArfKScKHs2nshz3k2le6crsg==
+ dependencies:
+ b4a "^1.6.4"
+ fast-fifo "^1.2.0"
+ streamx "^2.15.0"
+
+tar@6.1.13:
+ version "6.1.13"
+ resolved "https://registry.yarnpkg.com/tar/-/tar-6.1.13.tgz#46e22529000f612180601a6fe0680e7da508847b"
+ integrity sha512-jdIBIN6LTIe2jqzay/2vtYLlBHa3JF42ot3h1dW8Q0PaAG4v8rm0cvpVePtau5C6OKXGGcgO9q2AMNSWxiLqKw==
+ dependencies:
+ chownr "^2.0.0"
+ fs-minipass "^2.0.0"
+ minipass "^4.0.0"
+ minizlib "^2.1.1"
+ mkdirp "^1.0.3"
+ yallist "^4.0.0"
+
+tar@^6.1.11:
+ version "6.2.0"
+ resolved "https://registry.yarnpkg.com/tar/-/tar-6.2.0.tgz#b14ce49a79cb1cd23bc9b016302dea5474493f73"
+ integrity sha512-/Wo7DcT0u5HUV486xg675HtjNd3BXZ6xDbzsCUZPt5iw8bTQ63bP0Raut3mvro9u+CUyq7YQd8Cx55fsZXxqLQ==
+ dependencies:
+ chownr "^2.0.0"
+ fs-minipass "^2.0.0"
+ minipass "^5.0.0"
+ minizlib "^2.1.1"
+ mkdirp "^1.0.3"
+ yallist "^4.0.0"
+
+tarn@^3.0.2:
+ version "3.0.2"
+ resolved "https://registry.yarnpkg.com/tarn/-/tarn-3.0.2.tgz#73b6140fbb881b71559c4f8bfde3d9a4b3d27693"
+ integrity sha512-51LAVKUSZSVfI05vjPESNc5vwqqZpbXCsU+/+wxlOrUjk2SnFTt97v9ZgQrD4YmxYW1Px6w2KjaDitCfkvgxMQ==
+
+terser-webpack-plugin@^5.3.7:
+ version "5.3.10"
+ resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-5.3.10.tgz#904f4c9193c6fd2a03f693a2150c62a92f40d199"
+ integrity sha512-BKFPWlPDndPs+NGGCr1U59t0XScL5317Y0UReNrHaw9/FwhPENlq6bfgs+4yPfyP51vqC1bQ4rp1EfXW5ZSH9w==
+ dependencies:
+ "@jridgewell/trace-mapping" "^0.3.20"
+ jest-worker "^27.4.5"
+ schema-utils "^3.1.1"
+ serialize-javascript "^6.0.1"
+ terser "^5.26.0"
+
+terser@^5.10.0, terser@^5.26.0:
+ version "5.26.0"
+ resolved "https://registry.yarnpkg.com/terser/-/terser-5.26.0.tgz#ee9f05d929f4189a9c28a0feb889d96d50126fe1"
+ integrity sha512-dytTGoE2oHgbNV9nTzgBEPaqAWvcJNl66VZ0BkJqlvp71IjO8CxdBx/ykCNb47cLnCmCvRZ6ZR0tLkqvZCdVBQ==
+ dependencies:
+ "@jridgewell/source-map" "^0.3.3"
+ acorn "^8.8.2"
+ commander "^2.20.0"
+ source-map-support "~0.5.20"
+
+text-hex@1.0.x:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/text-hex/-/text-hex-1.0.0.tgz#69dc9c1b17446ee79a92bf5b884bb4b9127506f5"
+ integrity sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==
+
+thenify-all@^1.0.0:
+ version "1.6.0"
+ resolved "https://registry.yarnpkg.com/thenify-all/-/thenify-all-1.6.0.tgz#1a1918d402d8fc3f98fbf234db0bcc8cc10e9726"
+ integrity sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==
+ dependencies:
+ thenify ">= 3.1.0 < 4"
+
+"thenify@>= 3.1.0 < 4":
+ version "3.3.1"
+ resolved "https://registry.yarnpkg.com/thenify/-/thenify-3.3.1.tgz#8932e686a4066038a016dd9e2ca46add9838a95f"
+ integrity sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==
+ dependencies:
+ any-promise "^1.0.0"
+
+through2@^2.0.1, through2@~2.0.3:
+ version "2.0.5"
+ resolved "https://registry.yarnpkg.com/through2/-/through2-2.0.5.tgz#01c1e39eb31d07cb7d03a96a70823260b23132cd"
+ integrity sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==
+ dependencies:
+ readable-stream "~2.3.6"
+ xtend "~4.0.1"
+
+through@^2.3.6:
+ version "2.3.8"
+ resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5"
+ integrity sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==
+
+tildify@2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/tildify/-/tildify-2.0.0.tgz#f205f3674d677ce698b7067a99e949ce03b4754a"
+ integrity sha512-Cc+OraorugtXNfs50hU9KS369rFXCfgGLpfCfvlc+Ud5u6VWmUQsOAa9HbTvheQdYnrdJqqv1e5oIqXppMYnSw==
+
+tiny-invariant@1.0.6:
+ version "1.0.6"
+ resolved "https://registry.yarnpkg.com/tiny-invariant/-/tiny-invariant-1.0.6.tgz#b3f9b38835e36a41c843a3b0907a5a7b3755de73"
+ integrity sha512-FOyLWWVjG+aC0UqG76V53yAWdXfH8bO6FNmyZOuUrzDzK8DI3/JRY25UD7+g49JWM1LXwymsKERB+DzI0dTEQA==
+
+tiny-invariant@^1.0.2:
+ version "1.3.1"
+ resolved "https://registry.yarnpkg.com/tiny-invariant/-/tiny-invariant-1.3.1.tgz#8560808c916ef02ecfd55e66090df23a4b7aa642"
+ integrity sha512-AD5ih2NlSssTCwsMznbvwMZpJ1cbhkGd2uueNxzv2jDlEeZdU04JQfRnggJQ8DrcVBGjAsCKwFBbDlVNtEMlzw==
+
+tiny-warning@^1.0.0, tiny-warning@^1.0.2, tiny-warning@^1.0.3:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/tiny-warning/-/tiny-warning-1.0.3.tgz#94a30db453df4c643d0fd566060d60a875d84754"
+ integrity sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==
+
+title-case@^2.1.0:
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/title-case/-/title-case-2.1.1.tgz#3e127216da58d2bc5becf137ab91dae3a7cd8faa"
+ integrity sha512-EkJoZ2O3zdCz3zJsYCsxyq2OC5hrxR9mfdd5I+w8h/tmFfeOxJ+vvkxsKxdmN0WtS9zLdHEgfgVOiMVgv+Po4Q==
+ dependencies:
+ no-case "^2.2.0"
+ upper-case "^1.0.3"
+
+titleize@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/titleize/-/titleize-3.0.0.tgz#71c12eb7fdd2558aa8a44b0be83b8a76694acd53"
+ integrity sha512-KxVu8EYHDPBdUYdKZdKtU2aj2XfEx9AfjXxE/Aj0vT06w2icA09Vus1rh6eSu1y01akYg6BjIK/hxyLJINoMLQ==
+
+tmp@^0.0.33:
+ version "0.0.33"
+ resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9"
+ integrity sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==
+ dependencies:
+ os-tmpdir "~1.0.2"
+
+to-fast-properties@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e"
+ integrity sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==
+
+to-object-path@^0.3.0:
+ version "0.3.0"
+ resolved "https://registry.yarnpkg.com/to-object-path/-/to-object-path-0.3.0.tgz#297588b7b0e7e0ac08e04e672f85c1f4999e17af"
+ integrity sha512-9mWHdnGRuh3onocaHzukyvCZhzvr6tiflAy/JRFXcJX0TjgfWA9pk9t8CMbzmBE4Jfw58pXbkngtBtqYxzNEyg==
+ dependencies:
+ kind-of "^3.0.2"
+
+to-regex-range@^2.1.0:
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-2.1.1.tgz#7c80c17b9dfebe599e27367e0d4dd5590141db38"
+ integrity sha512-ZZWNfCjUokXXDGXFpZehJIkZqq91BcULFq/Pi7M5i4JnxXdhMKAK682z8bCW3o8Hj1wuuzoKcW3DfVzaP6VuNg==
+ dependencies:
+ is-number "^3.0.0"
+ repeat-string "^1.6.1"
+
+to-regex-range@^5.0.1:
+ version "5.0.1"
+ resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4"
+ integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==
+ dependencies:
+ is-number "^7.0.0"
+
+to-regex@^3.0.1, to-regex@^3.0.2:
+ version "3.0.2"
+ resolved "https://registry.yarnpkg.com/to-regex/-/to-regex-3.0.2.tgz#13cfdd9b336552f30b51f33a8ae1b42a7a7599ce"
+ integrity sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==
+ dependencies:
+ define-property "^2.0.2"
+ extend-shallow "^3.0.2"
+ regex-not "^1.0.2"
+ safe-regex "^1.1.0"
+
+toidentifier@1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.1.tgz#3be34321a88a820ed1bd80dfaa33e479fbb8dd35"
+ integrity sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==
+
+toposort@^2.0.2:
+ version "2.0.2"
+ resolved "https://registry.yarnpkg.com/toposort/-/toposort-2.0.2.tgz#ae21768175d1559d48bef35420b2f4962f09c330"
+ integrity sha512-0a5EOkAUp8D4moMi2W8ZF8jcga7BgZd91O/yabJCFY8az+XSzeGyTKs0Aoo897iV1Nj6guFq8orWDS96z91oGg==
+
+totalist@^3.0.0:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/totalist/-/totalist-3.0.1.tgz#ba3a3d600c915b1a97872348f79c127475f6acf8"
+ integrity sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==
+
+tr46@~0.0.3:
+ version "0.0.3"
+ resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a"
+ integrity sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==
+
+transliteration@2.3.5:
+ version "2.3.5"
+ resolved "https://registry.yarnpkg.com/transliteration/-/transliteration-2.3.5.tgz#8f92309575f69e4a8a525dab4ff705ebcf961c45"
+ integrity sha512-HAGI4Lq4Q9dZ3Utu2phaWgtm3vB6PkLUFqWAScg/UW+1eZ/Tg6Exo4oC0/3VUol/w4BlefLhUUSVBr/9/ZGQOw==
+ dependencies:
+ yargs "^17.5.1"
+
+tree-kill@^1.2.2:
+ version "1.2.2"
+ resolved "https://registry.yarnpkg.com/tree-kill/-/tree-kill-1.2.2.tgz#4ca09a9092c88b73a7cdc5e8a01b507b0790a0cc"
+ integrity sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==
+
+triple-beam@^1.3.0:
+ version "1.4.1"
+ resolved "https://registry.yarnpkg.com/triple-beam/-/triple-beam-1.4.1.tgz#6fde70271dc6e5d73ca0c3b24e2d92afb7441984"
+ integrity sha512-aZbgViZrg1QNcG+LULa7nhZpJTZSLm/mXnHXnbAbjmN5aSa0y7V+wvv6+4WaBtpISJzThKy+PIPxc1Nq1EJ9mg==
+
+tslib@^1.10.0, tslib@^1.11.1, tslib@^1.9.0, tslib@^1.9.3:
+ version "1.14.1"
+ resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00"
+ integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==
+
+tslib@^2.0.0, tslib@^2.0.3, tslib@^2.1.0, tslib@^2.3.1, tslib@^2.4.0, tslib@^2.5.0, tslib@^2.6.0:
+ version "2.6.2"
+ resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.2.tgz#703ac29425e7b37cd6fd456e92404d46d1f3e4ae"
+ integrity sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==
+
+tsscmp@1.0.6:
+ version "1.0.6"
+ resolved "https://registry.yarnpkg.com/tsscmp/-/tsscmp-1.0.6.tgz#85b99583ac3589ec4bfef825b5000aa911d605eb"
+ integrity sha512-LxhtAkPDTkVCMQjt2h6eBVY28KCjikZqZfMcC15YBeNjkgUpdCfBu5HoiOTDu86v6smE8yOjyEktJ8hlbANHQA==
+
+tunnel-agent@^0.6.0:
+ version "0.6.0"
+ resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd"
+ integrity sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==
+ dependencies:
+ safe-buffer "^5.0.1"
+
+type-fest@^0.20.2:
+ version "0.20.2"
+ resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4"
+ integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==
+
+type-fest@^0.21.3:
+ version "0.21.3"
+ resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.21.3.tgz#d260a24b0198436e133fa26a524a6d65fa3b2e37"
+ integrity sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==
+
+type-fest@^0.6.0:
+ version "0.6.0"
+ resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.6.0.tgz#8d2a2370d3df886eb5c90ada1c5bf6188acf838b"
+ integrity sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==
+
+type-fest@^0.8.1:
+ version "0.8.1"
+ resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.8.1.tgz#09e249ebde851d3b1e48d27c105444667f17b83d"
+ integrity sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==
+
+type-fest@^2.18.0, type-fest@^2.19.0:
+ version "2.19.0"
+ resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-2.19.0.tgz#88068015bb33036a598b952e55e9311a60fd3a9b"
+ integrity sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==
+
+type-is@^1.6.14, type-is@^1.6.16, type-is@^1.6.18:
+ version "1.6.18"
+ resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131"
+ integrity sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==
+ dependencies:
+ media-typer "0.3.0"
+ mime-types "~2.1.24"
+
+typedarray-to-buffer@^3.1.5:
+ version "3.1.5"
+ resolved "https://registry.yarnpkg.com/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz#a97ee7a9ff42691b9f783ff1bc5112fe3fca9080"
+ integrity sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==
+ dependencies:
+ is-typedarray "^1.0.0"
+
+typescript@5.2.2:
+ version "5.2.2"
+ resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.2.2.tgz#5ebb5e5a5b75f085f22bc3f8460fba308310fa78"
+ integrity sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==
+
+typescript@^5.3.3:
+ version "5.3.3"
+ resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.3.3.tgz#b3ce6ba258e72e6305ba66f5c9b452aaee3ffe37"
+ integrity sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==
+
+uc.micro@^1.0.1, uc.micro@^1.0.5:
+ version "1.0.6"
+ resolved "https://registry.yarnpkg.com/uc.micro/-/uc.micro-1.0.6.tgz#9c411a802a409a91fc6cf74081baba34b24499ac"
+ integrity sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==
+
+uglify-js@^3.1.4:
+ version "3.17.4"
+ resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.17.4.tgz#61678cf5fa3f5b7eb789bb345df29afb8257c22c"
+ integrity sha512-T9q82TJI9e/C1TAxYvfb16xO120tMVFZrGA3f9/P4424DNu6ypK103y0GPFVa17yotwSyZW5iYXgjYHkGrJW/g==
+
+umzug@3.2.1:
+ version "3.2.1"
+ resolved "https://registry.yarnpkg.com/umzug/-/umzug-3.2.1.tgz#01c3a109efb037a10a317d4191be22810c37b195"
+ integrity sha512-XyWQowvP9CKZycKc/Zg9SYWrAWX/gJCE799AUTFqk8yC3tp44K1xWr3LoFF0MNEjClKOo1suCr5ASnoy+KltdA==
+ dependencies:
+ "@rushstack/ts-command-line" "^4.12.2"
+ emittery "^0.12.1"
+ fs-jetpack "^4.3.1"
+ glob "^8.0.3"
+ pony-cause "^2.1.2"
+ type-fest "^2.18.0"
+
+unc-path-regex@^0.1.2:
+ version "0.1.2"
+ resolved "https://registry.yarnpkg.com/unc-path-regex/-/unc-path-regex-0.1.2.tgz#e73dd3d7b0d7c5ed86fbac6b0ae7d8c6a69d50fa"
+ integrity sha512-eXL4nmJT7oCpkZsHZUOJo8hcX3GbsiDOa0Qu9F646fi8dT3XuSVopVqAcEiVzSKKH7UoDti23wNX3qGFxcW5Qg==
+
+undici-types@~5.26.4:
+ version "5.26.5"
+ resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-5.26.5.tgz#bcd539893d00b56e964fd2657a4866b221a65617"
+ integrity sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==
+
+union-value@^1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/union-value/-/union-value-1.0.1.tgz#0b6fe7b835aecda61c6ea4d4f02c14221e109847"
+ integrity sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==
+ dependencies:
+ arr-union "^3.1.0"
+ get-value "^2.0.6"
+ is-extendable "^0.1.1"
+ set-value "^2.0.1"
+
+unique-string@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/unique-string/-/unique-string-2.0.0.tgz#39c6451f81afb2749de2b233e3f7c5e8843bd89d"
+ integrity sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==
+ dependencies:
+ crypto-random-string "^2.0.0"
+
+universalify@^2.0.0:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/universalify/-/universalify-2.0.1.tgz#168efc2180964e6386d061e094df61afe239b18d"
+ integrity sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==
+
+unload@2.2.0:
+ version "2.2.0"
+ resolved "https://registry.yarnpkg.com/unload/-/unload-2.2.0.tgz#ccc88fdcad345faa06a92039ec0f80b488880ef7"
+ integrity sha512-B60uB5TNBLtN6/LsgAf3udH9saB5p7gqJwcFfbOEZ8BcBHnGwCf6G/TGiEqkRAxX7zAFIUtzdrXQSdL3Q/wqNA==
+ dependencies:
+ "@babel/runtime" "^7.6.2"
+ detect-node "^2.0.4"
+
+unpipe@1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec"
+ integrity sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==
+
+unset-value@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/unset-value/-/unset-value-1.0.0.tgz#8376873f7d2335179ffb1e6fc3a8ed0dfc8ab559"
+ integrity sha512-PcA2tsuGSF9cnySLHTLSh2qrQiJ70mn+r+Glzxv2TWZblxsxCC52BDlZoPCsz7STd9pN7EZetkWZBAvk4cgZdQ==
+ dependencies:
+ has-value "^0.3.1"
+ isobject "^3.0.0"
+
+untildify@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/untildify/-/untildify-4.0.0.tgz#2bc947b953652487e4600949fb091e3ae8cd919b"
+ integrity sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw==
+
+update-browserslist-db@^1.0.13:
+ version "1.0.13"
+ resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz#3c5e4f5c083661bd38ef64b6328c26ed6c8248c4"
+ integrity sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==
+ dependencies:
+ escalade "^3.1.1"
+ picocolors "^1.0.0"
+
+upper-case-first@^1.1.0, upper-case-first@^1.1.2:
+ version "1.1.2"
+ resolved "https://registry.yarnpkg.com/upper-case-first/-/upper-case-first-1.1.2.tgz#5d79bedcff14419518fd2edb0a0507c9b6859115"
+ integrity sha512-wINKYvI3Db8dtjikdAqoBbZoP6Q+PZUyfMR7pmwHzjC2quzSkUq5DmPrTtPEqHaz8AGtmsB4TqwapMTM1QAQOQ==
+ dependencies:
+ upper-case "^1.1.1"
+
+upper-case@^1.0.3, upper-case@^1.1.0, upper-case@^1.1.1, upper-case@^1.1.3:
+ version "1.1.3"
+ resolved "https://registry.yarnpkg.com/upper-case/-/upper-case-1.1.3.tgz#f6b4501c2ec4cdd26ba78be7222961de77621598"
+ integrity sha512-WRbjgmYzgXkCV7zNVpy5YgrHgbBv126rMALQQMrmzOVC4GM2waQ9x7xtm8VU+1yF2kWyPzI9zbZ48n4vSxwfSA==
+
+uri-js@^4.2.2:
+ version "4.4.1"
+ resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e"
+ integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==
+ dependencies:
+ punycode "^2.1.0"
+
+urix@^0.1.0:
+ version "0.1.0"
+ resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72"
+ integrity sha512-Am1ousAhSLBeB9cG/7k7r2R0zj50uDRlZHPGbazid5s9rlF1F/QKYObEKSIunSjIOkJZqwRRLpvewjEkM7pSqg==
+
+url-join@4.0.1:
+ version "4.0.1"
+ resolved "https://registry.yarnpkg.com/url-join/-/url-join-4.0.1.tgz#b642e21a2646808ffa178c4c5fda39844e12cde7"
+ integrity sha512-jk1+QP6ZJqyOiuEI9AEWQfju/nB2Pw466kbA0LEZljHwKeMgd9WrAEgEGxjPDD2+TNbbb37rTyhEfrCXfuKXnA==
+
+url@0.10.3:
+ version "0.10.3"
+ resolved "https://registry.yarnpkg.com/url/-/url-0.10.3.tgz#021e4d9c7705f21bbf37d03ceb58767402774c64"
+ integrity sha512-hzSUW2q06EqL1gKM/a+obYHLIO6ct2hwPuviqTTOcfFVc61UbfJ2Q32+uGL/HCPxKqrdGB5QUwIe7UqlDgwsOQ==
+ dependencies:
+ punycode "1.3.2"
+ querystring "0.2.0"
+
+use-callback-ref@^1.3.0:
+ version "1.3.1"
+ resolved "https://registry.yarnpkg.com/use-callback-ref/-/use-callback-ref-1.3.1.tgz#9be64c3902cbd72b07fe55e56408ae3a26036fd0"
+ integrity sha512-Lg4Vx1XZQauB42Hw3kK7JM6yjVjgFmFC5/Ab797s79aARomD2nEErc4mCgM8EZrARLmmbWpi5DGCadmK50DcAQ==
+ dependencies:
+ tslib "^2.0.0"
+
+use-isomorphic-layout-effect@^1.1.2:
+ version "1.1.2"
+ resolved "https://registry.yarnpkg.com/use-isomorphic-layout-effect/-/use-isomorphic-layout-effect-1.1.2.tgz#497cefb13d863d687b08477d9e5a164ad8c1a6fb"
+ integrity sha512-49L8yCO3iGT/ZF9QttjwLF/ZD9Iwto5LnH5LmEdk/6cFmXddqi2ulF0edxTwjj+7mqvpVVGQWvbXZdn32wRSHA==
+
+use-sidecar@^1.1.2:
+ version "1.1.2"
+ resolved "https://registry.yarnpkg.com/use-sidecar/-/use-sidecar-1.1.2.tgz#2f43126ba2d7d7e117aa5855e5d8f0276dfe73c2"
+ integrity sha512-epTbsLuzZ7lPClpz2TyryBfztm7m+28DlEv2ZCQ3MDr5ssiwyOwGH/e5F9CkfWjJ1t4clvI58yF822/GUkjjhw==
+ dependencies:
+ detect-node-es "^1.1.0"
+ tslib "^2.0.0"
+
+use-sync-external-store@^1.0.0:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz#7dbefd6ef3fe4e767a0cf5d7287aacfb5846928a"
+ integrity sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==
+
+use@^3.1.0:
+ version "3.1.1"
+ resolved "https://registry.yarnpkg.com/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f"
+ integrity sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==
+
+user-home@^1.1.1:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/user-home/-/user-home-1.1.1.tgz#2b5be23a32b63a7c9deb8d0f28d485724a3df190"
+ integrity sha512-aggiKfEEubv3UwRNqTzLInZpAOmKzwdHqEBmW/hBA/mt99eg+b4VrX6i+IRLxU8+WJYfa33rGwRseg4eElUgsQ==
+
+util-deprecate@^1.0.1, util-deprecate@^1.0.2, util-deprecate@~1.0.1:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
+ integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==
+
+util@^0.12.3, util@^0.12.4:
+ version "0.12.5"
+ resolved "https://registry.yarnpkg.com/util/-/util-0.12.5.tgz#5f17a6059b73db61a875668781a1c2b136bd6fbc"
+ integrity sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==
+ dependencies:
+ inherits "^2.0.3"
+ is-arguments "^1.0.4"
+ is-generator-function "^1.0.7"
+ is-typed-array "^1.1.3"
+ which-typed-array "^1.1.2"
+
+utila@~0.4:
+ version "0.4.0"
+ resolved "https://registry.yarnpkg.com/utila/-/utila-0.4.0.tgz#8a16a05d445657a3aea5eecc5b12a4fa5379772c"
+ integrity sha512-Z0DbgELS9/L/75wZbro8xAnT50pBVFQZ+hUEueGDU5FN51YSCYM+jdxsfCiHjwNP/4LCDD0i/graKpeBnOXKRA==
+
+utils-merge@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713"
+ integrity sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==
+
+uuid@8.0.0:
+ version "8.0.0"
+ resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.0.0.tgz#bc6ccf91b5ff0ac07bbcdbf1c7c4e150db4dbb6c"
+ integrity sha512-jOXGuXZAWdsTH7eZLtyXMqUb9EcWMGZNbL9YcGBJl4MH4nrxHmZJhEHvyLFrkxo+28uLb/NYRcStH48fnD0Vzw==
+
+uuid@^8.3.2:
+ version "8.3.2"
+ resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2"
+ integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==
+
+v8flags@^2.0.10:
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/v8flags/-/v8flags-2.1.1.tgz#aab1a1fa30d45f88dd321148875ac02c0b55e5b4"
+ integrity sha512-SKfhk/LlaXzvtowJabLZwD4K6SGRYeoxA7KJeISlUMAB/NT4CBkZjMq3WceX2Ckm4llwqYVo8TICgsDYCBU2tA==
+ dependencies:
+ user-home "^1.1.1"
+
+validate-npm-package-license@^3.0.1:
+ version "3.0.4"
+ resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz#fc91f6b9c7ba15c857f4cb2c5defeec39d4f410a"
+ integrity sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==
+ dependencies:
+ spdx-correct "^3.0.0"
+ spdx-expression-parse "^3.0.0"
+
+value-equal@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/value-equal/-/value-equal-1.0.1.tgz#1e0b794c734c5c0cade179c437d356d931a34d6c"
+ integrity sha512-NOJ6JZCAWr0zlxZt+xqCHNTEKOsrks2HQd4MqhP1qy4z1SkbEP467eNx6TgDKXMvUOb+OENfJCZwM+16n7fRfw==
+
+vary@^1.1.2:
+ version "1.1.2"
+ resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc"
+ integrity sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==
+
+vite@4.4.9:
+ version "4.4.9"
+ resolved "https://registry.yarnpkg.com/vite/-/vite-4.4.9.tgz#1402423f1a2f8d66fd8d15e351127c7236d29d3d"
+ integrity sha512-2mbUn2LlUmNASWwSCNSJ/EG2HuSRTnVNaydp6vMCm5VIqJsjMfbIWtbH2kDuwUVW5mMUKKZvGPX/rqeqVvv1XA==
+ dependencies:
+ esbuild "^0.18.10"
+ postcss "^8.4.27"
+ rollup "^3.27.1"
+ optionalDependencies:
+ fsevents "~2.3.2"
+
+w3c-keyname@^2.2.4:
+ version "2.2.8"
+ resolved "https://registry.yarnpkg.com/w3c-keyname/-/w3c-keyname-2.2.8.tgz#7b17c8c6883d4e8b86ac8aba79d39e880f8869c5"
+ integrity sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ==
+
+watchpack@^2.4.0:
+ version "2.4.0"
+ resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-2.4.0.tgz#fa33032374962c78113f93c7f2fb4c54c9862a5d"
+ integrity sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==
+ dependencies:
+ glob-to-regexp "^0.4.1"
+ graceful-fs "^4.1.2"
+
+wcwidth@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/wcwidth/-/wcwidth-1.0.1.tgz#f0b0dcf915bc5ff1528afadb2c0e17b532da2fe8"
+ integrity sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==
+ dependencies:
+ defaults "^1.0.3"
+
+web-encoding@^1.1.5:
+ version "1.1.5"
+ resolved "https://registry.yarnpkg.com/web-encoding/-/web-encoding-1.1.5.tgz#fc810cf7667364a6335c939913f5051d3e0c4864"
+ integrity sha512-HYLeVCdJ0+lBYV2FvNZmv3HJ2Nt0QYXqZojk3d9FJOLkwnuhzM9tmamh8d7HPM8QqjKH8DeHkFTx+CFlWpZZDA==
+ dependencies:
+ util "^0.12.3"
+ optionalDependencies:
+ "@zxing/text-encoding" "0.9.0"
+
+webidl-conversions@^3.0.0:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871"
+ integrity sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==
+
+webpack-bundle-analyzer@^4.9.0:
+ version "4.10.1"
+ resolved "https://registry.yarnpkg.com/webpack-bundle-analyzer/-/webpack-bundle-analyzer-4.10.1.tgz#84b7473b630a7b8c21c741f81d8fe4593208b454"
+ integrity sha512-s3P7pgexgT/HTUSYgxJyn28A+99mmLq4HsJepMPzu0R8ImJc52QNqaFYW1Z2z2uIb1/J3eYgaAWVpaC+v/1aAQ==
+ dependencies:
+ "@discoveryjs/json-ext" "0.5.7"
+ acorn "^8.0.4"
+ acorn-walk "^8.0.0"
+ commander "^7.2.0"
+ debounce "^1.2.1"
+ escape-string-regexp "^4.0.0"
+ gzip-size "^6.0.0"
+ html-escaper "^2.0.2"
+ is-plain-object "^5.0.0"
+ opener "^1.5.2"
+ picocolors "^1.0.0"
+ sirv "^2.0.3"
+ ws "^7.3.1"
+
+webpack-dev-middleware@6.1.1:
+ version "6.1.1"
+ resolved "https://registry.yarnpkg.com/webpack-dev-middleware/-/webpack-dev-middleware-6.1.1.tgz#6bbc257ec83ae15522de7a62f995630efde7cc3d"
+ integrity sha512-y51HrHaFeeWir0YO4f0g+9GwZawuigzcAdRNon6jErXy/SqV/+O6eaVAzDqE6t3e3NpGeR5CS+cCDaTC+V3yEQ==
+ dependencies:
+ colorette "^2.0.10"
+ memfs "^3.4.12"
+ mime-types "^2.1.31"
+ range-parser "^1.2.1"
+ schema-utils "^4.0.0"
+
+webpack-hot-middleware@2.25.4:
+ version "2.25.4"
+ resolved "https://registry.yarnpkg.com/webpack-hot-middleware/-/webpack-hot-middleware-2.25.4.tgz#d8bc9e9cb664fc3105c8e83d2b9ed436bee4e193"
+ integrity sha512-IRmTspuHM06aZh98OhBJtqLpeWFM8FXJS5UYpKYxCJzyFoyWj1w6VGFfomZU7OPA55dMLrQK0pRT1eQ3PACr4w==
+ dependencies:
+ ansi-html-community "0.0.8"
+ html-entities "^2.1.0"
+ strip-ansi "^6.0.0"
+
+webpack-sources@^1.4.3:
+ version "1.4.3"
+ resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-1.4.3.tgz#eedd8ec0b928fbf1cbfe994e22d2d890f330a933"
+ integrity sha512-lgTS3Xhv1lCOKo7SA5TjKXMjpSM4sBjNV5+q2bqesbSPs5FjGmU6jjtBSkX9b4qW87vDIsCIlUPOEhbZrMdjeQ==
+ dependencies:
+ source-list-map "^2.0.0"
+ source-map "~0.6.1"
+
+webpack-sources@^3.2.3:
+ version "3.2.3"
+ resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-3.2.3.tgz#2d4daab8451fd4b240cc27055ff6a0c2ccea0cde"
+ integrity sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==
+
+webpack@^5.88.1:
+ version "5.89.0"
+ resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.89.0.tgz#56b8bf9a34356e93a6625770006490bf3a7f32dc"
+ integrity sha512-qyfIC10pOr70V+jkmud8tMfajraGCZMBWJtrmuBymQKCrLTRejBI8STDp1MCyZu/QTdZSeacCQYpYNQVOzX5kw==
+ dependencies:
+ "@types/eslint-scope" "^3.7.3"
+ "@types/estree" "^1.0.0"
+ "@webassemblyjs/ast" "^1.11.5"
+ "@webassemblyjs/wasm-edit" "^1.11.5"
+ "@webassemblyjs/wasm-parser" "^1.11.5"
+ acorn "^8.7.1"
+ acorn-import-assertions "^1.9.0"
+ browserslist "^4.14.5"
+ chrome-trace-event "^1.0.2"
+ enhanced-resolve "^5.15.0"
+ es-module-lexer "^1.2.1"
+ eslint-scope "5.1.1"
+ events "^3.2.0"
+ glob-to-regexp "^0.4.1"
+ graceful-fs "^4.2.9"
+ json-parse-even-better-errors "^2.3.1"
+ loader-runner "^4.2.0"
+ mime-types "^2.1.27"
+ neo-async "^2.6.2"
+ schema-utils "^3.2.0"
+ tapable "^2.1.1"
+ terser-webpack-plugin "^5.3.7"
+ watchpack "^2.4.0"
+ webpack-sources "^3.2.3"
+
+whatwg-url@^5.0.0:
+ version "5.0.0"
+ resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-5.0.0.tgz#966454e8765462e37644d3626f6742ce8b70965d"
+ integrity sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==
+ dependencies:
+ tr46 "~0.0.3"
+ webidl-conversions "^3.0.0"
+
+which-boxed-primitive@^1.0.2:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz#13757bc89b209b049fe5d86430e21cf40a89a8e6"
+ integrity sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==
+ dependencies:
+ is-bigint "^1.0.1"
+ is-boolean-object "^1.1.0"
+ is-number-object "^1.0.4"
+ is-string "^1.0.5"
+ is-symbol "^1.0.3"
+
+which-collection@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/which-collection/-/which-collection-1.0.1.tgz#70eab71ebbbd2aefaf32f917082fc62cdcb70906"
+ integrity sha512-W8xeTUwaln8i3K/cY1nGXzdnVZlidBcagyNFtBdD5kxnb4TvGKR7FfSIS3mYpwWS1QUCutfKz8IY8RjftB0+1A==
+ dependencies:
+ is-map "^2.0.1"
+ is-set "^2.0.1"
+ is-weakmap "^2.0.1"
+ is-weakset "^2.0.1"
+
+which-typed-array@^1.1.11, which-typed-array@^1.1.13, which-typed-array@^1.1.2:
+ version "1.1.13"
+ resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.13.tgz#870cd5be06ddb616f504e7b039c4c24898184d36"
+ integrity sha512-P5Nra0qjSncduVPEAr7xhoF5guty49ArDTwzJ/yNuPIbZppyRxFQsRCWrocxIY+CnMVG+qfbU2FmDKyvSGClow==
+ dependencies:
+ available-typed-arrays "^1.0.5"
+ call-bind "^1.0.4"
+ for-each "^0.3.3"
+ gopd "^1.0.1"
+ has-tostringtag "^1.0.0"
+
+which@^1.2.14:
+ version "1.3.1"
+ resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a"
+ integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==
+ dependencies:
+ isexe "^2.0.0"
+
+which@^2.0.1:
+ version "2.0.2"
+ resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1"
+ integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==
+ dependencies:
+ isexe "^2.0.0"
+
+wide-align@^1.1.2:
+ version "1.1.5"
+ resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.5.tgz#df1d4c206854369ecf3c9a4898f1b23fbd9d15d3"
+ integrity sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==
+ dependencies:
+ string-width "^1.0.2 || 2 || 3 || 4"
+
+widest-line@^3.1.0:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/widest-line/-/widest-line-3.1.0.tgz#8292333bbf66cb45ff0de1603b136b7ae1496eca"
+ integrity sha512-NsmoXalsWVDMGupxZ5R08ka9flZjjiLvHVAWYOKtiKM8ujtZWr9cRffak+uSE48+Ob8ObalXpwyeUiyDD6QFgg==
+ dependencies:
+ string-width "^4.0.0"
+
+winston-transport@^4.5.0:
+ version "4.6.0"
+ resolved "https://registry.yarnpkg.com/winston-transport/-/winston-transport-4.6.0.tgz#f1c1a665ad1b366df72199e27892721832a19e1b"
+ integrity sha512-wbBA9PbPAHxKiygo7ub7BYRiKxms0tpfU2ljtWzb3SjRjv5yl6Ozuy/TkXf00HTAt+Uylo3gSkNwzc4ME0wiIg==
+ dependencies:
+ logform "^2.3.2"
+ readable-stream "^3.6.0"
+ triple-beam "^1.3.0"
+
+winston@3.10.0:
+ version "3.10.0"
+ resolved "https://registry.yarnpkg.com/winston/-/winston-3.10.0.tgz#d033cb7bd3ced026fed13bf9d92c55b903116803"
+ integrity sha512-nT6SIDaE9B7ZRO0u3UvdrimG0HkB7dSTAgInQnNR2SOPJ4bvq5q79+pXLftKmP52lJGW15+H5MCK0nM9D3KB/g==
+ dependencies:
+ "@colors/colors" "1.5.0"
+ "@dabh/diagnostics" "^2.0.2"
+ async "^3.2.3"
+ is-stream "^2.0.0"
+ logform "^2.4.0"
+ one-time "^1.0.0"
+ readable-stream "^3.4.0"
+ safe-stable-stringify "^2.3.1"
+ stack-trace "0.0.x"
+ triple-beam "^1.3.0"
+ winston-transport "^4.5.0"
+
+wordwrap@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb"
+ integrity sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==
+
+wrap-ansi@^6.0.1:
+ version "6.2.0"
+ resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-6.2.0.tgz#e9393ba07102e6c91a3b221478f0257cd2856e53"
+ integrity sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==
+ dependencies:
+ ansi-styles "^4.0.0"
+ string-width "^4.1.0"
+ strip-ansi "^6.0.0"
+
+wrap-ansi@^7.0.0:
+ version "7.0.0"
+ resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43"
+ integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==
+ dependencies:
+ ansi-styles "^4.0.0"
+ string-width "^4.1.0"
+ strip-ansi "^6.0.0"
+
+wrappy@1:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
+ integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==
+
+write-file-atomic@^3.0.0:
+ version "3.0.3"
+ resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-3.0.3.tgz#56bd5c5a5c70481cd19c571bd39ab965a5de56e8"
+ integrity sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==
+ dependencies:
+ imurmurhash "^0.1.4"
+ is-typedarray "^1.0.0"
+ signal-exit "^3.0.2"
+ typedarray-to-buffer "^3.1.5"
+
+ws@8.13.0:
+ version "8.13.0"
+ resolved "https://registry.yarnpkg.com/ws/-/ws-8.13.0.tgz#9a9fb92f93cf41512a0735c8f4dd09b8a1211cd0"
+ integrity sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==
+
+ws@^7.3.1:
+ version "7.5.9"
+ resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.9.tgz#54fa7db29f4c7cec68b1ddd3a89de099942bb591"
+ integrity sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==
+
+xdg-basedir@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/xdg-basedir/-/xdg-basedir-4.0.0.tgz#4bc8d9984403696225ef83a1573cbbcb4e79db13"
+ integrity sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q==
+
+xml2js@0.5.0:
+ version "0.5.0"
+ resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.5.0.tgz#d9440631fbb2ed800203fad106f2724f62c493b7"
+ integrity sha512-drPFnkQJik/O+uPKpqSgr22mpuFHqKdbS835iAQrUC73L2F5WkboIRd63ai/2Yg6I1jzifPFKH2NTK+cfglkIA==
+ dependencies:
+ sax ">=0.6.0"
+ xmlbuilder "~11.0.0"
+
+xmlbuilder@~11.0.0:
+ version "11.0.1"
+ resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-11.0.1.tgz#be9bae1c8a046e76b31127726347d0ad7002beb3"
+ integrity sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==
+
+xtend@^4.0.0, xtend@~4.0.1:
+ version "4.0.2"
+ resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54"
+ integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==
+
+y18n@^5.0.5:
+ version "5.0.8"
+ resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55"
+ integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==
+
+yallist@^3.0.2:
+ version "3.1.1"
+ resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd"
+ integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==
+
+yallist@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72"
+ integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==
+
+yaml@^1.10.0:
+ version "1.10.2"
+ resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.10.2.tgz#2301c5ffbf12b467de8da2333a459e29e7920e4b"
+ integrity sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==
+
+yargs-parser@^20.2.2:
+ version "20.2.9"
+ resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee"
+ integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==
+
+yargs-parser@^21.1.1:
+ version "21.1.1"
+ resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-21.1.1.tgz#9096bceebf990d21bb31fa9516e0ede294a77d35"
+ integrity sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==
+
+yargs@^16.1.0:
+ version "16.2.0"
+ resolved "https://registry.yarnpkg.com/yargs/-/yargs-16.2.0.tgz#1c82bf0f6b6a66eafce7ef30e376f49a12477f66"
+ integrity sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==
+ dependencies:
+ cliui "^7.0.2"
+ escalade "^3.1.1"
+ get-caller-file "^2.0.5"
+ require-directory "^2.1.1"
+ string-width "^4.2.0"
+ y18n "^5.0.5"
+ yargs-parser "^20.2.2"
+
+yargs@^17.3.1, yargs@^17.5.1, yargs@^17.7.2:
+ version "17.7.2"
+ resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.7.2.tgz#991df39aca675a192b816e1e0363f9d75d2aa269"
+ integrity sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==
+ dependencies:
+ cliui "^8.0.1"
+ escalade "^3.1.1"
+ get-caller-file "^2.0.5"
+ require-directory "^2.1.1"
+ string-width "^4.2.3"
+ y18n "^5.0.5"
+ yargs-parser "^21.1.1"
+
+ylru@^1.2.0:
+ version "1.3.2"
+ resolved "https://registry.yarnpkg.com/ylru/-/ylru-1.3.2.tgz#0de48017473275a4cbdfc83a1eaf67c01af8a785"
+ integrity sha512-RXRJzMiK6U2ye0BlGGZnmpwJDPgakn6aNQ0A7gHRbD4I0uvK4TW6UqkK1V0pp9jskjJBAXd3dRrbzWkqJ+6cxA==
+
+yocto-queue@^0.1.0:
+ version "0.1.0"
+ resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b"
+ integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==
+
+yup@0.32.9:
+ version "0.32.9"
+ resolved "https://registry.yarnpkg.com/yup/-/yup-0.32.9.tgz#9367bec6b1b0e39211ecbca598702e106019d872"
+ integrity sha512-Ci1qN+i2H0XpY7syDQ0k5zKQ/DoxO0LzPg8PAR/X4Mpj6DqaeCoIYEEjDJwhArh3Fa7GWbQQVDZKeXYlSH4JMg==
+ dependencies:
+ "@babel/runtime" "^7.10.5"
+ "@types/lodash" "^4.14.165"
+ lodash "^4.17.20"
+ lodash-es "^4.17.15"
+ nanoclone "^0.2.1"
+ property-expr "^2.0.4"
+ toposort "^2.0.2"
+
+yup@^0.32.11:
+ version "0.32.11"
+ resolved "https://registry.yarnpkg.com/yup/-/yup-0.32.11.tgz#d67fb83eefa4698607982e63f7ca4c5ed3cf18c5"
+ integrity sha512-Z2Fe1bn+eLstG8DRR6FTavGD+MeAwyfmouhHsIUgaADz8jvFKbO/fXc2trJKZg+5EBjh4gGm3iU/t3onKlXHIg==
+ dependencies:
+ "@babel/runtime" "^7.15.4"
+ "@types/lodash" "^4.14.175"
+ lodash "^4.17.21"
+ lodash-es "^4.17.21"
+ nanoclone "^0.2.1"
+ property-expr "^2.0.4"
+ toposort "^2.0.2"
diff --git a/packages/uppy/.env.old b/packages/uppy/.env.old
new file mode 100644
index 0000000..af0355b
--- /dev/null
+++ b/packages/uppy/.env.old
@@ -0,0 +1,30 @@
+SESSION_SECRET=a9834jjajfajfiojaoejfbitco####$#iniswhigjlbutoonlyifyour8asl
+PORT=5000
+FILEPATH=/tmp
+HOST=http://localhost:5000
+UPLOAD_URLS=http://localhost:5000
+SECRET=afjafifjfjSHHHHHHdontdtouchtiafImS+____cared
+SERVER_BASE_URL=http://localhost:5000
+B2_ENDPOINT=s3.us-west-000.backblazeb2.com
+B2_BUCKET=fp-usc-dev
+B2_SECRET=K0004kP+ZfsINYsvWMGYdX66Gr5ZvIo
+B2_KEY=000d37f13a933b80000000034
+DRIVE_KEY=886031456924-jiuukhfte5n0cfkktevgojpum54dn6r3.apps.googleusercontent.com
+DRIVE_SECRET=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
+DROPBOX_KEY=zvaxniaf1gunns9
+DROPBOX_SECRET=cclglkkjkoqqo3v
+JWT_SECRET=GRYMjvirjfI6GxzkbNQMhg==
+STRAPI_API_KEY=9ad1b224cb399219cae910569875aa76ff2bd408db7e799653d4317198e326f04694abbecb31efc2d5b845c39e348940bb548b07ecf1d3fff07535d92df001700ce8dfea96dd3fd8a720c49f366761537f0042a74b4e35100b783f54be28e13086c96a1d437ff31c80568618ef94ef7de7ba3f8396651f2797ff2eb6091e1a7f
+STRAPI_URL=http://localhost:1337
+
+
+#B2_ENDPOINT=s3.us-west-000.backblazeb2.com
+#B2_BUCKET=futureporn-uppy
+#B2_SECRET=K000NRFAHCIWBYOhXa1QlabBzi5Puvk
+#B2_KEY=000d37f13a933b80000000025
+#B2_BUCKET=0d53c79f31b3ead983030b18
+#B2_KEY_ID=000d37f13a933b80000000025
+#B2_KEY_NAME=futureporn-uppy-2023-05-05
+#B2_APPLICATION_KEY=K000NRFAHCIWBYOhXa1QlabBzi5Puvk
+
+
diff --git a/packages/uppy/.env.production b/packages/uppy/.env.production
new file mode 100644
index 0000000..6184cfb
--- /dev/null
+++ b/packages/uppy/.env.production
@@ -0,0 +1,17 @@
+SESSION_SECRET=a9834jjajfajfiojaoejfbitco####$#iniswhigjlbutoonlyifyour8asl
+PORT=5000
+FILEPATH=/tmp
+HOST=https://uppy.futureporn.net
+UPLOAD_URLS=https://uppy.futureporn.net
+SECRET=afjafifjfjSHHHHHHdontdtouchtiafImS+____cared
+SERVER_BASE_URL=http://uppy.futureporn.net
+B2_ENDPOINT=s3.us-west-000.backblazeb2.com
+B2_BUCKET=futureporn
+B2_SECRET=K000euvnkS7IiMiCUQA3iCy/qxwwvLw
+B2_KEY=000d37f13a933b8000000002a
+DRIVE_KEY=886031456924-jiuukhfte5n0cfkktevgojpum54dn6r3.apps.googleusercontent.com
+DRIVE_SECRET=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
+DROPBOX_KEY=zvaxniaf1gunns9
+DROPBOX_SECRET=cclglkkjkoqqo3v
+JWT_SECRET=GRYMjvirjfI6GxzkbNQMhg==
+
diff --git a/packages/uppy/.gitignore b/packages/uppy/.gitignore
new file mode 100644
index 0000000..7610089
--- /dev/null
+++ b/packages/uppy/.gitignore
@@ -0,0 +1,145 @@
+# Created by https://www.toptal.com/developers/gitignore/api/node
+# Edit at https://www.toptal.com/developers/gitignore?templates=node
+
+### Node ###
+# Logs
+logs
+*.log
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+lerna-debug.log*
+.pnpm-debug.log*
+
+# Diagnostic reports (https://nodejs.org/api/report.html)
+report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
+
+# Runtime data
+pids
+*.pid
+*.seed
+*.pid.lock
+
+# Directory for instrumented libs generated by jscoverage/JSCover
+lib-cov
+
+# Coverage directory used by tools like istanbul
+coverage
+*.lcov
+
+# nyc test coverage
+.nyc_output
+
+# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
+.grunt
+
+# Bower dependency directory (https://bower.io/)
+bower_components
+
+# node-waf configuration
+.lock-wscript
+
+# Compiled binary addons (https://nodejs.org/api/addons.html)
+build/Release
+
+# Dependency directories
+node_modules/
+jspm_packages/
+
+# Snowpack dependency directory (https://snowpack.dev/)
+web_modules/
+
+# TypeScript cache
+*.tsbuildinfo
+
+# Optional npm cache directory
+.npm
+
+# Optional eslint cache
+.eslintcache
+
+# Optional stylelint cache
+.stylelintcache
+
+# Microbundle cache
+.rpt2_cache/
+.rts2_cache_cjs/
+.rts2_cache_es/
+.rts2_cache_umd/
+
+# Optional REPL history
+.node_repl_history
+
+# Output of 'npm pack'
+*.tgz
+
+# Yarn Integrity file
+.yarn-integrity
+
+# dotenv environment variable files
+.env
+.env.development.local
+.env.test.local
+.env.production.local
+.env.local
+
+# parcel-bundler cache (https://parceljs.org/)
+.cache
+.parcel-cache
+
+# Next.js build output
+.next
+out
+
+# Nuxt.js build / generate output
+.nuxt
+dist
+
+# Gatsby files
+.cache/
+# Comment in the public line in if your project uses Gatsby and not Next.js
+# https://nextjs.org/blog/next-9-1#public-directory-support
+# public
+
+# vuepress build output
+.vuepress/dist
+
+# vuepress v2.x temp and cache directory
+.temp
+
+# Docusaurus cache and generated files
+.docusaurus
+
+# Serverless directories
+.serverless/
+
+# FuseBox cache
+.fusebox/
+
+# DynamoDB Local files
+.dynamodb/
+
+# TernJS port file
+.tern-port
+
+# Stores VSCode versions used for testing VSCode extensions
+.vscode-test
+
+# yarn v2
+.yarn/cache
+.yarn/unplugged
+.yarn/build-state.yml
+.yarn/install-state.gz
+.pnp.*
+
+### Node Patch ###
+# Serverless Webpack directories
+.webpack/
+
+# Optional stylelint cache
+
+# SvelteKit build / generate output
+.svelte-kit
+
+# End of https://www.toptal.com/developers/gitignore/api/node
+
diff --git a/packages/uppy/Dockerfile b/packages/uppy/Dockerfile
new file mode 100644
index 0000000..e8c9e7e
--- /dev/null
+++ b/packages/uppy/Dockerfile
@@ -0,0 +1,15 @@
+FROM node:20-alpine as base
+ENV PNPM_HOME="/pnpm"
+ENV PATH="$PNPM_HOME:$PATH"
+WORKDIR /app
+RUN corepack enable
+
+FROM base as build
+COPY ./packages/uppy/package.json ./
+COPY ./packages/uppy/index.js ./
+RUN --mount=type=cache,id=pnpm,target=/pnpm/store pnpm install
+
+FROM build as run
+ENTRYPOINT ["pnpm"]
+CMD ["start"]
+
diff --git a/packages/uppy/README.md b/packages/uppy/README.md
new file mode 100644
index 0000000..0207a7b
--- /dev/null
+++ b/packages/uppy/README.md
@@ -0,0 +1,14 @@
+# fp-uppy
+
+## B2 Bucket CORS configuration
+
+Apply the rules to the bucket, using b2 CLI
+
+See **apply-backblaze-cors-rules.sh**
+
+Verify using `b2-linux get-bucket futureporn-uppy-dev`
+
+### Reference
+
+https://www.backblaze.com/docs/cloud-storage-enable-cors-with-the-cli
+https://uppy.io/docs/aws-s3-multipart/#setting-up-your-s3-bucket
\ No newline at end of file
diff --git a/packages/uppy/apply-backblaze-cors-rules.sh b/packages/uppy/apply-backblaze-cors-rules.sh
new file mode 100755
index 0000000..82b56c9
--- /dev/null
+++ b/packages/uppy/apply-backblaze-cors-rules.sh
@@ -0,0 +1,8 @@
+#/bin/bash
+
+source ../../.env
+echo "allowedOrigin ${NEXT_PUBLIC_SITE_URL} to bucket ${UPPY_B2_BUCKET}"
+b2-linux \
+ update-bucket \
+ --corsRules "[{\"corsRuleName\":\"allowUploads\", \"allowedOrigins\": [\"${NEXT_PUBLIC_SITE_URL}\"], \"allowedHeaders\": [\"*\"], \"allowedOperations\": [\"s3_head\", \"s3_get\", \"s3_put\"], \"exposeHeaders\": [\"x-bz-content-sha1\", \"etag\"], \"maxAgeSeconds\": 3600}]" \
+ "${UPPY_B2_BUCKET}" allPrivate
diff --git a/packages/uppy/index.js b/packages/uppy/index.js
new file mode 100644
index 0000000..c96d715
--- /dev/null
+++ b/packages/uppy/index.js
@@ -0,0 +1,124 @@
+#!/usr/bin/env node
+
+import dotenv from 'dotenv'
+dotenv.config()
+import express from 'express'
+import bodyParser from 'body-parser'
+import session from 'express-session'
+import companion from '@uppy/companion'
+import $MemoryStore from 'memorystore'
+import cors from 'cors'
+import jwt from 'jsonwebtoken'
+
+
+const appEnv = new Array(
+ 'SESSION_SECRET',
+ 'PORT',
+ 'FILEPATH',
+ 'UPLOAD_URLS',
+ 'SECRET',
+ 'B2_KEY',
+ 'B2_SECRET',
+ 'B2_BUCKET',
+ 'B2_ENDPOINT',
+ 'DRIVE_KEY',
+ 'DRIVE_SECRET',
+ 'DROPBOX_KEY',
+ 'DROPBOX_SECRET',
+ 'JWT_SECRET',
+ 'NEXT_PUBLIC_SITE_URL'
+)
+
+const appContext = {
+ env: appEnv.reduce((acc, ev) => {
+ if (typeof process.env[ev] === 'undefined') throw new Error(`${ev} is undefined in env`);
+ acc[ev] = process.env[ev];
+ return acc;
+ }, {})
+};
+
+
+const MemoryStore = $MemoryStore(session)
+
+console.log(`NEXT_PUBLIC_SITE_URL=${process.env.NEXT_PUBLIC_SITE_URL}`);
+const corsOptions = {
+ origin: process.env.NEXT_PUBLIC_SITE_URL,
+ methods: ['POST','OPTIONS'],
+ allowedHeaders: ['Authorization', 'X-Easter-Egg', 'Content-Type', 'Uppy-Versions', 'Accept'],
+ exposedHeaders: ['Access-Control-Allow-Headers']
+}
+
+
+const app = express();
+app.use(cors(corsOptions))
+app.use(bodyParser.json())
+app.use(
+ session({
+ store: new MemoryStore({
+ checkPeriod: 86400000 // prune expired entries every 24h
+ }),
+ saveUninitialized: false,
+ secret: process.env.SESSION_SECRET,
+ resave: false,
+ })
+)
+
+function verifyToken(req, res, next) {
+ const authHeader = req.headers['authorization'];
+ const token = authHeader && authHeader.split(' ')[1];
+
+ if (!token) {
+ return res.sendStatus(401);
+ }
+
+ jwt.verify(token, new Buffer.from(process.env.JWT_SECRET, 'base64'), (err, user) => {
+ if (err) {
+ return res.sendStatus(403);
+ }
+ req.user = user;
+ next();
+ });
+}
+
+
+const config = {
+ debug: true,
+ logClientVersion: true,
+ secret: process.env.SECRET,
+ filePath: process.env.FILEPATH,
+ server: {
+ host: process.env.HOST
+ },
+ uploadUrls: process.env.UPLOAD_URLS,
+ s3: {
+ key: process.env.B2_KEY,
+ secret: process.env.B2_SECRET,
+ bucket: process.env.B2_BUCKET,
+ region: process.env.B2_REGION,
+ endpoint: process.env.B2_ENDPOINT,
+ getAccelerateEndpoint: false
+ },
+ // providerOptions: {
+ // drive: {
+ // key: process.env.DRIVE_KEY,
+ // secret: process.env.DRIVE_SECRET,
+ // },
+ // dropbox: {
+ // key: process.env.DROPBOX_KEY,
+ // secret: process.env.DROPBOX_SECRET,
+ // },
+ // }
+}
+
+
+const { app: companionApp, emitter } = companion.app(config);
+
+
+app.use(verifyToken, companionApp);
+
+
+const server = app.listen(process.env.PORT)
+
+companion.socket(server)
+
+
diff --git a/packages/uppy/package.json b/packages/uppy/package.json
new file mode 100644
index 0000000..940d991
--- /dev/null
+++ b/packages/uppy/package.json
@@ -0,0 +1,31 @@
+{
+ "type": "module",
+ "name": "fp-uppy",
+ "version": "1.0.0",
+ "description": "",
+ "main": "index.js",
+ "scripts": {
+ "test": "echo \"Error: no test specified\" && exit 1",
+ "start": "node index",
+ "dev": "nodemon --watch **/*.js --watch .env --watch package.json index"
+ },
+ "keywords": [],
+ "author": "",
+ "license": "Unlicense",
+ "devDependencies": {
+ "nodemon": "^3.0.3"
+ },
+ "dependencies": {
+ "@uppy/aws-s3-multipart": "^2.0.0",
+ "@uppy/companion": "4.12.0",
+ "body-parser": "^1.20.2",
+ "cors": "^2.8.5",
+ "dotenv": "^16.3.1",
+ "express": "^4.18.2",
+ "express-session": "^1.17.3",
+ "jsonwebtoken": "^9.0.2",
+ "memorystore": "^1.6.7",
+ "react-hook-form": "^7.49.3",
+ "yup": "link:@hookform/resolvers/yup"
+ }
+}
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
new file mode 100644
index 0000000..e49835e
--- /dev/null
+++ b/pnpm-lock.yaml
@@ -0,0 +1,6817 @@
+lockfileVersion: '6.0'
+
+settings:
+ autoInstallPeers: true
+ excludeLinksFromLockfile: false
+
+importers:
+
+ packages/next:
+ dependencies:
+ '@fortawesome/fontawesome-free':
+ specifier: ^6.5.1
+ version: 6.5.1
+ '@fortawesome/fontawesome-svg-core':
+ specifier: ^6.5.1
+ version: 6.5.1
+ '@fortawesome/free-brands-svg-icons':
+ specifier: ^6.5.1
+ version: 6.5.1
+ '@fortawesome/free-solid-svg-icons':
+ specifier: ^6.5.1
+ version: 6.5.1
+ '@fortawesome/react-fontawesome':
+ specifier: ^0.2.0
+ version: 0.2.0(@fortawesome/fontawesome-svg-core@6.5.1)(react@18.2.0)
+ '@fullcalendar/core':
+ specifier: ^6.1.10
+ version: 6.1.10
+ '@fullcalendar/daygrid':
+ specifier: ^6.1.10
+ version: 6.1.10(@fullcalendar/core@6.1.10)
+ '@fullcalendar/interaction':
+ specifier: ^6.1.10
+ version: 6.1.10(@fullcalendar/core@6.1.10)
+ '@fullcalendar/multimonth':
+ specifier: ^6.1.10
+ version: 6.1.10(@fullcalendar/core@6.1.10)
+ '@fullcalendar/react':
+ specifier: ^6.1.10
+ version: 6.1.10(@fullcalendar/core@6.1.10)(react-dom@18.2.0)(react@18.2.0)
+ '@hookform/error-message':
+ specifier: ^2.0.1
+ version: 2.0.1(react-dom@18.2.0)(react-hook-form@7.49.3)(react@18.2.0)
+ '@hookform/resolvers':
+ specifier: ^3.3.4
+ version: 3.3.4(react-hook-form@7.49.3)
+ '@mux/blurhash':
+ specifier: ^0.1.2
+ version: 0.1.2
+ '@mux/mux-player':
+ specifier: ^2.3.1
+ version: 2.3.1
+ '@mux/mux-player-react':
+ specifier: ^2.3.1
+ version: 2.3.1(@types/react-dom@18.2.18)(@types/react@18.2.47)(react-dom@18.2.0)(react@18.2.0)
+ '@paralleldrive/cuid2':
+ specifier: ^2.2.2
+ version: 2.2.2
+ '@react-hookz/web':
+ specifier: ^24.0.2
+ version: 24.0.2(react-dom@18.2.0)(react@18.2.0)
+ '@types/lodash':
+ specifier: ^4.14.202
+ version: 4.14.202
+ '@types/qs':
+ specifier: ^6.9.11
+ version: 6.9.11
+ '@types/react':
+ specifier: ^18.2.47
+ version: 18.2.47
+ '@types/react-dom':
+ specifier: ^18.2.18
+ version: 18.2.18
+ '@uppy/aws-s3':
+ specifier: ^3.6.0
+ version: 3.6.0(@uppy/core@3.8.0)
+ '@uppy/aws-s3-multipart':
+ specifier: ^3.3.0
+ version: 3.10.0(@uppy/core@3.8.0)
+ '@uppy/core':
+ specifier: ^3.8.0
+ version: 3.8.0
+ '@uppy/dashboard':
+ specifier: ^3.7.1
+ version: 3.7.1(@uppy/core@3.8.0)
+ '@uppy/drag-drop':
+ specifier: ^3.0.3
+ version: 3.0.3(@uppy/core@3.8.0)
+ '@uppy/file-input':
+ specifier: ^3.0.4
+ version: 3.0.4(@uppy/core@3.8.0)
+ '@uppy/progress-bar':
+ specifier: ^3.0.4
+ version: 3.0.4(@uppy/core@3.8.0)
+ '@uppy/react':
+ specifier: ^3.2.1
+ version: 3.2.1(@uppy/core@3.8.0)(@uppy/dashboard@3.7.1)(@uppy/drag-drop@3.0.3)(@uppy/file-input@3.0.4)(@uppy/progress-bar@3.0.4)(react@18.2.0)
+ '@uppy/remote-sources':
+ specifier: ^1.1.0
+ version: 1.1.0(@uppy/core@3.8.0)
+ bulma:
+ specifier: ^0.9.4
+ version: 0.9.4
+ bulma-prefers-dark:
+ specifier: 0.1.0-beta.1
+ version: 0.1.0-beta.1
+ cal-heatmap:
+ specifier: ^4.2.4
+ version: 4.2.4
+ date-fns:
+ specifier: ^2.0.0
+ version: 2.30.0
+ date-fns-tz:
+ specifier: ^2.0.0
+ version: 2.0.0(date-fns@2.30.0)
+ dayjs:
+ specifier: ^1.11.10
+ version: 1.11.10
+ feed:
+ specifier: ^4.2.2
+ version: 4.2.2
+ gray-matter:
+ specifier: ^4.0.3
+ version: 4.0.3
+ hls.js:
+ specifier: ^1.5.1
+ version: 1.5.1
+ lodash:
+ specifier: ^4.17.21
+ version: 4.17.21
+ lunarphase-js:
+ specifier: ^2.0.1
+ version: 2.0.1
+ multiformats:
+ specifier: ^13.0.1
+ version: 13.0.1
+ next:
+ specifier: ^14.0.4
+ version: 14.0.4(react-dom@18.2.0)(react@18.2.0)(sass@1.69.7)
+ next-goatcounter:
+ specifier: ^1.0.5
+ version: 1.0.5(next@14.0.4)(react-dom@18.2.0)(react@18.2.0)
+ nextjs-toploader:
+ specifier: ^1.6.4
+ version: 1.6.4(next@14.0.4)(react-dom@18.2.0)(react@18.2.0)
+ plyr:
+ specifier: ^3.7.8
+ version: 3.7.8
+ plyr-react:
+ specifier: ^5.3.0
+ version: 5.3.0(plyr@3.7.8)(react@18.2.0)
+ prism-react-renderer:
+ specifier: ^2.3.1
+ version: 2.3.1(react@18.2.0)
+ qs:
+ specifier: ^6.11.2
+ version: 6.11.2
+ react:
+ specifier: ^18.2.0
+ version: 18.2.0
+ react-dom:
+ specifier: ^18.2.0
+ version: 18.2.0(react@18.2.0)
+ react-hook-form:
+ specifier: ^7.49.3
+ version: 7.49.3(react@18.2.0)
+ react-loading-skeleton:
+ specifier: ^3.3.1
+ version: 3.3.1(react@18.2.0)
+ react-toastify:
+ specifier: ^9.1.3
+ version: 9.1.3(react-dom@18.2.0)(react@18.2.0)
+ sass:
+ specifier: ^1.69.7
+ version: 1.69.7
+ sharp:
+ specifier: ^0.33.2
+ version: 0.33.2
+ slugify:
+ specifier: ^1.6.6
+ version: 1.6.6
+ yup:
+ specifier: ^1.3.3
+ version: 1.3.3
+ devDependencies:
+ '@types/node':
+ specifier: ^20.11.0
+ version: 20.11.0
+ eslint:
+ specifier: ^8.56.0
+ version: 8.56.0
+ eslint-config-next:
+ specifier: 14.0.4
+ version: 14.0.4(eslint@8.56.0)(typescript@5.3.3)
+ tsc:
+ specifier: ^2.0.4
+ version: 2.0.4
+ typescript:
+ specifier: 5.3.3
+ version: 5.3.3
+
+ packages/uppy:
+ dependencies:
+ '@uppy/aws-s3-multipart':
+ specifier: ^2.0.0
+ version: 2.4.3(@uppy/core@2.3.4)
+ '@uppy/companion':
+ specifier: 4.12.0
+ version: 4.12.0
+ body-parser:
+ specifier: ^1.20.2
+ version: 1.20.2
+ cors:
+ specifier: ^2.8.5
+ version: 2.8.5
+ dotenv:
+ specifier: ^16.3.1
+ version: 16.3.1
+ express:
+ specifier: ^4.18.2
+ version: 4.18.2
+ express-session:
+ specifier: ^1.17.3
+ version: 1.17.3
+ jsonwebtoken:
+ specifier: ^9.0.2
+ version: 9.0.2
+ memorystore:
+ specifier: ^1.6.7
+ version: 1.6.7
+ react-hook-form:
+ specifier: ^7.49.3
+ version: 7.49.3(react@18.2.0)
+ yup:
+ specifier: link:@hookform/resolvers/yup
+ version: link:@hookform/resolvers/yup
+ devDependencies:
+ nodemon:
+ specifier: ^3.0.3
+ version: 3.0.3
+
+packages:
+
+ /@aashutoshrathi/word-wrap@1.2.6:
+ resolution: {integrity: sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==}
+ engines: {node: '>=0.10.0'}
+ dev: true
+
+ /@aws-crypto/crc32@3.0.0:
+ resolution: {integrity: sha512-IzSgsrxUcsrejQbPVilIKy16kAT52EwB6zSaI+M3xxIhKh5+aldEyvI+z6erM7TCLB2BJsFrtHjp6/4/sr+3dA==}
+ dependencies:
+ '@aws-crypto/util': 3.0.0
+ '@aws-sdk/types': 3.489.0
+ tslib: 1.14.1
+ dev: false
+
+ /@aws-crypto/crc32c@3.0.0:
+ resolution: {integrity: sha512-ENNPPManmnVJ4BTXlOjAgD7URidbAznURqD0KvfREyc4o20DPYdEldU1f5cQ7Jbj0CJJSPaMIk/9ZshdB3210w==}
+ dependencies:
+ '@aws-crypto/util': 3.0.0
+ '@aws-sdk/types': 3.489.0
+ tslib: 1.14.1
+ dev: false
+
+ /@aws-crypto/ie11-detection@3.0.0:
+ resolution: {integrity: sha512-341lBBkiY1DfDNKai/wXM3aujNBkXR7tq1URPQDL9wi3AUbI80NR74uF1TXHMm7po1AcnFk8iu2S2IeU/+/A+Q==}
+ dependencies:
+ tslib: 1.14.1
+ dev: false
+
+ /@aws-crypto/sha1-browser@3.0.0:
+ resolution: {integrity: sha512-NJth5c997GLHs6nOYTzFKTbYdMNA6/1XlKVgnZoaZcQ7z7UJlOgj2JdbHE8tiYLS3fzXNCguct77SPGat2raSw==}
+ dependencies:
+ '@aws-crypto/ie11-detection': 3.0.0
+ '@aws-crypto/supports-web-crypto': 3.0.0
+ '@aws-crypto/util': 3.0.0
+ '@aws-sdk/types': 3.489.0
+ '@aws-sdk/util-locate-window': 3.465.0
+ '@aws-sdk/util-utf8-browser': 3.259.0
+ tslib: 1.14.1
+ dev: false
+
+ /@aws-crypto/sha256-browser@3.0.0:
+ resolution: {integrity: sha512-8VLmW2B+gjFbU5uMeqtQM6Nj0/F1bro80xQXCW6CQBWgosFWXTx77aeOF5CAIAmbOK64SdMBJdNr6J41yP5mvQ==}
+ dependencies:
+ '@aws-crypto/ie11-detection': 3.0.0
+ '@aws-crypto/sha256-js': 3.0.0
+ '@aws-crypto/supports-web-crypto': 3.0.0
+ '@aws-crypto/util': 3.0.0
+ '@aws-sdk/types': 3.489.0
+ '@aws-sdk/util-locate-window': 3.465.0
+ '@aws-sdk/util-utf8-browser': 3.259.0
+ tslib: 1.14.1
+ dev: false
+
+ /@aws-crypto/sha256-js@3.0.0:
+ resolution: {integrity: sha512-PnNN7os0+yd1XvXAy23CFOmTbMaDxgxXtTKHybrJ39Y8kGzBATgBFibWJKH6BhytLI/Zyszs87xCOBNyBig6vQ==}
+ dependencies:
+ '@aws-crypto/util': 3.0.0
+ '@aws-sdk/types': 3.489.0
+ tslib: 1.14.1
+ dev: false
+
+ /@aws-crypto/supports-web-crypto@3.0.0:
+ resolution: {integrity: sha512-06hBdMwUAb2WFTuGG73LSC0wfPu93xWwo5vL2et9eymgmu3Id5vFAHBbajVWiGhPO37qcsdCap/FqXvJGJWPIg==}
+ dependencies:
+ tslib: 1.14.1
+ dev: false
+
+ /@aws-crypto/util@3.0.0:
+ resolution: {integrity: sha512-2OJlpeJpCR48CC8r+uKVChzs9Iungj9wkZrl8Z041DWEWvyIHILYKCPNzJghKsivj+S3mLo6BVc7mBNzdxA46w==}
+ dependencies:
+ '@aws-sdk/types': 3.489.0
+ '@aws-sdk/util-utf8-browser': 3.259.0
+ tslib: 1.14.1
+ dev: false
+
+ /@aws-sdk/client-s3@3.490.0:
+ resolution: {integrity: sha512-fBj3CJ3+5R+l/sc93Z9mKw8gM2b9K6vEhC9qSCG2XNymLd9YqlRft1peQ7VymrWywAHX3Koz1GCUrFEVNONiMw==}
+ engines: {node: '>=14.0.0'}
+ dependencies:
+ '@aws-crypto/sha1-browser': 3.0.0
+ '@aws-crypto/sha256-browser': 3.0.0
+ '@aws-crypto/sha256-js': 3.0.0
+ '@aws-sdk/client-sts': 3.490.0
+ '@aws-sdk/core': 3.490.0
+ '@aws-sdk/credential-provider-node': 3.490.0
+ '@aws-sdk/middleware-bucket-endpoint': 3.489.0
+ '@aws-sdk/middleware-expect-continue': 3.489.0
+ '@aws-sdk/middleware-flexible-checksums': 3.489.0
+ '@aws-sdk/middleware-host-header': 3.489.0
+ '@aws-sdk/middleware-location-constraint': 3.489.0
+ '@aws-sdk/middleware-logger': 3.489.0
+ '@aws-sdk/middleware-recursion-detection': 3.489.0
+ '@aws-sdk/middleware-sdk-s3': 3.489.0
+ '@aws-sdk/middleware-signing': 3.489.0
+ '@aws-sdk/middleware-ssec': 3.489.0
+ '@aws-sdk/middleware-user-agent': 3.489.0
+ '@aws-sdk/region-config-resolver': 3.489.0
+ '@aws-sdk/signature-v4-multi-region': 3.489.0
+ '@aws-sdk/types': 3.489.0
+ '@aws-sdk/util-endpoints': 3.489.0
+ '@aws-sdk/util-user-agent-browser': 3.489.0
+ '@aws-sdk/util-user-agent-node': 3.489.0
+ '@aws-sdk/xml-builder': 3.485.0
+ '@smithy/config-resolver': 2.0.23
+ '@smithy/core': 1.2.2
+ '@smithy/eventstream-serde-browser': 2.0.16
+ '@smithy/eventstream-serde-config-resolver': 2.0.16
+ '@smithy/eventstream-serde-node': 2.0.16
+ '@smithy/fetch-http-handler': 2.3.2
+ '@smithy/hash-blob-browser': 2.0.17
+ '@smithy/hash-node': 2.0.18
+ '@smithy/hash-stream-node': 2.0.18
+ '@smithy/invalid-dependency': 2.0.16
+ '@smithy/md5-js': 2.0.18
+ '@smithy/middleware-content-length': 2.0.18
+ '@smithy/middleware-endpoint': 2.3.0
+ '@smithy/middleware-retry': 2.0.26
+ '@smithy/middleware-serde': 2.0.16
+ '@smithy/middleware-stack': 2.0.10
+ '@smithy/node-config-provider': 2.1.9
+ '@smithy/node-http-handler': 2.2.2
+ '@smithy/protocol-http': 3.0.12
+ '@smithy/smithy-client': 2.2.1
+ '@smithy/types': 2.8.0
+ '@smithy/url-parser': 2.0.16
+ '@smithy/util-base64': 2.0.1
+ '@smithy/util-body-length-browser': 2.0.1
+ '@smithy/util-body-length-node': 2.1.0
+ '@smithy/util-defaults-mode-browser': 2.0.24
+ '@smithy/util-defaults-mode-node': 2.0.32
+ '@smithy/util-endpoints': 1.0.8
+ '@smithy/util-retry': 2.0.9
+ '@smithy/util-stream': 2.0.24
+ '@smithy/util-utf8': 2.0.2
+ '@smithy/util-waiter': 2.0.16
+ fast-xml-parser: 4.2.5
+ tslib: 2.6.2
+ transitivePeerDependencies:
+ - aws-crt
+ dev: false
+
+ /@aws-sdk/client-sso@3.490.0:
+ resolution: {integrity: sha512-yfxoHmCL1w/IKmFRfzCxdVCQrGlSQf4eei9iVEm5oi3iE8REFyPj3o/BmKQEHG3h2ITK5UbdYDb5TY4xoYHsyA==}
+ engines: {node: '>=14.0.0'}
+ dependencies:
+ '@aws-crypto/sha256-browser': 3.0.0
+ '@aws-crypto/sha256-js': 3.0.0
+ '@aws-sdk/core': 3.490.0
+ '@aws-sdk/middleware-host-header': 3.489.0
+ '@aws-sdk/middleware-logger': 3.489.0
+ '@aws-sdk/middleware-recursion-detection': 3.489.0
+ '@aws-sdk/middleware-user-agent': 3.489.0
+ '@aws-sdk/region-config-resolver': 3.489.0
+ '@aws-sdk/types': 3.489.0
+ '@aws-sdk/util-endpoints': 3.489.0
+ '@aws-sdk/util-user-agent-browser': 3.489.0
+ '@aws-sdk/util-user-agent-node': 3.489.0
+ '@smithy/config-resolver': 2.0.23
+ '@smithy/core': 1.2.2
+ '@smithy/fetch-http-handler': 2.3.2
+ '@smithy/hash-node': 2.0.18
+ '@smithy/invalid-dependency': 2.0.16
+ '@smithy/middleware-content-length': 2.0.18
+ '@smithy/middleware-endpoint': 2.3.0
+ '@smithy/middleware-retry': 2.0.26
+ '@smithy/middleware-serde': 2.0.16
+ '@smithy/middleware-stack': 2.0.10
+ '@smithy/node-config-provider': 2.1.9
+ '@smithy/node-http-handler': 2.2.2
+ '@smithy/protocol-http': 3.0.12
+ '@smithy/smithy-client': 2.2.1
+ '@smithy/types': 2.8.0
+ '@smithy/url-parser': 2.0.16
+ '@smithy/util-base64': 2.0.1
+ '@smithy/util-body-length-browser': 2.0.1
+ '@smithy/util-body-length-node': 2.1.0
+ '@smithy/util-defaults-mode-browser': 2.0.24
+ '@smithy/util-defaults-mode-node': 2.0.32
+ '@smithy/util-endpoints': 1.0.8
+ '@smithy/util-retry': 2.0.9
+ '@smithy/util-utf8': 2.0.2
+ tslib: 2.6.2
+ transitivePeerDependencies:
+ - aws-crt
+ dev: false
+
+ /@aws-sdk/client-sts@3.490.0:
+ resolution: {integrity: sha512-n2vQ5Qu2qi2I0XMI+IH99ElpIRHOJTa1+sqNC4juMYxKQBMvw+EnsqUtaL3QvTHoyxNB/R7mpkeBB6SzPQ1TtA==}
+ engines: {node: '>=14.0.0'}
+ dependencies:
+ '@aws-crypto/sha256-browser': 3.0.0
+ '@aws-crypto/sha256-js': 3.0.0
+ '@aws-sdk/core': 3.490.0
+ '@aws-sdk/credential-provider-node': 3.490.0
+ '@aws-sdk/middleware-host-header': 3.489.0
+ '@aws-sdk/middleware-logger': 3.489.0
+ '@aws-sdk/middleware-recursion-detection': 3.489.0
+ '@aws-sdk/middleware-user-agent': 3.489.0
+ '@aws-sdk/region-config-resolver': 3.489.0
+ '@aws-sdk/types': 3.489.0
+ '@aws-sdk/util-endpoints': 3.489.0
+ '@aws-sdk/util-user-agent-browser': 3.489.0
+ '@aws-sdk/util-user-agent-node': 3.489.0
+ '@smithy/config-resolver': 2.0.23
+ '@smithy/core': 1.2.2
+ '@smithy/fetch-http-handler': 2.3.2
+ '@smithy/hash-node': 2.0.18
+ '@smithy/invalid-dependency': 2.0.16
+ '@smithy/middleware-content-length': 2.0.18
+ '@smithy/middleware-endpoint': 2.3.0
+ '@smithy/middleware-retry': 2.0.26
+ '@smithy/middleware-serde': 2.0.16
+ '@smithy/middleware-stack': 2.0.10
+ '@smithy/node-config-provider': 2.1.9
+ '@smithy/node-http-handler': 2.2.2
+ '@smithy/protocol-http': 3.0.12
+ '@smithy/smithy-client': 2.2.1
+ '@smithy/types': 2.8.0
+ '@smithy/url-parser': 2.0.16
+ '@smithy/util-base64': 2.0.1
+ '@smithy/util-body-length-browser': 2.0.1
+ '@smithy/util-body-length-node': 2.1.0
+ '@smithy/util-defaults-mode-browser': 2.0.24
+ '@smithy/util-defaults-mode-node': 2.0.32
+ '@smithy/util-endpoints': 1.0.8
+ '@smithy/util-middleware': 2.0.9
+ '@smithy/util-retry': 2.0.9
+ '@smithy/util-utf8': 2.0.2
+ fast-xml-parser: 4.2.5
+ tslib: 2.6.2
+ transitivePeerDependencies:
+ - aws-crt
+ dev: false
+
+ /@aws-sdk/core@3.490.0:
+ resolution: {integrity: sha512-TSBWkXtxMU7q1Zo6w3v5wIOr/sj7P5Jw3OyO7lJrFGsPsDC2xwpxkVqTesDxkzgMRypO52xjYEmveagn1xxBHg==}
+ engines: {node: '>=14.0.0'}
+ dependencies:
+ '@smithy/core': 1.2.2
+ '@smithy/protocol-http': 3.0.12
+ '@smithy/signature-v4': 2.0.19
+ '@smithy/smithy-client': 2.2.1
+ '@smithy/types': 2.8.0
+ tslib: 2.6.2
+ dev: false
+
+ /@aws-sdk/credential-provider-env@3.489.0:
+ resolution: {integrity: sha512-5PqYsx9G5SB2tqPT9/z/u0EkF6D4wP6HTMWQs+DfMdmwXihrqQAgeYaTtV3KbXqb88p6sfacwxhUvE6+Rm494w==}
+ engines: {node: '>=14.0.0'}
+ dependencies:
+ '@aws-sdk/types': 3.489.0
+ '@smithy/property-provider': 2.0.17
+ '@smithy/types': 2.8.0
+ tslib: 2.6.2
+ dev: false
+
+ /@aws-sdk/credential-provider-ini@3.490.0:
+ resolution: {integrity: sha512-7m63zyCpVqj9FsoDxWMWWRvL6c7zZzOcXYkHZmHujVVlmAXH0RT/vkXFkYgt+Ku+ov+v5NQrzwO5TmVoRt6O8g==}
+ engines: {node: '>=14.0.0'}
+ dependencies:
+ '@aws-sdk/credential-provider-env': 3.489.0
+ '@aws-sdk/credential-provider-process': 3.489.0
+ '@aws-sdk/credential-provider-sso': 3.490.0
+ '@aws-sdk/credential-provider-web-identity': 3.489.0
+ '@aws-sdk/types': 3.489.0
+ '@smithy/credential-provider-imds': 2.1.5
+ '@smithy/property-provider': 2.0.17
+ '@smithy/shared-ini-file-loader': 2.2.8
+ '@smithy/types': 2.8.0
+ tslib: 2.6.2
+ transitivePeerDependencies:
+ - aws-crt
+ dev: false
+
+ /@aws-sdk/credential-provider-node@3.490.0:
+ resolution: {integrity: sha512-Gh33u2O5Xbout8G3z/Z5H/CZzdG1ophxf/XS3iMFxA1cazQ7swY1UMmGvB7Lm7upvax5anXouItD1Ph3gzKc4w==}
+ engines: {node: '>=14.0.0'}
+ dependencies:
+ '@aws-sdk/credential-provider-env': 3.489.0
+ '@aws-sdk/credential-provider-ini': 3.490.0
+ '@aws-sdk/credential-provider-process': 3.489.0
+ '@aws-sdk/credential-provider-sso': 3.490.0
+ '@aws-sdk/credential-provider-web-identity': 3.489.0
+ '@aws-sdk/types': 3.489.0
+ '@smithy/credential-provider-imds': 2.1.5
+ '@smithy/property-provider': 2.0.17
+ '@smithy/shared-ini-file-loader': 2.2.8
+ '@smithy/types': 2.8.0
+ tslib: 2.6.2
+ transitivePeerDependencies:
+ - aws-crt
+ dev: false
+
+ /@aws-sdk/credential-provider-process@3.489.0:
+ resolution: {integrity: sha512-3vKQYJZ5cZYjy0870CPmbmKRBgATw2xCygxhn4m4UDCjOXVXcGUtYD51DMWsvBo3S0W8kH+FIJV4yuEDMFqLFQ==}
+ engines: {node: '>=14.0.0'}
+ dependencies:
+ '@aws-sdk/types': 3.489.0
+ '@smithy/property-provider': 2.0.17
+ '@smithy/shared-ini-file-loader': 2.2.8
+ '@smithy/types': 2.8.0
+ tslib: 2.6.2
+ dev: false
+
+ /@aws-sdk/credential-provider-sso@3.490.0:
+ resolution: {integrity: sha512-3UUBUoPbFvT58IhS4Vb23omYj/QPNkjgxu9p9ruQ3KSjLkanI4w8t/l/jljA65q83P7CoLnM5UKG9L7RA8/V1Q==}
+ engines: {node: '>=14.0.0'}
+ dependencies:
+ '@aws-sdk/client-sso': 3.490.0
+ '@aws-sdk/token-providers': 3.489.0
+ '@aws-sdk/types': 3.489.0
+ '@smithy/property-provider': 2.0.17
+ '@smithy/shared-ini-file-loader': 2.2.8
+ '@smithy/types': 2.8.0
+ tslib: 2.6.2
+ transitivePeerDependencies:
+ - aws-crt
+ dev: false
+
+ /@aws-sdk/credential-provider-web-identity@3.489.0:
+ resolution: {integrity: sha512-mjIuE2Wg1H/ds0nXQ/7vfusEDudmdd8YzKZI1y5O4n60iZZtyB2RNIECtvLMx1EQAKclidY7/06qQkArrGau5Q==}
+ engines: {node: '>=14.0.0'}
+ dependencies:
+ '@aws-sdk/types': 3.489.0
+ '@smithy/property-provider': 2.0.17
+ '@smithy/types': 2.8.0
+ tslib: 2.6.2
+ dev: false
+
+ /@aws-sdk/lib-storage@3.490.0(@aws-sdk/client-s3@3.490.0):
+ resolution: {integrity: sha512-JLRabk0bHzEd0G5RF+62/kyiIKSwrstW9WC0/CEvIfZbFbDPE4Ncd8q97YLUTFiIGDNsEcjW8DSbA6Feezcwhg==}
+ engines: {node: '>=14.0.0'}
+ peerDependencies:
+ '@aws-sdk/client-s3': ^3.0.0
+ dependencies:
+ '@aws-sdk/client-s3': 3.490.0
+ '@smithy/abort-controller': 2.0.16
+ '@smithy/middleware-endpoint': 2.3.0
+ '@smithy/smithy-client': 2.2.1
+ buffer: 5.6.0
+ events: 3.3.0
+ stream-browserify: 3.0.0
+ tslib: 2.6.2
+ dev: false
+
+ /@aws-sdk/middleware-bucket-endpoint@3.489.0:
+ resolution: {integrity: sha512-6rJ5bpNMKo7sEKQ6p2DMbQwM+ahMYASRxfdyH7hs18blvlcS20H1RYpNmJMqPPjxMwUWruty2JPMIRl4DFcv8w==}
+ engines: {node: '>=14.0.0'}
+ dependencies:
+ '@aws-sdk/types': 3.489.0
+ '@aws-sdk/util-arn-parser': 3.465.0
+ '@smithy/node-config-provider': 2.1.9
+ '@smithy/protocol-http': 3.0.12
+ '@smithy/types': 2.8.0
+ '@smithy/util-config-provider': 2.1.0
+ tslib: 2.6.2
+ dev: false
+
+ /@aws-sdk/middleware-expect-continue@3.489.0:
+ resolution: {integrity: sha512-2RZfnVZFaGHwzPDQJsyf9SXufu1gUd4VsMhm7dC7SWF85XmpDrozbFznS/tD22QdtyWjerLoydZJMq229hpPqg==}
+ engines: {node: '>=14.0.0'}
+ dependencies:
+ '@aws-sdk/types': 3.489.0
+ '@smithy/protocol-http': 3.0.12
+ '@smithy/types': 2.8.0
+ tslib: 2.6.2
+ dev: false
+
+ /@aws-sdk/middleware-flexible-checksums@3.489.0:
+ resolution: {integrity: sha512-Cy3rBUMr4P7raxzrJFWNRshfKrKV2EojawaC9Bfk/T8aFlV+FmVrRg4ISAXMOfS5pfy3xfAbvkzjOaeqCsGfrA==}
+ engines: {node: '>=14.0.0'}
+ dependencies:
+ '@aws-crypto/crc32': 3.0.0
+ '@aws-crypto/crc32c': 3.0.0
+ '@aws-sdk/types': 3.489.0
+ '@smithy/is-array-buffer': 2.0.0
+ '@smithy/protocol-http': 3.0.12
+ '@smithy/types': 2.8.0
+ '@smithy/util-utf8': 2.0.2
+ tslib: 2.6.2
+ dev: false
+
+ /@aws-sdk/middleware-host-header@3.489.0:
+ resolution: {integrity: sha512-Cl7HJ1jhOfllwf0CRx1eB4ypRGMqdGKWpc0eSTXty7wWSvCdMZUhwfjQqu2bIOIlgYxg/gFu6TVmVZ6g4O8PlA==}
+ engines: {node: '>=14.0.0'}
+ dependencies:
+ '@aws-sdk/types': 3.489.0
+ '@smithy/protocol-http': 3.0.12
+ '@smithy/types': 2.8.0
+ tslib: 2.6.2
+ dev: false
+
+ /@aws-sdk/middleware-location-constraint@3.489.0:
+ resolution: {integrity: sha512-NIVr+kHR2N6gxFeE3TNw2mEBxgj0N9xXBLy3dNYMMlAUvQlT/0z9HlC9+3XqcTS/Z5ElF/+pei6nqXTVt0He9A==}
+ engines: {node: '>=14.0.0'}
+ dependencies:
+ '@aws-sdk/types': 3.489.0
+ '@smithy/types': 2.8.0
+ tslib: 2.6.2
+ dev: false
+
+ /@aws-sdk/middleware-logger@3.489.0:
+ resolution: {integrity: sha512-+EVDnWese61MdImcBNAgz/AhTcIZJaska/xsU3GWU9CP905x4a4qZdB7fExFMDu1Jlz5pJqNteFYYHCFMJhHfg==}
+ engines: {node: '>=14.0.0'}
+ dependencies:
+ '@aws-sdk/types': 3.489.0
+ '@smithy/types': 2.8.0
+ tslib: 2.6.2
+ dev: false
+
+ /@aws-sdk/middleware-recursion-detection@3.489.0:
+ resolution: {integrity: sha512-m4rU+fTzziQcu9DKjRNZ4nQlXENEd2ZnJblJV4ONdWqqEjbmOgOj3P6aCCQlJdIbzuNvX1FBOZ5tY59ZpERo7Q==}
+ engines: {node: '>=14.0.0'}
+ dependencies:
+ '@aws-sdk/types': 3.489.0
+ '@smithy/protocol-http': 3.0.12
+ '@smithy/types': 2.8.0
+ tslib: 2.6.2
+ dev: false
+
+ /@aws-sdk/middleware-sdk-s3@3.489.0:
+ resolution: {integrity: sha512-/GGASx7mK9qEgy1znvleYMZKVqm3sOdGghqKdy2zgoGcH2jH+fZrLM0lDMT9bvdITmOCbJJs2rVHP3xm/ZWcXg==}
+ engines: {node: '>=14.0.0'}
+ dependencies:
+ '@aws-sdk/types': 3.489.0
+ '@aws-sdk/util-arn-parser': 3.465.0
+ '@smithy/node-config-provider': 2.1.9
+ '@smithy/protocol-http': 3.0.12
+ '@smithy/signature-v4': 2.0.19
+ '@smithy/smithy-client': 2.2.1
+ '@smithy/types': 2.8.0
+ '@smithy/util-config-provider': 2.1.0
+ tslib: 2.6.2
+ dev: false
+
+ /@aws-sdk/middleware-signing@3.489.0:
+ resolution: {integrity: sha512-rlHcWYZn6Ym3v/u0DvKNDiD7ogIzEsHlerm0lowTiQbszkFobOiUClRTALwvsUZdAAztl706qO1OKbnGnD6Ubw==}
+ engines: {node: '>=14.0.0'}
+ dependencies:
+ '@aws-sdk/types': 3.489.0
+ '@smithy/property-provider': 2.0.17
+ '@smithy/protocol-http': 3.0.12
+ '@smithy/signature-v4': 2.0.19
+ '@smithy/types': 2.8.0
+ '@smithy/util-middleware': 2.0.9
+ tslib: 2.6.2
+ dev: false
+
+ /@aws-sdk/middleware-ssec@3.489.0:
+ resolution: {integrity: sha512-5RQg8dqERAmi1OfVEV9fbTA5NKmcvKDYP79YtH08IEFIsHWU1Y5NoqL7mXkkNyBrJNBVyasYijAbTzOuM707eg==}
+ engines: {node: '>=14.0.0'}
+ dependencies:
+ '@aws-sdk/types': 3.489.0
+ '@smithy/types': 2.8.0
+ tslib: 2.6.2
+ dev: false
+
+ /@aws-sdk/middleware-user-agent@3.489.0:
+ resolution: {integrity: sha512-M54Cv2fAN3GGgdfUjLtZ4wFUIrfM/ivbXv4DgpcNsacEQ2g4H+weQgKp41X7XZW8MWAzl+k1zJaryK69RYNQkQ==}
+ engines: {node: '>=14.0.0'}
+ dependencies:
+ '@aws-sdk/types': 3.489.0
+ '@aws-sdk/util-endpoints': 3.489.0
+ '@smithy/protocol-http': 3.0.12
+ '@smithy/types': 2.8.0
+ tslib: 2.6.2
+ dev: false
+
+ /@aws-sdk/region-config-resolver@3.489.0:
+ resolution: {integrity: sha512-UvrnB78XTz9ddby7mr0vuUHn2MO3VTjzaIu+GQhyedMGQU0QlIQrYOlzbbu4LC5rL1O8FxFLUxRe/AAjgwyuGw==}
+ engines: {node: '>=14.0.0'}
+ dependencies:
+ '@aws-sdk/types': 3.489.0
+ '@smithy/node-config-provider': 2.1.9
+ '@smithy/types': 2.8.0
+ '@smithy/util-config-provider': 2.1.0
+ '@smithy/util-middleware': 2.0.9
+ tslib: 2.6.2
+ dev: false
+
+ /@aws-sdk/s3-presigned-post@3.490.0:
+ resolution: {integrity: sha512-0jHY5hLqcSxQJAqgzuTHgc13Nebel6XOOA6Fovtw+1u0s3+5bSAY6wSNq+d4vQFN8sd+74givjDtC4gqitQR8Q==}
+ engines: {node: '>=14.0.0'}
+ dependencies:
+ '@aws-sdk/client-s3': 3.490.0
+ '@aws-sdk/types': 3.489.0
+ '@aws-sdk/util-format-url': 3.489.0
+ '@smithy/middleware-endpoint': 2.3.0
+ '@smithy/signature-v4': 2.0.19
+ '@smithy/types': 2.8.0
+ '@smithy/util-hex-encoding': 2.0.0
+ '@smithy/util-utf8': 2.0.2
+ tslib: 2.6.2
+ transitivePeerDependencies:
+ - aws-crt
+ dev: false
+
+ /@aws-sdk/s3-request-presigner@3.490.0:
+ resolution: {integrity: sha512-ZHs+FlcTv9MKMM0b9svxxQio4FiRxDNstKYG8sbm9YEoahYV25h3K3butUiThaiOeYePOD7jHdbdXz4/XasxXg==}
+ engines: {node: '>=14.0.0'}
+ dependencies:
+ '@aws-sdk/signature-v4-multi-region': 3.489.0
+ '@aws-sdk/types': 3.489.0
+ '@aws-sdk/util-format-url': 3.489.0
+ '@smithy/middleware-endpoint': 2.3.0
+ '@smithy/protocol-http': 3.0.12
+ '@smithy/smithy-client': 2.2.1
+ '@smithy/types': 2.8.0
+ tslib: 2.6.2
+ dev: false
+
+ /@aws-sdk/signature-v4-multi-region@3.489.0:
+ resolution: {integrity: sha512-kYFM7Opu36EkFlzXdVNOBFpQApgnuaTu/U/qYhGyuzeD+HNnYgZEsd/tDro1DQ074jVy3GN9ttJSYxq5I4oTkA==}
+ engines: {node: '>=14.0.0'}
+ dependencies:
+ '@aws-sdk/middleware-sdk-s3': 3.489.0
+ '@aws-sdk/types': 3.489.0
+ '@smithy/protocol-http': 3.0.12
+ '@smithy/signature-v4': 2.0.19
+ '@smithy/types': 2.8.0
+ tslib: 2.6.2
+ dev: false
+
+ /@aws-sdk/token-providers@3.489.0:
+ resolution: {integrity: sha512-hSgjB8CMQoA8EIQ0ripDjDtbBcWDSa+7vSBYPIzksyknaGERR/GUfGXLV2dpm5t17FgFG6irT5f3ZlBzarL8Dw==}
+ engines: {node: '>=14.0.0'}
+ dependencies:
+ '@aws-crypto/sha256-browser': 3.0.0
+ '@aws-crypto/sha256-js': 3.0.0
+ '@aws-sdk/middleware-host-header': 3.489.0
+ '@aws-sdk/middleware-logger': 3.489.0
+ '@aws-sdk/middleware-recursion-detection': 3.489.0
+ '@aws-sdk/middleware-user-agent': 3.489.0
+ '@aws-sdk/region-config-resolver': 3.489.0
+ '@aws-sdk/types': 3.489.0
+ '@aws-sdk/util-endpoints': 3.489.0
+ '@aws-sdk/util-user-agent-browser': 3.489.0
+ '@aws-sdk/util-user-agent-node': 3.489.0
+ '@smithy/config-resolver': 2.0.23
+ '@smithy/fetch-http-handler': 2.3.2
+ '@smithy/hash-node': 2.0.18
+ '@smithy/invalid-dependency': 2.0.16
+ '@smithy/middleware-content-length': 2.0.18
+ '@smithy/middleware-endpoint': 2.3.0
+ '@smithy/middleware-retry': 2.0.26
+ '@smithy/middleware-serde': 2.0.16
+ '@smithy/middleware-stack': 2.0.10
+ '@smithy/node-config-provider': 2.1.9
+ '@smithy/node-http-handler': 2.2.2
+ '@smithy/property-provider': 2.0.17
+ '@smithy/protocol-http': 3.0.12
+ '@smithy/shared-ini-file-loader': 2.2.8
+ '@smithy/smithy-client': 2.2.1
+ '@smithy/types': 2.8.0
+ '@smithy/url-parser': 2.0.16
+ '@smithy/util-base64': 2.0.1
+ '@smithy/util-body-length-browser': 2.0.1
+ '@smithy/util-body-length-node': 2.1.0
+ '@smithy/util-defaults-mode-browser': 2.0.24
+ '@smithy/util-defaults-mode-node': 2.0.32
+ '@smithy/util-endpoints': 1.0.8
+ '@smithy/util-retry': 2.0.9
+ '@smithy/util-utf8': 2.0.2
+ tslib: 2.6.2
+ transitivePeerDependencies:
+ - aws-crt
+ dev: false
+
+ /@aws-sdk/types@3.489.0:
+ resolution: {integrity: sha512-kcDtLfKog/p0tC4gAeqJqWxAiEzfe2LRPnKamvSG2Mjbthx4R/alE2dxyIq/wW+nvRv0fqR3OD5kD1+eVfdr/w==}
+ engines: {node: '>=14.0.0'}
+ dependencies:
+ '@smithy/types': 2.8.0
+ tslib: 2.6.2
+ dev: false
+
+ /@aws-sdk/util-arn-parser@3.465.0:
+ resolution: {integrity: sha512-zOJ82vzDJFqBX9yZBlNeHHrul/kpx/DCoxzW5UBbZeb26kfV53QhMSoEmY8/lEbBqlqargJ/sgRC845GFhHNQw==}
+ engines: {node: '>=14.0.0'}
+ dependencies:
+ tslib: 2.6.2
+ dev: false
+
+ /@aws-sdk/util-endpoints@3.489.0:
+ resolution: {integrity: sha512-uGyG1u84ATX03mf7bT4xD9XD/vlYJGD5+RxMN/UpzeTfzXfh+jvCQWbOQ44z8ttFJWYQQqrLxkfpF/JgvALzLA==}
+ engines: {node: '>=14.0.0'}
+ dependencies:
+ '@aws-sdk/types': 3.489.0
+ '@smithy/types': 2.8.0
+ '@smithy/util-endpoints': 1.0.8
+ tslib: 2.6.2
+ dev: false
+
+ /@aws-sdk/util-format-url@3.489.0:
+ resolution: {integrity: sha512-yqIf9RMdOSxMUrv1BVDmrYp5kjLh4RxA17BTqzcQK8cXkRBqBP8ydbCQXENSv8LZSMH7AnrXNHBD1eiVuKRzZw==}
+ engines: {node: '>=14.0.0'}
+ dependencies:
+ '@aws-sdk/types': 3.489.0
+ '@smithy/querystring-builder': 2.0.16
+ '@smithy/types': 2.8.0
+ tslib: 2.6.2
+ dev: false
+
+ /@aws-sdk/util-locate-window@3.465.0:
+ resolution: {integrity: sha512-f+QNcWGswredzC1ExNAB/QzODlxwaTdXkNT5cvke2RLX8SFU5pYk6h4uCtWC0vWPELzOfMfloBrJefBzlarhsw==}
+ engines: {node: '>=14.0.0'}
+ dependencies:
+ tslib: 2.6.2
+ dev: false
+
+ /@aws-sdk/util-user-agent-browser@3.489.0:
+ resolution: {integrity: sha512-85B9KMsuMpAZauzWQ16r52ZBAHYnznW6BVitnBglsibN7oJKn10Hggt4QGuRhvQFCxQ8YhvBl7r+vQGFO4hxIw==}
+ dependencies:
+ '@aws-sdk/types': 3.489.0
+ '@smithy/types': 2.8.0
+ bowser: 2.11.0
+ tslib: 2.6.2
+ dev: false
+
+ /@aws-sdk/util-user-agent-node@3.489.0:
+ resolution: {integrity: sha512-CYdkBHig8sFNc0dv11Ni9WXvZQHeI5+z77OrDHKkbidFx/V4BDTuwZw4K1vWg62pzFOEfzunJFiULRcDZWJR3w==}
+ engines: {node: '>=14.0.0'}
+ peerDependencies:
+ aws-crt: '>=1.0.0'
+ peerDependenciesMeta:
+ aws-crt:
+ optional: true
+ dependencies:
+ '@aws-sdk/types': 3.489.0
+ '@smithy/node-config-provider': 2.1.9
+ '@smithy/types': 2.8.0
+ tslib: 2.6.2
+ dev: false
+
+ /@aws-sdk/util-utf8-browser@3.259.0:
+ resolution: {integrity: sha512-UvFa/vR+e19XookZF8RzFZBrw2EUkQWxiBW0yYQAhvk3C+QVGl0H3ouca8LDBlBfQKXwmW3huo/59H8rwb1wJw==}
+ dependencies:
+ tslib: 2.6.2
+ dev: false
+
+ /@aws-sdk/xml-builder@3.485.0:
+ resolution: {integrity: sha512-xQexPM6LINOIkf3NLFywplcbApifZRMWFN41TDWYSNgCUa5uC9fntfenw8N/HTx1n+McRCWSAFBTjDqY/2OLCQ==}
+ engines: {node: '>=14.0.0'}
+ dependencies:
+ '@smithy/types': 2.8.0
+ tslib: 2.6.2
+ dev: false
+
+ /@babel/runtime@7.23.8:
+ resolution: {integrity: sha512-Y7KbAP984rn1VGMbGqKmBLio9V7y5Je9GvU4rQPCPinCyNfUcToxIXl06d59URp/F3LwinvODxab5N/G6qggkw==}
+ engines: {node: '>=6.9.0'}
+ dependencies:
+ regenerator-runtime: 0.14.1
+
+ /@emnapi/runtime@0.45.0:
+ resolution: {integrity: sha512-Txumi3td7J4A/xTTwlssKieHKTGl3j4A1tglBx72auZ49YK7ePY6XZricgIg9mnZT4xPfA+UPCUdnhRuEFDL+w==}
+ requiresBuild: true
+ dependencies:
+ tslib: 2.6.2
+ dev: false
+ optional: true
+
+ /@eslint-community/eslint-utils@4.4.0(eslint@8.56.0):
+ resolution: {integrity: sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==}
+ engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+ peerDependencies:
+ eslint: ^6.0.0 || ^7.0.0 || >=8.0.0
+ dependencies:
+ eslint: 8.56.0
+ eslint-visitor-keys: 3.4.3
+ dev: true
+
+ /@eslint-community/regexpp@4.10.0:
+ resolution: {integrity: sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==}
+ engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0}
+ dev: true
+
+ /@eslint/eslintrc@2.1.4:
+ resolution: {integrity: sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==}
+ engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+ dependencies:
+ ajv: 6.12.6
+ debug: 4.3.4(supports-color@5.5.0)
+ espree: 9.6.1
+ globals: 13.24.0
+ ignore: 5.3.0
+ import-fresh: 3.3.0
+ js-yaml: 4.1.0
+ minimatch: 3.1.2
+ strip-json-comments: 3.1.1
+ transitivePeerDependencies:
+ - supports-color
+ dev: true
+
+ /@eslint/js@8.56.0:
+ resolution: {integrity: sha512-gMsVel9D7f2HLkBma9VbtzZRehRogVRfbr++f06nL2vnCGCNlzOD+/MUov/F4p8myyAHspEhVobgjpX64q5m6A==}
+ engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+ dev: true
+
+ /@fortawesome/fontawesome-common-types@6.5.1:
+ resolution: {integrity: sha512-GkWzv+L6d2bI5f/Vk6ikJ9xtl7dfXtoRu3YGE6nq0p/FFqA1ebMOAWg3XgRyb0I6LYyYkiAo+3/KrwuBp8xG7A==}
+ engines: {node: '>=6'}
+ requiresBuild: true
+ dev: false
+
+ /@fortawesome/fontawesome-free@6.5.1:
+ resolution: {integrity: sha512-CNy5vSwN3fsUStPRLX7fUYojyuzoEMSXPl7zSLJ8TgtRfjv24LOnOWKT2zYwaHZCJGkdyRnTmstR0P+Ah503Gw==}
+ engines: {node: '>=6'}
+ requiresBuild: true
+ dev: false
+
+ /@fortawesome/fontawesome-svg-core@6.5.1:
+ resolution: {integrity: sha512-MfRCYlQPXoLlpem+egxjfkEuP9UQswTrlCOsknus/NcMoblTH2g0jPrapbcIb04KGA7E2GZxbAccGZfWoYgsrQ==}
+ engines: {node: '>=6'}
+ requiresBuild: true
+ dependencies:
+ '@fortawesome/fontawesome-common-types': 6.5.1
+ dev: false
+
+ /@fortawesome/free-brands-svg-icons@6.5.1:
+ resolution: {integrity: sha512-093l7DAkx0aEtBq66Sf19MgoZewv1zeY9/4C7vSKPO4qMwEsW/2VYTUTpBtLwfb9T2R73tXaRDPmE4UqLCYHfg==}
+ engines: {node: '>=6'}
+ requiresBuild: true
+ dependencies:
+ '@fortawesome/fontawesome-common-types': 6.5.1
+ dev: false
+
+ /@fortawesome/free-solid-svg-icons@6.5.1:
+ resolution: {integrity: sha512-S1PPfU3mIJa59biTtXJz1oI0+KAXW6bkAb31XKhxdxtuXDiUIFsih4JR1v5BbxY7hVHsD1RKq+jRkVRaf773NQ==}
+ engines: {node: '>=6'}
+ requiresBuild: true
+ dependencies:
+ '@fortawesome/fontawesome-common-types': 6.5.1
+ dev: false
+
+ /@fortawesome/react-fontawesome@0.2.0(@fortawesome/fontawesome-svg-core@6.5.1)(react@18.2.0):
+ resolution: {integrity: sha512-uHg75Rb/XORTtVt7OS9WoK8uM276Ufi7gCzshVWkUJbHhh3svsUUeqXerrM96Wm7fRiDzfKRwSoahhMIkGAYHw==}
+ peerDependencies:
+ '@fortawesome/fontawesome-svg-core': ~1 || ~6
+ react: '>=16.3'
+ dependencies:
+ '@fortawesome/fontawesome-svg-core': 6.5.1
+ prop-types: 15.8.1
+ react: 18.2.0
+ dev: false
+
+ /@fullcalendar/core@6.1.10:
+ resolution: {integrity: sha512-oTXGJSAGpCf1oY+CKp5qYjMHkJCPBkJ3SHitl63n8Q6xKeiwQ4EF6Au451euUovREwJpLmD1AyZrCnWmtB9AVg==}
+ dependencies:
+ preact: 10.12.1
+ dev: false
+
+ /@fullcalendar/daygrid@6.1.10(@fullcalendar/core@6.1.10):
+ resolution: {integrity: sha512-Z4GRm1IyHKgxXFTWGcEI0nTsvYOIkpE0aMt3/o3ER2SZkF+hfwcDFhtj0c9+WhMjXFIWYeoTnA9rUOY7Zl/nxA==}
+ peerDependencies:
+ '@fullcalendar/core': ~6.1.10
+ dependencies:
+ '@fullcalendar/core': 6.1.10
+ dev: false
+
+ /@fullcalendar/interaction@6.1.10(@fullcalendar/core@6.1.10):
+ resolution: {integrity: sha512-aZRlwCpmDasq2RNeWV0ub20Uevare9Cb6iMlxCacx0fhOC14H28G9d1FsduJIecInL84SPGwt5ItqAYMsWv7zw==}
+ peerDependencies:
+ '@fullcalendar/core': ~6.1.10
+ dependencies:
+ '@fullcalendar/core': 6.1.10
+ dev: false
+
+ /@fullcalendar/multimonth@6.1.10(@fullcalendar/core@6.1.10):
+ resolution: {integrity: sha512-mLGEgD+sv8rNfKphyOCWRQapX7/nAvHgQmDTjuy4STlhHsddCYVmFlsSgF373ph1tXh41wAJUVdNO/pDmCvUfA==}
+ peerDependencies:
+ '@fullcalendar/core': ~6.1.10
+ dependencies:
+ '@fullcalendar/core': 6.1.10
+ '@fullcalendar/daygrid': 6.1.10(@fullcalendar/core@6.1.10)
+ dev: false
+
+ /@fullcalendar/react@6.1.10(@fullcalendar/core@6.1.10)(react-dom@18.2.0)(react@18.2.0):
+ resolution: {integrity: sha512-RVYevo5T4RUZzR8omlbnBwRCqVNJWKryzI0ZrFULyqIYggN6uPmMuB9GvbrTjDfKhsm438KQwwhJerg2lGh3xA==}
+ peerDependencies:
+ '@fullcalendar/core': ~6.1.10
+ react: ^16.7.0 || ^17 || ^18
+ react-dom: ^16.7.0 || ^17 || ^18
+ dependencies:
+ '@fullcalendar/core': 6.1.10
+ react: 18.2.0
+ react-dom: 18.2.0(react@18.2.0)
+ dev: false
+
+ /@hookform/error-message@2.0.1(react-dom@18.2.0)(react-hook-form@7.49.3)(react@18.2.0):
+ resolution: {integrity: sha512-U410sAr92xgxT1idlu9WWOVjndxLdgPUHEB8Schr27C9eh7/xUnITWpCMF93s+lGiG++D4JnbSnrb5A21AdSNg==}
+ peerDependencies:
+ react: '>=16.8.0'
+ react-dom: '>=16.8.0'
+ react-hook-form: ^7.0.0
+ dependencies:
+ react: 18.2.0
+ react-dom: 18.2.0(react@18.2.0)
+ react-hook-form: 7.49.3(react@18.2.0)
+ dev: false
+
+ /@hookform/resolvers@3.3.4(react-hook-form@7.49.3):
+ resolution: {integrity: sha512-o5cgpGOuJYrd+iMKvkttOclgwRW86EsWJZZRC23prf0uU2i48Htq4PuT73AVb9ionFyZrwYEITuOFGF+BydEtQ==}
+ peerDependencies:
+ react-hook-form: ^7.0.0
+ dependencies:
+ react-hook-form: 7.49.3(react@18.2.0)
+ dev: false
+
+ /@humanwhocodes/config-array@0.11.14:
+ resolution: {integrity: sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==}
+ engines: {node: '>=10.10.0'}
+ dependencies:
+ '@humanwhocodes/object-schema': 2.0.2
+ debug: 4.3.4(supports-color@5.5.0)
+ minimatch: 3.1.2
+ transitivePeerDependencies:
+ - supports-color
+ dev: true
+
+ /@humanwhocodes/module-importer@1.0.1:
+ resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==}
+ engines: {node: '>=12.22'}
+ dev: true
+
+ /@humanwhocodes/object-schema@2.0.2:
+ resolution: {integrity: sha512-6EwiSjwWYP7pTckG6I5eyFANjPhmPjUX9JRLUSfNPC7FX7zK9gyZAfUEaECL6ALTpGX5AjnBq3C9XmVWPitNpw==}
+ dev: true
+
+ /@img/sharp-darwin-arm64@0.33.2:
+ resolution: {integrity: sha512-itHBs1rPmsmGF9p4qRe++CzCgd+kFYktnsoR1sbIAfsRMrJZau0Tt1AH9KVnufc2/tU02Gf6Ibujx+15qRE03w==}
+ engines: {glibc: '>=2.26', node: ^18.17.0 || ^20.3.0 || >=21.0.0, npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'}
+ cpu: [arm64]
+ os: [darwin]
+ requiresBuild: true
+ optionalDependencies:
+ '@img/sharp-libvips-darwin-arm64': 1.0.1
+ dev: false
+ optional: true
+
+ /@img/sharp-darwin-x64@0.33.2:
+ resolution: {integrity: sha512-/rK/69Rrp9x5kaWBjVN07KixZanRr+W1OiyKdXcbjQD6KbW+obaTeBBtLUAtbBsnlTTmWthw99xqoOS7SsySDg==}
+ engines: {glibc: '>=2.26', node: ^18.17.0 || ^20.3.0 || >=21.0.0, npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'}
+ cpu: [x64]
+ os: [darwin]
+ requiresBuild: true
+ optionalDependencies:
+ '@img/sharp-libvips-darwin-x64': 1.0.1
+ dev: false
+ optional: true
+
+ /@img/sharp-libvips-darwin-arm64@1.0.1:
+ resolution: {integrity: sha512-kQyrSNd6lmBV7O0BUiyu/OEw9yeNGFbQhbxswS1i6rMDwBBSX+e+rPzu3S+MwAiGU3HdLze3PanQ4Xkfemgzcw==}
+ engines: {macos: '>=11', npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'}
+ cpu: [arm64]
+ os: [darwin]
+ requiresBuild: true
+ dev: false
+ optional: true
+
+ /@img/sharp-libvips-darwin-x64@1.0.1:
+ resolution: {integrity: sha512-eVU/JYLPVjhhrd8Tk6gosl5pVlvsqiFlt50wotCvdkFGf+mDNBJxMh+bvav+Wt3EBnNZWq8Sp2I7XfSjm8siog==}
+ engines: {macos: '>=10.13', npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'}
+ cpu: [x64]
+ os: [darwin]
+ requiresBuild: true
+ dev: false
+ optional: true
+
+ /@img/sharp-libvips-linux-arm64@1.0.1:
+ resolution: {integrity: sha512-bnGG+MJjdX70mAQcSLxgeJco11G+MxTz+ebxlz8Y3dxyeb3Nkl7LgLI0mXupoO+u1wRNx/iRj5yHtzA4sde1yA==}
+ engines: {glibc: '>=2.26', npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'}
+ cpu: [arm64]
+ os: [linux]
+ requiresBuild: true
+ dev: false
+ optional: true
+
+ /@img/sharp-libvips-linux-arm@1.0.1:
+ resolution: {integrity: sha512-FtdMvR4R99FTsD53IA3LxYGghQ82t3yt0ZQ93WMZ2xV3dqrb0E8zq4VHaTOuLEAuA83oDawHV3fd+BsAPadHIQ==}
+ engines: {glibc: '>=2.28', npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'}
+ cpu: [arm]
+ os: [linux]
+ requiresBuild: true
+ dev: false
+ optional: true
+
+ /@img/sharp-libvips-linux-s390x@1.0.1:
+ resolution: {integrity: sha512-3+rzfAR1YpMOeA2zZNp+aYEzGNWK4zF3+sdMxuCS3ey9HhDbJ66w6hDSHDMoap32DueFwhhs3vwooAB2MaK4XQ==}
+ engines: {glibc: '>=2.28', npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'}
+ cpu: [s390x]
+ os: [linux]
+ requiresBuild: true
+ dev: false
+ optional: true
+
+ /@img/sharp-libvips-linux-x64@1.0.1:
+ resolution: {integrity: sha512-3NR1mxFsaSgMMzz1bAnnKbSAI+lHXVTqAHgc1bgzjHuXjo4hlscpUxc0vFSAPKI3yuzdzcZOkq7nDPrP2F8Jgw==}
+ engines: {glibc: '>=2.26', npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'}
+ cpu: [x64]
+ os: [linux]
+ requiresBuild: true
+ dev: false
+ optional: true
+
+ /@img/sharp-libvips-linuxmusl-arm64@1.0.1:
+ resolution: {integrity: sha512-5aBRcjHDG/T6jwC3Edl3lP8nl9U2Yo8+oTl5drd1dh9Z1EBfzUKAJFUDTDisDjUwc7N4AjnPGfCA3jl3hY8uDg==}
+ engines: {musl: '>=1.2.2', npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'}
+ cpu: [arm64]
+ os: [linux]
+ requiresBuild: true
+ dev: false
+ optional: true
+
+ /@img/sharp-libvips-linuxmusl-x64@1.0.1:
+ resolution: {integrity: sha512-dcT7inI9DBFK6ovfeWRe3hG30h51cBAP5JXlZfx6pzc/Mnf9HFCQDLtYf4MCBjxaaTfjCCjkBxcy3XzOAo5txw==}
+ engines: {musl: '>=1.2.2', npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'}
+ cpu: [x64]
+ os: [linux]
+ requiresBuild: true
+ dev: false
+ optional: true
+
+ /@img/sharp-linux-arm64@0.33.2:
+ resolution: {integrity: sha512-pz0NNo882vVfqJ0yNInuG9YH71smP4gRSdeL09ukC2YLE6ZyZePAlWKEHgAzJGTiOh8Qkaov6mMIMlEhmLdKew==}
+ engines: {glibc: '>=2.26', node: ^18.17.0 || ^20.3.0 || >=21.0.0, npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'}
+ cpu: [arm64]
+ os: [linux]
+ requiresBuild: true
+ optionalDependencies:
+ '@img/sharp-libvips-linux-arm64': 1.0.1
+ dev: false
+ optional: true
+
+ /@img/sharp-linux-arm@0.33.2:
+ resolution: {integrity: sha512-Fndk/4Zq3vAc4G/qyfXASbS3HBZbKrlnKZLEJzPLrXoJuipFNNwTes71+Ki1hwYW5lch26niRYoZFAtZVf3EGA==}
+ engines: {glibc: '>=2.28', node: ^18.17.0 || ^20.3.0 || >=21.0.0, npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'}
+ cpu: [arm]
+ os: [linux]
+ requiresBuild: true
+ optionalDependencies:
+ '@img/sharp-libvips-linux-arm': 1.0.1
+ dev: false
+ optional: true
+
+ /@img/sharp-linux-s390x@0.33.2:
+ resolution: {integrity: sha512-MBoInDXDppMfhSzbMmOQtGfloVAflS2rP1qPcUIiITMi36Mm5YR7r0ASND99razjQUpHTzjrU1flO76hKvP5RA==}
+ engines: {glibc: '>=2.28', node: ^18.17.0 || ^20.3.0 || >=21.0.0, npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'}
+ cpu: [s390x]
+ os: [linux]
+ requiresBuild: true
+ optionalDependencies:
+ '@img/sharp-libvips-linux-s390x': 1.0.1
+ dev: false
+ optional: true
+
+ /@img/sharp-linux-x64@0.33.2:
+ resolution: {integrity: sha512-xUT82H5IbXewKkeF5aiooajoO1tQV4PnKfS/OZtb5DDdxS/FCI/uXTVZ35GQ97RZXsycojz/AJ0asoz6p2/H/A==}
+ engines: {glibc: '>=2.26', node: ^18.17.0 || ^20.3.0 || >=21.0.0, npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'}
+ cpu: [x64]
+ os: [linux]
+ requiresBuild: true
+ optionalDependencies:
+ '@img/sharp-libvips-linux-x64': 1.0.1
+ dev: false
+ optional: true
+
+ /@img/sharp-linuxmusl-arm64@0.33.2:
+ resolution: {integrity: sha512-F+0z8JCu/UnMzg8IYW1TMeiViIWBVg7IWP6nE0p5S5EPQxlLd76c8jYemG21X99UzFwgkRo5yz2DS+zbrnxZeA==}
+ engines: {musl: '>=1.2.2', node: ^18.17.0 || ^20.3.0 || >=21.0.0, npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'}
+ cpu: [arm64]
+ os: [linux]
+ requiresBuild: true
+ optionalDependencies:
+ '@img/sharp-libvips-linuxmusl-arm64': 1.0.1
+ dev: false
+ optional: true
+
+ /@img/sharp-linuxmusl-x64@0.33.2:
+ resolution: {integrity: sha512-+ZLE3SQmSL+Fn1gmSaM8uFusW5Y3J9VOf+wMGNnTtJUMUxFhv+P4UPaYEYT8tqnyYVaOVGgMN/zsOxn9pSsO2A==}
+ engines: {musl: '>=1.2.2', node: ^18.17.0 || ^20.3.0 || >=21.0.0, npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'}
+ cpu: [x64]
+ os: [linux]
+ requiresBuild: true
+ optionalDependencies:
+ '@img/sharp-libvips-linuxmusl-x64': 1.0.1
+ dev: false
+ optional: true
+
+ /@img/sharp-wasm32@0.33.2:
+ resolution: {integrity: sha512-fLbTaESVKuQcpm8ffgBD7jLb/CQLcATju/jxtTXR1XCLwbOQt+OL5zPHSDMmp2JZIeq82e18yE0Vv7zh6+6BfQ==}
+ engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0, npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'}
+ cpu: [wasm32]
+ requiresBuild: true
+ dependencies:
+ '@emnapi/runtime': 0.45.0
+ dev: false
+ optional: true
+
+ /@img/sharp-win32-ia32@0.33.2:
+ resolution: {integrity: sha512-okBpql96hIGuZ4lN3+nsAjGeggxKm7hIRu9zyec0lnfB8E7Z6p95BuRZzDDXZOl2e8UmR4RhYt631i7mfmKU8g==}
+ engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0, npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'}
+ cpu: [ia32]
+ os: [win32]
+ requiresBuild: true
+ dev: false
+ optional: true
+
+ /@img/sharp-win32-x64@0.33.2:
+ resolution: {integrity: sha512-E4magOks77DK47FwHUIGH0RYWSgRBfGdK56kIHSVeB9uIS4pPFr4N2kIVsXdQQo4LzOsENKV5KAhRlRL7eMAdg==}
+ engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0, npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'}
+ cpu: [x64]
+ os: [win32]
+ requiresBuild: true
+ dev: false
+ optional: true
+
+ /@mux/blurhash@0.1.2:
+ resolution: {integrity: sha512-fWLOXHS2l3CGyPHF4NSRLqZx9DDAz1WYC4YXD3du24xxibIKUyBYzg7PDtx54z5QaQ12ln5oPFvhH5LhaLzeZg==}
+ dependencies:
+ blurhash: 1.1.5
+ sharp: 0.30.7
+ dev: false
+
+ /@mux/mux-player-react@2.3.1(@types/react-dom@18.2.18)(@types/react@18.2.47)(react-dom@18.2.0)(react@18.2.0):
+ resolution: {integrity: sha512-kTNHmDLByomIZcbMWVayoFqpWf89+49m391W0moI0NvjN4wRwNGvwhYbWbj0xHhdDumgEf7MqbnbFRnuiibHiQ==}
+ peerDependencies:
+ '@types/react': ^17.0.0 || ^18
+ '@types/react-dom': '*'
+ react: ^17.0.2 || ^18
+ react-dom: ^17.0.2 || ^18
+ peerDependenciesMeta:
+ '@types/react':
+ optional: true
+ '@types/react-dom':
+ optional: true
+ dependencies:
+ '@mux/mux-player': 2.3.1
+ '@mux/playback-core': 0.22.1
+ '@types/react': 18.2.47
+ '@types/react-dom': 18.2.18
+ prop-types: 15.8.1
+ react: 18.2.0
+ react-dom: 18.2.0(react@18.2.0)
+ dev: false
+
+ /@mux/mux-player@2.3.1:
+ resolution: {integrity: sha512-yRR7Ec5LVJdmd431dQM7Lf6r9FdFQOXBBVADiv6HWdj+b+6duAinHA8w+Gfvibokc26l4YO7cQ27hWu29cGGUg==}
+ dependencies:
+ '@mux/mux-video': 0.17.2
+ '@mux/playback-core': 0.22.1
+ media-chrome: 2.0.1
+ dev: false
+
+ /@mux/mux-video@0.17.2:
+ resolution: {integrity: sha512-IIGZhUYPClUIOQ/VZZ7kjYcxTcSSSvm+yiv/+c4hHlreO1XLly8Oe1Dzq2xx12t1b+UUupIzx2Cnc8bzVEQTKA==}
+ dependencies:
+ '@mux/playback-core': 0.22.1
+ castable-video: 1.0.6
+ custom-media-element: 1.2.2
+ media-tracks: 0.3.0
+ dev: false
+
+ /@mux/playback-core@0.22.1:
+ resolution: {integrity: sha512-tsPMpcu/xYHQtO6USZwg80CDaXyc7UbyJGoqMU9P1o0e15X/KDcz179nhr6k0CXafg/yiwAlxPNGXnpwToWJ4w==}
+ dependencies:
+ hls.js: 1.4.14
+ mux-embed: 4.30.0
+ dev: false
+
+ /@next/env@14.0.4:
+ resolution: {integrity: sha512-irQnbMLbUNQpP1wcE5NstJtbuA/69kRfzBrpAD7Gsn8zm/CY6YQYc3HQBz8QPxwISG26tIm5afvvVbu508oBeQ==}
+ dev: false
+
+ /@next/eslint-plugin-next@14.0.4:
+ resolution: {integrity: sha512-U3qMNHmEZoVmHA0j/57nRfi3AscXNvkOnxDmle/69Jz/G0o/gWjXTDdlgILZdrxQ0Lw/jv2mPW8PGy0EGIHXhQ==}
+ dependencies:
+ glob: 7.1.7
+ dev: true
+
+ /@next/swc-darwin-arm64@14.0.4:
+ resolution: {integrity: sha512-mF05E/5uPthWzyYDyptcwHptucf/jj09i2SXBPwNzbgBNc+XnwzrL0U6BmPjQeOL+FiB+iG1gwBeq7mlDjSRPg==}
+ engines: {node: '>= 10'}
+ cpu: [arm64]
+ os: [darwin]
+ requiresBuild: true
+ dev: false
+ optional: true
+
+ /@next/swc-darwin-x64@14.0.4:
+ resolution: {integrity: sha512-IZQ3C7Bx0k2rYtrZZxKKiusMTM9WWcK5ajyhOZkYYTCc8xytmwSzR1skU7qLgVT/EY9xtXDG0WhY6fyujnI3rw==}
+ engines: {node: '>= 10'}
+ cpu: [x64]
+ os: [darwin]
+ requiresBuild: true
+ dev: false
+ optional: true
+
+ /@next/swc-linux-arm64-gnu@14.0.4:
+ resolution: {integrity: sha512-VwwZKrBQo/MGb1VOrxJ6LrKvbpo7UbROuyMRvQKTFKhNaXjUmKTu7wxVkIuCARAfiI8JpaWAnKR+D6tzpCcM4w==}
+ engines: {node: '>= 10'}
+ cpu: [arm64]
+ os: [linux]
+ requiresBuild: true
+ dev: false
+ optional: true
+
+ /@next/swc-linux-arm64-musl@14.0.4:
+ resolution: {integrity: sha512-8QftwPEW37XxXoAwsn+nXlodKWHfpMaSvt81W43Wh8dv0gkheD+30ezWMcFGHLI71KiWmHK5PSQbTQGUiidvLQ==}
+ engines: {node: '>= 10'}
+ cpu: [arm64]
+ os: [linux]
+ requiresBuild: true
+ dev: false
+ optional: true
+
+ /@next/swc-linux-x64-gnu@14.0.4:
+ resolution: {integrity: sha512-/s/Pme3VKfZAfISlYVq2hzFS8AcAIOTnoKupc/j4WlvF6GQ0VouS2Q2KEgPuO1eMBwakWPB1aYFIA4VNVh667A==}
+ engines: {node: '>= 10'}
+ cpu: [x64]
+ os: [linux]
+ requiresBuild: true
+ dev: false
+ optional: true
+
+ /@next/swc-linux-x64-musl@14.0.4:
+ resolution: {integrity: sha512-m8z/6Fyal4L9Bnlxde5g2Mfa1Z7dasMQyhEhskDATpqr+Y0mjOBZcXQ7G5U+vgL22cI4T7MfvgtrM2jdopqWaw==}
+ engines: {node: '>= 10'}
+ cpu: [x64]
+ os: [linux]
+ requiresBuild: true
+ dev: false
+ optional: true
+
+ /@next/swc-win32-arm64-msvc@14.0.4:
+ resolution: {integrity: sha512-7Wv4PRiWIAWbm5XrGz3D8HUkCVDMMz9igffZG4NB1p4u1KoItwx9qjATHz88kwCEal/HXmbShucaslXCQXUM5w==}
+ engines: {node: '>= 10'}
+ cpu: [arm64]
+ os: [win32]
+ requiresBuild: true
+ dev: false
+ optional: true
+
+ /@next/swc-win32-ia32-msvc@14.0.4:
+ resolution: {integrity: sha512-zLeNEAPULsl0phfGb4kdzF/cAVIfaC7hY+kt0/d+y9mzcZHsMS3hAS829WbJ31DkSlVKQeHEjZHIdhN+Pg7Gyg==}
+ engines: {node: '>= 10'}
+ cpu: [ia32]
+ os: [win32]
+ requiresBuild: true
+ dev: false
+ optional: true
+
+ /@next/swc-win32-x64-msvc@14.0.4:
+ resolution: {integrity: sha512-yEh2+R8qDlDCjxVpzOTEpBLQTEFAcP2A8fUFLaWNap9GitYKkKv1//y2S6XY6zsR4rCOPRpU7plYDR+az2n30A==}
+ engines: {node: '>= 10'}
+ cpu: [x64]
+ os: [win32]
+ requiresBuild: true
+ dev: false
+ optional: true
+
+ /@noble/hashes@1.3.3:
+ resolution: {integrity: sha512-V7/fPHgl+jsVPXqqeOzT8egNj2iBIVt+ECeMMG8TdcnTikP3oaBtUVqpT/gYCR68aEBJSF+XbYUxStjbFMqIIA==}
+ engines: {node: '>= 16'}
+ dev: false
+
+ /@nodelib/fs.scandir@2.1.5:
+ resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==}
+ engines: {node: '>= 8'}
+ dependencies:
+ '@nodelib/fs.stat': 2.0.5
+ run-parallel: 1.2.0
+ dev: true
+
+ /@nodelib/fs.stat@2.0.5:
+ resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==}
+ engines: {node: '>= 8'}
+ dev: true
+
+ /@nodelib/fs.walk@1.2.8:
+ resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==}
+ engines: {node: '>= 8'}
+ dependencies:
+ '@nodelib/fs.scandir': 2.1.5
+ fastq: 1.16.0
+ dev: true
+
+ /@observablehq/plot@0.6.13:
+ resolution: {integrity: sha512-ebQS4ENodOy+O3WUjhqv9jNPZENAZRQMIdO3ziOlAKfUzSf69+gaFAqqc04SGrQA6JwJjPYnbfeN3YIpNsCF/A==}
+ engines: {node: '>=12'}
+ dependencies:
+ d3: 7.8.5
+ interval-tree-1d: 1.0.4
+ isoformat: 0.2.1
+ dev: false
+
+ /@paralleldrive/cuid2@2.2.2:
+ resolution: {integrity: sha512-ZOBkgDwEdoYVlSeRbYYXs0S9MejQofiVYoTbKzy/6GQa39/q5tQU2IX46+shYnUkpEl3wc+J6wRlar7r2EK2xA==}
+ dependencies:
+ '@noble/hashes': 1.3.3
+ dev: false
+
+ /@popperjs/core@2.11.8:
+ resolution: {integrity: sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==}
+ dev: false
+
+ /@react-hookz/deep-equal@1.0.4:
+ resolution: {integrity: sha512-N56fTrAPUDz/R423pag+n6TXWbvlBZDtTehaGFjK0InmN+V2OFWLE/WmORhmn6Ce7dlwH5+tQN1LJFw3ngTJVg==}
+ dev: false
+
+ /@react-hookz/web@24.0.2(react-dom@18.2.0)(react@18.2.0):
+ resolution: {integrity: sha512-LhWw/LzhxKYRZDRIKd42mCMqRa9pTMSpwpwnfpa0hYoUNcrHw//3NlpoPlynkmKT3G88mumTTuV0HeWnNkarog==}
+ engines: {node: '>=18.0.0'}
+ peerDependencies:
+ js-cookie: ^3.0.5
+ react: ^16.8 || ^17 || ^18
+ react-dom: ^16.8 || ^17 || ^18
+ peerDependenciesMeta:
+ js-cookie:
+ optional: true
+ dependencies:
+ '@react-hookz/deep-equal': 1.0.4
+ react: 18.2.0
+ react-dom: 18.2.0(react@18.2.0)
+ dev: false
+
+ /@redis/bloom@1.0.2(@redis/client@1.2.0):
+ resolution: {integrity: sha512-EBw7Ag1hPgFzdznK2PBblc1kdlj5B5Cw3XwI9/oG7tSn85/HKy3X9xHy/8tm/eNXJYHLXHJL/pkwBpFMVVefkw==}
+ peerDependencies:
+ '@redis/client': ^1.0.0
+ dependencies:
+ '@redis/client': 1.2.0
+ dev: false
+
+ /@redis/client@1.2.0:
+ resolution: {integrity: sha512-a8Nlw5fv2EIAFJxTDSSDVUT7yfBGpZO96ybZXzQpgkyLg/dxtQ1uiwTc0EGfzg1mrPjZokeBSEGTbGXekqTNOg==}
+ engines: {node: '>=14'}
+ dependencies:
+ cluster-key-slot: 1.1.0
+ generic-pool: 3.8.2
+ yallist: 4.0.0
+ dev: false
+
+ /@redis/graph@1.0.1(@redis/client@1.2.0):
+ resolution: {integrity: sha512-oDE4myMCJOCVKYMygEMWuriBgqlS5FqdWerikMoJxzmmTUErnTRRgmIDa2VcgytACZMFqpAOWDzops4DOlnkfQ==}
+ peerDependencies:
+ '@redis/client': ^1.0.0
+ dependencies:
+ '@redis/client': 1.2.0
+ dev: false
+
+ /@redis/json@1.0.3(@redis/client@1.2.0):
+ resolution: {integrity: sha512-4X0Qv0BzD9Zlb0edkUoau5c1bInWSICqXAGrpwEltkncUwcxJIGEcVryZhLgb0p/3PkKaLIWkjhHRtLe9yiA7Q==}
+ peerDependencies:
+ '@redis/client': ^1.0.0
+ dependencies:
+ '@redis/client': 1.2.0
+ dev: false
+
+ /@redis/search@1.0.6(@redis/client@1.2.0):
+ resolution: {integrity: sha512-pP+ZQRis5P21SD6fjyCeLcQdps+LuTzp2wdUbzxEmNhleighDDTD5ck8+cYof+WLec4csZX7ks+BuoMw0RaZrA==}
+ peerDependencies:
+ '@redis/client': ^1.0.0
+ dependencies:
+ '@redis/client': 1.2.0
+ dev: false
+
+ /@redis/time-series@1.0.3(@redis/client@1.2.0):
+ resolution: {integrity: sha512-OFp0q4SGrTH0Mruf6oFsHGea58u8vS/iI5+NpYdicaM+7BgqBZH8FFvNZ8rYYLrUO/QRqMq72NpXmxLVNcdmjA==}
+ peerDependencies:
+ '@redis/client': ^1.0.0
+ dependencies:
+ '@redis/client': 1.2.0
+ dev: false
+
+ /@rushstack/eslint-patch@1.6.1:
+ resolution: {integrity: sha512-UY+FGM/2jjMkzQLn8pxcHGMaVLh9aEitG3zY2CiY7XHdLiz3bZOwa6oDxNqEMv7zZkV+cj5DOdz0cQ1BP5Hjgw==}
+ dev: true
+
+ /@sindresorhus/is@4.6.0:
+ resolution: {integrity: sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==}
+ engines: {node: '>=10'}
+ dev: false
+
+ /@smithy/abort-controller@2.0.16:
+ resolution: {integrity: sha512-4foO7738k8kM9flMHu3VLabqu7nPgvIj8TB909S0CnKx0YZz/dcDH3pZ/4JHdatfxlZdKF1JWOYCw9+v3HVVsw==}
+ engines: {node: '>=14.0.0'}
+ dependencies:
+ '@smithy/types': 2.8.0
+ tslib: 2.6.2
+ dev: false
+
+ /@smithy/chunked-blob-reader-native@2.0.1:
+ resolution: {integrity: sha512-N2oCZRglhWKm7iMBu7S6wDzXirjAofi7tAd26cxmgibRYOBS4D3hGfmkwCpHdASZzwZDD8rluh0Rcqw1JeZDRw==}
+ dependencies:
+ '@smithy/util-base64': 2.0.1
+ tslib: 2.6.2
+ dev: false
+
+ /@smithy/chunked-blob-reader@2.0.0:
+ resolution: {integrity: sha512-k+J4GHJsMSAIQPChGBrjEmGS+WbPonCXesoqP9fynIqjn7rdOThdH8FAeCmokP9mxTYKQAKoHCLPzNlm6gh7Wg==}
+ dependencies:
+ tslib: 2.6.2
+ dev: false
+
+ /@smithy/config-resolver@2.0.23:
+ resolution: {integrity: sha512-XakUqgtP2YY8Mi+Nlif5BiqJgWdvfxJafSpOSQeCOMizu+PUhE4fBQSy6xFcR+eInrwVadaABNxoJyGUMn15ew==}
+ engines: {node: '>=14.0.0'}
+ dependencies:
+ '@smithy/node-config-provider': 2.1.9
+ '@smithy/types': 2.8.0
+ '@smithy/util-config-provider': 2.1.0
+ '@smithy/util-middleware': 2.0.9
+ tslib: 2.6.2
+ dev: false
+
+ /@smithy/core@1.2.2:
+ resolution: {integrity: sha512-uLjrskLT+mWb0emTR5QaiAIxVEU7ndpptDaVDrTwwhD+RjvHhjIiGQ3YL5jKk1a5VSDQUA2RGkXvJ6XKRcz6Dg==}
+ engines: {node: '>=14.0.0'}
+ dependencies:
+ '@smithy/middleware-endpoint': 2.3.0
+ '@smithy/middleware-retry': 2.0.26
+ '@smithy/middleware-serde': 2.0.16
+ '@smithy/protocol-http': 3.0.12
+ '@smithy/smithy-client': 2.2.1
+ '@smithy/types': 2.8.0
+ '@smithy/util-middleware': 2.0.9
+ tslib: 2.6.2
+ dev: false
+
+ /@smithy/credential-provider-imds@2.1.5:
+ resolution: {integrity: sha512-VfvE6Wg1MUWwpTZFBnUD7zxvPhLY8jlHCzu6bCjlIYoWgXCDzZAML76IlZUEf45nib3rjehnFgg0s1rgsuN/bg==}
+ engines: {node: '>=14.0.0'}
+ dependencies:
+ '@smithy/node-config-provider': 2.1.9
+ '@smithy/property-provider': 2.0.17
+ '@smithy/types': 2.8.0
+ '@smithy/url-parser': 2.0.16
+ tslib: 2.6.2
+ dev: false
+
+ /@smithy/eventstream-codec@2.0.16:
+ resolution: {integrity: sha512-umYh5pdCE9GHgiMAH49zu9wXWZKNHHdKPm/lK22WYISTjqu29SepmpWNmPiBLy/yUu4HFEGJHIFrDWhbDlApaw==}
+ dependencies:
+ '@aws-crypto/crc32': 3.0.0
+ '@smithy/types': 2.8.0
+ '@smithy/util-hex-encoding': 2.0.0
+ tslib: 2.6.2
+ dev: false
+
+ /@smithy/eventstream-serde-browser@2.0.16:
+ resolution: {integrity: sha512-W+BdiN728R57KuZOcG0GczpIOEFf8S5RP/OdVH7T3FMCy8HU2bBU0vB5xZZR5c00VRdoeWrohNv3XlHoZuGRoA==}
+ engines: {node: '>=14.0.0'}
+ dependencies:
+ '@smithy/eventstream-serde-universal': 2.0.16
+ '@smithy/types': 2.8.0
+ tslib: 2.6.2
+ dev: false
+
+ /@smithy/eventstream-serde-config-resolver@2.0.16:
+ resolution: {integrity: sha512-8qrE4nh+Tg6m1SMFK8vlzoK+8bUFTlIhXidmmQfASMninXW3Iu0T0bI4YcIk4nLznHZdybQ0qGydIanvVZxzVg==}
+ engines: {node: '>=14.0.0'}
+ dependencies:
+ '@smithy/types': 2.8.0
+ tslib: 2.6.2
+ dev: false
+
+ /@smithy/eventstream-serde-node@2.0.16:
+ resolution: {integrity: sha512-NRNQuOa6mQdFSkqzY0IV37swHWx0SEoKxFtUfdZvfv0AVQPlSw4N7E3kcRSCpnHBr1kCuWWirdDlWcjWuD81MA==}
+ engines: {node: '>=14.0.0'}
+ dependencies:
+ '@smithy/eventstream-serde-universal': 2.0.16
+ '@smithy/types': 2.8.0
+ tslib: 2.6.2
+ dev: false
+
+ /@smithy/eventstream-serde-universal@2.0.16:
+ resolution: {integrity: sha512-ZyLnGaYQMLc75j9kKEVMJ3X6bdBE9qWxhZdTXM5RIltuytxJC3FaOhawBxjE+IL1enmWSIohHGZCm/pLwEliQA==}
+ engines: {node: '>=14.0.0'}
+ dependencies:
+ '@smithy/eventstream-codec': 2.0.16
+ '@smithy/types': 2.8.0
+ tslib: 2.6.2
+ dev: false
+
+ /@smithy/fetch-http-handler@2.3.2:
+ resolution: {integrity: sha512-O9R/OlnAOTsnysuSDjt0v2q6DcSvCz5cCFC/CFAWWcLyBwJDeFyGTCTszgpQTb19+Fi8uRwZE5/3ziAQBFeDMQ==}
+ dependencies:
+ '@smithy/protocol-http': 3.0.12
+ '@smithy/querystring-builder': 2.0.16
+ '@smithy/types': 2.8.0
+ '@smithy/util-base64': 2.0.1
+ tslib: 2.6.2
+ dev: false
+
+ /@smithy/hash-blob-browser@2.0.17:
+ resolution: {integrity: sha512-/mPpv1sRiRDdjO4zZuO8be6eeabmg5AVgKDfnmmqkpBtRyMGSJb968fjRuHt+FRAsIGywgIKJFmUUAYjhsi1oQ==}
+ dependencies:
+ '@smithy/chunked-blob-reader': 2.0.0
+ '@smithy/chunked-blob-reader-native': 2.0.1
+ '@smithy/types': 2.8.0
+ tslib: 2.6.2
+ dev: false
+
+ /@smithy/hash-node@2.0.18:
+ resolution: {integrity: sha512-gN2JFvAgnZCyDN9rJgcejfpK0uPPJrSortVVVVWsru9whS7eQey6+gj2eM5ln2i6rHNntIXzal1Fm9XOPuoaKA==}
+ engines: {node: '>=14.0.0'}
+ dependencies:
+ '@smithy/types': 2.8.0
+ '@smithy/util-buffer-from': 2.0.0
+ '@smithy/util-utf8': 2.0.2
+ tslib: 2.6.2
+ dev: false
+
+ /@smithy/hash-stream-node@2.0.18:
+ resolution: {integrity: sha512-OuFk+ITpv8CtxGjQcS8GA04faNycu9UMm6YobvQzjeEoXZ0dLF6sRfuzD+3S8RHPKpTyLuXtKG1+GiJycZ5TcA==}
+ engines: {node: '>=14.0.0'}
+ dependencies:
+ '@smithy/types': 2.8.0
+ '@smithy/util-utf8': 2.0.2
+ tslib: 2.6.2
+ dev: false
+
+ /@smithy/invalid-dependency@2.0.16:
+ resolution: {integrity: sha512-apEHakT/kmpNo1VFHP4W/cjfeP9U0x5qvfsLJubgp7UM/gq4qYp0GbqdE7QhsjUaYvEnrftRqs7+YrtWreV0wA==}
+ dependencies:
+ '@smithy/types': 2.8.0
+ tslib: 2.6.2
+ dev: false
+
+ /@smithy/is-array-buffer@2.0.0:
+ resolution: {integrity: sha512-z3PjFjMyZNI98JFRJi/U0nGoLWMSJlDjAW4QUX2WNZLas5C0CmVV6LJ01JI0k90l7FvpmixjWxPFmENSClQ7ug==}
+ engines: {node: '>=14.0.0'}
+ dependencies:
+ tslib: 2.6.2
+ dev: false
+
+ /@smithy/md5-js@2.0.18:
+ resolution: {integrity: sha512-bHwZ8/m6RbERQdVW5rJ2LzeW8qxfXv6Q/S7Fiudhso4pWRrksqLx3nsGZw7bmqqfN4zLqkxydxSa9+4c7s5zxg==}
+ dependencies:
+ '@smithy/types': 2.8.0
+ '@smithy/util-utf8': 2.0.2
+ tslib: 2.6.2
+ dev: false
+
+ /@smithy/middleware-content-length@2.0.18:
+ resolution: {integrity: sha512-ZJ9uKPTfxYheTKSKYB+GCvcj+izw9WGzRLhjn8n254q0jWLojUzn7Vw0l4R/Gq7Wdpf/qmk/ptD+6CCXHNVCaw==}
+ engines: {node: '>=14.0.0'}
+ dependencies:
+ '@smithy/protocol-http': 3.0.12
+ '@smithy/types': 2.8.0
+ tslib: 2.6.2
+ dev: false
+
+ /@smithy/middleware-endpoint@2.3.0:
+ resolution: {integrity: sha512-VsOAG2YQ8ykjSmKO+CIXdJBIWFo6AAvG6Iw95BakBTqk66/4BI7XyqLevoNSq/lZ6NgZv24sLmrcIN+fLDWBCg==}
+ engines: {node: '>=14.0.0'}
+ dependencies:
+ '@smithy/middleware-serde': 2.0.16
+ '@smithy/node-config-provider': 2.1.9
+ '@smithy/shared-ini-file-loader': 2.2.8
+ '@smithy/types': 2.8.0
+ '@smithy/url-parser': 2.0.16
+ '@smithy/util-middleware': 2.0.9
+ tslib: 2.6.2
+ dev: false
+
+ /@smithy/middleware-retry@2.0.26:
+ resolution: {integrity: sha512-Qzpxo0U5jfNiq9iD38U3e2bheXwvTEX4eue9xruIvEgh+UKq6dKuGqcB66oBDV7TD/mfoJi9Q/VmaiqwWbEp7A==}
+ engines: {node: '>=14.0.0'}
+ dependencies:
+ '@smithy/node-config-provider': 2.1.9
+ '@smithy/protocol-http': 3.0.12
+ '@smithy/service-error-classification': 2.0.9
+ '@smithy/smithy-client': 2.2.1
+ '@smithy/types': 2.8.0
+ '@smithy/util-middleware': 2.0.9
+ '@smithy/util-retry': 2.0.9
+ tslib: 2.6.2
+ uuid: 8.3.2
+ dev: false
+
+ /@smithy/middleware-serde@2.0.16:
+ resolution: {integrity: sha512-5EAd4t30pcc4M8TSSGq7q/x5IKrxfXR5+SrU4bgxNy7RPHQo2PSWBUco9C+D9Tfqp/JZvprRpK42dnupZafk2g==}
+ engines: {node: '>=14.0.0'}
+ dependencies:
+ '@smithy/types': 2.8.0
+ tslib: 2.6.2
+ dev: false
+
+ /@smithy/middleware-stack@2.0.10:
+ resolution: {integrity: sha512-I2rbxctNq9FAPPEcuA1ntZxkTKOPQFy7YBPOaD/MLg1zCvzv21CoNxR0py6J8ZVC35l4qE4nhxB0f7TF5/+Ldw==}
+ engines: {node: '>=14.0.0'}
+ dependencies:
+ '@smithy/types': 2.8.0
+ tslib: 2.6.2
+ dev: false
+
+ /@smithy/node-config-provider@2.1.9:
+ resolution: {integrity: sha512-tUyW/9xrRy+s7RXkmQhgYkAPMpTIF8izK4orhHjNFEKR3QZiOCbWB546Y8iB/Fpbm3O9+q0Af9rpywLKJOwtaQ==}
+ engines: {node: '>=14.0.0'}
+ dependencies:
+ '@smithy/property-provider': 2.0.17
+ '@smithy/shared-ini-file-loader': 2.2.8
+ '@smithy/types': 2.8.0
+ tslib: 2.6.2
+ dev: false
+
+ /@smithy/node-http-handler@2.2.2:
+ resolution: {integrity: sha512-XO58TO/Eul/IBQKFKaaBtXJi0ItEQQCT+NI4IiKHCY/4KtqaUT6y/wC1EvDqlA9cP7Dyjdj7FdPs4DyynH3u7g==}
+ engines: {node: '>=14.0.0'}
+ dependencies:
+ '@smithy/abort-controller': 2.0.16
+ '@smithy/protocol-http': 3.0.12
+ '@smithy/querystring-builder': 2.0.16
+ '@smithy/types': 2.8.0
+ tslib: 2.6.2
+ dev: false
+
+ /@smithy/property-provider@2.0.17:
+ resolution: {integrity: sha512-+VkeZbVu7qtQ2DjI48Qwaf9fPOr3gZIwxQpuLJgRRSkWsdSvmaTCxI3gzRFKePB63Ts9r4yjn4HkxSCSkdWmcQ==}
+ engines: {node: '>=14.0.0'}
+ dependencies:
+ '@smithy/types': 2.8.0
+ tslib: 2.6.2
+ dev: false
+
+ /@smithy/protocol-http@3.0.12:
+ resolution: {integrity: sha512-Xz4iaqLiaBfbQpB9Hgi3VcZYbP7xRDXYhd8XWChh4v94uw7qwmvlxdU5yxzfm6ACJM66phHrTbS5TVvj5uQ72w==}
+ engines: {node: '>=14.0.0'}
+ dependencies:
+ '@smithy/types': 2.8.0
+ tslib: 2.6.2
+ dev: false
+
+ /@smithy/querystring-builder@2.0.16:
+ resolution: {integrity: sha512-Q/GsJT0C0mijXMRs7YhZLLCP5FcuC4797lYjKQkME5CZohnLC4bEhylAd2QcD3gbMKNjCw8+T2I27WKiV/wToA==}
+ engines: {node: '>=14.0.0'}
+ dependencies:
+ '@smithy/types': 2.8.0
+ '@smithy/util-uri-escape': 2.0.0
+ tslib: 2.6.2
+ dev: false
+
+ /@smithy/querystring-parser@2.0.16:
+ resolution: {integrity: sha512-c4ueAuL6BDYKWpkubjrQthZKoC3L5kql5O++ovekNxiexRXTlLIVlCR4q3KziOktLIw66EU9SQljPXd/oN6Okg==}
+ engines: {node: '>=14.0.0'}
+ dependencies:
+ '@smithy/types': 2.8.0
+ tslib: 2.6.2
+ dev: false
+
+ /@smithy/service-error-classification@2.0.9:
+ resolution: {integrity: sha512-0K+8GvtwI7VkGmmInPydM2XZyBfIqLIbfR7mDQ+oPiz8mIinuHbV6sxOLdvX1Jv/myk7XTK9orgt3tuEpBu/zg==}
+ engines: {node: '>=14.0.0'}
+ dependencies:
+ '@smithy/types': 2.8.0
+ dev: false
+
+ /@smithy/shared-ini-file-loader@2.2.8:
+ resolution: {integrity: sha512-E62byatbwSWrtq9RJ7xN40tqrRKDGrEL4EluyNpaIDvfvet06a/QC58oHw2FgVaEgkj0tXZPjZaKrhPfpoU0qw==}
+ engines: {node: '>=14.0.0'}
+ dependencies:
+ '@smithy/types': 2.8.0
+ tslib: 2.6.2
+ dev: false
+
+ /@smithy/signature-v4@2.0.19:
+ resolution: {integrity: sha512-nwc3JihdM+kcJjtORv/n7qRHN2Kfh7S2RJI2qr8pz9UcY5TD8rSCRGQ0g81HgyS3jZ5X9U/L4p014P3FonBPhg==}
+ engines: {node: '>=14.0.0'}
+ dependencies:
+ '@smithy/eventstream-codec': 2.0.16
+ '@smithy/is-array-buffer': 2.0.0
+ '@smithy/types': 2.8.0
+ '@smithy/util-hex-encoding': 2.0.0
+ '@smithy/util-middleware': 2.0.9
+ '@smithy/util-uri-escape': 2.0.0
+ '@smithy/util-utf8': 2.0.2
+ tslib: 2.6.2
+ dev: false
+
+ /@smithy/smithy-client@2.2.1:
+ resolution: {integrity: sha512-SpD7FLK92XV2fon2hMotaNDa2w5VAy5/uVjP9WFmjGSgWM8pTPVkHcDl1yFs5Z8LYbij0FSz+DbCBK6i+uXXUA==}
+ engines: {node: '>=14.0.0'}
+ dependencies:
+ '@smithy/middleware-endpoint': 2.3.0
+ '@smithy/middleware-stack': 2.0.10
+ '@smithy/protocol-http': 3.0.12
+ '@smithy/types': 2.8.0
+ '@smithy/util-stream': 2.0.24
+ tslib: 2.6.2
+ dev: false
+
+ /@smithy/types@2.8.0:
+ resolution: {integrity: sha512-h9sz24cFgt/W1Re22OlhQKmUZkNh244ApgRsUDYinqF8R+QgcsBIX344u2j61TPshsTz3CvL6HYU1DnQdsSrHA==}
+ engines: {node: '>=14.0.0'}
+ dependencies:
+ tslib: 2.6.2
+ dev: false
+
+ /@smithy/url-parser@2.0.16:
+ resolution: {integrity: sha512-Wfz5WqAoRT91TjRy1JeLR0fXtkIXHGsMbgzKFTx7E68SrZ55TB8xoG+vm11Ru4gheFTMXjAjwAxv1jQdC+pAQA==}
+ dependencies:
+ '@smithy/querystring-parser': 2.0.16
+ '@smithy/types': 2.8.0
+ tslib: 2.6.2
+ dev: false
+
+ /@smithy/util-base64@2.0.1:
+ resolution: {integrity: sha512-DlI6XFYDMsIVN+GH9JtcRp3j02JEVuWIn/QOZisVzpIAprdsxGveFed0bjbMRCqmIFe8uetn5rxzNrBtIGrPIQ==}
+ engines: {node: '>=14.0.0'}
+ dependencies:
+ '@smithy/util-buffer-from': 2.0.0
+ tslib: 2.6.2
+ dev: false
+
+ /@smithy/util-body-length-browser@2.0.1:
+ resolution: {integrity: sha512-NXYp3ttgUlwkaug4bjBzJ5+yIbUbUx8VsSLuHZROQpoik+gRkIBeEG9MPVYfvPNpuXb/puqodeeUXcKFe7BLOQ==}
+ dependencies:
+ tslib: 2.6.2
+ dev: false
+
+ /@smithy/util-body-length-node@2.1.0:
+ resolution: {integrity: sha512-/li0/kj/y3fQ3vyzn36NTLGmUwAICb7Jbe/CsWCktW363gh1MOcpEcSO3mJ344Gv2dqz8YJCLQpb6hju/0qOWw==}
+ engines: {node: '>=14.0.0'}
+ dependencies:
+ tslib: 2.6.2
+ dev: false
+
+ /@smithy/util-buffer-from@2.0.0:
+ resolution: {integrity: sha512-/YNnLoHsR+4W4Vf2wL5lGv0ksg8Bmk3GEGxn2vEQt52AQaPSCuaO5PM5VM7lP1K9qHRKHwrPGktqVoAHKWHxzw==}
+ engines: {node: '>=14.0.0'}
+ dependencies:
+ '@smithy/is-array-buffer': 2.0.0
+ tslib: 2.6.2
+ dev: false
+
+ /@smithy/util-config-provider@2.1.0:
+ resolution: {integrity: sha512-S6V0JvvhQgFSGLcJeT1CBsaTR03MM8qTuxMH9WPCCddlSo2W0V5jIHimHtIQALMLEDPGQ0ROSRr/dU0O+mxiQg==}
+ engines: {node: '>=14.0.0'}
+ dependencies:
+ tslib: 2.6.2
+ dev: false
+
+ /@smithy/util-defaults-mode-browser@2.0.24:
+ resolution: {integrity: sha512-TsP5mBuLgO2C21+laNG2nHYZEyUdkbGURv2tHvSuQQxLz952MegX95uwdxOY2jR2H4GoKuVRfdJq7w4eIjGYeg==}
+ engines: {node: '>= 10.0.0'}
+ dependencies:
+ '@smithy/property-provider': 2.0.17
+ '@smithy/smithy-client': 2.2.1
+ '@smithy/types': 2.8.0
+ bowser: 2.11.0
+ tslib: 2.6.2
+ dev: false
+
+ /@smithy/util-defaults-mode-node@2.0.32:
+ resolution: {integrity: sha512-d0S33dXA2cq1NyorVMroMrEtqKMr3MlyLITcfTBf9pXiigYiPMOtbSI7czHIfDbuVuM89Cg0urAgpt73QV9mPQ==}
+ engines: {node: '>= 10.0.0'}
+ dependencies:
+ '@smithy/config-resolver': 2.0.23
+ '@smithy/credential-provider-imds': 2.1.5
+ '@smithy/node-config-provider': 2.1.9
+ '@smithy/property-provider': 2.0.17
+ '@smithy/smithy-client': 2.2.1
+ '@smithy/types': 2.8.0
+ tslib: 2.6.2
+ dev: false
+
+ /@smithy/util-endpoints@1.0.8:
+ resolution: {integrity: sha512-l8zVuyZZ61IzZBYp5NWvsAhbaAjYkt0xg9R4xUASkg5SEeTT2meHOJwJHctKMFUXe4QZbn9fR2MaBYjP2119+w==}
+ engines: {node: '>= 14.0.0'}
+ dependencies:
+ '@smithy/node-config-provider': 2.1.9
+ '@smithy/types': 2.8.0
+ tslib: 2.6.2
+ dev: false
+
+ /@smithy/util-hex-encoding@2.0.0:
+ resolution: {integrity: sha512-c5xY+NUnFqG6d7HFh1IFfrm3mGl29lC+vF+geHv4ToiuJCBmIfzx6IeHLg+OgRdPFKDXIw6pvi+p3CsscaMcMA==}
+ engines: {node: '>=14.0.0'}
+ dependencies:
+ tslib: 2.6.2
+ dev: false
+
+ /@smithy/util-middleware@2.0.9:
+ resolution: {integrity: sha512-PnCnBJ07noMX1lMDTEefmxSlusWJUiLfrme++MfK5TD0xz8NYmakgoXy5zkF/16zKGmiwOeKAztWT/Vjk1KRIQ==}
+ engines: {node: '>=14.0.0'}
+ dependencies:
+ '@smithy/types': 2.8.0
+ tslib: 2.6.2
+ dev: false
+
+ /@smithy/util-retry@2.0.9:
+ resolution: {integrity: sha512-46BFWe9RqB6g7f4mxm3W3HlqknqQQmWHKlhoqSFZuGNuiDU5KqmpebMbvC3tjTlUkqn4xa2Z7s3Hwb0HNs5scw==}
+ engines: {node: '>= 14.0.0'}
+ dependencies:
+ '@smithy/service-error-classification': 2.0.9
+ '@smithy/types': 2.8.0
+ tslib: 2.6.2
+ dev: false
+
+ /@smithy/util-stream@2.0.24:
+ resolution: {integrity: sha512-hRpbcRrOxDriMVmbya+Mv77VZVupxRAsfxVDKS54XuiURhdiwCUXJP0X1iJhHinuUf6n8pBF0MkG9C8VooMnWw==}
+ engines: {node: '>=14.0.0'}
+ dependencies:
+ '@smithy/fetch-http-handler': 2.3.2
+ '@smithy/node-http-handler': 2.2.2
+ '@smithy/types': 2.8.0
+ '@smithy/util-base64': 2.0.1
+ '@smithy/util-buffer-from': 2.0.0
+ '@smithy/util-hex-encoding': 2.0.0
+ '@smithy/util-utf8': 2.0.2
+ tslib: 2.6.2
+ dev: false
+
+ /@smithy/util-uri-escape@2.0.0:
+ resolution: {integrity: sha512-ebkxsqinSdEooQduuk9CbKcI+wheijxEb3utGXkCoYQkJnwTnLbH1JXGimJtUkQwNQbsbuYwG2+aFVyZf5TLaw==}
+ engines: {node: '>=14.0.0'}
+ dependencies:
+ tslib: 2.6.2
+ dev: false
+
+ /@smithy/util-utf8@2.0.2:
+ resolution: {integrity: sha512-qOiVORSPm6Ce4/Yu6hbSgNHABLP2VMv8QOC3tTDNHHlWY19pPyc++fBTbZPtx6egPXi4HQxKDnMxVxpbtX2GoA==}
+ engines: {node: '>=14.0.0'}
+ dependencies:
+ '@smithy/util-buffer-from': 2.0.0
+ tslib: 2.6.2
+ dev: false
+
+ /@smithy/util-waiter@2.0.16:
+ resolution: {integrity: sha512-5i4YONHQ6HoUWDd+X0frpxTXxSXgJhUFl+z0iMy/zpUmVeCQY2or3Vss6DzHKKMMQL4pmVHpQm9WayHDorFdZg==}
+ engines: {node: '>=14.0.0'}
+ dependencies:
+ '@smithy/abort-controller': 2.0.16
+ '@smithy/types': 2.8.0
+ tslib: 2.6.2
+ dev: false
+
+ /@swc/helpers@0.5.2:
+ resolution: {integrity: sha512-E4KcWTpoLHqwPHLxidpOqQbcrZVgi0rsmmZXUle1jXmJfuIf/UWpczUJ7MZZ5tlxytgJXyp0w4PGkkeLiuIdZw==}
+ dependencies:
+ tslib: 2.6.2
+ dev: false
+
+ /@szmarczak/http-timer@4.0.6:
+ resolution: {integrity: sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w==}
+ engines: {node: '>=10'}
+ dependencies:
+ defer-to-connect: 2.0.1
+ dev: false
+
+ /@transloadit/prettier-bytes@0.0.7:
+ resolution: {integrity: sha512-VeJbUb0wEKbcwaSlj5n+LscBl9IPgLPkHVGBkh00cztv6X4L/TJXK58LzFuBKX7/GAfiGhIwH67YTLTlzvIzBA==}
+ dev: false
+
+ /@transloadit/prettier-bytes@0.0.9:
+ resolution: {integrity: sha512-pCvdmea/F3Tn4hAtHqNXmjcixSaroJJ+L3STXlYJdir1g1m2mRQpWbN8a4SvgQtaw2930Ckhdx8qXdXBFMKbAA==}
+ dev: false
+
+ /@types/cacheable-request@6.0.3:
+ resolution: {integrity: sha512-IQ3EbTzGxIigb1I3qPZc1rWJnH0BmSKv5QYTalEwweFvyBDLSAe24zP0le/hyi7ecGfZVlIVAg4BZqb8WBwKqw==}
+ dependencies:
+ '@types/http-cache-semantics': 4.0.4
+ '@types/keyv': 3.1.4
+ '@types/node': 20.11.5
+ '@types/responselike': 1.0.3
+ dev: false
+
+ /@types/http-cache-semantics@4.0.4:
+ resolution: {integrity: sha512-1m0bIFVc7eJWyve9S0RnuRgcQqF/Xd5QsUZAZeQFr1Q3/p9JWoQQEqmVy+DPTNpGXwhgIetAoYF8JSc33q29QA==}
+ dev: false
+
+ /@types/json5@0.0.29:
+ resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==}
+ dev: true
+
+ /@types/keyv@3.1.4:
+ resolution: {integrity: sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==}
+ dependencies:
+ '@types/node': 20.11.5
+ dev: false
+
+ /@types/lodash@4.14.202:
+ resolution: {integrity: sha512-OvlIYQK9tNneDlS0VN54LLd5uiPCBOp7gS5Z0f1mjoJYBrtStzgmJBxONW3U6OZqdtNzZPmn9BS/7WI7BFFcFQ==}
+ dev: false
+
+ /@types/node@20.11.0:
+ resolution: {integrity: sha512-o9bjXmDNcF7GbM4CNQpmi+TutCgap/K3w1JyKgxAjqx41zp9qlIAVFi0IhCNsJcXolEqLWhbFbEeL0PvYm4pcQ==}
+ dependencies:
+ undici-types: 5.26.5
+ dev: true
+
+ /@types/node@20.11.5:
+ resolution: {integrity: sha512-g557vgQjUUfN76MZAN/dt1z3dzcUsimuysco0KeluHgrPdJXkP/XdAURgyO2W9fZWHRtRBiVKzKn8vyOAwlG+w==}
+ dependencies:
+ undici-types: 5.26.5
+ dev: false
+
+ /@types/nprogress@0.2.3:
+ resolution: {integrity: sha512-k7kRA033QNtC+gLc4VPlfnue58CM1iQLgn1IMAU8VPHGOj7oIHPp9UlhedEnD/Gl8evoCjwkZjlBORtZ3JByUA==}
+ dev: false
+
+ /@types/prismjs@1.26.3:
+ resolution: {integrity: sha512-A0D0aTXvjlqJ5ZILMz3rNfDBOx9hHxLZYv2by47Sm/pqW35zzjusrZTryatjN/Rf8Us2gZrJD+KeHbUSTux1Cw==}
+ dev: false
+
+ /@types/prop-types@15.7.11:
+ resolution: {integrity: sha512-ga8y9v9uyeiLdpKddhxYQkxNDrfvuPrlFb0N1qnZZByvcElJaXthF1UhvCh9TLWJBEHeNtdnbysW7Y6Uq8CVng==}
+ dev: false
+
+ /@types/qs@6.9.11:
+ resolution: {integrity: sha512-oGk0gmhnEJK4Yyk+oI7EfXsLayXatCWPHary1MtcmbAifkobT9cM9yutG/hZKIseOU0MqbIwQ/u2nn/Gb+ltuQ==}
+ dev: false
+
+ /@types/react-dom@18.2.18:
+ resolution: {integrity: sha512-TJxDm6OfAX2KJWJdMEVTwWke5Sc/E/RlnPGvGfS0W7+6ocy2xhDVQVh/KvC2Uf7kACs+gDytdusDSdWfWkaNzw==}
+ dependencies:
+ '@types/react': 18.2.47
+ dev: false
+
+ /@types/react@18.2.47:
+ resolution: {integrity: sha512-xquNkkOirwyCgoClNk85BjP+aqnIS+ckAJ8i37gAbDs14jfW/J23f2GItAf33oiUPQnqNMALiFeoM9Y5mbjpVQ==}
+ dependencies:
+ '@types/prop-types': 15.7.11
+ '@types/scheduler': 0.16.8
+ csstype: 3.1.3
+ dev: false
+
+ /@types/responselike@1.0.3:
+ resolution: {integrity: sha512-H/+L+UkTV33uf49PH5pCAUBVPNj2nDBXTN+qS1dOwyyg24l3CcicicCA7ca+HMvJBZcFgl5r8e+RR6elsb4Lyw==}
+ dependencies:
+ '@types/node': 20.11.5
+ dev: false
+
+ /@types/retry@0.12.2:
+ resolution: {integrity: sha512-XISRgDJ2Tc5q4TRqvgJtzsRkFYNJzZrhTdtMoGVBttwzzQJkPnS3WWTFc7kuDRoPtPakl+T+OfdEUjYJj7Jbow==}
+ dev: false
+
+ /@types/scheduler@0.16.8:
+ resolution: {integrity: sha512-WZLiwShhwLRmeV6zH+GkbOFT6Z6VklCItrDioxUnv+u4Ll+8vKeFySoFyK/0ctcRpOmwAicELfmys1sDc/Rw+A==}
+ dev: false
+
+ /@typescript-eslint/parser@6.18.1(eslint@8.56.0)(typescript@5.3.3):
+ resolution: {integrity: sha512-zct/MdJnVaRRNy9e84XnVtRv9Vf91/qqe+hZJtKanjojud4wAVy/7lXxJmMyX6X6J+xc6c//YEWvpeif8cAhWA==}
+ engines: {node: ^16.0.0 || >=18.0.0}
+ peerDependencies:
+ eslint: ^7.0.0 || ^8.0.0
+ typescript: '*'
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+ dependencies:
+ '@typescript-eslint/scope-manager': 6.18.1
+ '@typescript-eslint/types': 6.18.1
+ '@typescript-eslint/typescript-estree': 6.18.1(typescript@5.3.3)
+ '@typescript-eslint/visitor-keys': 6.18.1
+ debug: 4.3.4(supports-color@5.5.0)
+ eslint: 8.56.0
+ typescript: 5.3.3
+ transitivePeerDependencies:
+ - supports-color
+ dev: true
+
+ /@typescript-eslint/scope-manager@6.18.1:
+ resolution: {integrity: sha512-BgdBwXPFmZzaZUuw6wKiHKIovms97a7eTImjkXCZE04TGHysG+0hDQPmygyvgtkoB/aOQwSM/nWv3LzrOIQOBw==}
+ engines: {node: ^16.0.0 || >=18.0.0}
+ dependencies:
+ '@typescript-eslint/types': 6.18.1
+ '@typescript-eslint/visitor-keys': 6.18.1
+ dev: true
+
+ /@typescript-eslint/types@6.18.1:
+ resolution: {integrity: sha512-4TuMAe+tc5oA7wwfqMtB0Y5OrREPF1GeJBAjqwgZh1lEMH5PJQgWgHGfYufVB51LtjD+peZylmeyxUXPfENLCw==}
+ engines: {node: ^16.0.0 || >=18.0.0}
+ dev: true
+
+ /@typescript-eslint/typescript-estree@6.18.1(typescript@5.3.3):
+ resolution: {integrity: sha512-fv9B94UAhywPRhUeeV/v+3SBDvcPiLxRZJw/xZeeGgRLQZ6rLMG+8krrJUyIf6s1ecWTzlsbp0rlw7n9sjufHA==}
+ engines: {node: ^16.0.0 || >=18.0.0}
+ peerDependencies:
+ typescript: '*'
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+ dependencies:
+ '@typescript-eslint/types': 6.18.1
+ '@typescript-eslint/visitor-keys': 6.18.1
+ debug: 4.3.4(supports-color@5.5.0)
+ globby: 11.1.0
+ is-glob: 4.0.3
+ minimatch: 9.0.3
+ semver: 7.5.4
+ ts-api-utils: 1.0.3(typescript@5.3.3)
+ typescript: 5.3.3
+ transitivePeerDependencies:
+ - supports-color
+ dev: true
+
+ /@typescript-eslint/visitor-keys@6.18.1:
+ resolution: {integrity: sha512-/kvt0C5lRqGoCfsbmm7/CwMqoSkY3zzHLIjdhHZQW3VFrnz7ATecOHR7nb7V+xn4286MBxfnQfQhAmCI0u+bJA==}
+ engines: {node: ^16.0.0 || >=18.0.0}
+ dependencies:
+ '@typescript-eslint/types': 6.18.1
+ eslint-visitor-keys: 3.4.3
+ dev: true
+
+ /@ungap/structured-clone@1.2.0:
+ resolution: {integrity: sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==}
+ dev: true
+
+ /@uppy/aws-s3-multipart@2.4.3(@uppy/core@2.3.4):
+ resolution: {integrity: sha512-2z/mTmDceQimsHGEXuhdUL6v7Twsj1TKLDTxp+YPEtf9cuSBhzwkUd/YltHHa8tH/ocdDXs4rwLuMZBXNIo0Qw==}
+ peerDependencies:
+ '@uppy/core': ^2.3.3
+ dependencies:
+ '@uppy/companion-client': 2.2.2
+ '@uppy/core': 2.3.4
+ '@uppy/utils': 4.1.3
+ dev: false
+
+ /@uppy/aws-s3-multipart@3.10.0(@uppy/core@3.8.0):
+ resolution: {integrity: sha512-WzMOMFwz+zDpTPgiciIguz4ANskdmNYgUdQ0mkz/8UEnwOcfncD6S9MO6nMmRPqax2C0+CugROYGUzA2t5aSWA==}
+ peerDependencies:
+ '@uppy/core': ^3.8.0
+ dependencies:
+ '@uppy/companion-client': 3.7.0
+ '@uppy/core': 3.8.0
+ '@uppy/utils': 5.7.0
+ dev: false
+
+ /@uppy/aws-s3@3.6.0(@uppy/core@3.8.0):
+ resolution: {integrity: sha512-CbQH+RwX2ZdZZur7kG8N+Re17PQO/TGe0Tl4kh1Lbz/Tajjg3M1vL7a0DAd9MFakIC44h27MMIUiD3sZqaOWuQ==}
+ peerDependencies:
+ '@uppy/core': ^3.8.0
+ dependencies:
+ '@uppy/aws-s3-multipart': 3.10.0(@uppy/core@3.8.0)
+ '@uppy/companion-client': 3.7.0
+ '@uppy/core': 3.8.0
+ '@uppy/utils': 5.7.0
+ '@uppy/xhr-upload': 3.6.0(@uppy/core@3.8.0)
+ nanoid: 4.0.2
+ dev: false
+
+ /@uppy/box@2.2.0(@uppy/core@3.8.0):
+ resolution: {integrity: sha512-n59tcqTzYLgYMbZ3U7bUq9VUIMqifrLPu/yJOfx875jg+tjwsAVNVKN1SIlpcr2DArcd7Q1mhlPPshUWJpH47A==}
+ peerDependencies:
+ '@uppy/core': ^3.8.0
+ dependencies:
+ '@uppy/companion-client': 3.7.0
+ '@uppy/core': 3.8.0
+ '@uppy/provider-views': 3.8.0(@uppy/core@3.8.0)
+ '@uppy/utils': 5.7.0
+ preact: 10.12.1
+ dev: false
+
+ /@uppy/companion-client@2.2.2:
+ resolution: {integrity: sha512-5mTp2iq97/mYSisMaBtFRry6PTgZA6SIL7LePteOV5x0/DxKfrZW3DEiQERJmYpHzy7k8johpm2gHnEKto56Og==}
+ dependencies:
+ '@uppy/utils': 4.1.3
+ namespace-emitter: 2.0.1
+ dev: false
+
+ /@uppy/companion-client@3.7.0:
+ resolution: {integrity: sha512-37qJNMkqo01SM9h2gkFbV6e+aXM02s2zAda2dGsRLRsjvl/Tx69NlmxJ3xqG/7HWRnYcbBWtspb7y0tt1i/afg==}
+ dependencies:
+ '@uppy/utils': 5.7.0
+ namespace-emitter: 2.0.1
+ p-retry: 6.2.0
+ dev: false
+
+ /@uppy/companion@4.12.0:
+ resolution: {integrity: sha512-Q/1c7HZ/XwMiy0vY978fgFsfOumW8M2AHSIDnAceFKrLkBVQVL+SXj8DnkUTgsxzI/TLShCmuj0kU4oTeC+4rg==}
+ engines: {node: ^14.19.0 || ^16.15.0 || >=18.0.0}
+ hasBin: true
+ dependencies:
+ '@aws-sdk/client-s3': 3.490.0
+ '@aws-sdk/client-sts': 3.490.0
+ '@aws-sdk/lib-storage': 3.490.0(@aws-sdk/client-s3@3.490.0)
+ '@aws-sdk/s3-presigned-post': 3.490.0
+ '@aws-sdk/s3-request-presigner': 3.490.0
+ atob: 2.1.2
+ body-parser: 1.20.0
+ chalk: 4.1.2
+ common-tags: 1.8.2
+ connect-redis: 7.1.0(express-session@1.17.3)
+ content-disposition: 0.5.4
+ cookie-parser: 1.4.6
+ cors: 2.8.5
+ escape-goat: 3.0.0
+ escape-string-regexp: 4.0.0
+ express: 4.18.1
+ express-interceptor: 1.2.0
+ express-prom-bundle: 6.5.0(prom-client@14.0.1)
+ express-request-id: 1.4.1
+ express-session: 1.17.3
+ form-data: 3.0.1
+ got: 11.8.6
+ grant: 5.4.21
+ helmet: 4.6.0
+ ipaddr.js: 2.1.0
+ jsonwebtoken: 9.0.0
+ lodash: 4.17.21
+ mime-types: 2.1.35
+ moment: 2.30.1
+ moment-timezone: 0.5.44
+ morgan: 1.10.0
+ ms: 2.1.3
+ node-schedule: 2.1.0
+ prom-client: 14.0.1
+ redis: 4.2.0
+ serialize-error: 2.1.0
+ serialize-javascript: 6.0.2
+ tus-js-client: 3.1.3
+ validator: 13.11.0
+ ws: 8.8.1
+ transitivePeerDependencies:
+ - aws-crt
+ - bufferutil
+ - supports-color
+ - utf-8-validate
+ dev: false
+
+ /@uppy/core@2.3.4:
+ resolution: {integrity: sha512-iWAqppC8FD8mMVqewavCz+TNaet6HPXitmGXpGGREGrakZ4FeuWytVdrelydzTdXx6vVKkOmI2FLztGg73sENQ==}
+ dependencies:
+ '@transloadit/prettier-bytes': 0.0.7
+ '@uppy/store-default': 2.1.1
+ '@uppy/utils': 4.1.3
+ lodash.throttle: 4.1.1
+ mime-match: 1.0.2
+ namespace-emitter: 2.0.1
+ nanoid: 3.3.7
+ preact: 10.19.3
+ dev: false
+
+ /@uppy/core@3.8.0:
+ resolution: {integrity: sha512-C93vVhid929+VLGjaD9CZOLJDg8GkEGMUGveFp3Tyo/wujiG+sB3fOF+c6TzKpzPLfNtVpskU1BnI7tZrq1LWw==}
+ dependencies:
+ '@transloadit/prettier-bytes': 0.0.9
+ '@uppy/store-default': 3.2.0
+ '@uppy/utils': 5.7.0
+ lodash: 4.17.21
+ mime-match: 1.0.2
+ namespace-emitter: 2.0.1
+ nanoid: 4.0.2
+ preact: 10.12.1
+ dev: false
+
+ /@uppy/dashboard@3.7.1(@uppy/core@3.8.0):
+ resolution: {integrity: sha512-qtCMXd2Ymrw0qNGSTlEEMyyDkGUCm+wX5/VrmV9lnfT7JtlSfotUK0K6KvkBeu2v1Chsu27C6Xlq6RddZMR2xQ==}
+ peerDependencies:
+ '@uppy/core': ^3.7.1
+ dependencies:
+ '@transloadit/prettier-bytes': 0.0.7
+ '@uppy/core': 3.8.0
+ '@uppy/informer': 3.0.4(@uppy/core@3.8.0)
+ '@uppy/provider-views': 3.8.0(@uppy/core@3.8.0)
+ '@uppy/status-bar': 3.2.5(@uppy/core@3.8.0)
+ '@uppy/thumbnail-generator': 3.0.6(@uppy/core@3.8.0)
+ '@uppy/utils': 5.7.0
+ classnames: 2.5.1
+ is-shallow-equal: 1.0.1
+ lodash: 4.17.21
+ memoize-one: 6.0.0
+ nanoid: 4.0.2
+ preact: 10.12.1
+ dev: false
+
+ /@uppy/drag-drop@3.0.3(@uppy/core@3.8.0):
+ resolution: {integrity: sha512-0bCgQKxg+9vkxQipTgrX9yQIuK9a0hZrkipm1+Ynq6jTeig49b7II1bWYnoKdiYhi6nRE4UnDJf4z09yCAU7rA==}
+ peerDependencies:
+ '@uppy/core': ^3.4.0
+ dependencies:
+ '@uppy/core': 3.8.0
+ '@uppy/utils': 5.7.0
+ preact: 10.12.1
+ dev: false
+
+ /@uppy/dropbox@3.2.0(@uppy/core@3.8.0):
+ resolution: {integrity: sha512-gJ3516kmG3Ogg92GyevKh26W4ByNzTEEZsf+vQe/InaPsdxZcuJKq7vRlGn9z6xMu5gisSX32z1YzGgjSNAtFw==}
+ peerDependencies:
+ '@uppy/core': ^3.8.0
+ dependencies:
+ '@uppy/companion-client': 3.7.0
+ '@uppy/core': 3.8.0
+ '@uppy/provider-views': 3.8.0(@uppy/core@3.8.0)
+ '@uppy/utils': 5.7.0
+ preact: 10.12.1
+ dev: false
+
+ /@uppy/facebook@3.2.0(@uppy/core@3.8.0):
+ resolution: {integrity: sha512-G2VWV/IrFV1M5pAD3o6tqo3hmtkbCgLbIUxOtRzvcPfKFDLAkjURQPUbsr0sgSjbot7FgAYWRwb5lmbLh5Szjg==}
+ peerDependencies:
+ '@uppy/core': ^3.8.0
+ dependencies:
+ '@uppy/companion-client': 3.7.0
+ '@uppy/core': 3.8.0
+ '@uppy/provider-views': 3.8.0(@uppy/core@3.8.0)
+ '@uppy/utils': 5.7.0
+ preact: 10.12.1
+ dev: false
+
+ /@uppy/file-input@3.0.4(@uppy/core@3.8.0):
+ resolution: {integrity: sha512-D7Nw9GgpABYTcC8SZluDyxd+ppe7+gJejNbPZqMpQyW1S/ME3me55dkDQaVWn8yrgv7347zO2ciue9Rfmko+rQ==}
+ peerDependencies:
+ '@uppy/core': ^3.6.0
+ dependencies:
+ '@uppy/core': 3.8.0
+ '@uppy/utils': 5.7.0
+ preact: 10.12.1
+ dev: false
+
+ /@uppy/google-drive@3.4.0(@uppy/core@3.8.0):
+ resolution: {integrity: sha512-QqWNaIi9VYap7hjFA34f0p47/dKylOyzwkF1nKl5REtLG5t0e99gOfQpTYEc7cUBvEqiOB3EipXmrVyDvBNqMA==}
+ peerDependencies:
+ '@uppy/core': ^3.8.0
+ dependencies:
+ '@uppy/companion-client': 3.7.0
+ '@uppy/core': 3.8.0
+ '@uppy/provider-views': 3.8.0(@uppy/core@3.8.0)
+ '@uppy/utils': 5.7.0
+ preact: 10.12.1
+ dev: false
+
+ /@uppy/informer@3.0.4(@uppy/core@3.8.0):
+ resolution: {integrity: sha512-gzocdxn8qAFsW2EryehwjghladaBgv6Isjte53FTBV7o/vjaHPP6huKGbYpljyuQi8i9V+KrmvNGslofssgJ4g==}
+ peerDependencies:
+ '@uppy/core': ^3.6.0
+ dependencies:
+ '@uppy/core': 3.8.0
+ '@uppy/utils': 5.7.0
+ preact: 10.12.1
+ dev: false
+
+ /@uppy/instagram@3.2.0(@uppy/core@3.8.0):
+ resolution: {integrity: sha512-KmSi/Frn1WNHTu6zQA0GwAJuy4K8JopuYg16jjy02imq8H5szG/dTC2lr6wxsfhXGzOGvX0/x9oLUFC6ipD9dg==}
+ peerDependencies:
+ '@uppy/core': ^3.8.0
+ dependencies:
+ '@uppy/companion-client': 3.7.0
+ '@uppy/core': 3.8.0
+ '@uppy/provider-views': 3.8.0(@uppy/core@3.8.0)
+ '@uppy/utils': 5.7.0
+ preact: 10.12.1
+ dev: false
+
+ /@uppy/onedrive@3.2.0(@uppy/core@3.8.0):
+ resolution: {integrity: sha512-VsAcWUAi6T+V0KxB5PyxTIT3c/bYGlAWWIDZTD+a4zkmgf7wDMozd5ww8NTMUHBjssrv+TVLVXgc06e0b++0gA==}
+ peerDependencies:
+ '@uppy/core': ^3.8.0
+ dependencies:
+ '@uppy/companion-client': 3.7.0
+ '@uppy/core': 3.8.0
+ '@uppy/provider-views': 3.8.0(@uppy/core@3.8.0)
+ '@uppy/utils': 5.7.0
+ preact: 10.12.1
+ dev: false
+
+ /@uppy/progress-bar@3.0.4(@uppy/core@3.8.0):
+ resolution: {integrity: sha512-sxv/mG7Uc9uyTnRvfcXBhO+TWd+UqjuW5aHXCKWwTkMgDShHR0T46sEk12q+jwgbFwyeFg3p0GU3hgUxqxiEUQ==}
+ peerDependencies:
+ '@uppy/core': ^3.6.0
+ dependencies:
+ '@uppy/core': 3.8.0
+ '@uppy/utils': 5.7.0
+ preact: 10.12.1
+ dev: false
+
+ /@uppy/provider-views@3.8.0(@uppy/core@3.8.0):
+ resolution: {integrity: sha512-sTtx5bgsg2WVR+MyF0gnnM3Z7g3CyFx+Stlz//AvB6g27EMqtqO4zwDR3mestMrETkWYov5bhhqUbt2BaeANpA==}
+ peerDependencies:
+ '@uppy/core': ^3.8.0
+ dependencies:
+ '@uppy/core': 3.8.0
+ '@uppy/utils': 5.7.0
+ classnames: 2.5.1
+ nanoid: 4.0.2
+ p-queue: 7.4.1
+ preact: 10.12.1
+ dev: false
+
+ /@uppy/react@3.2.1(@uppy/core@3.8.0)(@uppy/dashboard@3.7.1)(@uppy/drag-drop@3.0.3)(@uppy/file-input@3.0.4)(@uppy/progress-bar@3.0.4)(react@18.2.0):
+ resolution: {integrity: sha512-PoLplDF6YDI7f06T8ORnJhav6CcKNSYWJETXqItZR3jcXIve6pdcCuskqd+l0yiYWf4J2IdyLQXtzgGfIJl7xQ==}
+ peerDependencies:
+ '@uppy/core': ^3.7.1
+ '@uppy/dashboard': ^3.7.1
+ '@uppy/drag-drop': ^3.0.3
+ '@uppy/file-input': ^3.0.4
+ '@uppy/progress-bar': ^3.0.4
+ '@uppy/status-bar': ^3.2.5
+ react: ^16.0.0 || ^17.0.0 || ^18.0.0
+ peerDependenciesMeta:
+ '@uppy/dashboard':
+ optional: true
+ '@uppy/drag-drop':
+ optional: true
+ '@uppy/file-input':
+ optional: true
+ '@uppy/progress-bar':
+ optional: true
+ '@uppy/status-bar':
+ optional: true
+ dependencies:
+ '@uppy/core': 3.8.0
+ '@uppy/dashboard': 3.7.1(@uppy/core@3.8.0)
+ '@uppy/drag-drop': 3.0.3(@uppy/core@3.8.0)
+ '@uppy/file-input': 3.0.4(@uppy/core@3.8.0)
+ '@uppy/progress-bar': 3.0.4(@uppy/core@3.8.0)
+ '@uppy/utils': 5.7.0
+ prop-types: 15.8.1
+ react: 18.2.0
+ dev: false
+
+ /@uppy/remote-sources@1.1.0(@uppy/core@3.8.0):
+ resolution: {integrity: sha512-OHLoNafZAfDzGHOr3RRxapih0HifUFNMWNorP7W5qf0Khrf2PSs7hLQTu+SG/akCrZLzlBt8ooBUISmEwGs46g==}
+ peerDependencies:
+ '@uppy/core': ^3.6.0
+ dependencies:
+ '@uppy/box': 2.2.0(@uppy/core@3.8.0)
+ '@uppy/core': 3.8.0
+ '@uppy/dashboard': 3.7.1(@uppy/core@3.8.0)
+ '@uppy/dropbox': 3.2.0(@uppy/core@3.8.0)
+ '@uppy/facebook': 3.2.0(@uppy/core@3.8.0)
+ '@uppy/google-drive': 3.4.0(@uppy/core@3.8.0)
+ '@uppy/instagram': 3.2.0(@uppy/core@3.8.0)
+ '@uppy/onedrive': 3.2.0(@uppy/core@3.8.0)
+ '@uppy/unsplash': 3.2.3(@uppy/core@3.8.0)
+ '@uppy/url': 3.5.0(@uppy/core@3.8.0)
+ '@uppy/zoom': 2.2.0(@uppy/core@3.8.0)
+ dev: false
+
+ /@uppy/status-bar@3.2.5(@uppy/core@3.8.0):
+ resolution: {integrity: sha512-bRSxBPio5B+Kuf6w8ll+/i9VUwG8f0FnbZ1yQvCr8J9vxhd0Z5hvwhX4NP8uzHC6ZPJHlEQOTsxzGQ6y+Mdm0A==}
+ peerDependencies:
+ '@uppy/core': ^3.6.0
+ dependencies:
+ '@transloadit/prettier-bytes': 0.0.9
+ '@uppy/core': 3.8.0
+ '@uppy/utils': 5.7.0
+ classnames: 2.5.1
+ preact: 10.12.1
+ dev: false
+
+ /@uppy/store-default@2.1.1:
+ resolution: {integrity: sha512-xnpTxvot2SeAwGwbvmJ899ASk5tYXhmZzD/aCFsXePh/v8rNvR2pKlcQUH7cF/y4baUGq3FHO/daKCok/mpKqQ==}
+ dev: false
+
+ /@uppy/store-default@3.2.0:
+ resolution: {integrity: sha512-Y7t0peUG89ZKa30vM4qlRIC6uKxIfOANeMT9Nzjwcxvzz8l7es22jG3eAj9WF2F7YSu7xdsH8ODs6SIrJJ8gow==}
+ dev: false
+
+ /@uppy/thumbnail-generator@3.0.6(@uppy/core@3.8.0):
+ resolution: {integrity: sha512-gsi/BQBiunHneXCbo8VglFbhEb0CoQXQjCyGNKoEq/deEcbXhBBDxkiGcgv83l5GZJl2jLiKWqXnXAXREkldrQ==}
+ peerDependencies:
+ '@uppy/core': ^3.6.0
+ dependencies:
+ '@uppy/core': 3.8.0
+ '@uppy/utils': 5.7.0
+ exifr: 7.1.3
+ dev: false
+
+ /@uppy/unsplash@3.2.3(@uppy/core@3.8.0):
+ resolution: {integrity: sha512-+3ubnrACFO0kqnYGOCZQXKPcl6WJaj4GouXdnn+c6axgYQrMNUQMrMeGGTRx/pvKAm8qWY4y8LEv+UjJMIHpKw==}
+ peerDependencies:
+ '@uppy/core': ^3.6.0
+ dependencies:
+ '@uppy/companion-client': 3.7.0
+ '@uppy/core': 3.8.0
+ '@uppy/provider-views': 3.8.0(@uppy/core@3.8.0)
+ '@uppy/utils': 5.7.0
+ preact: 10.12.1
+ dev: false
+
+ /@uppy/url@3.5.0(@uppy/core@3.8.0):
+ resolution: {integrity: sha512-uNdfe0OLAtkrDlL9fwLN+zo/sQl01StEsaytT/JrhK4Hdw/15KYiTmmMbDGBdSSpDoKC54wuebSpR+c8KKC2EA==}
+ peerDependencies:
+ '@uppy/core': ^3.8.0
+ dependencies:
+ '@uppy/companion-client': 3.7.0
+ '@uppy/core': 3.8.0
+ '@uppy/utils': 5.7.0
+ nanoid: 4.0.2
+ preact: 10.12.1
+ dev: false
+
+ /@uppy/utils@4.1.3:
+ resolution: {integrity: sha512-nTuMvwWYobnJcytDO3t+D6IkVq/Qs4Xv3vyoEZ+Iaf8gegZP+rEyoaFT2CK5XLRMienPyqRqNbIfRuFaOWSIFw==}
+ dependencies:
+ lodash.throttle: 4.1.1
+ dev: false
+
+ /@uppy/utils@5.7.0:
+ resolution: {integrity: sha512-AJj7gAx5YfMgyevwOxVdIP2h4Nw/O6h57wKA6gj+Lce6tMORcqzGt4yQiKBsrBI0bPyFWCbzA3vX5t0//1JCBA==}
+ dependencies:
+ lodash: 4.17.21
+ preact: 10.19.3
+ dev: false
+
+ /@uppy/xhr-upload@3.6.0(@uppy/core@3.8.0):
+ resolution: {integrity: sha512-HgWr+CvJzJXAp639AiZatdEWmRdhhN5LrjTZurAkvm9nPQarpi1bo0DChO+1bpkXWOR/1VarBbZOr8lNecEn7Q==}
+ peerDependencies:
+ '@uppy/core': ^3.8.0
+ dependencies:
+ '@uppy/companion-client': 3.7.0
+ '@uppy/core': 3.8.0
+ '@uppy/utils': 5.7.0
+ nanoid: 4.0.2
+ dev: false
+
+ /@uppy/zoom@2.2.0(@uppy/core@3.8.0):
+ resolution: {integrity: sha512-+UTfuFicCFaBsp7SiJVJ7O+YJSxz1g83AJ/ZL6zQAq2HWw/jT0GF/Ttb+f40nauJ6vMLrIbucOJZEWSj42Im8Q==}
+ peerDependencies:
+ '@uppy/core': ^3.8.0
+ dependencies:
+ '@uppy/companion-client': 3.7.0
+ '@uppy/core': 3.8.0
+ '@uppy/provider-views': 3.8.0(@uppy/core@3.8.0)
+ '@uppy/utils': 5.7.0
+ preact: 10.12.1
+ dev: false
+
+ /abbrev@1.1.1:
+ resolution: {integrity: sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==}
+ dev: true
+
+ /accepts@1.3.8:
+ resolution: {integrity: sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==}
+ engines: {node: '>= 0.6'}
+ dependencies:
+ mime-types: 2.1.35
+ negotiator: 0.6.3
+ dev: false
+
+ /acorn-jsx@5.3.2(acorn@8.11.3):
+ resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==}
+ peerDependencies:
+ acorn: ^6.0.0 || ^7.0.0 || ^8.0.0
+ dependencies:
+ acorn: 8.11.3
+ dev: true
+
+ /acorn@8.11.3:
+ resolution: {integrity: sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==}
+ engines: {node: '>=0.4.0'}
+ hasBin: true
+ dev: true
+
+ /ajv@6.12.6:
+ resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==}
+ dependencies:
+ fast-deep-equal: 3.1.3
+ fast-json-stable-stringify: 2.1.0
+ json-schema-traverse: 0.4.1
+ uri-js: 4.4.1
+ dev: true
+
+ /ansi-regex@5.0.1:
+ resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==}
+ engines: {node: '>=8'}
+ dev: true
+
+ /ansi-styles@4.3.0:
+ resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==}
+ engines: {node: '>=8'}
+ dependencies:
+ color-convert: 2.0.1
+
+ /anymatch@3.1.3:
+ resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==}
+ engines: {node: '>= 8'}
+ dependencies:
+ normalize-path: 3.0.0
+ picomatch: 2.3.1
+
+ /argparse@1.0.10:
+ resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==}
+ dependencies:
+ sprintf-js: 1.0.3
+ dev: false
+
+ /argparse@2.0.1:
+ resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==}
+ dev: true
+
+ /aria-query@5.3.0:
+ resolution: {integrity: sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==}
+ dependencies:
+ dequal: 2.0.3
+ dev: true
+
+ /array-buffer-byte-length@1.0.0:
+ resolution: {integrity: sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A==}
+ dependencies:
+ call-bind: 1.0.5
+ is-array-buffer: 3.0.2
+ dev: true
+
+ /array-flatten@1.1.1:
+ resolution: {integrity: sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==}
+ dev: false
+
+ /array-includes@3.1.7:
+ resolution: {integrity: sha512-dlcsNBIiWhPkHdOEEKnehA+RNUWDc4UqFtnIXU4uuYDPtA4LDkr7qip2p0VvFAEXNDr0yWZ9PJyIRiGjRLQzwQ==}
+ engines: {node: '>= 0.4'}
+ dependencies:
+ call-bind: 1.0.5
+ define-properties: 1.2.1
+ es-abstract: 1.22.3
+ get-intrinsic: 1.2.2
+ is-string: 1.0.7
+ dev: true
+
+ /array-union@2.1.0:
+ resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==}
+ engines: {node: '>=8'}
+ dev: true
+
+ /array.prototype.findlastindex@1.2.3:
+ resolution: {integrity: sha512-LzLoiOMAxvy+Gd3BAq3B7VeIgPdo+Q8hthvKtXybMvRV0jrXfJM/t8mw7nNlpEcVlVUnCnM2KSX4XU5HmpodOA==}
+ engines: {node: '>= 0.4'}
+ dependencies:
+ call-bind: 1.0.5
+ define-properties: 1.2.1
+ es-abstract: 1.22.3
+ es-shim-unscopables: 1.0.2
+ get-intrinsic: 1.2.2
+ dev: true
+
+ /array.prototype.flat@1.3.2:
+ resolution: {integrity: sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA==}
+ engines: {node: '>= 0.4'}
+ dependencies:
+ call-bind: 1.0.5
+ define-properties: 1.2.1
+ es-abstract: 1.22.3
+ es-shim-unscopables: 1.0.2
+ dev: true
+
+ /array.prototype.flatmap@1.3.2:
+ resolution: {integrity: sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ==}
+ engines: {node: '>= 0.4'}
+ dependencies:
+ call-bind: 1.0.5
+ define-properties: 1.2.1
+ es-abstract: 1.22.3
+ es-shim-unscopables: 1.0.2
+ dev: true
+
+ /array.prototype.tosorted@1.1.2:
+ resolution: {integrity: sha512-HuQCHOlk1Weat5jzStICBCd83NxiIMwqDg/dHEsoefabn/hJRj5pVdWcPUSpRrwhwxZOsQassMpgN/xRYFBMIg==}
+ dependencies:
+ call-bind: 1.0.5
+ define-properties: 1.2.1
+ es-abstract: 1.22.3
+ es-shim-unscopables: 1.0.2
+ get-intrinsic: 1.2.2
+ dev: true
+
+ /arraybuffer.prototype.slice@1.0.2:
+ resolution: {integrity: sha512-yMBKppFur/fbHu9/6USUe03bZ4knMYiwFBcyiaXB8Go0qNehwX6inYPzK9U0NeQvGxKthcmHcaR8P5MStSRBAw==}
+ engines: {node: '>= 0.4'}
+ dependencies:
+ array-buffer-byte-length: 1.0.0
+ call-bind: 1.0.5
+ define-properties: 1.2.1
+ es-abstract: 1.22.3
+ get-intrinsic: 1.2.2
+ is-array-buffer: 3.0.2
+ is-shared-array-buffer: 1.0.2
+ dev: true
+
+ /asn1.js@5.4.1:
+ resolution: {integrity: sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA==}
+ requiresBuild: true
+ dependencies:
+ bn.js: 4.12.0
+ inherits: 2.0.4
+ minimalistic-assert: 1.0.1
+ safer-buffer: 2.1.2
+ dev: false
+ optional: true
+
+ /ast-types-flow@0.0.8:
+ resolution: {integrity: sha512-OH/2E5Fg20h2aPrbe+QL8JZQFko0YZaF+j4mnQ7BGhfavO7OpSLa8a0y9sBwomHdSbkhTS8TQNayBfnW5DwbvQ==}
+ dev: true
+
+ /asynciterator.prototype@1.0.0:
+ resolution: {integrity: sha512-wwHYEIS0Q80f5mosx3L/dfG5t5rjEa9Ft51GTaNt862EnpyGHpgz2RkZvLPp1oF5TnAiTohkEKVEu8pQPJI7Vg==}
+ dependencies:
+ has-symbols: 1.0.3
+ dev: true
+
+ /asynckit@0.4.0:
+ resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==}
+ dev: false
+
+ /atob@2.1.2:
+ resolution: {integrity: sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==}
+ engines: {node: '>= 4.5.0'}
+ hasBin: true
+ dev: false
+
+ /available-typed-arrays@1.0.5:
+ resolution: {integrity: sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==}
+ engines: {node: '>= 0.4'}
+ dev: true
+
+ /axe-core@4.7.0:
+ resolution: {integrity: sha512-M0JtH+hlOL5pLQwHOLNYZaXuhqmvS8oExsqB1SBYgA4Dk7u/xx+YdGHXaK5pyUfed5mYXdlYiphWq3G8cRi5JQ==}
+ engines: {node: '>=4'}
+ dev: true
+
+ /axobject-query@3.2.1:
+ resolution: {integrity: sha512-jsyHu61e6N4Vbz/v18DHwWYKK0bSWLqn47eeDSKPB7m8tqMHF9YJ+mhIk2lVteyZrY8tnSj/jHOv4YiTCuCJgg==}
+ dependencies:
+ dequal: 2.0.3
+ dev: true
+
+ /balanced-match@1.0.2:
+ resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
+ dev: true
+
+ /base64-js@1.5.1:
+ resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==}
+ dev: false
+
+ /basic-auth@2.0.1:
+ resolution: {integrity: sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg==}
+ engines: {node: '>= 0.8'}
+ dependencies:
+ safe-buffer: 5.1.2
+ dev: false
+
+ /binary-extensions@2.2.0:
+ resolution: {integrity: sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==}
+ engines: {node: '>=8'}
+
+ /binary-search-bounds@2.0.5:
+ resolution: {integrity: sha512-H0ea4Fd3lS1+sTEB2TgcLoK21lLhwEJzlQv3IN47pJS976Gx4zoWe0ak3q+uYh60ppQxg9F16Ri4tS1sfD4+jA==}
+ dev: false
+
+ /bintrees@1.0.2:
+ resolution: {integrity: sha512-VOMgTMwjAaUG580SXn3LacVgjurrbMme7ZZNYGSSV7mmtY6QQRh0Eg3pwIcntQ77DErK1L0NxkbetjcoXzVwKw==}
+ dev: false
+
+ /bl@4.1.0:
+ resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==}
+ dependencies:
+ buffer: 5.7.1
+ inherits: 2.0.4
+ readable-stream: 3.6.2
+ dev: false
+
+ /blurhash@1.1.5:
+ resolution: {integrity: sha512-a+LO3A2DfxTaTztsmkbLYmUzUeApi0LZuKalwbNmqAHR6HhJGMt1qSV/R3wc+w4DL28holjqO3Bg74aUGavGjg==}
+ dev: false
+
+ /bn.js@4.12.0:
+ resolution: {integrity: sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==}
+ requiresBuild: true
+ dev: false
+ optional: true
+
+ /body-parser@1.20.0:
+ resolution: {integrity: sha512-DfJ+q6EPcGKZD1QWUjSpqp+Q7bDQTsQIF4zfUAtZ6qk+H/3/QRhg9CEp39ss+/T2vw0+HaidC0ecJj/DRLIaKg==}
+ engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16}
+ dependencies:
+ bytes: 3.1.2
+ content-type: 1.0.5
+ debug: 2.6.9
+ depd: 2.0.0
+ destroy: 1.2.0
+ http-errors: 2.0.0
+ iconv-lite: 0.4.24
+ on-finished: 2.4.1
+ qs: 6.10.3
+ raw-body: 2.5.1
+ type-is: 1.6.18
+ unpipe: 1.0.0
+ transitivePeerDependencies:
+ - supports-color
+ dev: false
+
+ /body-parser@1.20.1:
+ resolution: {integrity: sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==}
+ engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16}
+ dependencies:
+ bytes: 3.1.2
+ content-type: 1.0.5
+ debug: 2.6.9
+ depd: 2.0.0
+ destroy: 1.2.0
+ http-errors: 2.0.0
+ iconv-lite: 0.4.24
+ on-finished: 2.4.1
+ qs: 6.11.0
+ raw-body: 2.5.1
+ type-is: 1.6.18
+ unpipe: 1.0.0
+ transitivePeerDependencies:
+ - supports-color
+ dev: false
+
+ /body-parser@1.20.2:
+ resolution: {integrity: sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==}
+ engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16}
+ dependencies:
+ bytes: 3.1.2
+ content-type: 1.0.5
+ debug: 2.6.9
+ depd: 2.0.0
+ destroy: 1.2.0
+ http-errors: 2.0.0
+ iconv-lite: 0.4.24
+ on-finished: 2.4.1
+ qs: 6.11.0
+ raw-body: 2.5.2
+ type-is: 1.6.18
+ unpipe: 1.0.0
+ transitivePeerDependencies:
+ - supports-color
+ dev: false
+
+ /bowser@2.11.0:
+ resolution: {integrity: sha512-AlcaJBi/pqqJBIQ8U9Mcpc9i8Aqxn88Skv5d+xBX006BY5u8N3mGLHa5Lgppa7L/HfwgwLgZ6NYs+Ag6uUmJRA==}
+ dev: false
+
+ /brace-expansion@1.1.11:
+ resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==}
+ dependencies:
+ balanced-match: 1.0.2
+ concat-map: 0.0.1
+ dev: true
+
+ /brace-expansion@2.0.1:
+ resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==}
+ dependencies:
+ balanced-match: 1.0.2
+ dev: true
+
+ /braces@3.0.2:
+ resolution: {integrity: sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==}
+ engines: {node: '>=8'}
+ dependencies:
+ fill-range: 7.0.1
+
+ /brorand@1.1.0:
+ resolution: {integrity: sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==}
+ requiresBuild: true
+ dev: false
+ optional: true
+
+ /buffer-equal-constant-time@1.0.1:
+ resolution: {integrity: sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==}
+ dev: false
+
+ /buffer-from@1.1.2:
+ resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==}
+ dev: false
+
+ /buffer@5.6.0:
+ resolution: {integrity: sha512-/gDYp/UtU0eA1ys8bOs9J6a+E/KWIY+DZ+Q2WESNUA0jFRsJOc0SNUO6xJ5SGA1xueg3NL65W6s+NY5l9cunuw==}
+ dependencies:
+ base64-js: 1.5.1
+ ieee754: 1.2.1
+ dev: false
+
+ /buffer@5.7.1:
+ resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==}
+ dependencies:
+ base64-js: 1.5.1
+ ieee754: 1.2.1
+ dev: false
+
+ /bulma-prefers-dark@0.1.0-beta.1:
+ resolution: {integrity: sha512-ti4sKxIIrTAvGtsYc9Rk66SUZSH/j63EU1hApQijQVlKFF0qBLGSb8E16HhI83KJaIeYP4aAHQv2tj0ara831A==}
+ dev: false
+
+ /bulma@0.9.4:
+ resolution: {integrity: sha512-86FlT5+1GrsgKbPLRRY7cGDg8fsJiP/jzTqXXVqiUZZ2aZT8uemEOHlU1CDU+TxklPEZ11HZNNWclRBBecP4CQ==}
+ dev: false
+
+ /busboy@1.6.0:
+ resolution: {integrity: sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==}
+ engines: {node: '>=10.16.0'}
+ dependencies:
+ streamsearch: 1.1.0
+ dev: false
+
+ /bytes@3.1.2:
+ resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==}
+ engines: {node: '>= 0.8'}
+ dev: false
+
+ /cacheable-lookup@5.0.4:
+ resolution: {integrity: sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA==}
+ engines: {node: '>=10.6.0'}
+ dev: false
+
+ /cacheable-request@7.0.4:
+ resolution: {integrity: sha512-v+p6ongsrp0yTGbJXjgxPow2+DL93DASP4kXCDKb8/bwRtt9OEF3whggkkDkGNzgcWy2XaF4a8nZglC7uElscg==}
+ engines: {node: '>=8'}
+ dependencies:
+ clone-response: 1.0.3
+ get-stream: 5.2.0
+ http-cache-semantics: 4.1.1
+ keyv: 4.5.4
+ lowercase-keys: 2.0.0
+ normalize-url: 6.1.0
+ responselike: 2.0.1
+ dev: false
+
+ /cal-heatmap@4.2.4:
+ resolution: {integrity: sha512-TTNoQTRxHXrttOEbkraKv9vy2VpfQIwVLQJTlAfcBusQK9qrBL/UBO+WloAxv2yrR+P8URA2cuXEdc5iztER9g==}
+ dependencies:
+ '@observablehq/plot': 0.6.13
+ '@popperjs/core': 2.11.8
+ d3-color: 3.1.0
+ d3-fetch: 3.0.1
+ d3-selection: 3.0.0
+ d3-transition: 3.0.1(d3-selection@3.0.0)
+ dayjs: 1.11.10
+ eventemitter3: 5.0.1
+ lodash-es: 4.17.21
+ dev: false
+
+ /call-bind@1.0.5:
+ resolution: {integrity: sha512-C3nQxfFZxFRVoJoGKKI8y3MOEo129NQ+FgQ08iye+Mk4zNZZGdjfs06bVTr+DBSlA66Q2VEcMki/cUCP4SercQ==}
+ dependencies:
+ function-bind: 1.1.2
+ get-intrinsic: 1.2.2
+ set-function-length: 1.1.1
+
+ /callsites@3.1.0:
+ resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==}
+ engines: {node: '>=6'}
+ dev: true
+
+ /caniuse-lite@1.0.30001576:
+ resolution: {integrity: sha512-ff5BdakGe2P3SQsMsiqmt1Lc8221NR1VzHj5jXN5vBny9A6fpze94HiVV/n7XRosOlsShJcvMv5mdnpjOGCEgg==}
+ dev: false
+
+ /castable-video@1.0.6:
+ resolution: {integrity: sha512-Ykw2uL4ZQnqX0j9KF9ksbDpyc8I53mFMswCKW9yV5TrwpWkdNqRHLlcU85W30BIw61fgDjgm0Xh5G0rbcmv23g==}
+ dependencies:
+ custom-media-element: 1.2.2
+ dev: false
+
+ /chalk@4.1.2:
+ resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==}
+ engines: {node: '>=10'}
+ dependencies:
+ ansi-styles: 4.3.0
+ supports-color: 7.2.0
+
+ /chokidar@3.5.3:
+ resolution: {integrity: sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==}
+ engines: {node: '>= 8.10.0'}
+ dependencies:
+ anymatch: 3.1.3
+ braces: 3.0.2
+ glob-parent: 5.1.2
+ is-binary-path: 2.1.0
+ is-glob: 4.0.3
+ normalize-path: 3.0.0
+ readdirp: 3.6.0
+ optionalDependencies:
+ fsevents: 2.3.3
+
+ /chownr@1.1.4:
+ resolution: {integrity: sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==}
+ dev: false
+
+ /classnames@2.5.1:
+ resolution: {integrity: sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==}
+ dev: false
+
+ /client-only@0.0.1:
+ resolution: {integrity: sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==}
+ dev: false
+
+ /clone-response@1.0.3:
+ resolution: {integrity: sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA==}
+ dependencies:
+ mimic-response: 1.0.1
+ dev: false
+
+ /clsx@1.2.1:
+ resolution: {integrity: sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==}
+ engines: {node: '>=6'}
+ dev: false
+
+ /clsx@2.1.0:
+ resolution: {integrity: sha512-m3iNNWpd9rl3jvvcBnu70ylMdrXt8Vlq4HYadnU5fwcOtvkSQWPmj7amUcDT2qYI7risszBjI5AUIUox9D16pg==}
+ engines: {node: '>=6'}
+ dev: false
+
+ /cluster-key-slot@1.1.0:
+ resolution: {integrity: sha512-2Nii8p3RwAPiFwsnZvukotvow2rIHM+yQ6ZcBXGHdniadkYGZYiGmkHJIbZPIV9nfv7m/U1IPMVVcAhoWFeklw==}
+ engines: {node: '>=0.10.0'}
+ dev: false
+
+ /color-convert@2.0.1:
+ resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==}
+ engines: {node: '>=7.0.0'}
+ dependencies:
+ color-name: 1.1.4
+
+ /color-name@1.1.4:
+ resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==}
+
+ /color-string@1.9.1:
+ resolution: {integrity: sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==}
+ dependencies:
+ color-name: 1.1.4
+ simple-swizzle: 0.2.2
+ dev: false
+
+ /color@4.2.3:
+ resolution: {integrity: sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==}
+ engines: {node: '>=12.5.0'}
+ dependencies:
+ color-convert: 2.0.1
+ color-string: 1.9.1
+ dev: false
+
+ /combine-errors@3.0.3:
+ resolution: {integrity: sha512-C8ikRNRMygCwaTx+Ek3Yr+OuZzgZjduCOfSQBjbM8V3MfgcjSTeto/GXP6PAwKvJz/v15b7GHZvx5rOlczFw/Q==}
+ dependencies:
+ custom-error-instance: 2.1.1
+ lodash.uniqby: 4.5.0
+ dev: false
+
+ /combined-stream@1.0.8:
+ resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==}
+ engines: {node: '>= 0.8'}
+ dependencies:
+ delayed-stream: 1.0.0
+ dev: false
+
+ /commander@7.2.0:
+ resolution: {integrity: sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==}
+ engines: {node: '>= 10'}
+ dev: false
+
+ /common-tags@1.8.2:
+ resolution: {integrity: sha512-gk/Z852D2Wtb//0I+kRFNKKE9dIIVirjoqPoA1wJU+XePVXZfGeBpk45+A1rKO4Q43prqWBNY/MiIeRLbPWUaA==}
+ engines: {node: '>=4.0.0'}
+ dev: false
+
+ /concat-map@0.0.1:
+ resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==}
+ dev: true
+
+ /connect-redis@7.1.0(express-session@1.17.3):
+ resolution: {integrity: sha512-UaqO1EirWjON2ENsyau7N5lbkrdYBpS6mYlXSeff/OYXsd6EGZ+SXSmNPoljL2PSua8fgjAEaldSA73PMZQ9Eg==}
+ engines: {node: '>=16'}
+ peerDependencies:
+ express-session: '>=1'
+ dependencies:
+ express-session: 1.17.3
+ dev: false
+
+ /content-disposition@0.5.4:
+ resolution: {integrity: sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==}
+ engines: {node: '>= 0.6'}
+ dependencies:
+ safe-buffer: 5.2.1
+ dev: false
+
+ /content-type@1.0.5:
+ resolution: {integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==}
+ engines: {node: '>= 0.6'}
+ dev: false
+
+ /cookie-parser@1.4.6:
+ resolution: {integrity: sha512-z3IzaNjdwUC2olLIB5/ITd0/setiaFMLYiZJle7xg5Fe9KWAceil7xszYfHHBtDFYLSgJduS2Ty0P1uJdPDJeA==}
+ engines: {node: '>= 0.8.0'}
+ dependencies:
+ cookie: 0.4.1
+ cookie-signature: 1.0.6
+ dev: false
+
+ /cookie-signature@1.0.6:
+ resolution: {integrity: sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==}
+ dev: false
+
+ /cookie-signature@1.2.1:
+ resolution: {integrity: sha512-78KWk9T26NhzXtuL26cIJ8/qNHANyJ/ZYrmEXFzUmhZdjpBv+DlWlOANRTGBt48YcyslsLrj0bMLFTmXvLRCOw==}
+ engines: {node: '>=6.6.0'}
+ requiresBuild: true
+ dev: false
+ optional: true
+
+ /cookie@0.4.1:
+ resolution: {integrity: sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA==}
+ engines: {node: '>= 0.6'}
+ dev: false
+
+ /cookie@0.4.2:
+ resolution: {integrity: sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==}
+ engines: {node: '>= 0.6'}
+ dev: false
+
+ /cookie@0.5.0:
+ resolution: {integrity: sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==}
+ engines: {node: '>= 0.6'}
+ dev: false
+
+ /core-js@3.35.0:
+ resolution: {integrity: sha512-ntakECeqg81KqMueeGJ79Q5ZgQNR+6eaE8sxGCx62zMbAIj65q+uYvatToew3m6eAGdU4gNZwpZ34NMe4GYswg==}
+ requiresBuild: true
+ dev: false
+
+ /cors@2.8.5:
+ resolution: {integrity: sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==}
+ engines: {node: '>= 0.10'}
+ dependencies:
+ object-assign: 4.1.1
+ vary: 1.1.2
+ dev: false
+
+ /cron-parser@3.5.0:
+ resolution: {integrity: sha512-wyVZtbRs6qDfFd8ap457w3XVntdvqcwBGxBoTvJQH9KGVKL/fB+h2k3C8AqiVxvUQKN1Ps/Ns46CNViOpVDhfQ==}
+ engines: {node: '>=0.8'}
+ dependencies:
+ is-nan: 1.3.2
+ luxon: 1.28.1
+ dev: false
+
+ /cross-spawn@7.0.3:
+ resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==}
+ engines: {node: '>= 8'}
+ dependencies:
+ path-key: 3.1.1
+ shebang-command: 2.0.0
+ which: 2.0.2
+ dev: true
+
+ /csstype@3.1.3:
+ resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==}
+ dev: false
+
+ /custom-error-instance@2.1.1:
+ resolution: {integrity: sha512-p6JFxJc3M4OTD2li2qaHkDCw9SfMw82Ldr6OC9Je1aXiGfhx2W8p3GaoeaGrPJTUN9NirTM/KTxHWMUdR1rsUg==}
+ dev: false
+
+ /custom-event-polyfill@1.0.7:
+ resolution: {integrity: sha512-TDDkd5DkaZxZFM8p+1I3yAlvM3rSr1wbrOliG4yJiwinMZN8z/iGL7BTlDkrJcYTmgUSb4ywVCc3ZaUtOtC76w==}
+ dev: false
+
+ /custom-media-element@1.2.2:
+ resolution: {integrity: sha512-tI+NjVRS485QlSxHeM3JIjdEZSJMLOZVp41/vvWukDmIkZSoYG9gLYl9GFZGBpY42UbRVo1eMlF7XkI/IiDHzQ==}
+ dev: false
+
+ /d3-array@3.2.4:
+ resolution: {integrity: sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==}
+ engines: {node: '>=12'}
+ dependencies:
+ internmap: 2.0.3
+ dev: false
+
+ /d3-axis@3.0.0:
+ resolution: {integrity: sha512-IH5tgjV4jE/GhHkRV0HiVYPDtvfjHQlQfJHs0usq7M30XcSBvOotpmH1IgkcXsO/5gEQZD43B//fc7SRT5S+xw==}
+ engines: {node: '>=12'}
+ dev: false
+
+ /d3-brush@3.0.0:
+ resolution: {integrity: sha512-ALnjWlVYkXsVIGlOsuWH1+3udkYFI48Ljihfnh8FZPF2QS9o+PzGLBslO0PjzVoHLZ2KCVgAM8NVkXPJB2aNnQ==}
+ engines: {node: '>=12'}
+ dependencies:
+ d3-dispatch: 3.0.1
+ d3-drag: 3.0.0
+ d3-interpolate: 3.0.1
+ d3-selection: 3.0.0
+ d3-transition: 3.0.1(d3-selection@3.0.0)
+ dev: false
+
+ /d3-chord@3.0.1:
+ resolution: {integrity: sha512-VE5S6TNa+j8msksl7HwjxMHDM2yNK3XCkusIlpX5kwauBfXuyLAtNg9jCp/iHH61tgI4sb6R/EIMWCqEIdjT/g==}
+ engines: {node: '>=12'}
+ dependencies:
+ d3-path: 3.1.0
+ dev: false
+
+ /d3-color@3.1.0:
+ resolution: {integrity: sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==}
+ engines: {node: '>=12'}
+ dev: false
+
+ /d3-contour@4.0.2:
+ resolution: {integrity: sha512-4EzFTRIikzs47RGmdxbeUvLWtGedDUNkTcmzoeyg4sP/dvCexO47AaQL7VKy/gul85TOxw+IBgA8US2xwbToNA==}
+ engines: {node: '>=12'}
+ dependencies:
+ d3-array: 3.2.4
+ dev: false
+
+ /d3-delaunay@6.0.4:
+ resolution: {integrity: sha512-mdjtIZ1XLAM8bm/hx3WwjfHt6Sggek7qH043O8KEjDXN40xi3vx/6pYSVTwLjEgiXQTbvaouWKynLBiUZ6SK6A==}
+ engines: {node: '>=12'}
+ dependencies:
+ delaunator: 5.0.0
+ dev: false
+
+ /d3-dispatch@3.0.1:
+ resolution: {integrity: sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg==}
+ engines: {node: '>=12'}
+ dev: false
+
+ /d3-drag@3.0.0:
+ resolution: {integrity: sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg==}
+ engines: {node: '>=12'}
+ dependencies:
+ d3-dispatch: 3.0.1
+ d3-selection: 3.0.0
+ dev: false
+
+ /d3-dsv@3.0.1:
+ resolution: {integrity: sha512-UG6OvdI5afDIFP9w4G0mNq50dSOsXHJaRE8arAS5o9ApWnIElp8GZw1Dun8vP8OyHOZ/QJUKUJwxiiCCnUwm+Q==}
+ engines: {node: '>=12'}
+ hasBin: true
+ dependencies:
+ commander: 7.2.0
+ iconv-lite: 0.6.3
+ rw: 1.3.3
+ dev: false
+
+ /d3-ease@3.0.1:
+ resolution: {integrity: sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==}
+ engines: {node: '>=12'}
+ dev: false
+
+ /d3-fetch@3.0.1:
+ resolution: {integrity: sha512-kpkQIM20n3oLVBKGg6oHrUchHM3xODkTzjMoj7aWQFq5QEM+R6E4WkzT5+tojDY7yjez8KgCBRoj4aEr99Fdqw==}
+ engines: {node: '>=12'}
+ dependencies:
+ d3-dsv: 3.0.1
+ dev: false
+
+ /d3-force@3.0.0:
+ resolution: {integrity: sha512-zxV/SsA+U4yte8051P4ECydjD/S+qeYtnaIyAs9tgHCqfguma/aAQDjo85A9Z6EKhBirHRJHXIgJUlffT4wdLg==}
+ engines: {node: '>=12'}
+ dependencies:
+ d3-dispatch: 3.0.1
+ d3-quadtree: 3.0.1
+ d3-timer: 3.0.1
+ dev: false
+
+ /d3-format@3.1.0:
+ resolution: {integrity: sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA==}
+ engines: {node: '>=12'}
+ dev: false
+
+ /d3-geo@3.1.0:
+ resolution: {integrity: sha512-JEo5HxXDdDYXCaWdwLRt79y7giK8SbhZJbFWXqbRTolCHFI5jRqteLzCsq51NKbUoX0PjBVSohxrx+NoOUujYA==}
+ engines: {node: '>=12'}
+ dependencies:
+ d3-array: 3.2.4
+ dev: false
+
+ /d3-hierarchy@3.1.2:
+ resolution: {integrity: sha512-FX/9frcub54beBdugHjDCdikxThEqjnR93Qt7PvQTOHxyiNCAlvMrHhclk3cD5VeAaq9fxmfRp+CnWw9rEMBuA==}
+ engines: {node: '>=12'}
+ dev: false
+
+ /d3-interpolate@3.0.1:
+ resolution: {integrity: sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==}
+ engines: {node: '>=12'}
+ dependencies:
+ d3-color: 3.1.0
+ dev: false
+
+ /d3-path@3.1.0:
+ resolution: {integrity: sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==}
+ engines: {node: '>=12'}
+ dev: false
+
+ /d3-polygon@3.0.1:
+ resolution: {integrity: sha512-3vbA7vXYwfe1SYhED++fPUQlWSYTTGmFmQiany/gdbiWgU/iEyQzyymwL9SkJjFFuCS4902BSzewVGsHHmHtXg==}
+ engines: {node: '>=12'}
+ dev: false
+
+ /d3-quadtree@3.0.1:
+ resolution: {integrity: sha512-04xDrxQTDTCFwP5H6hRhsRcb9xxv2RzkcsygFzmkSIOJy3PeRJP7sNk3VRIbKXcog561P9oU0/rVH6vDROAgUw==}
+ engines: {node: '>=12'}
+ dev: false
+
+ /d3-random@3.0.1:
+ resolution: {integrity: sha512-FXMe9GfxTxqd5D6jFsQ+DJ8BJS4E/fT5mqqdjovykEB2oFbTMDVdg1MGFxfQW+FBOGoB++k8swBrgwSHT1cUXQ==}
+ engines: {node: '>=12'}
+ dev: false
+
+ /d3-scale-chromatic@3.0.0:
+ resolution: {integrity: sha512-Lx9thtxAKrO2Pq6OO2Ua474opeziKr279P/TKZsMAhYyNDD3EnCffdbgeSYN5O7m2ByQsxtuP2CSDczNUIZ22g==}
+ engines: {node: '>=12'}
+ dependencies:
+ d3-color: 3.1.0
+ d3-interpolate: 3.0.1
+ dev: false
+
+ /d3-scale@4.0.2:
+ resolution: {integrity: sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==}
+ engines: {node: '>=12'}
+ dependencies:
+ d3-array: 3.2.4
+ d3-format: 3.1.0
+ d3-interpolate: 3.0.1
+ d3-time: 3.1.0
+ d3-time-format: 4.1.0
+ dev: false
+
+ /d3-selection@3.0.0:
+ resolution: {integrity: sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==}
+ engines: {node: '>=12'}
+ dev: false
+
+ /d3-shape@3.2.0:
+ resolution: {integrity: sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==}
+ engines: {node: '>=12'}
+ dependencies:
+ d3-path: 3.1.0
+ dev: false
+
+ /d3-time-format@4.1.0:
+ resolution: {integrity: sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==}
+ engines: {node: '>=12'}
+ dependencies:
+ d3-time: 3.1.0
+ dev: false
+
+ /d3-time@3.1.0:
+ resolution: {integrity: sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==}
+ engines: {node: '>=12'}
+ dependencies:
+ d3-array: 3.2.4
+ dev: false
+
+ /d3-timer@3.0.1:
+ resolution: {integrity: sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==}
+ engines: {node: '>=12'}
+ dev: false
+
+ /d3-transition@3.0.1(d3-selection@3.0.0):
+ resolution: {integrity: sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w==}
+ engines: {node: '>=12'}
+ peerDependencies:
+ d3-selection: 2 - 3
+ dependencies:
+ d3-color: 3.1.0
+ d3-dispatch: 3.0.1
+ d3-ease: 3.0.1
+ d3-interpolate: 3.0.1
+ d3-selection: 3.0.0
+ d3-timer: 3.0.1
+ dev: false
+
+ /d3-zoom@3.0.0:
+ resolution: {integrity: sha512-b8AmV3kfQaqWAuacbPuNbL6vahnOJflOhexLzMMNLga62+/nh0JzvJ0aO/5a5MVgUFGS7Hu1P9P03o3fJkDCyw==}
+ engines: {node: '>=12'}
+ dependencies:
+ d3-dispatch: 3.0.1
+ d3-drag: 3.0.0
+ d3-interpolate: 3.0.1
+ d3-selection: 3.0.0
+ d3-transition: 3.0.1(d3-selection@3.0.0)
+ dev: false
+
+ /d3@7.8.5:
+ resolution: {integrity: sha512-JgoahDG51ncUfJu6wX/1vWQEqOflgXyl4MaHqlcSruTez7yhaRKR9i8VjjcQGeS2en/jnFivXuaIMnseMMt0XA==}
+ engines: {node: '>=12'}
+ dependencies:
+ d3-array: 3.2.4
+ d3-axis: 3.0.0
+ d3-brush: 3.0.0
+ d3-chord: 3.0.1
+ d3-color: 3.1.0
+ d3-contour: 4.0.2
+ d3-delaunay: 6.0.4
+ d3-dispatch: 3.0.1
+ d3-drag: 3.0.0
+ d3-dsv: 3.0.1
+ d3-ease: 3.0.1
+ d3-fetch: 3.0.1
+ d3-force: 3.0.0
+ d3-format: 3.1.0
+ d3-geo: 3.1.0
+ d3-hierarchy: 3.1.2
+ d3-interpolate: 3.0.1
+ d3-path: 3.1.0
+ d3-polygon: 3.0.1
+ d3-quadtree: 3.0.1
+ d3-random: 3.0.1
+ d3-scale: 4.0.2
+ d3-scale-chromatic: 3.0.0
+ d3-selection: 3.0.0
+ d3-shape: 3.2.0
+ d3-time: 3.1.0
+ d3-time-format: 4.1.0
+ d3-timer: 3.0.1
+ d3-transition: 3.0.1(d3-selection@3.0.0)
+ d3-zoom: 3.0.0
+ dev: false
+
+ /damerau-levenshtein@1.0.8:
+ resolution: {integrity: sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==}
+ dev: true
+
+ /date-fns-tz@2.0.0(date-fns@2.30.0):
+ resolution: {integrity: sha512-OAtcLdB9vxSXTWHdT8b398ARImVwQMyjfYGkKD2zaGpHseG2UPHbHjXELReErZFxWdSLph3c2zOaaTyHfOhERQ==}
+ peerDependencies:
+ date-fns: '>=2.0.0'
+ dependencies:
+ date-fns: 2.30.0
+ dev: false
+
+ /date-fns@2.30.0:
+ resolution: {integrity: sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw==}
+ engines: {node: '>=0.11'}
+ dependencies:
+ '@babel/runtime': 7.23.8
+ dev: false
+
+ /dayjs@1.11.10:
+ resolution: {integrity: sha512-vjAczensTgRcqDERK0SR2XMwsF/tSvnvlv6VcF2GIhg6Sx4yOIt/irsr1RDJsKiIyBzJDpCoXiWWq28MqH2cnQ==}
+ dev: false
+
+ /debug@2.6.9:
+ resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==}
+ peerDependencies:
+ supports-color: '*'
+ peerDependenciesMeta:
+ supports-color:
+ optional: true
+ dependencies:
+ ms: 2.0.0
+ dev: false
+
+ /debug@3.2.7:
+ resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==}
+ peerDependencies:
+ supports-color: '*'
+ peerDependenciesMeta:
+ supports-color:
+ optional: true
+ dependencies:
+ ms: 2.1.3
+ dev: true
+
+ /debug@4.3.4(supports-color@5.5.0):
+ resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==}
+ engines: {node: '>=6.0'}
+ peerDependencies:
+ supports-color: '*'
+ peerDependenciesMeta:
+ supports-color:
+ optional: true
+ dependencies:
+ ms: 2.1.2
+ supports-color: 5.5.0
+
+ /decompress-response@6.0.0:
+ resolution: {integrity: sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==}
+ engines: {node: '>=10'}
+ dependencies:
+ mimic-response: 3.1.0
+ dev: false
+
+ /deep-extend@0.6.0:
+ resolution: {integrity: sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==}
+ engines: {node: '>=4.0.0'}
+ dev: false
+
+ /deep-is@0.1.4:
+ resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==}
+ dev: true
+
+ /defer-to-connect@2.0.1:
+ resolution: {integrity: sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==}
+ engines: {node: '>=10'}
+ dev: false
+
+ /define-data-property@1.1.1:
+ resolution: {integrity: sha512-E7uGkTzkk1d0ByLeSc6ZsFS79Axg+m1P/VsgYsxHgiuc3tFSj+MjMIwe90FC4lOAZzNBdY7kkO2P2wKdsQ1vgQ==}
+ engines: {node: '>= 0.4'}
+ dependencies:
+ get-intrinsic: 1.2.2
+ gopd: 1.0.1
+ has-property-descriptors: 1.0.1
+
+ /define-properties@1.2.1:
+ resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==}
+ engines: {node: '>= 0.4'}
+ dependencies:
+ define-data-property: 1.1.1
+ has-property-descriptors: 1.0.1
+ object-keys: 1.1.1
+
+ /delaunator@5.0.0:
+ resolution: {integrity: sha512-AyLvtyJdbv/U1GkiS6gUUzclRoAY4Gs75qkMygJJhU75LW4DNuSF2RMzpxs9jw9Oz1BobHjTdkG3zdP55VxAqw==}
+ dependencies:
+ robust-predicates: 3.0.2
+ dev: false
+
+ /delayed-stream@1.0.0:
+ resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==}
+ engines: {node: '>=0.4.0'}
+ dev: false
+
+ /depd@2.0.0:
+ resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==}
+ engines: {node: '>= 0.8'}
+ dev: false
+
+ /dequal@2.0.3:
+ resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==}
+ engines: {node: '>=6'}
+ dev: true
+
+ /destroy@1.2.0:
+ resolution: {integrity: sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==}
+ engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16}
+ dev: false
+
+ /detect-libc@2.0.2:
+ resolution: {integrity: sha512-UX6sGumvvqSaXgdKGUsgZWqcUyIXZ/vZTrlRT/iobiKhGL0zL4d3osHj3uqllWJK+i+sixDS/3COVEOFbupFyw==}
+ engines: {node: '>=8'}
+ dev: false
+
+ /dir-glob@3.0.1:
+ resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==}
+ engines: {node: '>=8'}
+ dependencies:
+ path-type: 4.0.0
+ dev: true
+
+ /doctrine@2.1.0:
+ resolution: {integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==}
+ engines: {node: '>=0.10.0'}
+ dependencies:
+ esutils: 2.0.3
+ dev: true
+
+ /doctrine@3.0.0:
+ resolution: {integrity: sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==}
+ engines: {node: '>=6.0.0'}
+ dependencies:
+ esutils: 2.0.3
+ dev: true
+
+ /dotenv@16.3.1:
+ resolution: {integrity: sha512-IPzF4w4/Rd94bA9imS68tZBaYyBWSCE47V1RGuMrB94iyTOIEwRmVL2x/4An+6mETpLrKJ5hQkB8W4kFAadeIQ==}
+ engines: {node: '>=12'}
+ dev: false
+
+ /ecdsa-sig-formatter@1.0.11:
+ resolution: {integrity: sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==}
+ dependencies:
+ safe-buffer: 5.2.1
+ dev: false
+
+ /ee-first@1.1.1:
+ resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==}
+ dev: false
+
+ /elliptic@6.5.4:
+ resolution: {integrity: sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==}
+ requiresBuild: true
+ dependencies:
+ bn.js: 4.12.0
+ brorand: 1.1.0
+ hash.js: 1.1.7
+ hmac-drbg: 1.0.1
+ inherits: 2.0.4
+ minimalistic-assert: 1.0.1
+ minimalistic-crypto-utils: 1.0.1
+ dev: false
+ optional: true
+
+ /emoji-regex@9.2.2:
+ resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==}
+ dev: true
+
+ /encodeurl@1.0.2:
+ resolution: {integrity: sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==}
+ engines: {node: '>= 0.8'}
+ dev: false
+
+ /end-of-stream@1.4.4:
+ resolution: {integrity: sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==}
+ dependencies:
+ once: 1.4.0
+ dev: false
+
+ /enhanced-resolve@5.15.0:
+ resolution: {integrity: sha512-LXYT42KJ7lpIKECr2mAXIaMldcNCh/7E0KBKOu4KSfkHmP+mZmSs+8V5gBAqisWBy0OO4W5Oyys0GO1Y8KtdKg==}
+ engines: {node: '>=10.13.0'}
+ dependencies:
+ graceful-fs: 4.2.11
+ tapable: 2.2.1
+ dev: true
+
+ /es-abstract@1.22.3:
+ resolution: {integrity: sha512-eiiY8HQeYfYH2Con2berK+To6GrK2RxbPawDkGq4UiCQQfZHb6wX9qQqkbpPqaxQFcl8d9QzZqo0tGE0VcrdwA==}
+ engines: {node: '>= 0.4'}
+ dependencies:
+ array-buffer-byte-length: 1.0.0
+ arraybuffer.prototype.slice: 1.0.2
+ available-typed-arrays: 1.0.5
+ call-bind: 1.0.5
+ es-set-tostringtag: 2.0.2
+ es-to-primitive: 1.2.1
+ function.prototype.name: 1.1.6
+ get-intrinsic: 1.2.2
+ get-symbol-description: 1.0.0
+ globalthis: 1.0.3
+ gopd: 1.0.1
+ has-property-descriptors: 1.0.1
+ has-proto: 1.0.1
+ has-symbols: 1.0.3
+ hasown: 2.0.0
+ internal-slot: 1.0.6
+ is-array-buffer: 3.0.2
+ is-callable: 1.2.7
+ is-negative-zero: 2.0.2
+ is-regex: 1.1.4
+ is-shared-array-buffer: 1.0.2
+ is-string: 1.0.7
+ is-typed-array: 1.1.12
+ is-weakref: 1.0.2
+ object-inspect: 1.13.1
+ object-keys: 1.1.1
+ object.assign: 4.1.5
+ regexp.prototype.flags: 1.5.1
+ safe-array-concat: 1.0.1
+ safe-regex-test: 1.0.2
+ string.prototype.trim: 1.2.8
+ string.prototype.trimend: 1.0.7
+ string.prototype.trimstart: 1.0.7
+ typed-array-buffer: 1.0.0
+ typed-array-byte-length: 1.0.0
+ typed-array-byte-offset: 1.0.0
+ typed-array-length: 1.0.4
+ unbox-primitive: 1.0.2
+ which-typed-array: 1.1.13
+ dev: true
+
+ /es-iterator-helpers@1.0.15:
+ resolution: {integrity: sha512-GhoY8uYqd6iwUl2kgjTm4CZAf6oo5mHK7BPqx3rKgx893YSsy0LGHV6gfqqQvZt/8xM8xeOnfXBCfqclMKkJ5g==}
+ dependencies:
+ asynciterator.prototype: 1.0.0
+ call-bind: 1.0.5
+ define-properties: 1.2.1
+ es-abstract: 1.22.3
+ es-set-tostringtag: 2.0.2
+ function-bind: 1.1.2
+ get-intrinsic: 1.2.2
+ globalthis: 1.0.3
+ has-property-descriptors: 1.0.1
+ has-proto: 1.0.1
+ has-symbols: 1.0.3
+ internal-slot: 1.0.6
+ iterator.prototype: 1.1.2
+ safe-array-concat: 1.0.1
+ dev: true
+
+ /es-set-tostringtag@2.0.2:
+ resolution: {integrity: sha512-BuDyupZt65P9D2D2vA/zqcI3G5xRsklm5N3xCwuiy+/vKy8i0ifdsQP1sLgO4tZDSCaQUSnmC48khknGMV3D2Q==}
+ engines: {node: '>= 0.4'}
+ dependencies:
+ get-intrinsic: 1.2.2
+ has-tostringtag: 1.0.0
+ hasown: 2.0.0
+ dev: true
+
+ /es-shim-unscopables@1.0.2:
+ resolution: {integrity: sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw==}
+ dependencies:
+ hasown: 2.0.0
+ dev: true
+
+ /es-to-primitive@1.2.1:
+ resolution: {integrity: sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==}
+ engines: {node: '>= 0.4'}
+ dependencies:
+ is-callable: 1.2.7
+ is-date-object: 1.0.5
+ is-symbol: 1.0.4
+ dev: true
+
+ /escape-goat@3.0.0:
+ resolution: {integrity: sha512-w3PwNZJwRxlp47QGzhuEBldEqVHHhh8/tIPcl6ecf2Bou99cdAt0knihBV0Ecc7CGxYduXVBDheH1K2oADRlvw==}
+ engines: {node: '>=10'}
+ dev: false
+
+ /escape-html@1.0.3:
+ resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==}
+ dev: false
+
+ /escape-string-regexp@4.0.0:
+ resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==}
+ engines: {node: '>=10'}
+
+ /eslint-config-next@14.0.4(eslint@8.56.0)(typescript@5.3.3):
+ resolution: {integrity: sha512-9/xbOHEQOmQtqvQ1UsTQZpnA7SlDMBtuKJ//S4JnoyK3oGLhILKXdBgu/UO7lQo/2xOykQULS1qQ6p2+EpHgAQ==}
+ peerDependencies:
+ eslint: ^7.23.0 || ^8.0.0
+ typescript: '>=3.3.1'
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+ dependencies:
+ '@next/eslint-plugin-next': 14.0.4
+ '@rushstack/eslint-patch': 1.6.1
+ '@typescript-eslint/parser': 6.18.1(eslint@8.56.0)(typescript@5.3.3)
+ eslint: 8.56.0
+ eslint-import-resolver-node: 0.3.9
+ eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/parser@6.18.1)(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1)(eslint@8.56.0)
+ eslint-plugin-import: 2.29.1(@typescript-eslint/parser@6.18.1)(eslint-import-resolver-typescript@3.6.1)(eslint@8.56.0)
+ eslint-plugin-jsx-a11y: 6.8.0(eslint@8.56.0)
+ eslint-plugin-react: 7.33.2(eslint@8.56.0)
+ eslint-plugin-react-hooks: 4.6.0(eslint@8.56.0)
+ typescript: 5.3.3
+ transitivePeerDependencies:
+ - eslint-import-resolver-webpack
+ - supports-color
+ dev: true
+
+ /eslint-import-resolver-node@0.3.9:
+ resolution: {integrity: sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==}
+ dependencies:
+ debug: 3.2.7
+ is-core-module: 2.13.1
+ resolve: 1.22.8
+ transitivePeerDependencies:
+ - supports-color
+ dev: true
+
+ /eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@6.18.1)(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1)(eslint@8.56.0):
+ resolution: {integrity: sha512-xgdptdoi5W3niYeuQxKmzVDTATvLYqhpwmykwsh7f6HIOStGWEIL9iqZgQDF9u9OEzrRwR8no5q2VT+bjAujTg==}
+ engines: {node: ^14.18.0 || >=16.0.0}
+ peerDependencies:
+ eslint: '*'
+ eslint-plugin-import: '*'
+ dependencies:
+ debug: 4.3.4(supports-color@5.5.0)
+ enhanced-resolve: 5.15.0
+ eslint: 8.56.0
+ eslint-module-utils: 2.8.0(@typescript-eslint/parser@6.18.1)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@8.56.0)
+ eslint-plugin-import: 2.29.1(@typescript-eslint/parser@6.18.1)(eslint-import-resolver-typescript@3.6.1)(eslint@8.56.0)
+ fast-glob: 3.3.2
+ get-tsconfig: 4.7.2
+ is-core-module: 2.13.1
+ is-glob: 4.0.3
+ transitivePeerDependencies:
+ - '@typescript-eslint/parser'
+ - eslint-import-resolver-node
+ - eslint-import-resolver-webpack
+ - supports-color
+ dev: true
+
+ /eslint-module-utils@2.8.0(@typescript-eslint/parser@6.18.1)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@8.56.0):
+ resolution: {integrity: sha512-aWajIYfsqCKRDgUfjEXNN/JlrzauMuSEy5sbd7WXbtW3EH6A6MpwEh42c7qD+MqQo9QMJ6fWLAeIJynx0g6OAw==}
+ engines: {node: '>=4'}
+ peerDependencies:
+ '@typescript-eslint/parser': '*'
+ eslint: '*'
+ eslint-import-resolver-node: '*'
+ eslint-import-resolver-typescript: '*'
+ eslint-import-resolver-webpack: '*'
+ peerDependenciesMeta:
+ '@typescript-eslint/parser':
+ optional: true
+ eslint:
+ optional: true
+ eslint-import-resolver-node:
+ optional: true
+ eslint-import-resolver-typescript:
+ optional: true
+ eslint-import-resolver-webpack:
+ optional: true
+ dependencies:
+ '@typescript-eslint/parser': 6.18.1(eslint@8.56.0)(typescript@5.3.3)
+ debug: 3.2.7
+ eslint: 8.56.0
+ eslint-import-resolver-node: 0.3.9
+ eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/parser@6.18.1)(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1)(eslint@8.56.0)
+ transitivePeerDependencies:
+ - supports-color
+ dev: true
+
+ /eslint-plugin-import@2.29.1(@typescript-eslint/parser@6.18.1)(eslint-import-resolver-typescript@3.6.1)(eslint@8.56.0):
+ resolution: {integrity: sha512-BbPC0cuExzhiMo4Ff1BTVwHpjjv28C5R+btTOGaCRC7UEz801up0JadwkeSk5Ued6TG34uaczuVuH6qyy5YUxw==}
+ engines: {node: '>=4'}
+ peerDependencies:
+ '@typescript-eslint/parser': '*'
+ eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8
+ peerDependenciesMeta:
+ '@typescript-eslint/parser':
+ optional: true
+ dependencies:
+ '@typescript-eslint/parser': 6.18.1(eslint@8.56.0)(typescript@5.3.3)
+ array-includes: 3.1.7
+ array.prototype.findlastindex: 1.2.3
+ array.prototype.flat: 1.3.2
+ array.prototype.flatmap: 1.3.2
+ debug: 3.2.7
+ doctrine: 2.1.0
+ eslint: 8.56.0
+ eslint-import-resolver-node: 0.3.9
+ eslint-module-utils: 2.8.0(@typescript-eslint/parser@6.18.1)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@8.56.0)
+ hasown: 2.0.0
+ is-core-module: 2.13.1
+ is-glob: 4.0.3
+ minimatch: 3.1.2
+ object.fromentries: 2.0.7
+ object.groupby: 1.0.1
+ object.values: 1.1.7
+ semver: 6.3.1
+ tsconfig-paths: 3.15.0
+ transitivePeerDependencies:
+ - eslint-import-resolver-typescript
+ - eslint-import-resolver-webpack
+ - supports-color
+ dev: true
+
+ /eslint-plugin-jsx-a11y@6.8.0(eslint@8.56.0):
+ resolution: {integrity: sha512-Hdh937BS3KdwwbBaKd5+PLCOmYY6U4f2h9Z2ktwtNKvIdIEu137rjYbcb9ApSbVJfWxANNuiKTD/9tOKjK9qOA==}
+ engines: {node: '>=4.0'}
+ peerDependencies:
+ eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8
+ dependencies:
+ '@babel/runtime': 7.23.8
+ aria-query: 5.3.0
+ array-includes: 3.1.7
+ array.prototype.flatmap: 1.3.2
+ ast-types-flow: 0.0.8
+ axe-core: 4.7.0
+ axobject-query: 3.2.1
+ damerau-levenshtein: 1.0.8
+ emoji-regex: 9.2.2
+ es-iterator-helpers: 1.0.15
+ eslint: 8.56.0
+ hasown: 2.0.0
+ jsx-ast-utils: 3.3.5
+ language-tags: 1.0.9
+ minimatch: 3.1.2
+ object.entries: 1.1.7
+ object.fromentries: 2.0.7
+ dev: true
+
+ /eslint-plugin-react-hooks@4.6.0(eslint@8.56.0):
+ resolution: {integrity: sha512-oFc7Itz9Qxh2x4gNHStv3BqJq54ExXmfC+a1NjAta66IAN87Wu0R/QArgIS9qKzX3dXKPI9H5crl9QchNMY9+g==}
+ engines: {node: '>=10'}
+ peerDependencies:
+ eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0
+ dependencies:
+ eslint: 8.56.0
+ dev: true
+
+ /eslint-plugin-react@7.33.2(eslint@8.56.0):
+ resolution: {integrity: sha512-73QQMKALArI8/7xGLNI/3LylrEYrlKZSb5C9+q3OtOewTnMQi5cT+aE9E41sLCmli3I9PGGmD1yiZydyo4FEPw==}
+ engines: {node: '>=4'}
+ peerDependencies:
+ eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8
+ dependencies:
+ array-includes: 3.1.7
+ array.prototype.flatmap: 1.3.2
+ array.prototype.tosorted: 1.1.2
+ doctrine: 2.1.0
+ es-iterator-helpers: 1.0.15
+ eslint: 8.56.0
+ estraverse: 5.3.0
+ jsx-ast-utils: 3.3.5
+ minimatch: 3.1.2
+ object.entries: 1.1.7
+ object.fromentries: 2.0.7
+ object.hasown: 1.1.3
+ object.values: 1.1.7
+ prop-types: 15.8.1
+ resolve: 2.0.0-next.5
+ semver: 6.3.1
+ string.prototype.matchall: 4.0.10
+ dev: true
+
+ /eslint-scope@7.2.2:
+ resolution: {integrity: sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==}
+ engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+ dependencies:
+ esrecurse: 4.3.0
+ estraverse: 5.3.0
+ dev: true
+
+ /eslint-visitor-keys@3.4.3:
+ resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==}
+ engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+ dev: true
+
+ /eslint@8.56.0:
+ resolution: {integrity: sha512-Go19xM6T9puCOWntie1/P997aXxFsOi37JIHRWI514Hc6ZnaHGKY9xFhrU65RT6CcBEzZoGG1e6Nq+DT04ZtZQ==}
+ engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+ hasBin: true
+ dependencies:
+ '@eslint-community/eslint-utils': 4.4.0(eslint@8.56.0)
+ '@eslint-community/regexpp': 4.10.0
+ '@eslint/eslintrc': 2.1.4
+ '@eslint/js': 8.56.0
+ '@humanwhocodes/config-array': 0.11.14
+ '@humanwhocodes/module-importer': 1.0.1
+ '@nodelib/fs.walk': 1.2.8
+ '@ungap/structured-clone': 1.2.0
+ ajv: 6.12.6
+ chalk: 4.1.2
+ cross-spawn: 7.0.3
+ debug: 4.3.4(supports-color@5.5.0)
+ doctrine: 3.0.0
+ escape-string-regexp: 4.0.0
+ eslint-scope: 7.2.2
+ eslint-visitor-keys: 3.4.3
+ espree: 9.6.1
+ esquery: 1.5.0
+ esutils: 2.0.3
+ fast-deep-equal: 3.1.3
+ file-entry-cache: 6.0.1
+ find-up: 5.0.0
+ glob-parent: 6.0.2
+ globals: 13.24.0
+ graphemer: 1.4.0
+ ignore: 5.3.0
+ imurmurhash: 0.1.4
+ is-glob: 4.0.3
+ is-path-inside: 3.0.3
+ js-yaml: 4.1.0
+ json-stable-stringify-without-jsonify: 1.0.1
+ levn: 0.4.1
+ lodash.merge: 4.6.2
+ minimatch: 3.1.2
+ natural-compare: 1.4.0
+ optionator: 0.9.3
+ strip-ansi: 6.0.1
+ text-table: 0.2.0
+ transitivePeerDependencies:
+ - supports-color
+ dev: true
+
+ /espree@9.6.1:
+ resolution: {integrity: sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==}
+ engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+ dependencies:
+ acorn: 8.11.3
+ acorn-jsx: 5.3.2(acorn@8.11.3)
+ eslint-visitor-keys: 3.4.3
+ dev: true
+
+ /esprima@4.0.1:
+ resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==}
+ engines: {node: '>=4'}
+ hasBin: true
+ dev: false
+
+ /esquery@1.5.0:
+ resolution: {integrity: sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==}
+ engines: {node: '>=0.10'}
+ dependencies:
+ estraverse: 5.3.0
+ dev: true
+
+ /esrecurse@4.3.0:
+ resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==}
+ engines: {node: '>=4.0'}
+ dependencies:
+ estraverse: 5.3.0
+ dev: true
+
+ /estraverse@5.3.0:
+ resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==}
+ engines: {node: '>=4.0'}
+ dev: true
+
+ /esutils@2.0.3:
+ resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==}
+ engines: {node: '>=0.10.0'}
+ dev: true
+
+ /etag@1.8.1:
+ resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==}
+ engines: {node: '>= 0.6'}
+ dev: false
+
+ /eventemitter3@5.0.1:
+ resolution: {integrity: sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==}
+ dev: false
+
+ /events@3.3.0:
+ resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==}
+ engines: {node: '>=0.8.x'}
+ dev: false
+
+ /exifr@7.1.3:
+ resolution: {integrity: sha512-g/aje2noHivrRSLbAUtBPWFbxKdKhgj/xr1vATDdUXPOFYJlQ62Ft0oy+72V6XLIpDJfHs6gXLbBLAolqOXYRw==}
+ dev: false
+
+ /expand-template@2.0.3:
+ resolution: {integrity: sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==}
+ engines: {node: '>=6'}
+ dev: false
+
+ /express-interceptor@1.2.0:
+ resolution: {integrity: sha512-fCbcJv8ZwabDg0M/3PmHUxfr/WKHGMpAicR9TfGdhANV4M1GBDSrBTenHIK3aegyRN5S6eDwlvyNFiLynnc19w==}
+ dependencies:
+ debug: 2.6.9
+ transitivePeerDependencies:
+ - supports-color
+ dev: false
+
+ /express-prom-bundle@6.5.0(prom-client@14.0.1):
+ resolution: {integrity: sha512-paFAm0FK7TV1Ln6Blh9edDt2mJ4Pk6Py/fjhZDMcoMHENYryBjCpnXDXuCu8NE1kkvp58IrPcAAkNeNqdvZnnw==}
+ engines: {node: '>=10'}
+ peerDependencies:
+ prom-client: '>=12.0.0'
+ dependencies:
+ on-finished: 2.4.1
+ prom-client: 14.0.1
+ url-value-parser: 2.2.0
+ dev: false
+
+ /express-request-id@1.4.1:
+ resolution: {integrity: sha512-qpxK6XhDYtdx9FvxwCHkUeZVWtkGbWR87hBAzGECfwYF/QQCPXEwwB2/9NGkOR1tT7/aLs9mma3CT0vjSzuZVw==}
+ dependencies:
+ uuid: 3.4.0
+ dev: false
+
+ /express-session@1.17.3:
+ resolution: {integrity: sha512-4+otWXlShYlG1Ma+2Jnn+xgKUZTMJ5QD3YvfilX3AcocOAbIkVylSWEklzALe/+Pu4qV6TYBj5GwOBFfdKqLBw==}
+ engines: {node: '>= 0.8.0'}
+ dependencies:
+ cookie: 0.4.2
+ cookie-signature: 1.0.6
+ debug: 2.6.9
+ depd: 2.0.0
+ on-headers: 1.0.2
+ parseurl: 1.3.3
+ safe-buffer: 5.2.1
+ uid-safe: 2.1.5
+ transitivePeerDependencies:
+ - supports-color
+ dev: false
+
+ /express@4.18.1:
+ resolution: {integrity: sha512-zZBcOX9TfehHQhtupq57OF8lFZ3UZi08Y97dwFCkD8p9d/d2Y3M+ykKcwaMDEL+4qyUolgBDX6AblpR3fL212Q==}
+ engines: {node: '>= 0.10.0'}
+ dependencies:
+ accepts: 1.3.8
+ array-flatten: 1.1.1
+ body-parser: 1.20.0
+ content-disposition: 0.5.4
+ content-type: 1.0.5
+ cookie: 0.5.0
+ cookie-signature: 1.0.6
+ debug: 2.6.9
+ depd: 2.0.0
+ encodeurl: 1.0.2
+ escape-html: 1.0.3
+ etag: 1.8.1
+ finalhandler: 1.2.0
+ fresh: 0.5.2
+ http-errors: 2.0.0
+ merge-descriptors: 1.0.1
+ methods: 1.1.2
+ on-finished: 2.4.1
+ parseurl: 1.3.3
+ path-to-regexp: 0.1.7
+ proxy-addr: 2.0.7
+ qs: 6.10.3
+ range-parser: 1.2.1
+ safe-buffer: 5.2.1
+ send: 0.18.0
+ serve-static: 1.15.0
+ setprototypeof: 1.2.0
+ statuses: 2.0.1
+ type-is: 1.6.18
+ utils-merge: 1.0.1
+ vary: 1.1.2
+ transitivePeerDependencies:
+ - supports-color
+ dev: false
+
+ /express@4.18.2:
+ resolution: {integrity: sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==}
+ engines: {node: '>= 0.10.0'}
+ dependencies:
+ accepts: 1.3.8
+ array-flatten: 1.1.1
+ body-parser: 1.20.1
+ content-disposition: 0.5.4
+ content-type: 1.0.5
+ cookie: 0.5.0
+ cookie-signature: 1.0.6
+ debug: 2.6.9
+ depd: 2.0.0
+ encodeurl: 1.0.2
+ escape-html: 1.0.3
+ etag: 1.8.1
+ finalhandler: 1.2.0
+ fresh: 0.5.2
+ http-errors: 2.0.0
+ merge-descriptors: 1.0.1
+ methods: 1.1.2
+ on-finished: 2.4.1
+ parseurl: 1.3.3
+ path-to-regexp: 0.1.7
+ proxy-addr: 2.0.7
+ qs: 6.11.0
+ range-parser: 1.2.1
+ safe-buffer: 5.2.1
+ send: 0.18.0
+ serve-static: 1.15.0
+ setprototypeof: 1.2.0
+ statuses: 2.0.1
+ type-is: 1.6.18
+ utils-merge: 1.0.1
+ vary: 1.1.2
+ transitivePeerDependencies:
+ - supports-color
+ dev: false
+
+ /extend-shallow@2.0.1:
+ resolution: {integrity: sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==}
+ engines: {node: '>=0.10.0'}
+ dependencies:
+ is-extendable: 0.1.1
+ dev: false
+
+ /fast-deep-equal@3.1.3:
+ resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==}
+ dev: true
+
+ /fast-glob@3.3.2:
+ resolution: {integrity: sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==}
+ engines: {node: '>=8.6.0'}
+ dependencies:
+ '@nodelib/fs.stat': 2.0.5
+ '@nodelib/fs.walk': 1.2.8
+ glob-parent: 5.1.2
+ merge2: 1.4.1
+ micromatch: 4.0.5
+ dev: true
+
+ /fast-json-stable-stringify@2.1.0:
+ resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==}
+ dev: true
+
+ /fast-levenshtein@2.0.6:
+ resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==}
+ dev: true
+
+ /fast-xml-parser@4.2.5:
+ resolution: {integrity: sha512-B9/wizE4WngqQftFPmdaMYlXoJlJOYxGQOanC77fq9k8+Z0v5dDSVh+3glErdIROP//s/jgb7ZuxKfB8nVyo0g==}
+ hasBin: true
+ dependencies:
+ strnum: 1.0.5
+ dev: false
+
+ /fastq@1.16.0:
+ resolution: {integrity: sha512-ifCoaXsDrsdkWTtiNJX5uzHDsrck5TzfKKDcuFFTIrrc/BS076qgEIfoIy1VeZqViznfKiysPYTh/QeHtnIsYA==}
+ dependencies:
+ reusify: 1.0.4
+ dev: true
+
+ /feed@4.2.2:
+ resolution: {integrity: sha512-u5/sxGfiMfZNtJ3OvQpXcvotFpYkL0n9u9mM2vkui2nGo8b4wvDkJ8gAkYqbA8QpGyFCv3RK0Z+Iv+9veCS9bQ==}
+ engines: {node: '>=0.4.0'}
+ dependencies:
+ xml-js: 1.6.11
+ dev: false
+
+ /file-entry-cache@6.0.1:
+ resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==}
+ engines: {node: ^10.12.0 || >=12.0.0}
+ dependencies:
+ flat-cache: 3.2.0
+ dev: true
+
+ /fill-range@7.0.1:
+ resolution: {integrity: sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==}
+ engines: {node: '>=8'}
+ dependencies:
+ to-regex-range: 5.0.1
+
+ /finalhandler@1.2.0:
+ resolution: {integrity: sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==}
+ engines: {node: '>= 0.8'}
+ dependencies:
+ debug: 2.6.9
+ encodeurl: 1.0.2
+ escape-html: 1.0.3
+ on-finished: 2.4.1
+ parseurl: 1.3.3
+ statuses: 2.0.1
+ unpipe: 1.0.0
+ transitivePeerDependencies:
+ - supports-color
+ dev: false
+
+ /find-up@5.0.0:
+ resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==}
+ engines: {node: '>=10'}
+ dependencies:
+ locate-path: 6.0.0
+ path-exists: 4.0.0
+ dev: true
+
+ /flat-cache@3.2.0:
+ resolution: {integrity: sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==}
+ engines: {node: ^10.12.0 || >=12.0.0}
+ dependencies:
+ flatted: 3.2.9
+ keyv: 4.5.4
+ rimraf: 3.0.2
+ dev: true
+
+ /flatted@3.2.9:
+ resolution: {integrity: sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ==}
+ dev: true
+
+ /for-each@0.3.3:
+ resolution: {integrity: sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==}
+ dependencies:
+ is-callable: 1.2.7
+ dev: true
+
+ /form-data@3.0.1:
+ resolution: {integrity: sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==}
+ engines: {node: '>= 6'}
+ dependencies:
+ asynckit: 0.4.0
+ combined-stream: 1.0.8
+ mime-types: 2.1.35
+ dev: false
+
+ /forwarded@0.2.0:
+ resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==}
+ engines: {node: '>= 0.6'}
+ dev: false
+
+ /fresh@0.5.2:
+ resolution: {integrity: sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==}
+ engines: {node: '>= 0.6'}
+ dev: false
+
+ /fs-constants@1.0.0:
+ resolution: {integrity: sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==}
+ dev: false
+
+ /fs.realpath@1.0.0:
+ resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==}
+ dev: true
+
+ /fsevents@2.3.3:
+ resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==}
+ engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
+ os: [darwin]
+ requiresBuild: true
+ optional: true
+
+ /function-bind@1.1.2:
+ resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==}
+
+ /function.prototype.name@1.1.6:
+ resolution: {integrity: sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==}
+ engines: {node: '>= 0.4'}
+ dependencies:
+ call-bind: 1.0.5
+ define-properties: 1.2.1
+ es-abstract: 1.22.3
+ functions-have-names: 1.2.3
+ dev: true
+
+ /functions-have-names@1.2.3:
+ resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==}
+ dev: true
+
+ /generic-pool@3.8.2:
+ resolution: {integrity: sha512-nGToKy6p3PAbYQ7p1UlWl6vSPwfwU6TMSWK7TTu+WUY4ZjyZQGniGGt2oNVvyNSpyZYSB43zMXVLcBm08MTMkg==}
+ engines: {node: '>= 4'}
+ dev: false
+
+ /get-intrinsic@1.2.2:
+ resolution: {integrity: sha512-0gSo4ml/0j98Y3lngkFEot/zhiCeWsbYIlZ+uZOVgzLyLaUw7wxUL+nCTP0XJvJg1AXulJRI3UJi8GsbDuxdGA==}
+ dependencies:
+ function-bind: 1.1.2
+ has-proto: 1.0.1
+ has-symbols: 1.0.3
+ hasown: 2.0.0
+
+ /get-stream@5.2.0:
+ resolution: {integrity: sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==}
+ engines: {node: '>=8'}
+ dependencies:
+ pump: 3.0.0
+ dev: false
+
+ /get-symbol-description@1.0.0:
+ resolution: {integrity: sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==}
+ engines: {node: '>= 0.4'}
+ dependencies:
+ call-bind: 1.0.5
+ get-intrinsic: 1.2.2
+ dev: true
+
+ /get-tsconfig@4.7.2:
+ resolution: {integrity: sha512-wuMsz4leaj5hbGgg4IvDU0bqJagpftG5l5cXIAvo8uZrqn0NJqwtfupTN00VnkQJPcIRrxYrm1Ue24btpCha2A==}
+ dependencies:
+ resolve-pkg-maps: 1.0.0
+ dev: true
+
+ /github-from-package@0.0.0:
+ resolution: {integrity: sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==}
+ dev: false
+
+ /glob-parent@5.1.2:
+ resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==}
+ engines: {node: '>= 6'}
+ dependencies:
+ is-glob: 4.0.3
+
+ /glob-parent@6.0.2:
+ resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==}
+ engines: {node: '>=10.13.0'}
+ dependencies:
+ is-glob: 4.0.3
+ dev: true
+
+ /glob-to-regexp@0.4.1:
+ resolution: {integrity: sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==}
+ dev: false
+
+ /glob@7.1.7:
+ resolution: {integrity: sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==}
+ dependencies:
+ fs.realpath: 1.0.0
+ inflight: 1.0.6
+ inherits: 2.0.4
+ minimatch: 3.1.2
+ once: 1.4.0
+ path-is-absolute: 1.0.1
+ dev: true
+
+ /glob@7.2.3:
+ resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==}
+ dependencies:
+ fs.realpath: 1.0.0
+ inflight: 1.0.6
+ inherits: 2.0.4
+ minimatch: 3.1.2
+ once: 1.4.0
+ path-is-absolute: 1.0.1
+ dev: true
+
+ /globals@13.24.0:
+ resolution: {integrity: sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==}
+ engines: {node: '>=8'}
+ dependencies:
+ type-fest: 0.20.2
+ dev: true
+
+ /globalthis@1.0.3:
+ resolution: {integrity: sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==}
+ engines: {node: '>= 0.4'}
+ dependencies:
+ define-properties: 1.2.1
+ dev: true
+
+ /globby@11.1.0:
+ resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==}
+ engines: {node: '>=10'}
+ dependencies:
+ array-union: 2.1.0
+ dir-glob: 3.0.1
+ fast-glob: 3.3.2
+ ignore: 5.3.0
+ merge2: 1.4.1
+ slash: 3.0.0
+ dev: true
+
+ /gopd@1.0.1:
+ resolution: {integrity: sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==}
+ dependencies:
+ get-intrinsic: 1.2.2
+
+ /got@11.8.6:
+ resolution: {integrity: sha512-6tfZ91bOr7bOXnK7PRDCGBLa1H4U080YHNaAQ2KsMGlLEzRbk44nsZF2E1IeRc3vtJHPVbKCYgdFbaGO2ljd8g==}
+ engines: {node: '>=10.19.0'}
+ dependencies:
+ '@sindresorhus/is': 4.6.0
+ '@szmarczak/http-timer': 4.0.6
+ '@types/cacheable-request': 6.0.3
+ '@types/responselike': 1.0.3
+ cacheable-lookup: 5.0.4
+ cacheable-request: 7.0.4
+ decompress-response: 6.0.0
+ http2-wrapper: 1.0.3
+ lowercase-keys: 2.0.0
+ p-cancelable: 2.1.1
+ responselike: 2.0.1
+ dev: false
+
+ /graceful-fs@4.2.11:
+ resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==}
+
+ /grant@5.4.21:
+ resolution: {integrity: sha512-QaoZudI9Gmh2W415gd71Iul6gpVH9sG1SkjfnGHtqYZopQDQ5PUVxRol5zFCrwGi9S0EbExbelHlZScgdChg2w==}
+ engines: {node: '>=12.0.0'}
+ dependencies:
+ qs: 6.11.2
+ request-compose: 2.1.6
+ request-oauth: 1.0.1
+ optionalDependencies:
+ cookie: 0.4.2
+ cookie-signature: 1.2.1
+ jwk-to-pem: 2.0.5
+ jws: 4.0.0
+ dev: false
+
+ /graphemer@1.4.0:
+ resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==}
+ dev: true
+
+ /gray-matter@4.0.3:
+ resolution: {integrity: sha512-5v6yZd4JK3eMI3FqqCouswVqwugaA9r4dNZB1wwcmrD02QkV5H0y7XBQW8QwQqEaZY1pM9aqORSORhJRdNK44Q==}
+ engines: {node: '>=6.0'}
+ dependencies:
+ js-yaml: 3.14.1
+ kind-of: 6.0.3
+ section-matter: 1.0.0
+ strip-bom-string: 1.0.0
+ dev: false
+
+ /has-bigints@1.0.2:
+ resolution: {integrity: sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==}
+ dev: true
+
+ /has-flag@3.0.0:
+ resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==}
+ engines: {node: '>=4'}
+
+ /has-flag@4.0.0:
+ resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==}
+ engines: {node: '>=8'}
+
+ /has-property-descriptors@1.0.1:
+ resolution: {integrity: sha512-VsX8eaIewvas0xnvinAe9bw4WfIeODpGYikiWYLH+dma0Jw6KHYqWiWfhQlgOVK8D6PvjubK5Uc4P0iIhIcNVg==}
+ dependencies:
+ get-intrinsic: 1.2.2
+
+ /has-proto@1.0.1:
+ resolution: {integrity: sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==}
+ engines: {node: '>= 0.4'}
+
+ /has-symbols@1.0.3:
+ resolution: {integrity: sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==}
+ engines: {node: '>= 0.4'}
+
+ /has-tostringtag@1.0.0:
+ resolution: {integrity: sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==}
+ engines: {node: '>= 0.4'}
+ dependencies:
+ has-symbols: 1.0.3
+ dev: true
+
+ /hash.js@1.1.7:
+ resolution: {integrity: sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==}
+ requiresBuild: true
+ dependencies:
+ inherits: 2.0.4
+ minimalistic-assert: 1.0.1
+ dev: false
+ optional: true
+
+ /hasown@2.0.0:
+ resolution: {integrity: sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==}
+ engines: {node: '>= 0.4'}
+ dependencies:
+ function-bind: 1.1.2
+
+ /helmet@4.6.0:
+ resolution: {integrity: sha512-HVqALKZlR95ROkrnesdhbbZJFi/rIVSoNq6f3jA/9u6MIbTsPh3xZwihjeI5+DO/2sOV6HMHooXcEOuwskHpTg==}
+ engines: {node: '>=10.0.0'}
+ dev: false
+
+ /hls.js@1.4.14:
+ resolution: {integrity: sha512-UppQjyvPVclg+6t2KY/Rv03h0+bA5u6zwqVoz4LAC/L0fgYmIaCD7ZCrwe8WI1Gv01be1XL0QFsRbSdIHV/Wbw==}
+ dev: false
+
+ /hls.js@1.5.1:
+ resolution: {integrity: sha512-SsUSlpyjOGnwBhVrVEG6vRFPU2SAJ0gUqrFdGeo7YPbOC0vuWK0TDMyp7n3QiaBC/Wkic771uqPnnVdT8/x+3Q==}
+ dev: false
+
+ /hmac-drbg@1.0.1:
+ resolution: {integrity: sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==}
+ requiresBuild: true
+ dependencies:
+ hash.js: 1.1.7
+ minimalistic-assert: 1.0.1
+ minimalistic-crypto-utils: 1.0.1
+ dev: false
+ optional: true
+
+ /http-cache-semantics@4.1.1:
+ resolution: {integrity: sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==}
+ dev: false
+
+ /http-errors@2.0.0:
+ resolution: {integrity: sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==}
+ engines: {node: '>= 0.8'}
+ dependencies:
+ depd: 2.0.0
+ inherits: 2.0.4
+ setprototypeof: 1.2.0
+ statuses: 2.0.1
+ toidentifier: 1.0.1
+ dev: false
+
+ /http2-wrapper@1.0.3:
+ resolution: {integrity: sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg==}
+ engines: {node: '>=10.19.0'}
+ dependencies:
+ quick-lru: 5.1.1
+ resolve-alpn: 1.2.1
+ dev: false
+
+ /iconv-lite@0.4.24:
+ resolution: {integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==}
+ engines: {node: '>=0.10.0'}
+ dependencies:
+ safer-buffer: 2.1.2
+ dev: false
+
+ /iconv-lite@0.6.3:
+ resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==}
+ engines: {node: '>=0.10.0'}
+ dependencies:
+ safer-buffer: 2.1.2
+ dev: false
+
+ /ieee754@1.2.1:
+ resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==}
+ dev: false
+
+ /ignore-by-default@1.0.1:
+ resolution: {integrity: sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==}
+ dev: true
+
+ /ignore@5.3.0:
+ resolution: {integrity: sha512-g7dmpshy+gD7mh88OC9NwSGTKoc3kyLAZQRU1mt53Aw/vnvfXnbC+F/7F7QoYVKbV+KNvJx8wArewKy1vXMtlg==}
+ engines: {node: '>= 4'}
+ dev: true
+
+ /immutable@4.3.4:
+ resolution: {integrity: sha512-fsXeu4J4i6WNWSikpI88v/PcVflZz+6kMhUfIwc5SY+poQRPnaf5V7qds6SUyUN3cVxEzuCab7QIoLOQ+DQ1wA==}
+ dev: false
+
+ /import-fresh@3.3.0:
+ resolution: {integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==}
+ engines: {node: '>=6'}
+ dependencies:
+ parent-module: 1.0.1
+ resolve-from: 4.0.0
+ dev: true
+
+ /imurmurhash@0.1.4:
+ resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==}
+ engines: {node: '>=0.8.19'}
+ dev: true
+
+ /inflight@1.0.6:
+ resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==}
+ dependencies:
+ once: 1.4.0
+ wrappy: 1.0.2
+ dev: true
+
+ /inherits@2.0.4:
+ resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==}
+
+ /ini@1.3.8:
+ resolution: {integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==}
+ dev: false
+
+ /internal-slot@1.0.6:
+ resolution: {integrity: sha512-Xj6dv+PsbtwyPpEflsejS+oIZxmMlV44zAhG479uYu89MsjcYOhCFnNyKrkJrihbsiasQyY0afoCl/9BLR65bg==}
+ engines: {node: '>= 0.4'}
+ dependencies:
+ get-intrinsic: 1.2.2
+ hasown: 2.0.0
+ side-channel: 1.0.4
+ dev: true
+
+ /internmap@2.0.3:
+ resolution: {integrity: sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==}
+ engines: {node: '>=12'}
+ dev: false
+
+ /interval-tree-1d@1.0.4:
+ resolution: {integrity: sha512-wY8QJH+6wNI0uh4pDQzMvl+478Qh7Rl4qLmqiluxALlNvl+I+o5x38Pw3/z7mDPTPS1dQalZJXsmbvxx5gclhQ==}
+ dependencies:
+ binary-search-bounds: 2.0.5
+ dev: false
+
+ /ipaddr.js@1.9.1:
+ resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==}
+ engines: {node: '>= 0.10'}
+ dev: false
+
+ /ipaddr.js@2.1.0:
+ resolution: {integrity: sha512-LlbxQ7xKzfBusov6UMi4MFpEg0m+mAm9xyNGEduwXMEDuf4WfzB/RZwMVYEd7IKGvh4IUkEXYxtAVu9T3OelJQ==}
+ engines: {node: '>= 10'}
+ dev: false
+
+ /is-array-buffer@3.0.2:
+ resolution: {integrity: sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w==}
+ dependencies:
+ call-bind: 1.0.5
+ get-intrinsic: 1.2.2
+ is-typed-array: 1.1.12
+ dev: true
+
+ /is-arrayish@0.3.2:
+ resolution: {integrity: sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==}
+ dev: false
+
+ /is-async-function@2.0.0:
+ resolution: {integrity: sha512-Y1JXKrfykRJGdlDwdKlLpLyMIiWqWvuSd17TvZk68PLAOGOoF4Xyav1z0Xhoi+gCYjZVeC5SI+hYFOfvXmGRCA==}
+ engines: {node: '>= 0.4'}
+ dependencies:
+ has-tostringtag: 1.0.0
+ dev: true
+
+ /is-bigint@1.0.4:
+ resolution: {integrity: sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==}
+ dependencies:
+ has-bigints: 1.0.2
+ dev: true
+
+ /is-binary-path@2.1.0:
+ resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==}
+ engines: {node: '>=8'}
+ dependencies:
+ binary-extensions: 2.2.0
+
+ /is-boolean-object@1.1.2:
+ resolution: {integrity: sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==}
+ engines: {node: '>= 0.4'}
+ dependencies:
+ call-bind: 1.0.5
+ has-tostringtag: 1.0.0
+ dev: true
+
+ /is-callable@1.2.7:
+ resolution: {integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==}
+ engines: {node: '>= 0.4'}
+ dev: true
+
+ /is-core-module@2.13.1:
+ resolution: {integrity: sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==}
+ dependencies:
+ hasown: 2.0.0
+ dev: true
+
+ /is-date-object@1.0.5:
+ resolution: {integrity: sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==}
+ engines: {node: '>= 0.4'}
+ dependencies:
+ has-tostringtag: 1.0.0
+ dev: true
+
+ /is-extendable@0.1.1:
+ resolution: {integrity: sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==}
+ engines: {node: '>=0.10.0'}
+ dev: false
+
+ /is-extglob@2.1.1:
+ resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==}
+ engines: {node: '>=0.10.0'}
+
+ /is-finalizationregistry@1.0.2:
+ resolution: {integrity: sha512-0by5vtUJs8iFQb5TYUHHPudOR+qXYIMKtiUzvLIZITZUjknFmziyBJuLhVRc+Ds0dREFlskDNJKYIdIzu/9pfw==}
+ dependencies:
+ call-bind: 1.0.5
+ dev: true
+
+ /is-generator-function@1.0.10:
+ resolution: {integrity: sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==}
+ engines: {node: '>= 0.4'}
+ dependencies:
+ has-tostringtag: 1.0.0
+ dev: true
+
+ /is-glob@4.0.3:
+ resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==}
+ engines: {node: '>=0.10.0'}
+ dependencies:
+ is-extglob: 2.1.1
+
+ /is-map@2.0.2:
+ resolution: {integrity: sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg==}
+ dev: true
+
+ /is-nan@1.3.2:
+ resolution: {integrity: sha512-E+zBKpQ2t6MEo1VsonYmluk9NxGrbzpeeLC2xIViuO2EjU2xsXsBPwTr3Ykv9l08UYEVEdWeRZNouaZqF6RN0w==}
+ engines: {node: '>= 0.4'}
+ dependencies:
+ call-bind: 1.0.5
+ define-properties: 1.2.1
+ dev: false
+
+ /is-negative-zero@2.0.2:
+ resolution: {integrity: sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==}
+ engines: {node: '>= 0.4'}
+ dev: true
+
+ /is-network-error@1.0.1:
+ resolution: {integrity: sha512-OwQXkwBJeESyhFw+OumbJVD58BFBJJI5OM5S1+eyrDKlgDZPX2XNT5gXS56GSD3NPbbwUuMlR1Q71SRp5SobuQ==}
+ engines: {node: '>=16'}
+ dev: false
+
+ /is-number-object@1.0.7:
+ resolution: {integrity: sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==}
+ engines: {node: '>= 0.4'}
+ dependencies:
+ has-tostringtag: 1.0.0
+ dev: true
+
+ /is-number@7.0.0:
+ resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==}
+ engines: {node: '>=0.12.0'}
+
+ /is-path-inside@3.0.3:
+ resolution: {integrity: sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==}
+ engines: {node: '>=8'}
+ dev: true
+
+ /is-regex@1.1.4:
+ resolution: {integrity: sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==}
+ engines: {node: '>= 0.4'}
+ dependencies:
+ call-bind: 1.0.5
+ has-tostringtag: 1.0.0
+ dev: true
+
+ /is-set@2.0.2:
+ resolution: {integrity: sha512-+2cnTEZeY5z/iXGbLhPrOAaK/Mau5k5eXq9j14CpRTftq0pAJu2MwVRSZhyZWBzx3o6X795Lz6Bpb6R0GKf37g==}
+ dev: true
+
+ /is-shallow-equal@1.0.1:
+ resolution: {integrity: sha512-lq5RvK+85Hs5J3p4oA4256M1FEffzmI533ikeDHvJd42nouRRx5wBzt36JuviiGe5dIPyHON/d0/Up+PBo6XkQ==}
+ dev: false
+
+ /is-shared-array-buffer@1.0.2:
+ resolution: {integrity: sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==}
+ dependencies:
+ call-bind: 1.0.5
+ dev: true
+
+ /is-stream@2.0.1:
+ resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==}
+ engines: {node: '>=8'}
+ dev: false
+
+ /is-string@1.0.7:
+ resolution: {integrity: sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==}
+ engines: {node: '>= 0.4'}
+ dependencies:
+ has-tostringtag: 1.0.0
+ dev: true
+
+ /is-symbol@1.0.4:
+ resolution: {integrity: sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==}
+ engines: {node: '>= 0.4'}
+ dependencies:
+ has-symbols: 1.0.3
+ dev: true
+
+ /is-typed-array@1.1.12:
+ resolution: {integrity: sha512-Z14TF2JNG8Lss5/HMqt0//T9JeHXttXy5pH/DBU4vi98ozO2btxzq9MwYDZYnKwU8nRsz/+GVFVRDq3DkVuSPg==}
+ engines: {node: '>= 0.4'}
+ dependencies:
+ which-typed-array: 1.1.13
+ dev: true
+
+ /is-weakmap@2.0.1:
+ resolution: {integrity: sha512-NSBR4kH5oVj1Uwvv970ruUkCV7O1mzgVFO4/rev2cLRda9Tm9HrL70ZPut4rOHgY0FNrUu9BCbXA2sdQ+x0chA==}
+ dev: true
+
+ /is-weakref@1.0.2:
+ resolution: {integrity: sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==}
+ dependencies:
+ call-bind: 1.0.5
+ dev: true
+
+ /is-weakset@2.0.2:
+ resolution: {integrity: sha512-t2yVvttHkQktwnNNmBQ98AhENLdPUTDTE21uPqAQ0ARwQfGeQKRVS0NNurH7bTf7RrvcVn1OOge45CnBeHCSmg==}
+ dependencies:
+ call-bind: 1.0.5
+ get-intrinsic: 1.2.2
+ dev: true
+
+ /isarray@2.0.5:
+ resolution: {integrity: sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==}
+ dev: true
+
+ /isexe@2.0.0:
+ resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==}
+ dev: true
+
+ /isoformat@0.2.1:
+ resolution: {integrity: sha512-tFLRAygk9NqrRPhJSnNGh7g7oaVWDwR0wKh/GM2LgmPa50Eg4UfyaCO4I8k6EqJHl1/uh2RAD6g06n5ygEnrjQ==}
+ dev: false
+
+ /iterator.prototype@1.1.2:
+ resolution: {integrity: sha512-DR33HMMr8EzwuRL8Y9D3u2BMj8+RqSE850jfGu59kS7tbmPLzGkZmVSfyCFSDxuZiEY6Rzt3T2NA/qU+NwVj1w==}
+ dependencies:
+ define-properties: 1.2.1
+ get-intrinsic: 1.2.2
+ has-symbols: 1.0.3
+ reflect.getprototypeof: 1.0.4
+ set-function-name: 2.0.1
+ dev: true
+
+ /js-base64@3.7.5:
+ resolution: {integrity: sha512-3MEt5DTINKqfScXKfJFrRbxkrnk2AxPWGBL/ycjz4dK8iqiSJ06UxD8jh8xuh6p10TX4t2+7FsBYVxxQbMg+qA==}
+ dev: false
+
+ /js-tokens@4.0.0:
+ resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==}
+
+ /js-yaml@3.14.1:
+ resolution: {integrity: sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==}
+ hasBin: true
+ dependencies:
+ argparse: 1.0.10
+ esprima: 4.0.1
+ dev: false
+
+ /js-yaml@4.1.0:
+ resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==}
+ hasBin: true
+ dependencies:
+ argparse: 2.0.1
+ dev: true
+
+ /json-buffer@3.0.1:
+ resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==}
+
+ /json-schema-traverse@0.4.1:
+ resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==}
+ dev: true
+
+ /json-stable-stringify-without-jsonify@1.0.1:
+ resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==}
+ dev: true
+
+ /json5@1.0.2:
+ resolution: {integrity: sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==}
+ hasBin: true
+ dependencies:
+ minimist: 1.2.8
+ dev: true
+
+ /jsonwebtoken@9.0.0:
+ resolution: {integrity: sha512-tuGfYXxkQGDPnLJ7SibiQgVgeDgfbPq2k2ICcbgqW8WxWLBAxKQM/ZCu/IT8SOSwmaYl4dpTFCW5xZv7YbbWUw==}
+ engines: {node: '>=12', npm: '>=6'}
+ dependencies:
+ jws: 3.2.2
+ lodash: 4.17.21
+ ms: 2.1.3
+ semver: 7.5.4
+ dev: false
+
+ /jsonwebtoken@9.0.2:
+ resolution: {integrity: sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ==}
+ engines: {node: '>=12', npm: '>=6'}
+ dependencies:
+ jws: 3.2.2
+ lodash.includes: 4.3.0
+ lodash.isboolean: 3.0.3
+ lodash.isinteger: 4.0.4
+ lodash.isnumber: 3.0.3
+ lodash.isplainobject: 4.0.6
+ lodash.isstring: 4.0.1
+ lodash.once: 4.1.1
+ ms: 2.1.3
+ semver: 7.5.4
+ dev: false
+
+ /jsx-ast-utils@3.3.5:
+ resolution: {integrity: sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==}
+ engines: {node: '>=4.0'}
+ dependencies:
+ array-includes: 3.1.7
+ array.prototype.flat: 1.3.2
+ object.assign: 4.1.5
+ object.values: 1.1.7
+ dev: true
+
+ /jwa@1.4.1:
+ resolution: {integrity: sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==}
+ dependencies:
+ buffer-equal-constant-time: 1.0.1
+ ecdsa-sig-formatter: 1.0.11
+ safe-buffer: 5.2.1
+ dev: false
+
+ /jwa@2.0.0:
+ resolution: {integrity: sha512-jrZ2Qx916EA+fq9cEAeCROWPTfCwi1IVHqT2tapuqLEVVDKFDENFw1oL+MwrTvH6msKxsd1YTDVw6uKEcsrLEA==}
+ requiresBuild: true
+ dependencies:
+ buffer-equal-constant-time: 1.0.1
+ ecdsa-sig-formatter: 1.0.11
+ safe-buffer: 5.2.1
+ dev: false
+ optional: true
+
+ /jwk-to-pem@2.0.5:
+ resolution: {integrity: sha512-L90jwellhO8jRKYwbssU9ifaMVqajzj3fpRjDKcsDzrslU9syRbFqfkXtT4B89HYAap+xsxNcxgBSB09ig+a7A==}
+ requiresBuild: true
+ dependencies:
+ asn1.js: 5.4.1
+ elliptic: 6.5.4
+ safe-buffer: 5.2.1
+ dev: false
+ optional: true
+
+ /jws@3.2.2:
+ resolution: {integrity: sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==}
+ dependencies:
+ jwa: 1.4.1
+ safe-buffer: 5.2.1
+ dev: false
+
+ /jws@4.0.0:
+ resolution: {integrity: sha512-KDncfTmOZoOMTFG4mBlG0qUIOlc03fmzH+ru6RgYVZhPkyiy/92Owlt/8UEN+a4TXR1FQetfIpJE8ApdvdVxTg==}
+ requiresBuild: true
+ dependencies:
+ jwa: 2.0.0
+ safe-buffer: 5.2.1
+ dev: false
+ optional: true
+
+ /keyv@4.5.4:
+ resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==}
+ dependencies:
+ json-buffer: 3.0.1
+
+ /kind-of@6.0.3:
+ resolution: {integrity: sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==}
+ engines: {node: '>=0.10.0'}
+ dev: false
+
+ /language-subtag-registry@0.3.22:
+ resolution: {integrity: sha512-tN0MCzyWnoz/4nHS6uxdlFWoUZT7ABptwKPQ52Ea7URk6vll88bWBVhodtnlfEuCcKWNGoc+uGbw1cwa9IKh/w==}
+ dev: true
+
+ /language-tags@1.0.9:
+ resolution: {integrity: sha512-MbjN408fEndfiQXbFQ1vnd+1NoLDsnQW41410oQBXiyXDMYH5z505juWa4KUE1LqxRC7DgOgZDbKLxHIwm27hA==}
+ engines: {node: '>=0.10'}
+ dependencies:
+ language-subtag-registry: 0.3.22
+ dev: true
+
+ /levn@0.4.1:
+ resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==}
+ engines: {node: '>= 0.8.0'}
+ dependencies:
+ prelude-ls: 1.2.1
+ type-check: 0.4.0
+ dev: true
+
+ /loadjs@4.2.0:
+ resolution: {integrity: sha512-AgQGZisAlTPbTEzrHPb6q+NYBMD+DP9uvGSIjSUM5uG+0jG15cb8axWpxuOIqrmQjn6scaaH8JwloiP27b2KXA==}
+ dev: false
+
+ /locate-path@6.0.0:
+ resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==}
+ engines: {node: '>=10'}
+ dependencies:
+ p-locate: 5.0.0
+ dev: true
+
+ /lodash-es@4.17.21:
+ resolution: {integrity: sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==}
+ dev: false
+
+ /lodash._baseiteratee@4.7.0:
+ resolution: {integrity: sha512-nqB9M+wITz0BX/Q2xg6fQ8mLkyfF7MU7eE+MNBNjTHFKeKaZAPEzEg+E8LWxKWf1DQVflNEn9N49yAuqKh2mWQ==}
+ dependencies:
+ lodash._stringtopath: 4.8.0
+ dev: false
+
+ /lodash._basetostring@4.12.0:
+ resolution: {integrity: sha512-SwcRIbyxnN6CFEEK4K1y+zuApvWdpQdBHM/swxP962s8HIxPO3alBH5t3m/dl+f4CMUug6sJb7Pww8d13/9WSw==}
+ dev: false
+
+ /lodash._baseuniq@4.6.0:
+ resolution: {integrity: sha512-Ja1YevpHZctlI5beLA7oc5KNDhGcPixFhcqSiORHNsp/1QTv7amAXzw+gu4YOvErqVlMVyIJGgtzeepCnnur0A==}
+ dependencies:
+ lodash._createset: 4.0.3
+ lodash._root: 3.0.1
+ dev: false
+
+ /lodash._createset@4.0.3:
+ resolution: {integrity: sha512-GTkC6YMprrJZCYU3zcqZj+jkXkrXzq3IPBcF/fIPpNEAB4hZEtXU8zp/RwKOvZl43NUmwDbyRk3+ZTbeRdEBXA==}
+ dev: false
+
+ /lodash._root@3.0.1:
+ resolution: {integrity: sha512-O0pWuFSK6x4EXhM1dhZ8gchNtG7JMqBtrHdoUFUWXD7dJnNSUze1GuyQr5sOs0aCvgGeI3o/OJW8f4ca7FDxmQ==}
+ dev: false
+
+ /lodash._stringtopath@4.8.0:
+ resolution: {integrity: sha512-SXL66C731p0xPDC5LZg4wI5H+dJo/EO4KTqOMwLYCH3+FmmfAKJEZCm6ohGpI+T1xwsDsJCfL4OnhorllvlTPQ==}
+ dependencies:
+ lodash._basetostring: 4.12.0
+ dev: false
+
+ /lodash.includes@4.3.0:
+ resolution: {integrity: sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==}
+ dev: false
+
+ /lodash.isboolean@3.0.3:
+ resolution: {integrity: sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==}
+ dev: false
+
+ /lodash.isinteger@4.0.4:
+ resolution: {integrity: sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==}
+ dev: false
+
+ /lodash.isnumber@3.0.3:
+ resolution: {integrity: sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==}
+ dev: false
+
+ /lodash.isplainobject@4.0.6:
+ resolution: {integrity: sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==}
+ dev: false
+
+ /lodash.isstring@4.0.1:
+ resolution: {integrity: sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==}
+ dev: false
+
+ /lodash.merge@4.6.2:
+ resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==}
+ dev: true
+
+ /lodash.once@4.1.1:
+ resolution: {integrity: sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==}
+ dev: false
+
+ /lodash.throttle@4.1.1:
+ resolution: {integrity: sha512-wIkUCfVKpVsWo3JSZlc+8MB5it+2AN5W8J7YVMST30UrvcQNZ1Okbj+rbVniijTWE6FGYy4XJq/rHkas8qJMLQ==}
+ dev: false
+
+ /lodash.uniqby@4.5.0:
+ resolution: {integrity: sha512-IRt7cfTtHy6f1aRVA5n7kT8rgN3N1nH6MOWLcHfpWG2SH19E3JksLK38MktLxZDhlAjCP9jpIXkOnRXlu6oByQ==}
+ dependencies:
+ lodash._baseiteratee: 4.7.0
+ lodash._baseuniq: 4.6.0
+ dev: false
+
+ /lodash@4.17.21:
+ resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==}
+ dev: false
+
+ /long-timeout@0.1.1:
+ resolution: {integrity: sha512-BFRuQUqc7x2NWxfJBCyUrN8iYUYznzL9JROmRz1gZ6KlOIgmoD+njPVbb+VNn2nGMKggMsK79iUNErillsrx7w==}
+ dev: false
+
+ /loose-envify@1.4.0:
+ resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==}
+ hasBin: true
+ dependencies:
+ js-tokens: 4.0.0
+
+ /lowercase-keys@2.0.0:
+ resolution: {integrity: sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==}
+ engines: {node: '>=8'}
+ dev: false
+
+ /lru-cache@4.1.5:
+ resolution: {integrity: sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==}
+ dependencies:
+ pseudomap: 1.0.2
+ yallist: 2.1.2
+ dev: false
+
+ /lru-cache@6.0.0:
+ resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==}
+ engines: {node: '>=10'}
+ dependencies:
+ yallist: 4.0.0
+
+ /lunarphase-js@2.0.1:
+ resolution: {integrity: sha512-QcCF6UxtifeSCDjbMT7FsczG4lHnWp1WRUpBy3IS5cG8pxtypk0VW/gw7xz+2vWYoaiVrt4NADZ+NR+ly4GvPg==}
+ dev: false
+
+ /luxon@1.28.1:
+ resolution: {integrity: sha512-gYHAa180mKrNIUJCbwpmD0aTu9kV0dREDrwNnuyFAsO1Wt0EVYSZelPnJlbj9HplzXX/YWXHFTL45kvZ53M0pw==}
+ dev: false
+
+ /media-chrome@2.0.1:
+ resolution: {integrity: sha512-6hoC5OY993t4o/YKYXn7YoWUAKG1UFAhnDXNN6kRRa5mnuL+Cwct/2Md16S4jjmTSmN5XjhEWwfCVM5NLHavOA==}
+ dev: false
+
+ /media-tracks@0.3.0:
+ resolution: {integrity: sha512-kicD8eOFwe6nD7jn7iM/0yuLzWuo6abWHURYwY7NhxL1dBif+lt0on4rLTs6VhKwAEE/BjT3wr+0vn1w8SBpag==}
+ dev: false
+
+ /media-typer@0.3.0:
+ resolution: {integrity: sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==}
+ engines: {node: '>= 0.6'}
+ dev: false
+
+ /memoize-one@6.0.0:
+ resolution: {integrity: sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw==}
+ dev: false
+
+ /memorystore@1.6.7:
+ resolution: {integrity: sha512-OZnmNY/NDrKohPQ+hxp0muBcBKrzKNtHr55DbqSx9hLsYVNnomSAMRAtI7R64t3gf3ID7tHQA7mG4oL3Hu9hdw==}
+ engines: {node: '>=0.10'}
+ dependencies:
+ debug: 4.3.4(supports-color@5.5.0)
+ lru-cache: 4.1.5
+ transitivePeerDependencies:
+ - supports-color
+ dev: false
+
+ /merge-descriptors@1.0.1:
+ resolution: {integrity: sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==}
+ dev: false
+
+ /merge2@1.4.1:
+ resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==}
+ engines: {node: '>= 8'}
+ dev: true
+
+ /methods@1.1.2:
+ resolution: {integrity: sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==}
+ engines: {node: '>= 0.6'}
+ dev: false
+
+ /micromatch@4.0.5:
+ resolution: {integrity: sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==}
+ engines: {node: '>=8.6'}
+ dependencies:
+ braces: 3.0.2
+ picomatch: 2.3.1
+ dev: true
+
+ /mime-db@1.52.0:
+ resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==}
+ engines: {node: '>= 0.6'}
+ dev: false
+
+ /mime-match@1.0.2:
+ resolution: {integrity: sha512-VXp/ugGDVh3eCLOBCiHZMYWQaTNUHv2IJrut+yXA6+JbLPXHglHwfS/5A5L0ll+jkCY7fIzRJcH6OIunF+c6Cg==}
+ dependencies:
+ wildcard: 1.1.2
+ dev: false
+
+ /mime-types@2.1.35:
+ resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==}
+ engines: {node: '>= 0.6'}
+ dependencies:
+ mime-db: 1.52.0
+ dev: false
+
+ /mime@1.6.0:
+ resolution: {integrity: sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==}
+ engines: {node: '>=4'}
+ hasBin: true
+ dev: false
+
+ /mimic-response@1.0.1:
+ resolution: {integrity: sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==}
+ engines: {node: '>=4'}
+ dev: false
+
+ /mimic-response@3.1.0:
+ resolution: {integrity: sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==}
+ engines: {node: '>=10'}
+ dev: false
+
+ /minimalistic-assert@1.0.1:
+ resolution: {integrity: sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==}
+ requiresBuild: true
+ dev: false
+ optional: true
+
+ /minimalistic-crypto-utils@1.0.1:
+ resolution: {integrity: sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==}
+ requiresBuild: true
+ dev: false
+ optional: true
+
+ /minimatch@3.1.2:
+ resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==}
+ dependencies:
+ brace-expansion: 1.1.11
+ dev: true
+
+ /minimatch@9.0.3:
+ resolution: {integrity: sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==}
+ engines: {node: '>=16 || 14 >=14.17'}
+ dependencies:
+ brace-expansion: 2.0.1
+ dev: true
+
+ /minimist@1.2.8:
+ resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==}
+
+ /mkdirp-classic@0.5.3:
+ resolution: {integrity: sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==}
+ dev: false
+
+ /moment-timezone@0.5.44:
+ resolution: {integrity: sha512-nv3YpzI/8lkQn0U6RkLd+f0W/zy/JnoR5/EyPz/dNkPTBjA2jNLCVxaiQ8QpeLymhSZvX0wCL5s27NQWdOPwAw==}
+ dependencies:
+ moment: 2.30.1
+ dev: false
+
+ /moment@2.30.1:
+ resolution: {integrity: sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==}
+ dev: false
+
+ /morgan@1.10.0:
+ resolution: {integrity: sha512-AbegBVI4sh6El+1gNwvD5YIck7nSA36weD7xvIxG4in80j/UoK8AEGaWnnz8v1GxonMCltmlNs5ZKbGvl9b1XQ==}
+ engines: {node: '>= 0.8.0'}
+ dependencies:
+ basic-auth: 2.0.1
+ debug: 2.6.9
+ depd: 2.0.0
+ on-finished: 2.3.0
+ on-headers: 1.0.2
+ transitivePeerDependencies:
+ - supports-color
+ dev: false
+
+ /ms@2.0.0:
+ resolution: {integrity: sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==}
+ dev: false
+
+ /ms@2.1.2:
+ resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==}
+
+ /ms@2.1.3:
+ resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==}
+
+ /multiformats@13.0.1:
+ resolution: {integrity: sha512-bt3R5iXe2O8xpp3wkmQhC73b/lC4S2ihU8Dndwcsysqbydqb8N+bpP116qMcClZ17g58iSIwtXUTcg2zT4sniA==}
+ dev: false
+
+ /mux-embed@4.30.0:
+ resolution: {integrity: sha512-XAgAp4CEvsiZL26GbruzeG1g33OWyrzuskDMavXUxDufTxS0/AxAhwoTTRqEzEJS9vnZa/X9R2GV3xRX1XMp2w==}
+ dev: false
+
+ /namespace-emitter@2.0.1:
+ resolution: {integrity: sha512-N/sMKHniSDJBjfrkbS/tpkPj4RAbvW3mr8UAzvlMHyun93XEm83IAvhWtJVHo+RHn/oO8Job5YN4b+wRjSVp5g==}
+ dev: false
+
+ /nanoid@3.3.7:
+ resolution: {integrity: sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==}
+ engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
+ hasBin: true
+ dev: false
+
+ /nanoid@4.0.2:
+ resolution: {integrity: sha512-7ZtY5KTCNheRGfEFxnedV5zFiORN1+Y1N6zvPTnHQd8ENUvfaDBeuJDZb2bN/oXwXxu3qkTXDzy57W5vAmDTBw==}
+ engines: {node: ^14 || ^16 || >=18}
+ hasBin: true
+ dev: false
+
+ /napi-build-utils@1.0.2:
+ resolution: {integrity: sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==}
+ dev: false
+
+ /natural-compare@1.4.0:
+ resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==}
+ dev: true
+
+ /negotiator@0.6.3:
+ resolution: {integrity: sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==}
+ engines: {node: '>= 0.6'}
+ dev: false
+
+ /next-goatcounter@1.0.5(next@14.0.4)(react-dom@18.2.0)(react@18.2.0):
+ resolution: {integrity: sha512-t2khpwRk1sDeZwth8wg0SF6MKAQ4lrUJ0qKFETmeEkIudcrc6hbMSvmhiVc8XrpTl13S4F2wWRH248FSyY8Gvw==}
+ peerDependencies:
+ next: '>14.0.0'
+ react: '>18.0.0'
+ react-dom: '>18.0.0'
+ dependencies:
+ next: 14.0.4(react-dom@18.2.0)(react@18.2.0)(sass@1.69.7)
+ react: 18.2.0
+ react-dom: 18.2.0(react@18.2.0)
+ dev: false
+
+ /next@14.0.4(react-dom@18.2.0)(react@18.2.0)(sass@1.69.7):
+ resolution: {integrity: sha512-qbwypnM7327SadwFtxXnQdGiKpkuhaRLE2uq62/nRul9cj9KhQ5LhHmlziTNqUidZotw/Q1I9OjirBROdUJNgA==}
+ engines: {node: '>=18.17.0'}
+ hasBin: true
+ peerDependencies:
+ '@opentelemetry/api': ^1.1.0
+ react: ^18.2.0
+ react-dom: ^18.2.0
+ sass: ^1.3.0
+ peerDependenciesMeta:
+ '@opentelemetry/api':
+ optional: true
+ sass:
+ optional: true
+ dependencies:
+ '@next/env': 14.0.4
+ '@swc/helpers': 0.5.2
+ busboy: 1.6.0
+ caniuse-lite: 1.0.30001576
+ graceful-fs: 4.2.11
+ postcss: 8.4.31
+ react: 18.2.0
+ react-dom: 18.2.0(react@18.2.0)
+ sass: 1.69.7
+ styled-jsx: 5.1.1(react@18.2.0)
+ watchpack: 2.4.0
+ optionalDependencies:
+ '@next/swc-darwin-arm64': 14.0.4
+ '@next/swc-darwin-x64': 14.0.4
+ '@next/swc-linux-arm64-gnu': 14.0.4
+ '@next/swc-linux-arm64-musl': 14.0.4
+ '@next/swc-linux-x64-gnu': 14.0.4
+ '@next/swc-linux-x64-musl': 14.0.4
+ '@next/swc-win32-arm64-msvc': 14.0.4
+ '@next/swc-win32-ia32-msvc': 14.0.4
+ '@next/swc-win32-x64-msvc': 14.0.4
+ transitivePeerDependencies:
+ - '@babel/core'
+ - babel-plugin-macros
+ dev: false
+
+ /nextjs-toploader@1.6.4(next@14.0.4)(react-dom@18.2.0)(react@18.2.0):
+ resolution: {integrity: sha512-KYLQ+0MvGdFk9JwOQfRtaYBAsyuX67Ca5QTa51RGNO4gQx64KLSE+ryHjUQ5LcDczHotp0l32GgksQW9vucUkw==}
+ peerDependencies:
+ next: '>= 6.0.0'
+ react: '>= 16.0.0'
+ react-dom: '>= 16.0.0'
+ dependencies:
+ '@types/nprogress': 0.2.3
+ next: 14.0.4(react-dom@18.2.0)(react@18.2.0)(sass@1.69.7)
+ nprogress: 0.2.0
+ prop-types: 15.8.1
+ react: 18.2.0
+ react-dom: 18.2.0(react@18.2.0)
+ dev: false
+
+ /node-abi@3.54.0:
+ resolution: {integrity: sha512-p7eGEiQil0YUV3ItH4/tBb781L5impVmmx2E9FRKF7d18XXzp4PGT2tdYMFY6wQqgxD0IwNZOiSJ0/K0fSi/OA==}
+ engines: {node: '>=10'}
+ dependencies:
+ semver: 7.5.4
+ dev: false
+
+ /node-addon-api@5.1.0:
+ resolution: {integrity: sha512-eh0GgfEkpnoWDq+VY8OyvYhFEzBk6jIYbRKdIlyTiAXIVJ8PyBaKb0rp7oDtoddbdoHWhq8wwr+XZ81F1rpNdA==}
+ dev: false
+
+ /node-schedule@2.1.0:
+ resolution: {integrity: sha512-nl4JTiZ7ZQDc97MmpTq9BQjYhq7gOtoh7SiPH069gBFBj0PzD8HI7zyFs6rzqL8Y5tTiEEYLxgtbx034YPrbyQ==}
+ engines: {node: '>=6'}
+ dependencies:
+ cron-parser: 3.5.0
+ long-timeout: 0.1.1
+ sorted-array-functions: 1.3.0
+ dev: false
+
+ /nodemon@3.0.3:
+ resolution: {integrity: sha512-7jH/NXbFPxVaMwmBCC2B9F/V6X1VkEdNgx3iu9jji8WxWcvhMWkmhNWhI5077zknOnZnBzba9hZP6bCPJLSReQ==}
+ engines: {node: '>=10'}
+ hasBin: true
+ dependencies:
+ chokidar: 3.5.3
+ debug: 4.3.4(supports-color@5.5.0)
+ ignore-by-default: 1.0.1
+ minimatch: 3.1.2
+ pstree.remy: 1.1.8
+ semver: 7.5.4
+ simple-update-notifier: 2.0.0
+ supports-color: 5.5.0
+ touch: 3.1.0
+ undefsafe: 2.0.5
+ dev: true
+
+ /nopt@1.0.10:
+ resolution: {integrity: sha512-NWmpvLSqUrgrAC9HCuxEvb+PSloHpqVu+FqcO4eeF2h5qYRhA7ev6KvelyQAKtegUbC6RypJnlEOhd8vloNKYg==}
+ hasBin: true
+ dependencies:
+ abbrev: 1.1.1
+ dev: true
+
+ /normalize-path@3.0.0:
+ resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==}
+ engines: {node: '>=0.10.0'}
+
+ /normalize-url@6.1.0:
+ resolution: {integrity: sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==}
+ engines: {node: '>=10'}
+ dev: false
+
+ /nprogress@0.2.0:
+ resolution: {integrity: sha512-I19aIingLgR1fmhftnbWWO3dXc0hSxqHQHQb3H8m+K3TnEn/iSeTZZOyvKXWqQESMwuUVnatlCnZdLBZZt2VSA==}
+ dev: false
+
+ /oauth-sign@0.9.0:
+ resolution: {integrity: sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==}
+ dev: false
+
+ /object-assign@4.1.1:
+ resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==}
+ engines: {node: '>=0.10.0'}
+
+ /object-inspect@1.13.1:
+ resolution: {integrity: sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==}
+
+ /object-keys@1.1.1:
+ resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==}
+ engines: {node: '>= 0.4'}
+
+ /object.assign@4.1.5:
+ resolution: {integrity: sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==}
+ engines: {node: '>= 0.4'}
+ dependencies:
+ call-bind: 1.0.5
+ define-properties: 1.2.1
+ has-symbols: 1.0.3
+ object-keys: 1.1.1
+ dev: true
+
+ /object.entries@1.1.7:
+ resolution: {integrity: sha512-jCBs/0plmPsOnrKAfFQXRG2NFjlhZgjjcBLSmTnEhU8U6vVTsVe8ANeQJCHTl3gSsI4J+0emOoCgoKlmQPMgmA==}
+ engines: {node: '>= 0.4'}
+ dependencies:
+ call-bind: 1.0.5
+ define-properties: 1.2.1
+ es-abstract: 1.22.3
+ dev: true
+
+ /object.fromentries@2.0.7:
+ resolution: {integrity: sha512-UPbPHML6sL8PI/mOqPwsH4G6iyXcCGzLin8KvEPenOZN5lpCNBZZQ+V62vdjB1mQHrmqGQt5/OJzemUA+KJmEA==}
+ engines: {node: '>= 0.4'}
+ dependencies:
+ call-bind: 1.0.5
+ define-properties: 1.2.1
+ es-abstract: 1.22.3
+ dev: true
+
+ /object.groupby@1.0.1:
+ resolution: {integrity: sha512-HqaQtqLnp/8Bn4GL16cj+CUYbnpe1bh0TtEaWvybszDG4tgxCJuRpV8VGuvNaI1fAnI4lUJzDG55MXcOH4JZcQ==}
+ dependencies:
+ call-bind: 1.0.5
+ define-properties: 1.2.1
+ es-abstract: 1.22.3
+ get-intrinsic: 1.2.2
+ dev: true
+
+ /object.hasown@1.1.3:
+ resolution: {integrity: sha512-fFI4VcYpRHvSLXxP7yiZOMAd331cPfd2p7PFDVbgUsYOfCT3tICVqXWngbjr4m49OvsBwUBQ6O2uQoJvy3RexA==}
+ dependencies:
+ define-properties: 1.2.1
+ es-abstract: 1.22.3
+ dev: true
+
+ /object.values@1.1.7:
+ resolution: {integrity: sha512-aU6xnDFYT3x17e/f0IiiwlGPTy2jzMySGfUB4fq6z7CV8l85CWHDk5ErhyhpfDHhrOMwGFhSQkhMGHaIotA6Ng==}
+ engines: {node: '>= 0.4'}
+ dependencies:
+ call-bind: 1.0.5
+ define-properties: 1.2.1
+ es-abstract: 1.22.3
+ dev: true
+
+ /on-finished@2.3.0:
+ resolution: {integrity: sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==}
+ engines: {node: '>= 0.8'}
+ dependencies:
+ ee-first: 1.1.1
+ dev: false
+
+ /on-finished@2.4.1:
+ resolution: {integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==}
+ engines: {node: '>= 0.8'}
+ dependencies:
+ ee-first: 1.1.1
+ dev: false
+
+ /on-headers@1.0.2:
+ resolution: {integrity: sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==}
+ engines: {node: '>= 0.8'}
+ dev: false
+
+ /once@1.4.0:
+ resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==}
+ dependencies:
+ wrappy: 1.0.2
+
+ /optionator@0.9.3:
+ resolution: {integrity: sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==}
+ engines: {node: '>= 0.8.0'}
+ dependencies:
+ '@aashutoshrathi/word-wrap': 1.2.6
+ deep-is: 0.1.4
+ fast-levenshtein: 2.0.6
+ levn: 0.4.1
+ prelude-ls: 1.2.1
+ type-check: 0.4.0
+ dev: true
+
+ /p-cancelable@2.1.1:
+ resolution: {integrity: sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg==}
+ engines: {node: '>=8'}
+ dev: false
+
+ /p-limit@3.1.0:
+ resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==}
+ engines: {node: '>=10'}
+ dependencies:
+ yocto-queue: 0.1.0
+ dev: true
+
+ /p-locate@5.0.0:
+ resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==}
+ engines: {node: '>=10'}
+ dependencies:
+ p-limit: 3.1.0
+ dev: true
+
+ /p-queue@7.4.1:
+ resolution: {integrity: sha512-vRpMXmIkYF2/1hLBKisKeVYJZ8S2tZ0zEAmIJgdVKP2nq0nh4qCdf8bgw+ZgKrkh71AOCaqzwbJJk1WtdcF3VA==}
+ engines: {node: '>=12'}
+ dependencies:
+ eventemitter3: 5.0.1
+ p-timeout: 5.1.0
+ dev: false
+
+ /p-retry@6.2.0:
+ resolution: {integrity: sha512-JA6nkq6hKyWLLasXQXUrO4z8BUZGUt/LjlJxx8Gb2+2ntodU/SS63YZ8b0LUTbQ8ZB9iwOfhEPhg4ykKnn2KsA==}
+ engines: {node: '>=16.17'}
+ dependencies:
+ '@types/retry': 0.12.2
+ is-network-error: 1.0.1
+ retry: 0.13.1
+ dev: false
+
+ /p-timeout@5.1.0:
+ resolution: {integrity: sha512-auFDyzzzGZZZdHz3BtET9VEz0SE/uMEAx7uWfGPucfzEwwe/xH0iVeZibQmANYE/hp9T2+UUZT5m+BKyrDp3Ew==}
+ engines: {node: '>=12'}
+ dev: false
+
+ /parent-module@1.0.1:
+ resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==}
+ engines: {node: '>=6'}
+ dependencies:
+ callsites: 3.1.0
+ dev: true
+
+ /parseurl@1.3.3:
+ resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==}
+ engines: {node: '>= 0.8'}
+ dev: false
+
+ /path-exists@4.0.0:
+ resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==}
+ engines: {node: '>=8'}
+ dev: true
+
+ /path-is-absolute@1.0.1:
+ resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==}
+ engines: {node: '>=0.10.0'}
+ dev: true
+
+ /path-key@3.1.1:
+ resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==}
+ engines: {node: '>=8'}
+ dev: true
+
+ /path-parse@1.0.7:
+ resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==}
+ dev: true
+
+ /path-to-regexp@0.1.7:
+ resolution: {integrity: sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==}
+ dev: false
+
+ /path-type@4.0.0:
+ resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==}
+ engines: {node: '>=8'}
+ dev: true
+
+ /picocolors@1.0.0:
+ resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==}
+ dev: false
+
+ /picomatch@2.3.1:
+ resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==}
+ engines: {node: '>=8.6'}
+
+ /plyr-react@5.3.0(plyr@3.7.8)(react@18.2.0):
+ resolution: {integrity: sha512-m36/HrpHwg1N2rq3E31E8/kpAH55vk6qHUg17MG4uu9jbWYxnkN39lLmZQwxW7/qpDPfW5aGUJ6R3u23V0R3zA==}
+ engines: {node: '>=16'}
+ peerDependencies:
+ plyr: ^3.7.7
+ react: '>=16.8'
+ peerDependenciesMeta:
+ react:
+ optional: true
+ dependencies:
+ plyr: 3.7.8
+ react: 18.2.0
+ react-aptor: 2.0.0(react@18.2.0)
+ dev: false
+
+ /plyr@3.7.8:
+ resolution: {integrity: sha512-yG/EHDobwbB/uP+4Bm6eUpJ93f8xxHjjk2dYcD1Oqpe1EcuQl5tzzw9Oq+uVAzd2lkM11qZfydSiyIpiB8pgdA==}
+ dependencies:
+ core-js: 3.35.0
+ custom-event-polyfill: 1.0.7
+ loadjs: 4.2.0
+ rangetouch: 2.0.1
+ url-polyfill: 1.1.12
+ dev: false
+
+ /postcss@8.4.31:
+ resolution: {integrity: sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==}
+ engines: {node: ^10 || ^12 || >=14}
+ dependencies:
+ nanoid: 3.3.7
+ picocolors: 1.0.0
+ source-map-js: 1.0.2
+ dev: false
+
+ /preact@10.12.1:
+ resolution: {integrity: sha512-l8386ixSsBdbreOAkqtrwqHwdvR35ID8c3rKPa8lCWuO86dBi32QWHV4vfsZK1utLLFMvw+Z5Ad4XLkZzchscg==}
+ dev: false
+
+ /preact@10.19.3:
+ resolution: {integrity: sha512-nHHTeFVBTHRGxJXKkKu5hT8C/YWBkPso4/Gad6xuj5dbptt9iF9NZr9pHbPhBrnT2klheu7mHTxTZ/LjwJiEiQ==}
+ dev: false
+
+ /prebuild-install@7.1.1:
+ resolution: {integrity: sha512-jAXscXWMcCK8GgCoHOfIr0ODh5ai8mj63L2nWrjuAgXE6tDyYGnx4/8o/rCgU+B4JSyZBKbeZqzhtwtC3ovxjw==}
+ engines: {node: '>=10'}
+ hasBin: true
+ dependencies:
+ detect-libc: 2.0.2
+ expand-template: 2.0.3
+ github-from-package: 0.0.0
+ minimist: 1.2.8
+ mkdirp-classic: 0.5.3
+ napi-build-utils: 1.0.2
+ node-abi: 3.54.0
+ pump: 3.0.0
+ rc: 1.2.8
+ simple-get: 4.0.1
+ tar-fs: 2.1.1
+ tunnel-agent: 0.6.0
+ dev: false
+
+ /prelude-ls@1.2.1:
+ resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==}
+ engines: {node: '>= 0.8.0'}
+ dev: true
+
+ /prism-react-renderer@2.3.1(react@18.2.0):
+ resolution: {integrity: sha512-Rdf+HzBLR7KYjzpJ1rSoxT9ioO85nZngQEoFIhL07XhtJHlCU3SOz0GJ6+qvMyQe0Se+BV3qpe6Yd/NmQF5Juw==}
+ peerDependencies:
+ react: '>=16.0.0'
+ dependencies:
+ '@types/prismjs': 1.26.3
+ clsx: 2.1.0
+ react: 18.2.0
+ dev: false
+
+ /prom-client@14.0.1:
+ resolution: {integrity: sha512-HxTArb6fkOntQHoRGvv4qd/BkorjliiuO2uSWC2KC17MUTKYttWdDoXX/vxOhQdkoECEM9BBH0pj2l8G8kev6w==}
+ engines: {node: '>=10'}
+ dependencies:
+ tdigest: 0.1.2
+ dev: false
+
+ /prop-types@15.8.1:
+ resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==}
+ dependencies:
+ loose-envify: 1.4.0
+ object-assign: 4.1.1
+ react-is: 16.13.1
+
+ /proper-lockfile@4.1.2:
+ resolution: {integrity: sha512-TjNPblN4BwAWMXU8s9AEz4JmQxnD1NNL7bNOY/AKUzyamc379FWASUhc/K1pL2noVb+XmZKLL68cjzLsiOAMaA==}
+ dependencies:
+ graceful-fs: 4.2.11
+ retry: 0.12.0
+ signal-exit: 3.0.7
+ dev: false
+
+ /property-expr@2.0.6:
+ resolution: {integrity: sha512-SVtmxhRE/CGkn3eZY1T6pC8Nln6Fr/lu1mKSgRud0eC73whjGfoAogbn78LkD8aFL0zz3bAFerKSnOl7NlErBA==}
+ dev: false
+
+ /proxy-addr@2.0.7:
+ resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==}
+ engines: {node: '>= 0.10'}
+ dependencies:
+ forwarded: 0.2.0
+ ipaddr.js: 1.9.1
+ dev: false
+
+ /pseudomap@1.0.2:
+ resolution: {integrity: sha512-b/YwNhb8lk1Zz2+bXXpS/LK9OisiZZ1SNsSLxN1x2OXVEhW2Ckr/7mWE5vrC1ZTiJlD9g19jWszTmJsB+oEpFQ==}
+ dev: false
+
+ /pstree.remy@1.1.8:
+ resolution: {integrity: sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==}
+ dev: true
+
+ /pump@3.0.0:
+ resolution: {integrity: sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==}
+ dependencies:
+ end-of-stream: 1.4.4
+ once: 1.4.0
+ dev: false
+
+ /punycode@2.3.1:
+ resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==}
+ engines: {node: '>=6'}
+ dev: true
+
+ /qs@6.10.3:
+ resolution: {integrity: sha512-wr7M2E0OFRfIfJZjKGieI8lBKb7fRCH4Fv5KNPEs7gJ8jadvotdsS08PzOKR7opXhZ/Xkjtt3WF9g38drmyRqQ==}
+ engines: {node: '>=0.6'}
+ dependencies:
+ side-channel: 1.0.4
+ dev: false
+
+ /qs@6.11.0:
+ resolution: {integrity: sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==}
+ engines: {node: '>=0.6'}
+ dependencies:
+ side-channel: 1.0.4
+ dev: false
+
+ /qs@6.11.2:
+ resolution: {integrity: sha512-tDNIz22aBzCDxLtVH++VnTfzxlfeK5CbqohpSqpJgj1Wg/cQbStNAz3NuqCs5vV+pjBsK4x4pN9HlVh7rcYRiA==}
+ engines: {node: '>=0.6'}
+ dependencies:
+ side-channel: 1.0.4
+ dev: false
+
+ /querystringify@2.2.0:
+ resolution: {integrity: sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==}
+ dev: false
+
+ /queue-microtask@1.2.3:
+ resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==}
+ dev: true
+
+ /quick-lru@5.1.1:
+ resolution: {integrity: sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==}
+ engines: {node: '>=10'}
+ dev: false
+
+ /random-bytes@1.0.0:
+ resolution: {integrity: sha512-iv7LhNVO047HzYR3InF6pUcUsPQiHTM1Qal51DcGSuZFBil1aBBWG5eHPNek7bvILMaYJ/8RU1e8w1AMdHmLQQ==}
+ engines: {node: '>= 0.8'}
+ dev: false
+
+ /randombytes@2.1.0:
+ resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==}
+ dependencies:
+ safe-buffer: 5.2.1
+ dev: false
+
+ /range-parser@1.2.1:
+ resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==}
+ engines: {node: '>= 0.6'}
+ dev: false
+
+ /rangetouch@2.0.1:
+ resolution: {integrity: sha512-sln+pNSc8NGaHoLzwNBssFSf/rSYkqeBXzX1AtJlkJiUaVSJSbRAWJk+4omsXkN+EJalzkZhWQ3th1m0FpR5xA==}
+ dev: false
+
+ /raw-body@2.5.1:
+ resolution: {integrity: sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==}
+ engines: {node: '>= 0.8'}
+ dependencies:
+ bytes: 3.1.2
+ http-errors: 2.0.0
+ iconv-lite: 0.4.24
+ unpipe: 1.0.0
+ dev: false
+
+ /raw-body@2.5.2:
+ resolution: {integrity: sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==}
+ engines: {node: '>= 0.8'}
+ dependencies:
+ bytes: 3.1.2
+ http-errors: 2.0.0
+ iconv-lite: 0.4.24
+ unpipe: 1.0.0
+ dev: false
+
+ /rc@1.2.8:
+ resolution: {integrity: sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==}
+ hasBin: true
+ dependencies:
+ deep-extend: 0.6.0
+ ini: 1.3.8
+ minimist: 1.2.8
+ strip-json-comments: 2.0.1
+ dev: false
+
+ /react-aptor@2.0.0(react@18.2.0):
+ resolution: {integrity: sha512-YnCayokuhAwmBBP4Oc0bbT2l6ApfsjbY3DEEVUddIKZEBlGl1npzjHHzWnSqWuboSbMZvRqUM01Io9yiIp1wcg==}
+ engines: {node: '>=12.7.0'}
+ peerDependencies:
+ react: '>=16.8'
+ peerDependenciesMeta:
+ react:
+ optional: true
+ dependencies:
+ react: 18.2.0
+ dev: false
+
+ /react-dom@18.2.0(react@18.2.0):
+ resolution: {integrity: sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==}
+ peerDependencies:
+ react: ^18.2.0
+ dependencies:
+ loose-envify: 1.4.0
+ react: 18.2.0
+ scheduler: 0.23.0
+ dev: false
+
+ /react-hook-form@7.49.3(react@18.2.0):
+ resolution: {integrity: sha512-foD6r3juidAT1cOZzpmD/gOKt7fRsDhXXZ0y28+Al1CHgX+AY1qIN9VSIIItXRq1dN68QrRwl1ORFlwjBaAqeQ==}
+ engines: {node: '>=18', pnpm: '8'}
+ peerDependencies:
+ react: ^16.8.0 || ^17 || ^18
+ dependencies:
+ react: 18.2.0
+ dev: false
+
+ /react-is@16.13.1:
+ resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==}
+
+ /react-loading-skeleton@3.3.1(react@18.2.0):
+ resolution: {integrity: sha512-NilqqwMh2v9omN7LteiDloEVpFyMIa0VGqF+ukqp0ncVlYu1sKYbYGX9JEl+GtOT9TKsh04zCHAbavnQ2USldA==}
+ peerDependencies:
+ react: '>=16.8.0'
+ dependencies:
+ react: 18.2.0
+ dev: false
+
+ /react-toastify@9.1.3(react-dom@18.2.0)(react@18.2.0):
+ resolution: {integrity: sha512-fPfb8ghtn/XMxw3LkxQBk3IyagNpF/LIKjOBflbexr2AWxAH1MJgvnESwEwBn9liLFXgTKWgBSdZpw9m4OTHTg==}
+ peerDependencies:
+ react: '>=16'
+ react-dom: '>=16'
+ dependencies:
+ clsx: 1.2.1
+ react: 18.2.0
+ react-dom: 18.2.0(react@18.2.0)
+ dev: false
+
+ /react@18.2.0:
+ resolution: {integrity: sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==}
+ engines: {node: '>=0.10.0'}
+ dependencies:
+ loose-envify: 1.4.0
+ dev: false
+
+ /readable-stream@3.6.2:
+ resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==}
+ engines: {node: '>= 6'}
+ dependencies:
+ inherits: 2.0.4
+ string_decoder: 1.3.0
+ util-deprecate: 1.0.2
+ dev: false
+
+ /readdirp@3.6.0:
+ resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==}
+ engines: {node: '>=8.10.0'}
+ dependencies:
+ picomatch: 2.3.1
+
+ /redis@4.2.0:
+ resolution: {integrity: sha512-bCR0gKVhIXFg8zCQjXEANzgI01DDixtPZgIUZHBCmwqixnu+MK3Tb2yqGjh+HCLASQVVgApiwhNkv+FoedZOGQ==}
+ dependencies:
+ '@redis/bloom': 1.0.2(@redis/client@1.2.0)
+ '@redis/client': 1.2.0
+ '@redis/graph': 1.0.1(@redis/client@1.2.0)
+ '@redis/json': 1.0.3(@redis/client@1.2.0)
+ '@redis/search': 1.0.6(@redis/client@1.2.0)
+ '@redis/time-series': 1.0.3(@redis/client@1.2.0)
+ dev: false
+
+ /reflect.getprototypeof@1.0.4:
+ resolution: {integrity: sha512-ECkTw8TmJwW60lOTR+ZkODISW6RQ8+2CL3COqtiJKLd6MmB45hN51HprHFziKLGkAuTGQhBb91V8cy+KHlaCjw==}
+ engines: {node: '>= 0.4'}
+ dependencies:
+ call-bind: 1.0.5
+ define-properties: 1.2.1
+ es-abstract: 1.22.3
+ get-intrinsic: 1.2.2
+ globalthis: 1.0.3
+ which-builtin-type: 1.1.3
+ dev: true
+
+ /regenerator-runtime@0.14.1:
+ resolution: {integrity: sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==}
+
+ /regexp.prototype.flags@1.5.1:
+ resolution: {integrity: sha512-sy6TXMN+hnP/wMy+ISxg3krXx7BAtWVO4UouuCN/ziM9UEne0euamVNafDfvC83bRNr95y0V5iijeDQFUNpvrg==}
+ engines: {node: '>= 0.4'}
+ dependencies:
+ call-bind: 1.0.5
+ define-properties: 1.2.1
+ set-function-name: 2.0.1
+ dev: true
+
+ /request-compose@2.1.6:
+ resolution: {integrity: sha512-S07L+2VbJB32WddD/o/PnYGKym63zLVbymygVWXvt8L79VAngcjAxhHaGuFOICLxEV90EasEPzqPKKHPspXP8w==}
+ engines: {node: '>=12.0.0'}
+ dev: false
+
+ /request-oauth@1.0.1:
+ resolution: {integrity: sha512-85THTg1RgOYtqQw42JON6AqvHLptlj1biw265Tsq4fD4cPdUvhDB2Qh9NTv17yCD322ROuO9aOmpc4GyayGVBA==}
+ engines: {node: '>=8.0.0'}
+ dependencies:
+ oauth-sign: 0.9.0
+ qs: 6.11.2
+ uuid: 8.3.2
+ dev: false
+
+ /requires-port@1.0.0:
+ resolution: {integrity: sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==}
+ dev: false
+
+ /resolve-alpn@1.2.1:
+ resolution: {integrity: sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==}
+ dev: false
+
+ /resolve-from@4.0.0:
+ resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==}
+ engines: {node: '>=4'}
+ dev: true
+
+ /resolve-pkg-maps@1.0.0:
+ resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==}
+ dev: true
+
+ /resolve@1.22.8:
+ resolution: {integrity: sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==}
+ hasBin: true
+ dependencies:
+ is-core-module: 2.13.1
+ path-parse: 1.0.7
+ supports-preserve-symlinks-flag: 1.0.0
+ dev: true
+
+ /resolve@2.0.0-next.5:
+ resolution: {integrity: sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA==}
+ hasBin: true
+ dependencies:
+ is-core-module: 2.13.1
+ path-parse: 1.0.7
+ supports-preserve-symlinks-flag: 1.0.0
+ dev: true
+
+ /responselike@2.0.1:
+ resolution: {integrity: sha512-4gl03wn3hj1HP3yzgdI7d3lCkF95F21Pz4BPGvKHinyQzALR5CapwC8yIi0Rh58DEMQ/SguC03wFj2k0M/mHhw==}
+ dependencies:
+ lowercase-keys: 2.0.0
+ dev: false
+
+ /retry@0.12.0:
+ resolution: {integrity: sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==}
+ engines: {node: '>= 4'}
+ dev: false
+
+ /retry@0.13.1:
+ resolution: {integrity: sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==}
+ engines: {node: '>= 4'}
+ dev: false
+
+ /reusify@1.0.4:
+ resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==}
+ engines: {iojs: '>=1.0.0', node: '>=0.10.0'}
+ dev: true
+
+ /rimraf@3.0.2:
+ resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==}
+ hasBin: true
+ dependencies:
+ glob: 7.2.3
+ dev: true
+
+ /robust-predicates@3.0.2:
+ resolution: {integrity: sha512-IXgzBWvWQwE6PrDI05OvmXUIruQTcoMDzRsOd5CDvHCVLcLHMTSYvOK5Cm46kWqlV3yAbuSpBZdJ5oP5OUoStg==}
+ dev: false
+
+ /run-parallel@1.2.0:
+ resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==}
+ dependencies:
+ queue-microtask: 1.2.3
+ dev: true
+
+ /rw@1.3.3:
+ resolution: {integrity: sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==}
+ dev: false
+
+ /safe-array-concat@1.0.1:
+ resolution: {integrity: sha512-6XbUAseYE2KtOuGueyeobCySj9L4+66Tn6KQMOPQJrAJEowYKW/YR/MGJZl7FdydUdaFu4LYyDZjxf4/Nmo23Q==}
+ engines: {node: '>=0.4'}
+ dependencies:
+ call-bind: 1.0.5
+ get-intrinsic: 1.2.2
+ has-symbols: 1.0.3
+ isarray: 2.0.5
+ dev: true
+
+ /safe-buffer@5.1.2:
+ resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==}
+ dev: false
+
+ /safe-buffer@5.2.1:
+ resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==}
+ dev: false
+
+ /safe-regex-test@1.0.2:
+ resolution: {integrity: sha512-83S9w6eFq12BBIJYvjMux6/dkirb8+4zJRA9cxNBVb7Wq5fJBW+Xze48WqR8pxua7bDuAaaAxtVVd4Idjp1dBQ==}
+ engines: {node: '>= 0.4'}
+ dependencies:
+ call-bind: 1.0.5
+ get-intrinsic: 1.2.2
+ is-regex: 1.1.4
+ dev: true
+
+ /safer-buffer@2.1.2:
+ resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==}
+ dev: false
+
+ /sass@1.69.7:
+ resolution: {integrity: sha512-rzj2soDeZ8wtE2egyLXgOOHQvaC2iosZrkF6v3EUG+tBwEvhqUCzm0VP3k9gHF9LXbSrRhT5SksoI56Iw8NPnQ==}
+ engines: {node: '>=14.0.0'}
+ hasBin: true
+ dependencies:
+ chokidar: 3.5.3
+ immutable: 4.3.4
+ source-map-js: 1.0.2
+ dev: false
+
+ /sax@1.3.0:
+ resolution: {integrity: sha512-0s+oAmw9zLl1V1cS9BtZN7JAd0cW5e0QH4W3LWEK6a4LaLEA2OTpGYWDY+6XasBLtz6wkm3u1xRw95mRuJ59WA==}
+ dev: false
+
+ /scheduler@0.23.0:
+ resolution: {integrity: sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==}
+ dependencies:
+ loose-envify: 1.4.0
+ dev: false
+
+ /section-matter@1.0.0:
+ resolution: {integrity: sha512-vfD3pmTzGpufjScBh50YHKzEu2lxBWhVEHsNGoEXmCmn2hKGfeNLYMzCJpe8cD7gqX7TJluOVpBkAequ6dgMmA==}
+ engines: {node: '>=4'}
+ dependencies:
+ extend-shallow: 2.0.1
+ kind-of: 6.0.3
+ dev: false
+
+ /semver@6.3.1:
+ resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==}
+ hasBin: true
+ dev: true
+
+ /semver@7.5.4:
+ resolution: {integrity: sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==}
+ engines: {node: '>=10'}
+ hasBin: true
+ dependencies:
+ lru-cache: 6.0.0
+
+ /send@0.18.0:
+ resolution: {integrity: sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==}
+ engines: {node: '>= 0.8.0'}
+ dependencies:
+ debug: 2.6.9
+ depd: 2.0.0
+ destroy: 1.2.0
+ encodeurl: 1.0.2
+ escape-html: 1.0.3
+ etag: 1.8.1
+ fresh: 0.5.2
+ http-errors: 2.0.0
+ mime: 1.6.0
+ ms: 2.1.3
+ on-finished: 2.4.1
+ range-parser: 1.2.1
+ statuses: 2.0.1
+ transitivePeerDependencies:
+ - supports-color
+ dev: false
+
+ /serialize-error@2.1.0:
+ resolution: {integrity: sha512-ghgmKt5o4Tly5yEG/UJp8qTd0AN7Xalw4XBtDEKP655B699qMEtra1WlXeE6WIvdEG481JvRxULKsInq/iNysw==}
+ engines: {node: '>=0.10.0'}
+ dev: false
+
+ /serialize-javascript@6.0.2:
+ resolution: {integrity: sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==}
+ dependencies:
+ randombytes: 2.1.0
+ dev: false
+
+ /serve-static@1.15.0:
+ resolution: {integrity: sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==}
+ engines: {node: '>= 0.8.0'}
+ dependencies:
+ encodeurl: 1.0.2
+ escape-html: 1.0.3
+ parseurl: 1.3.3
+ send: 0.18.0
+ transitivePeerDependencies:
+ - supports-color
+ dev: false
+
+ /set-function-length@1.1.1:
+ resolution: {integrity: sha512-VoaqjbBJKiWtg4yRcKBQ7g7wnGnLV3M8oLvVWwOk2PdYY6PEFegR1vezXR0tw6fZGF9csVakIRjrJiy2veSBFQ==}
+ engines: {node: '>= 0.4'}
+ dependencies:
+ define-data-property: 1.1.1
+ get-intrinsic: 1.2.2
+ gopd: 1.0.1
+ has-property-descriptors: 1.0.1
+
+ /set-function-name@2.0.1:
+ resolution: {integrity: sha512-tMNCiqYVkXIZgc2Hnoy2IvC/f8ezc5koaRFkCjrpWzGpCd3qbZXPzVy9MAZzK1ch/X0jvSkojys3oqJN0qCmdA==}
+ engines: {node: '>= 0.4'}
+ dependencies:
+ define-data-property: 1.1.1
+ functions-have-names: 1.2.3
+ has-property-descriptors: 1.0.1
+ dev: true
+
+ /setprototypeof@1.2.0:
+ resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==}
+ dev: false
+
+ /sharp@0.30.7:
+ resolution: {integrity: sha512-G+MY2YW33jgflKPTXXptVO28HvNOo9G3j0MybYAHeEmby+QuD2U98dT6ueht9cv/XDqZspSpIhoSW+BAKJ7Hig==}
+ engines: {node: '>=12.13.0'}
+ requiresBuild: true
+ dependencies:
+ color: 4.2.3
+ detect-libc: 2.0.2
+ node-addon-api: 5.1.0
+ prebuild-install: 7.1.1
+ semver: 7.5.4
+ simple-get: 4.0.1
+ tar-fs: 2.1.1
+ tunnel-agent: 0.6.0
+ dev: false
+
+ /sharp@0.33.2:
+ resolution: {integrity: sha512-WlYOPyyPDiiM07j/UO+E720ju6gtNtHjEGg5vovUk1Lgxyjm2LFO+37Nt/UI3MMh2l6hxTWQWi7qk3cXJTutcQ==}
+ engines: {libvips: '>=8.15.1', node: ^18.17.0 || ^20.3.0 || >=21.0.0}
+ requiresBuild: true
+ dependencies:
+ color: 4.2.3
+ detect-libc: 2.0.2
+ semver: 7.5.4
+ optionalDependencies:
+ '@img/sharp-darwin-arm64': 0.33.2
+ '@img/sharp-darwin-x64': 0.33.2
+ '@img/sharp-libvips-darwin-arm64': 1.0.1
+ '@img/sharp-libvips-darwin-x64': 1.0.1
+ '@img/sharp-libvips-linux-arm': 1.0.1
+ '@img/sharp-libvips-linux-arm64': 1.0.1
+ '@img/sharp-libvips-linux-s390x': 1.0.1
+ '@img/sharp-libvips-linux-x64': 1.0.1
+ '@img/sharp-libvips-linuxmusl-arm64': 1.0.1
+ '@img/sharp-libvips-linuxmusl-x64': 1.0.1
+ '@img/sharp-linux-arm': 0.33.2
+ '@img/sharp-linux-arm64': 0.33.2
+ '@img/sharp-linux-s390x': 0.33.2
+ '@img/sharp-linux-x64': 0.33.2
+ '@img/sharp-linuxmusl-arm64': 0.33.2
+ '@img/sharp-linuxmusl-x64': 0.33.2
+ '@img/sharp-wasm32': 0.33.2
+ '@img/sharp-win32-ia32': 0.33.2
+ '@img/sharp-win32-x64': 0.33.2
+ dev: false
+
+ /shebang-command@2.0.0:
+ resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==}
+ engines: {node: '>=8'}
+ dependencies:
+ shebang-regex: 3.0.0
+ dev: true
+
+ /shebang-regex@3.0.0:
+ resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==}
+ engines: {node: '>=8'}
+ dev: true
+
+ /side-channel@1.0.4:
+ resolution: {integrity: sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==}
+ dependencies:
+ call-bind: 1.0.5
+ get-intrinsic: 1.2.2
+ object-inspect: 1.13.1
+
+ /signal-exit@3.0.7:
+ resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==}
+ dev: false
+
+ /simple-concat@1.0.1:
+ resolution: {integrity: sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==}
+ dev: false
+
+ /simple-get@4.0.1:
+ resolution: {integrity: sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==}
+ dependencies:
+ decompress-response: 6.0.0
+ once: 1.4.0
+ simple-concat: 1.0.1
+ dev: false
+
+ /simple-swizzle@0.2.2:
+ resolution: {integrity: sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==}
+ dependencies:
+ is-arrayish: 0.3.2
+ dev: false
+
+ /simple-update-notifier@2.0.0:
+ resolution: {integrity: sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==}
+ engines: {node: '>=10'}
+ dependencies:
+ semver: 7.5.4
+ dev: true
+
+ /slash@3.0.0:
+ resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==}
+ engines: {node: '>=8'}
+ dev: true
+
+ /slugify@1.6.6:
+ resolution: {integrity: sha512-h+z7HKHYXj6wJU+AnS/+IH8Uh9fdcX1Lrhg1/VMdf9PwoBQXFcXiAdsy2tSK0P6gKwJLXp02r90ahUCqHk9rrw==}
+ engines: {node: '>=8.0.0'}
+ dev: false
+
+ /sorted-array-functions@1.3.0:
+ resolution: {integrity: sha512-2sqgzeFlid6N4Z2fUQ1cvFmTOLRi/sEDzSQ0OKYchqgoPmQBVyM3959qYx3fpS6Esef80KjmpgPeEr028dP3OA==}
+ dev: false
+
+ /source-map-js@1.0.2:
+ resolution: {integrity: sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==}
+ engines: {node: '>=0.10.0'}
+ dev: false
+
+ /sprintf-js@1.0.3:
+ resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==}
+ dev: false
+
+ /statuses@2.0.1:
+ resolution: {integrity: sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==}
+ engines: {node: '>= 0.8'}
+ dev: false
+
+ /stream-browserify@3.0.0:
+ resolution: {integrity: sha512-H73RAHsVBapbim0tU2JwwOiXUj+fikfiaoYAKHF3VJfA0pe2BCzkhAHBlLG6REzE+2WNZcxOXjK7lkso+9euLA==}
+ dependencies:
+ inherits: 2.0.4
+ readable-stream: 3.6.2
+ dev: false
+
+ /streamsearch@1.1.0:
+ resolution: {integrity: sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==}
+ engines: {node: '>=10.0.0'}
+ dev: false
+
+ /string.prototype.matchall@4.0.10:
+ resolution: {integrity: sha512-rGXbGmOEosIQi6Qva94HUjgPs9vKW+dkG7Y8Q5O2OYkWL6wFaTRZO8zM4mhP94uX55wgyrXzfS2aGtGzUL7EJQ==}
+ dependencies:
+ call-bind: 1.0.5
+ define-properties: 1.2.1
+ es-abstract: 1.22.3
+ get-intrinsic: 1.2.2
+ has-symbols: 1.0.3
+ internal-slot: 1.0.6
+ regexp.prototype.flags: 1.5.1
+ set-function-name: 2.0.1
+ side-channel: 1.0.4
+ dev: true
+
+ /string.prototype.trim@1.2.8:
+ resolution: {integrity: sha512-lfjY4HcixfQXOfaqCvcBuOIapyaroTXhbkfJN3gcB1OtyupngWK4sEET9Knd0cXd28kTUqu/kHoV4HKSJdnjiQ==}
+ engines: {node: '>= 0.4'}
+ dependencies:
+ call-bind: 1.0.5
+ define-properties: 1.2.1
+ es-abstract: 1.22.3
+ dev: true
+
+ /string.prototype.trimend@1.0.7:
+ resolution: {integrity: sha512-Ni79DqeB72ZFq1uH/L6zJ+DKZTkOtPIHovb3YZHQViE+HDouuU4mBrLOLDn5Dde3RF8qw5qVETEjhu9locMLvA==}
+ dependencies:
+ call-bind: 1.0.5
+ define-properties: 1.2.1
+ es-abstract: 1.22.3
+ dev: true
+
+ /string.prototype.trimstart@1.0.7:
+ resolution: {integrity: sha512-NGhtDFu3jCEm7B4Fy0DpLewdJQOZcQ0rGbwQ/+stjnrp2i+rlKeCvos9hOIeCmqwratM47OBxY7uFZzjxHXmrg==}
+ dependencies:
+ call-bind: 1.0.5
+ define-properties: 1.2.1
+ es-abstract: 1.22.3
+ dev: true
+
+ /string_decoder@1.3.0:
+ resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==}
+ dependencies:
+ safe-buffer: 5.2.1
+ dev: false
+
+ /strip-ansi@6.0.1:
+ resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==}
+ engines: {node: '>=8'}
+ dependencies:
+ ansi-regex: 5.0.1
+ dev: true
+
+ /strip-bom-string@1.0.0:
+ resolution: {integrity: sha512-uCC2VHvQRYu+lMh4My/sFNmF2klFymLX1wHJeXnbEJERpV/ZsVuonzerjfrGpIGF7LBVa1O7i9kjiWvJiFck8g==}
+ engines: {node: '>=0.10.0'}
+ dev: false
+
+ /strip-bom@3.0.0:
+ resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==}
+ engines: {node: '>=4'}
+ dev: true
+
+ /strip-json-comments@2.0.1:
+ resolution: {integrity: sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==}
+ engines: {node: '>=0.10.0'}
+ dev: false
+
+ /strip-json-comments@3.1.1:
+ resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==}
+ engines: {node: '>=8'}
+ dev: true
+
+ /strnum@1.0.5:
+ resolution: {integrity: sha512-J8bbNyKKXl5qYcR36TIO8W3mVGVHrmmxsd5PAItGkmyzwJvybiw2IVq5nqd0i4LSNSkB/sx9VHllbfFdr9k1JA==}
+ dev: false
+
+ /styled-jsx@5.1.1(react@18.2.0):
+ resolution: {integrity: sha512-pW7uC1l4mBZ8ugbiZrcIsiIvVx1UmTfw7UkC3Um2tmfUq9Bhk8IiyEIPl6F8agHgjzku6j0xQEZbfA5uSgSaCw==}
+ engines: {node: '>= 12.0.0'}
+ peerDependencies:
+ '@babel/core': '*'
+ babel-plugin-macros: '*'
+ react: '>= 16.8.0 || 17.x.x || ^18.0.0-0'
+ peerDependenciesMeta:
+ '@babel/core':
+ optional: true
+ babel-plugin-macros:
+ optional: true
+ dependencies:
+ client-only: 0.0.1
+ react: 18.2.0
+ dev: false
+
+ /supports-color@5.5.0:
+ resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==}
+ engines: {node: '>=4'}
+ dependencies:
+ has-flag: 3.0.0
+
+ /supports-color@7.2.0:
+ resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==}
+ engines: {node: '>=8'}
+ dependencies:
+ has-flag: 4.0.0
+
+ /supports-preserve-symlinks-flag@1.0.0:
+ resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==}
+ engines: {node: '>= 0.4'}
+ dev: true
+
+ /tapable@2.2.1:
+ resolution: {integrity: sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==}
+ engines: {node: '>=6'}
+ dev: true
+
+ /tar-fs@2.1.1:
+ resolution: {integrity: sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==}
+ dependencies:
+ chownr: 1.1.4
+ mkdirp-classic: 0.5.3
+ pump: 3.0.0
+ tar-stream: 2.2.0
+ dev: false
+
+ /tar-stream@2.2.0:
+ resolution: {integrity: sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==}
+ engines: {node: '>=6'}
+ dependencies:
+ bl: 4.1.0
+ end-of-stream: 1.4.4
+ fs-constants: 1.0.0
+ inherits: 2.0.4
+ readable-stream: 3.6.2
+ dev: false
+
+ /tdigest@0.1.2:
+ resolution: {integrity: sha512-+G0LLgjjo9BZX2MfdvPfH+MKLCrxlXSYec5DaPYP1fe6Iyhf0/fSmJ0bFiZ1F8BT6cGXl2LpltQptzjXKWEkKA==}
+ dependencies:
+ bintrees: 1.0.2
+ dev: false
+
+ /text-table@0.2.0:
+ resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==}
+ dev: true
+
+ /tiny-case@1.0.3:
+ resolution: {integrity: sha512-Eet/eeMhkO6TX8mnUteS9zgPbUMQa4I6Kkp5ORiBD5476/m+PIRiumP5tmh5ioJpH7k51Kehawy2UDfsnxxY8Q==}
+ dev: false
+
+ /to-regex-range@5.0.1:
+ resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==}
+ engines: {node: '>=8.0'}
+ dependencies:
+ is-number: 7.0.0
+
+ /toidentifier@1.0.1:
+ resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==}
+ engines: {node: '>=0.6'}
+ dev: false
+
+ /toposort@2.0.2:
+ resolution: {integrity: sha512-0a5EOkAUp8D4moMi2W8ZF8jcga7BgZd91O/yabJCFY8az+XSzeGyTKs0Aoo897iV1Nj6guFq8orWDS96z91oGg==}
+ dev: false
+
+ /touch@3.1.0:
+ resolution: {integrity: sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA==}
+ hasBin: true
+ dependencies:
+ nopt: 1.0.10
+ dev: true
+
+ /ts-api-utils@1.0.3(typescript@5.3.3):
+ resolution: {integrity: sha512-wNMeqtMz5NtwpT/UZGY5alT+VoKdSsOOP/kqHFcUW1P/VRhH2wJ48+DN2WwUliNbQ976ETwDL0Ifd2VVvgonvg==}
+ engines: {node: '>=16.13.0'}
+ peerDependencies:
+ typescript: '>=4.2.0'
+ dependencies:
+ typescript: 5.3.3
+ dev: true
+
+ /tsc@2.0.4:
+ resolution: {integrity: sha512-fzoSieZI5KKJVBYGvwbVZs/J5za84f2lSTLPYf6AGiIf43tZ3GNrI1QzTLcjtyDDP4aLxd46RTZq1nQxe7+k5Q==}
+ hasBin: true
+ dev: true
+
+ /tsconfig-paths@3.15.0:
+ resolution: {integrity: sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==}
+ dependencies:
+ '@types/json5': 0.0.29
+ json5: 1.0.2
+ minimist: 1.2.8
+ strip-bom: 3.0.0
+ dev: true
+
+ /tslib@1.14.1:
+ resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==}
+ dev: false
+
+ /tslib@2.6.2:
+ resolution: {integrity: sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==}
+ dev: false
+
+ /tunnel-agent@0.6.0:
+ resolution: {integrity: sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==}
+ dependencies:
+ safe-buffer: 5.2.1
+ dev: false
+
+ /tus-js-client@3.1.3:
+ resolution: {integrity: sha512-n9k6rI/nPOuP2TaqPG6Ogz3a3V1cSH9en7N0VH4gh95jmG8JA58TJzLms2lBfb7aKVb3fdUunqYEG3WnQnZRvQ==}
+ dependencies:
+ buffer-from: 1.1.2
+ combine-errors: 3.0.3
+ is-stream: 2.0.1
+ js-base64: 3.7.5
+ lodash.throttle: 4.1.1
+ proper-lockfile: 4.1.2
+ url-parse: 1.5.10
+ dev: false
+
+ /type-check@0.4.0:
+ resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==}
+ engines: {node: '>= 0.8.0'}
+ dependencies:
+ prelude-ls: 1.2.1
+ dev: true
+
+ /type-fest@0.20.2:
+ resolution: {integrity: sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==}
+ engines: {node: '>=10'}
+ dev: true
+
+ /type-fest@2.19.0:
+ resolution: {integrity: sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==}
+ engines: {node: '>=12.20'}
+ dev: false
+
+ /type-is@1.6.18:
+ resolution: {integrity: sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==}
+ engines: {node: '>= 0.6'}
+ dependencies:
+ media-typer: 0.3.0
+ mime-types: 2.1.35
+ dev: false
+
+ /typed-array-buffer@1.0.0:
+ resolution: {integrity: sha512-Y8KTSIglk9OZEr8zywiIHG/kmQ7KWyjseXs1CbSo8vC42w7hg2HgYTxSWwP0+is7bWDc1H+Fo026CpHFwm8tkw==}
+ engines: {node: '>= 0.4'}
+ dependencies:
+ call-bind: 1.0.5
+ get-intrinsic: 1.2.2
+ is-typed-array: 1.1.12
+ dev: true
+
+ /typed-array-byte-length@1.0.0:
+ resolution: {integrity: sha512-Or/+kvLxNpeQ9DtSydonMxCx+9ZXOswtwJn17SNLvhptaXYDJvkFFP5zbfU/uLmvnBJlI4yrnXRxpdWH/M5tNA==}
+ engines: {node: '>= 0.4'}
+ dependencies:
+ call-bind: 1.0.5
+ for-each: 0.3.3
+ has-proto: 1.0.1
+ is-typed-array: 1.1.12
+ dev: true
+
+ /typed-array-byte-offset@1.0.0:
+ resolution: {integrity: sha512-RD97prjEt9EL8YgAgpOkf3O4IF9lhJFr9g0htQkm0rchFp/Vx7LW5Q8fSXXub7BXAODyUQohRMyOc3faCPd0hg==}
+ engines: {node: '>= 0.4'}
+ dependencies:
+ available-typed-arrays: 1.0.5
+ call-bind: 1.0.5
+ for-each: 0.3.3
+ has-proto: 1.0.1
+ is-typed-array: 1.1.12
+ dev: true
+
+ /typed-array-length@1.0.4:
+ resolution: {integrity: sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng==}
+ dependencies:
+ call-bind: 1.0.5
+ for-each: 0.3.3
+ is-typed-array: 1.1.12
+ dev: true
+
+ /typescript@5.3.3:
+ resolution: {integrity: sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==}
+ engines: {node: '>=14.17'}
+ hasBin: true
+ dev: true
+
+ /uid-safe@2.1.5:
+ resolution: {integrity: sha512-KPHm4VL5dDXKz01UuEd88Df+KzynaohSL9fBh096KWAxSKZQDI2uBrVqtvRM4rwrIrRRKsdLNML/lnaaVSRioA==}
+ engines: {node: '>= 0.8'}
+ dependencies:
+ random-bytes: 1.0.0
+ dev: false
+
+ /unbox-primitive@1.0.2:
+ resolution: {integrity: sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==}
+ dependencies:
+ call-bind: 1.0.5
+ has-bigints: 1.0.2
+ has-symbols: 1.0.3
+ which-boxed-primitive: 1.0.2
+ dev: true
+
+ /undefsafe@2.0.5:
+ resolution: {integrity: sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==}
+ dev: true
+
+ /undici-types@5.26.5:
+ resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==}
+
+ /unpipe@1.0.0:
+ resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==}
+ engines: {node: '>= 0.8'}
+ dev: false
+
+ /uri-js@4.4.1:
+ resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==}
+ dependencies:
+ punycode: 2.3.1
+ dev: true
+
+ /url-parse@1.5.10:
+ resolution: {integrity: sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==}
+ dependencies:
+ querystringify: 2.2.0
+ requires-port: 1.0.0
+ dev: false
+
+ /url-polyfill@1.1.12:
+ resolution: {integrity: sha512-mYFmBHCapZjtcNHW0MDq9967t+z4Dmg5CJ0KqysK3+ZbyoNOWQHksGCTWwDhxGXllkWlOc10Xfko6v4a3ucM6A==}
+ dev: false
+
+ /url-value-parser@2.2.0:
+ resolution: {integrity: sha512-yIQdxJpgkPamPPAPuGdS7Q548rLhny42tg8d4vyTNzFqvOnwqrgHXvgehT09U7fwrzxi3RxCiXjoNUNnNOlQ8A==}
+ engines: {node: '>=6.0.0'}
+ dev: false
+
+ /util-deprecate@1.0.2:
+ resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==}
+ dev: false
+
+ /utils-merge@1.0.1:
+ resolution: {integrity: sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==}
+ engines: {node: '>= 0.4.0'}
+ dev: false
+
+ /uuid@3.4.0:
+ resolution: {integrity: sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==}
+ deprecated: Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.
+ hasBin: true
+ dev: false
+
+ /uuid@8.3.2:
+ resolution: {integrity: sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==}
+ hasBin: true
+ dev: false
+
+ /validator@13.11.0:
+ resolution: {integrity: sha512-Ii+sehpSfZy+At5nPdnyMhx78fEoPDkR2XW/zimHEL3MyGJQOCQ7WeP20jPYRz7ZCpcKLB21NxuXHF3bxjStBQ==}
+ engines: {node: '>= 0.10'}
+ dev: false
+
+ /vary@1.1.2:
+ resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==}
+ engines: {node: '>= 0.8'}
+ dev: false
+
+ /watchpack@2.4.0:
+ resolution: {integrity: sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==}
+ engines: {node: '>=10.13.0'}
+ dependencies:
+ glob-to-regexp: 0.4.1
+ graceful-fs: 4.2.11
+ dev: false
+
+ /which-boxed-primitive@1.0.2:
+ resolution: {integrity: sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==}
+ dependencies:
+ is-bigint: 1.0.4
+ is-boolean-object: 1.1.2
+ is-number-object: 1.0.7
+ is-string: 1.0.7
+ is-symbol: 1.0.4
+ dev: true
+
+ /which-builtin-type@1.1.3:
+ resolution: {integrity: sha512-YmjsSMDBYsM1CaFiayOVT06+KJeXf0o5M/CAd4o1lTadFAtacTUM49zoYxr/oroopFDfhvN6iEcBxUyc3gvKmw==}
+ engines: {node: '>= 0.4'}
+ dependencies:
+ function.prototype.name: 1.1.6
+ has-tostringtag: 1.0.0
+ is-async-function: 2.0.0
+ is-date-object: 1.0.5
+ is-finalizationregistry: 1.0.2
+ is-generator-function: 1.0.10
+ is-regex: 1.1.4
+ is-weakref: 1.0.2
+ isarray: 2.0.5
+ which-boxed-primitive: 1.0.2
+ which-collection: 1.0.1
+ which-typed-array: 1.1.13
+ dev: true
+
+ /which-collection@1.0.1:
+ resolution: {integrity: sha512-W8xeTUwaln8i3K/cY1nGXzdnVZlidBcagyNFtBdD5kxnb4TvGKR7FfSIS3mYpwWS1QUCutfKz8IY8RjftB0+1A==}
+ dependencies:
+ is-map: 2.0.2
+ is-set: 2.0.2
+ is-weakmap: 2.0.1
+ is-weakset: 2.0.2
+ dev: true
+
+ /which-typed-array@1.1.13:
+ resolution: {integrity: sha512-P5Nra0qjSncduVPEAr7xhoF5guty49ArDTwzJ/yNuPIbZppyRxFQsRCWrocxIY+CnMVG+qfbU2FmDKyvSGClow==}
+ engines: {node: '>= 0.4'}
+ dependencies:
+ available-typed-arrays: 1.0.5
+ call-bind: 1.0.5
+ for-each: 0.3.3
+ gopd: 1.0.1
+ has-tostringtag: 1.0.0
+ dev: true
+
+ /which@2.0.2:
+ resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==}
+ engines: {node: '>= 8'}
+ hasBin: true
+ dependencies:
+ isexe: 2.0.0
+ dev: true
+
+ /wildcard@1.1.2:
+ resolution: {integrity: sha512-DXukZJxpHA8LuotRwL0pP1+rS6CS7FF2qStDDE1C7DDg2rLud2PXRMuEDYIPhgEezwnlHNL4c+N6MfMTjCGTng==}
+ dev: false
+
+ /wrappy@1.0.2:
+ resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==}
+
+ /ws@8.8.1:
+ resolution: {integrity: sha512-bGy2JzvzkPowEJV++hF07hAD6niYSr0JzBNo/J29WsB57A2r7Wlc1UFcTR9IzrPvuNVO4B8LGqF8qcpsVOhJCA==}
+ engines: {node: '>=10.0.0'}
+ peerDependencies:
+ bufferutil: ^4.0.1
+ utf-8-validate: ^5.0.2
+ peerDependenciesMeta:
+ bufferutil:
+ optional: true
+ utf-8-validate:
+ optional: true
+ dev: false
+
+ /xml-js@1.6.11:
+ resolution: {integrity: sha512-7rVi2KMfwfWFl+GpPg6m80IVMWXLRjO+PxTq7V2CDhoGak0wzYzFgUY2m4XJ47OGdXd8eLE8EmwfAmdjw7lC1g==}
+ hasBin: true
+ dependencies:
+ sax: 1.3.0
+ dev: false
+
+ /yallist@2.1.2:
+ resolution: {integrity: sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A==}
+ dev: false
+
+ /yallist@4.0.0:
+ resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==}
+
+ /yocto-queue@0.1.0:
+ resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==}
+ engines: {node: '>=10'}
+ dev: true
+
+ /yup@1.3.3:
+ resolution: {integrity: sha512-v8QwZSsHH2K3/G9WSkp6mZKO+hugKT1EmnMqLNUcfu51HU9MDyhlETT/JgtzprnrnQHPWsjc6MUDMBp/l9fNnw==}
+ dependencies:
+ property-expr: 2.0.6
+ tiny-case: 1.0.3
+ toposort: 2.0.2
+ type-fest: 2.19.0
+ dev: false
diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml
new file mode 100644
index 0000000..bb166d2
--- /dev/null
+++ b/pnpm-workspace.yaml
@@ -0,0 +1,5 @@
+packages:
+ - 'packages/next'
+ - 'packages/uppy'
+
+# strapi is not on here because it's not compatible with pnpm