diff --git a/.dockerignore b/.dockerignore
index 8cb62fd..f0ff6f5 100644
--- a/.dockerignore
+++ b/.dockerignore
@@ -16,4 +16,14 @@ app.json
compose/
docker-compose.*
.vscode
-charts/**/charts
\ No newline at end of file
+charts/**/charts
+
+
+packages/strapi/.tmp/
+packages/strapi/.cache/
+packages/strapi/.git/
+packages/strapi/.env
+packages/strapi/build/
+packages/strapi/node_modules/
+packages/strapi/data/
+packages/strapi/backup
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
index 84a7d94..fdea064 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,6 @@
+**/.env
+*~
+
charts/**/charts
.envrc
compose/
diff --git a/ARCHITECHTURE.md b/ARCHITECHTURE.md
index 866dea6..594ee97 100644
--- a/ARCHITECHTURE.md
+++ b/ARCHITECHTURE.md
@@ -4,6 +4,8 @@ pnpm required for workspaces.
Kubernetes for Development using Tiltfile
+kubefwd and entr for DNS in dev cluster
+
dokku for Production, deployed with `git push`.
(dokku is slowly being replaced by Kubernetes)
diff --git a/Makefile b/Makefile
index 229f0ed..4f02da7 100644
--- a/Makefile
+++ b/Makefile
@@ -30,6 +30,21 @@ tilt:
tilt up
secrets:
+
+ kubectl --namespace futureporn delete secret frp --ignore-not-found
+ kubectl --namespace futureporn create secret generic frp \
+ --from-literal=token=${FRP_TOKEN}
+
+ kubectl --namespace futureporn delete secret scout --ignore-not-found
+ kubectl --namespace futureporn create secret generic scout \
+ --from-literal=recentsToken=${SCOUT_RECENTS_TOKEN} \
+ --from-literal=strapiApiKey=${SCOUT_STRAPI_API_KEY} \
+ --from-literal=imapServer=${SCOUT_IMAP_SERVER} \
+ --from-literal=imapPort=${SCOUT_IMAP_PORT} \
+ --from-literal=imapUsername=${SCOUT_IMAP_USERNAME} \
+ --from-literal=imapPassword=${SCOUT_IMAP_PASSWORD} \
+ --from-literal=imapAccessToken=${SCOUT_IMAP_ACCESS_TOKEN} \
+
kubectl --namespace futureporn delete secret link2cid --ignore-not-found
kubectl --namespace futureporn create secret generic link2cid \
--from-literal=apiKey=${LINK2CID_API_KEY}
@@ -38,7 +53,6 @@ secrets:
kubectl --namespace cert-manager create secret generic vultr \
--from-literal=apiKey=${VULTR_API_KEY}
-
kubectl --namespace futureporn delete secret vultr --ignore-not-found
kubectl --namespace futureporn create secret generic vultr \
--from-literal=containerRegistryUsername=${VULTR_CONTAINER_REGISTRY_USERNAME} \
@@ -58,7 +72,7 @@ secrets:
--from-literal=adminJwtSecret=${STRAPI_ADMIN_JWT_SECRET} \
--from-literal=apiTokenSalt=${STRAPI_API_TOKEN_SALT} \
--from-literal=appKeys=${STRAPI_APP_KEYS} \
- --from-literal=databaseUrl=postgres://${POSTGRES_USER}:${POSTGRES_PASSWORD}@${POSTGRES_HOST}:${POSTGRES_PORT}/${POSTGRES_DB} \
+ --from-literal=databaseUrl=postgres.futureporn.svc.cluster.local://${POSTGRES_USER}:${POSTGRES_PASSWORD}@${POSTGRES_HOST}:${POSTGRES_PORT}/${POSTGRES_DB} \
--from-literal=jwtSecret=${STRAPI_JWT_SECRET} \
--from-literal=muxPlaybackRestrictionId=${MUX_PLAYBACK_RESTRICTION_ID} \
--from-literal=muxSigningKeyPrivateKey=${MUX_SIGNING_KEY_PRIVATE_KEY} \
@@ -73,15 +87,9 @@ secrets:
--from-literal=cdnBucketUscUrl=${CDN_BUCKET_USC_URL} \
--from-literal=transferTokenSalt=${TRANSFER_TOKEN_SALT}
-
-
-
-# --from-literal=sessionSecret=$(SESSION_SECRET) \
-# --from-literal=twitchClientId=$(TWITCH_CLIENT_ID) \
-# --from-literal=twitchClientSecret=$(TWITCH_CLIENT_SECRET) \
-# --from-literal=gumroadClientId=$(GUMROAD_CLIENT_ID) \
-# --from-literal=gumroadClientSecret=$(GUMROAD_CLIENT_SECRET)
-
+ kubectl --namespace futureporn delete secret realtime --ignore-not-found
+ kubectl --namespace futureporn create secret generic realtime \
+ --from-literal=postgresRealtimeConnectionString=${POSTGRES_REALTIME_CONNECTION_STRING}
define _script
cat <<'EOF' | ctlptl apply -f -
@@ -100,6 +108,19 @@ minikube:
minikube addons enable metrics-server
+kind:
+ bash -x ./scripts/kind-with-local-registry.sh
+
+deps:
+ sudo pamac install make entr nvm minikube kubectl docker helm
+ curl -fsSL https://raw.githubusercontent.com/tilt-dev/tilt/master/scripts/install.sh | bash
+ curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash
+ echo "go to https://github.com/txn2/kubefwd/releases/latest to get kubefwd"
+ echo "go to https://github.com/tilt-dev/ctlptl/releases/latest to get ctlptl"
+ sudo systemctl enable docker
+ sudo systemctl start docker
+ usermod -aG docker cj
+ newgrp docker
# A gitea act runner which runs locally
# https://docs.gitea.com/next/usage/actions/overview
diff --git a/apps/base/windmill/windmill.yaml b/apps/base/windmill/windmill.yaml
index 116feca..ef922c5 100644
--- a/apps/base/windmill/windmill.yaml
+++ b/apps/base/windmill/windmill.yaml
@@ -24,7 +24,7 @@ spec:
kind: HelmRepository
name: bitnami
values:
- fullnameOverride: windmill-postgresql-cool
+ fullnameOverride: windmill-postgresql-uncool
postgresql:
auth:
postgresPassword: windmill
diff --git a/apps/staging/chisel/chisel.yaml b/apps/staging/chisel/chisel.yaml
new file mode 100644
index 0000000..c63a8a8
--- /dev/null
+++ b/apps/staging/chisel/chisel.yaml
@@ -0,0 +1,25 @@
+
+apiVersion: source.toolkit.fluxcd.io/v1beta2
+kind: GitRepository
+metadata:
+ name: chisel-operator
+ namespace: futureporn
+spec:
+ interval: 5m
+ url: https://github.com/FyraLabs/chisel-operator
+ ref:
+ branch: master
+---
+apiVersion: kustomize.toolkit.fluxcd.io/v1beta2
+kind: Kustomization
+metadata:
+ name: chisel-operator
+ namespace: futureporn
+spec:
+ interval: 10m
+ targetNamespace: futureporn
+ sourceRef:
+ kind: GitRepository
+ name: chisel-operator
+ path: "./kustomize"
+ prune: true
\ No newline at end of file
diff --git a/apps/staging/chisel/kustomization.yaml b/apps/staging/chisel/kustomization.yaml
new file mode 100644
index 0000000..624a6a1
--- /dev/null
+++ b/apps/staging/chisel/kustomization.yaml
@@ -0,0 +1,5 @@
+apiVersion: kustomize.config.k8s.io/v1beta1
+kind: Kustomization
+namespace: futureporn
+resources:
+ - chisel.yaml
diff --git a/charts/fp/templates-staging/capture.yaml b/charts/fp/templates-staging/capture.yaml
new file mode 100644
index 0000000..d62a959
--- /dev/null
+++ b/charts/fp/templates-staging/capture.yaml
@@ -0,0 +1,37 @@
+apiVersion: v1
+kind: Service
+metadata:
+ name: capture
+ namespace: futureporn
+spec:
+ selector:
+ app.kubernetes.io/name: capture
+ ports:
+ - name: capture
+ port: 80
+ targetPort: 5566
+
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: capture
+ namespace: futureporn
+ labels:
+ app: capture
+spec:
+ replicas: 1
+ selector:
+ matchLabels:
+ app: capture
+ template:
+ metadata:
+ labels:
+ app: capture
+ spec:
+ containers:
+ - name: capture
+ image: "{{ .Values.capture.containerName }}"
+ ports:
+ - containerPort: 5566
+
diff --git a/charts/fp/templates-staging/echo.yaml b/charts/fp/templates-staging/echo.yaml
new file mode 100644
index 0000000..81ee4bf
--- /dev/null
+++ b/charts/fp/templates-staging/echo.yaml
@@ -0,0 +1,122 @@
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: echo-deployment
+ namespace: futureporn
+ labels:
+ app.kubernetes.io/name: echo
+spec:
+ replicas: 1
+ selector:
+ matchLabels:
+ app: echo-server
+ template:
+ metadata:
+ labels:
+ app: echo-server
+ spec:
+ containers:
+ - name: echo-server
+ resources:
+ limits:
+ cpu: 500m
+ memory: 512Mi
+ image: jmalloc/echo-server
+ ports:
+ - name: http
+ containerPort: 8080
+
+---
+apiVersion: v1
+kind: Service
+metadata:
+ name: echo
+ namespace: futureporn
+ labels:
+ app.kubernetes.io/name: echo
+spec:
+ ports:
+ - name: http
+ port: 8080
+ targetPort: http
+ protocol: TCP
+ selector:
+ app: echo-server
+
+# ---
+# apiVersion: networking.k8s.io/v1
+# kind: Ingress
+# metadata:
+# name: ngrok
+# namespace: futureporn
+# annotations:
+# kubernetes.io/ingress.class: ngrok
+# k8s.ngrok.com/namespace: futureporn
+# k8s.ngrok.com/service: ngrok
+# spec:
+# ingressClassName: ngrok
+# tls:
+# - secretName: ngrok-tls
+# hosts:
+# - "{{ .Values.ngrok.hostname }}"
+# rules:
+# - host: "{{ .Values.ngrok.hostname }}"
+# http:
+# paths:
+# - path: /echo
+# pathType: Prefix
+# backend:
+# service:
+# name: echo
+# port:
+# number: 8080
+# - path: /game
+# pathType: Prefix
+# backend:
+# service:
+# name: game-2048
+# port:
+# number: 8080
+ # - path: /strapi
+ # pathType: Prefix
+ # backend:
+ # service:
+ # name: strapi
+ # port:
+ # number: 1337
+ # - path: /next
+ # pathType: Prefix
+ # backend:
+ # service:
+ # name: next
+ # port:
+ # number: 3000
+
+# ---
+# apiVersion: networking.k8s.io/v1
+# kind: Ingress
+# metadata:
+# name: echo-ing
+# namespace: futureporn
+# annotations:
+# kubernetes.io/ingress.class: nginx
+# cert-manager.io/cluster-issuer: letsencrypt-staging
+# spec:
+# backend:
+# serviceName: echo-service
+# servicePort: 8080
+# tls:
+# - secretName: next-tls
+# hosts:
+# - echo.test
+# rules:
+# - host: echo.test
+# http:
+# paths:
+# - path: /
+# pathType: Prefix
+# backend:
+# service:
+# name: echo-service
+# port:
+# number: 8080
diff --git a/charts/fp/templates/external-dns.yaml b/charts/fp/templates-staging/external-dns.yaml
similarity index 94%
rename from charts/fp/templates/external-dns.yaml
rename to charts/fp/templates-staging/external-dns.yaml
index f6b28d9..017dd48 100644
--- a/charts/fp/templates/external-dns.yaml
+++ b/charts/fp/templates-staging/external-dns.yaml
@@ -1,3 +1,6 @@
+{{ if eq .Values.managedBy "Helm" }}
+
+---
apiVersion: v1
kind: ServiceAccount
metadata:
@@ -29,7 +32,8 @@ roleRef:
subjects:
- kind: ServiceAccount
name: external-dns
- namespace: default
+ namespace: futureporn
+
---
apiVersion: apps/v1
kind: Deployment
@@ -60,3 +64,5 @@ spec:
secretKeyRef:
name: vultr
key: apiKey
+
+{{ end }}
\ No newline at end of file
diff --git a/charts/fp/templates-staging/frp.yaml b/charts/fp/templates-staging/frp.yaml
new file mode 100644
index 0000000..8291fc9
--- /dev/null
+++ b/charts/fp/templates-staging/frp.yaml
@@ -0,0 +1,34 @@
+{{ if eq .Values.managedBy "tilt" }}
+
+---
+apiVersion: frp.zufardhiyaulhaq.com/v1alpha1
+kind: Client
+metadata:
+ name: client-01
+ namespace: futureporn
+spec:
+ server:
+ host: 155.138.254.201
+ port: 7000
+ authentication:
+ token:
+ secret:
+ name: frp
+ key: token
+
+---
+apiVersion: frp.zufardhiyaulhaq.com/v1alpha1
+kind: Upstream
+metadata:
+ name: echo
+ namespace: futureporn
+spec:
+ client: client-01
+ tcp:
+ host: echo.futureporn.svc.cluster.local
+ port: 8080
+ server:
+ port: 8080
+ proxyProtocol: v2
+
+{{ end }}
\ No newline at end of file
diff --git a/charts/fp/templates-staging/game.yaml b/charts/fp/templates-staging/game.yaml
new file mode 100644
index 0000000..30f5d74
--- /dev/null
+++ b/charts/fp/templates-staging/game.yaml
@@ -0,0 +1,34 @@
+apiVersion: v1
+kind: Service
+metadata:
+ name: game-2048
+ namespace: futureporn
+spec:
+ ports:
+ - name: http
+ port: 8080
+ targetPort: 8080
+ selector:
+ app: game-2048
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: game-2048
+ namespace: futureporn
+spec:
+ replicas: 1
+ selector:
+ matchLabels:
+ app: game-2048
+ template:
+ metadata:
+ labels:
+ app: game-2048
+ spec:
+ containers:
+ - name: backend
+ image: mendhak/http-https-echo
+ ports:
+ - name: http
+ containerPort: 8080
\ No newline at end of file
diff --git a/charts/fp/templates-staging/ingress.yaml.noexec b/charts/fp/templates-staging/ingress.yaml.noexec
new file mode 100644
index 0000000..eff31c7
--- /dev/null
+++ b/charts/fp/templates-staging/ingress.yaml.noexec
@@ -0,0 +1,108 @@
+---
+kind: ClusterRole
+apiVersion: rbac.authorization.k8s.io/v1beta1
+metadata:
+ name: traefik-ingress-controller
+rules:
+ - apiGroups:
+ - ""
+ resources:
+ - services
+ - endpoints
+ - secrets
+ verbs:
+ - get
+ - list
+ - watch
+ - apiGroups:
+ - extensions
+ resources:
+ - ingresses
+ verbs:
+ - get
+ - list
+ - watch
+ - apiGroups:
+ - extensions
+ resources:
+ - ingresses/status
+ verbs:
+ - update
+---
+kind: ClusterRoleBinding
+apiVersion: rbac.authorization.k8s.io/v1beta1
+metadata:
+ name: traefik-ingress-controller
+roleRef:
+ apiGroup: rbac.authorization.k8s.io
+ kind: ClusterRole
+ name: traefik-ingress-controller
+subjects:
+- kind: ServiceAccount
+ name: traefik-ingress-controller
+ namespace: kube-system
+
+
+---
+apiVersion: v1
+kind: ServiceAccount
+metadata:
+ name: traefik-ingress-controller
+ namespace: kube-system
+---
+kind: DaemonSet
+apiVersion: apps/v1
+metadata:
+ name: traefik-ingress-controller
+ namespace: kube-system
+ labels:
+ k8s-app: traefik-ingress-lb
+spec:
+ selector:
+ matchLabels:
+ k8s-app: traefik-ingress-lb
+ name: traefik-ingress-lb
+ template:
+ metadata:
+ labels:
+ k8s-app: traefik-ingress-lb
+ name: traefik-ingress-lb
+ spec:
+ serviceAccountName: traefik-ingress-controller
+ terminationGracePeriodSeconds: 60
+ containers:
+ - image: traefik:v1.7
+ name: traefik-ingress-lb
+ ports:
+ - name: http
+ containerPort: 80
+ hostPort: 80
+ - name: admin
+ containerPort: 8080
+ hostPort: 8080
+ securityContext:
+ capabilities:
+ drop:
+ - ALL
+ add:
+ - NET_BIND_SERVICE
+ args:
+ - --api
+ - --kubernetes
+ - --logLevel=INFO
+---
+kind: Service
+apiVersion: v1
+metadata:
+ name: traefik-ingress-service
+ namespace: kube-system
+spec:
+ selector:
+ k8s-app: traefik-ingress-lb
+ ports:
+ - protocol: TCP
+ port: 80
+ name: web
+ - protocol: TCP
+ port: 8080
+ name: admin
\ No newline at end of file
diff --git a/charts/fp/templates-staging/ipfs-service.yaml b/charts/fp/templates-staging/ipfs-service.yaml
new file mode 100644
index 0000000..27e9cbe
--- /dev/null
+++ b/charts/fp/templates-staging/ipfs-service.yaml
@@ -0,0 +1,70 @@
+{{ if eq .Values.managedBy "Helm" }}
+
+apiVersion: v1
+kind: Pod
+metadata:
+ name: ipfs-pod
+ namespace: default
+ labels:
+ app.kubernetes.io/name: ipfs
+spec:
+ containers:
+ - name: ipfs
+ image: ipfs/kubo
+ ports:
+ - containerPort: 5001
+ - containerPort: 8080
+ volumeMounts:
+ - name: ipfs-pvc
+ mountPath: /data/ipfs
+ restartPolicy: OnFailure
+ volumes:
+ - name: ipfs-pvc
+ persistentVolumeClaim:
+ claimName: ipfs-pvc
+
+
+apiVersion: v1
+kind: PersistentVolumeClaim
+metadata:
+ name: ipfs
+ namespace: default
+ annotations:
+ meta.helm.sh/release-name: fp
+ meta.helm.sh/release-namespace: default
+ labels:
+ app.kubernetes.io/managed-by: {{ .Values.managedBy }}
+spec:
+ accessModes:
+ - ReadWriteOnce
+ resources:
+ requests:
+ storage: 40Gi
+ storageClassName: {{ .Values.storageClassName }}
+
+
+
+apiVersion: v1
+kind: Service
+metadata:
+ name: ipfs-service
+ namespace: default
+ annotations:
+ meta.helm.sh/release-name: fp
+ meta.helm.sh/release-namespace: default
+ labels:
+ app.kubernetes.io/managed-by: {{ .Values.managedBy }}
+spec:
+ selector:
+ app.kubernetes.io/name: ipfs
+ ports:
+ - name: gateway
+ protocol: TCP
+ port: 8080
+ targetPort: 8080
+ - name: api
+ protocol: TCP
+ port: 5001
+ targetPort: 5001
+
+{{ end }}
\ No newline at end of file
diff --git a/charts/fp/templates/link2cid.yaml b/charts/fp/templates-staging/link2cid.yaml.noexec
similarity index 93%
rename from charts/fp/templates/link2cid.yaml
rename to charts/fp/templates-staging/link2cid.yaml.noexec
index fb43b6b..6a87f08 100644
--- a/charts/fp/templates/link2cid.yaml
+++ b/charts/fp/templates-staging/link2cid.yaml.noexec
@@ -2,7 +2,7 @@ apiVersion: v1
kind: Service
metadata:
name: link2cid
- namespace: default
+ namespace: futureporn
spec:
selector:
app: link2cid
@@ -22,7 +22,7 @@ apiVersion: apps/v1
kind: Deployment
metadata:
name: link2cid
- namespace: default
+ namespace: futureporn
spec:
selector:
matchLabels:
@@ -54,10 +54,10 @@ apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: link2cid
- namespace: default
+ namespace: futureporn
annotations:
meta.helm.sh/release-name: fp
- meta.helm.sh/release-namespace: default
+ meta.helm.sh/release-namespace: futureporn
labels:
app.kubernetes.io/managed-by: {{ .Values.managedBy }}
spec:
@@ -75,7 +75,7 @@ apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: link2cid-ingress
- namespace: default
+ namespace: futureporn
annotations:
kubernetes.io/ingress.class: "nginx"
nginx.ingress.kubernetes.io/ssl-redirect: "true"
diff --git a/charts/fp/templates-staging/ngrok.yaml b/charts/fp/templates-staging/ngrok.yaml
new file mode 100644
index 0000000..f987f7d
--- /dev/null
+++ b/charts/fp/templates-staging/ngrok.yaml
@@ -0,0 +1,47 @@
+{{ if eq .Values.managedBy "tilt" }}
+---
+apiVersion: networking.k8s.io/v1
+kind: Ingress
+metadata:
+ name: ngrok
+ namespace: futureporn
+ annotations:
+ kubernetes.io/ingress.class: ngrok
+ k8s.ngrok.com/namespace: futureporn
+ k8s.ngrok.com/service: ngrok
+spec:
+ ingressClassName: ngrok
+ rules:
+ - host: "{{ .Values.ngrok.hostname }}"
+ http:
+ paths:
+ - path: /echo
+ pathType: Prefix
+ backend:
+ service:
+ name: echo
+ port:
+ number: 8080
+ - path: /next
+ pathType: Prefix
+ backend:
+ service:
+ name: next
+ port:
+ number: 3000
+ - path: /strapi
+ pathType: Prefix
+ backend:
+ service:
+ name: strapi
+ port:
+ number: 1337
+ # - path: /snake
+ # pathType: Prefix
+ # backend:
+ # service:
+ # name: snake
+ # port:
+ # number: 8080
+{{ end }}
+
diff --git a/charts/fp/templates-staging/realtime.yaml b/charts/fp/templates-staging/realtime.yaml
new file mode 100644
index 0000000..2b7753c
--- /dev/null
+++ b/charts/fp/templates-staging/realtime.yaml
@@ -0,0 +1,65 @@
+apiVersion: v1
+kind: Service
+metadata:
+ name: realtime
+ namespace: futureporn
+spec:
+ selector:
+ app.kubernetes.io/name: realtime
+ ports:
+ - name: realtime
+ port: 80
+ targetPort: 5535
+
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: realtime
+ namespace: futureporn
+ labels:
+ app: realtime
+spec:
+ replicas: 1
+ selector:
+ matchLabels:
+ app: realtime
+ template:
+ metadata:
+ labels:
+ app: realtime
+ spec:
+ containers:
+ - name: realtime
+ image: "{{ .Values.realtime.containerName }}"
+ ports:
+ - containerPort: 5535
+
+
+{{ if eq .Values.managedBy "Helm" }}
+---
+apiVersion: networking.k8s.io/v1
+kind: Ingress
+metadata:
+ name: realtime
+ namespace: futureporn
+annotations:
+ kubernetes.io/ingress.class: nginx
+ cert-manager.io/cluster-issuer: letsencrypt-staging
+spec:
+tls:
+ - secretName: realtime-tls
+ hosts:
+ - realtime.futureporn.net
+rules:
+ - host: realtime.futureporn.net
+ http:
+ paths:
+ - path: /
+ pathType: Prefix
+ backend:
+ service:
+ name: realtime
+ port:
+ number: 5535
+{{ end }}
\ No newline at end of file
diff --git a/charts/fp/templates-staging/snake.yaml b/charts/fp/templates-staging/snake.yaml
new file mode 100644
index 0000000..af91585
--- /dev/null
+++ b/charts/fp/templates-staging/snake.yaml
@@ -0,0 +1,35 @@
+apiVersion: v1
+kind: Service
+metadata:
+ name: snake
+ namespace: futureporn
+spec:
+ ports:
+ - name: http
+ port: 8080
+ targetPort: 8080
+ selector:
+ app: snake
+
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: snake
+ namespace: futureporn
+spec:
+ replicas: 2
+ selector:
+ matchLabels:
+ app: snake
+ template:
+ metadata:
+ labels:
+ app: snake
+ spec:
+ containers:
+ - name: snake
+ image: thoschu/de.schulte360.web.snake
+ ports:
+ - name: http
+ containerPort: 8080
\ No newline at end of file
diff --git a/charts/fp/templates/.gitignore b/charts/fp/templates/.gitignore
new file mode 100644
index 0000000..df2b9aa
--- /dev/null
+++ b/charts/fp/templates/.gitignore
@@ -0,0 +1 @@
+strapi-app.yaml
\ No newline at end of file
diff --git a/charts/fp/templates/ipfs-pod.yaml b/charts/fp/templates/ipfs-pod.yaml
deleted file mode 100644
index 078b441..0000000
--- a/charts/fp/templates/ipfs-pod.yaml
+++ /dev/null
@@ -1,22 +0,0 @@
-apiVersion: v1
-kind: Pod
-metadata:
- name: ipfs-pod
- namespace: default
- labels:
- app.kubernetes.io/name: ipfs
-spec:
- containers:
- - name: ipfs
- image: ipfs/kubo
- ports:
- - containerPort: 5001
- - containerPort: 8080
- volumeMounts:
- - name: ipfs-pvc
- mountPath: /data/ipfs
- restartPolicy: OnFailure
- volumes:
- - name: ipfs-pvc
- persistentVolumeClaim:
- claimName: ipfs-pvc
diff --git a/charts/fp/templates/ipfs-pvc.yaml b/charts/fp/templates/ipfs-pvc.yaml
deleted file mode 100644
index 616fb97..0000000
--- a/charts/fp/templates/ipfs-pvc.yaml
+++ /dev/null
@@ -1,18 +0,0 @@
-apiVersion: v1
-kind: PersistentVolumeClaim
-metadata:
- name: ipfs-pvc
- namespace: default
- annotations:
- meta.helm.sh/release-name: fp
- meta.helm.sh/release-namespace: default
- labels:
- app.kubernetes.io/managed-by: {{ .Values.managedBy }}
-spec:
- accessModes:
- - ReadWriteOnce
- resources:
- requests:
- storage: 40Gi
- storageClassName: {{ .Values.storageClassName }}
-
diff --git a/charts/fp/templates/ipfs-service.yaml b/charts/fp/templates/ipfs-service.yaml
deleted file mode 100644
index c43bc44..0000000
--- a/charts/fp/templates/ipfs-service.yaml
+++ /dev/null
@@ -1,23 +0,0 @@
-apiVersion: v1
-kind: Service
-metadata:
- name: ipfs-service
- namespace: default
- annotations:
- meta.helm.sh/release-name: fp
- meta.helm.sh/release-namespace: default
- labels:
- app.kubernetes.io/managed-by: {{ .Values.managedBy }}
-spec:
- selector:
- app.kubernetes.io/name: ipfs
- ports:
- - name: gateway
- protocol: TCP
- port: 8080
- targetPort: 8080
- - name: api
- protocol: TCP
- port: 5001
- targetPort: 5001
-
diff --git a/charts/fp/templates/letsencrypt-prod.yaml b/charts/fp/templates/letsencrypt-prod.yaml
deleted file mode 100644
index c8299cc..0000000
--- a/charts/fp/templates/letsencrypt-prod.yaml
+++ /dev/null
@@ -1,22 +0,0 @@
-
----
-apiVersion: cert-manager.io/v1
-kind: ClusterIssuer
-metadata:
- name: letsencrypt-prod
-spec:
- acme:
- # server: https://acme-staging-v02.api.letsencrypt.org/directory
- server: https://acme-v02.api.letsencrypt.org/directory
- email: {{ .Values.adminEmail }}
- privateKeySecretRef:
- name: letsencrypt-prod
- solvers:
- - dns01:
- webhook:
- groupName: acme.vultr.com
- solverName: vultr
- config:
- apiKeySecretRef:
- key: apiKey
- name: vultr
\ No newline at end of file
diff --git a/charts/fp/templates/letsencrypt-staging.yaml b/charts/fp/templates/letsencrypt.yaml
similarity index 56%
rename from charts/fp/templates/letsencrypt-staging.yaml
rename to charts/fp/templates/letsencrypt.yaml
index e581d7b..4394076 100644
--- a/charts/fp/templates/letsencrypt-staging.yaml
+++ b/charts/fp/templates/letsencrypt.yaml
@@ -1,3 +1,4 @@
+{{ if eq .Values.managedBy "Helm" }}
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
@@ -21,3 +22,28 @@ spec:
apiKeySecretRef:
key: apiKey
name: vultr-credentials
+
+
+---
+apiVersion: cert-manager.io/v1
+kind: ClusterIssuer
+metadata:
+ name: letsencrypt-prod
+spec:
+ acme:
+ # server: https://acme-staging-v02.api.letsencrypt.org/directory
+ server: https://acme-v02.api.letsencrypt.org/directory
+ email: {{ .Values.adminEmail }}
+ privateKeySecretRef:
+ name: letsencrypt-prod
+ solvers:
+ - dns01:
+ webhook:
+ groupName: acme.vultr.com
+ solverName: vultr
+ config:
+ apiKeySecretRef:
+ key: apiKey
+ name: vultr
+
+{{ end }}
\ No newline at end of file
diff --git a/charts/fp/templates/next.yaml b/charts/fp/templates/next.yaml
new file mode 100644
index 0000000..ccdbcde
--- /dev/null
+++ b/charts/fp/templates/next.yaml
@@ -0,0 +1,65 @@
+apiVersion: v1
+kind: Service
+metadata:
+ name: next
+ namespace: futureporn
+spec:
+ selector:
+ app.kubernetes.io/name: next
+ ports:
+ - name: web
+ port: 3000
+ targetPort: 3000
+
+---
+apiVersion: v1
+kind: Pod
+metadata:
+ name: next
+ namespace: futureporn
+ labels:
+ app.kubernetes.io/name: next
+spec:
+ containers:
+ - name: next
+ image: "{{ .Values.next.containerName }}"
+ env:
+ - name: HOSTNAME
+ value: 0.0.0.0
+ ports:
+ - name: web
+ containerPort: 3000
+ resources: {}
+ restartPolicy: OnFailure
+
+
+{{ if eq .Values.managedBy "Helm" }}
+---
+apiVersion: networking.k8s.io/v1
+kind: Ingress
+metadata:
+ name: next
+ namespace: futureporn
+ annotations:
+ kubernetes.io/ingress.class: nginx
+ cert-manager.io/cluster-issuer: "{{ .Values.next.certIssuer }}"
+spec:
+ backend:
+ serviceName: next
+ servicePort: 3000
+ tls:
+ - secretName: next-tls
+ hosts:
+ - "{{ .Values.next.hostname }}"
+ rules:
+ - host: "{{ .Values.next.hostname }}"
+ http:
+ paths:
+ - path: /
+ pathType: Prefix
+ backend:
+ service:
+ name: next
+ port:
+ number: 3000
+{{ end }}
\ No newline at end of file
diff --git a/charts/fp/templates/pgadmin.yaml b/charts/fp/templates/pgadmin.yaml
new file mode 100644
index 0000000..99da4a6
--- /dev/null
+++ b/charts/fp/templates/pgadmin.yaml
@@ -0,0 +1,53 @@
+apiVersion: v1
+kind: Service
+metadata:
+ name: pgadmin
+ namespace: futureporn
+spec:
+ selector:
+ app.kubernetes.io/name: pgadmin
+ ports:
+ - name: web
+ protocol: TCP
+ port: 5050
+ targetPort: 5050
+status:
+ loadBalancer: {}
+
+---
+apiVersion: v1
+kind: Pod
+metadata:
+ name: pgadmin
+ namespace: futureporn
+ labels:
+ app.kubernetes.io/name: pgadmin
+spec:
+ containers:
+ - name: pgadmin
+ image: dpage/pgadmin4
+ ports:
+ - containerPort: 5050
+ resources:
+ limits:
+ cpu: 500m
+ memory: 1Gi
+ env:
+ - name: PGADMIN_LISTEN_PORT
+ value: '5050'
+ - name: POSTGRES_PASSWORD
+ valueFrom:
+ secretKeyRef:
+ name: postgres
+ key: password
+ - name: PGADMIN_DEFAULT_PASSWORD
+ valueFrom:
+ secretKeyRef:
+ name: pgadmin
+ key: defaultPassword
+ - name: PGADMIN_DEFAULT_EMAIL
+ valueFrom:
+ secretKeyRef:
+ name: pgadmin
+ key: defaultEmail
+ restartPolicy: OnFailure
\ No newline at end of file
diff --git a/charts/fp/templates/piko.yaml b/charts/fp/templates/piko.yaml
new file mode 100644
index 0000000..a026dcb
--- /dev/null
+++ b/charts/fp/templates/piko.yaml
@@ -0,0 +1,101 @@
+
+# In development, we need a piko agent
+{{ if eq .Values.managedBy "tilt" }}
+
+{{ end }}
+
+
+# In production, we need a piko server
+{{ if eq .Values.managedBy "Helm" }}
+---
+apiVersion: v1
+kind: Service
+metadata:
+ name: piko
+ namespace: futureporn
+ labels:
+ app: piko
+spec:
+ ports:
+ - port: 8000
+ name: proxy
+ - port: 8001
+ name: upstream
+ - port: 8002
+ name: admin
+ - port: 8003
+ name: gossip
+ clusterIP: None
+ selector:
+ app: piko
+---
+apiVersion: v1
+kind: ConfigMap
+metadata:
+ name: server-config
+data:
+ server.yaml: |
+ cluster:
+ node_id_prefix: ${POD_NAME}-
+ join:
+ - piko
+---
+apiVersion: apps/v1
+kind: StatefulSet
+metadata:
+ name: piko
+spec:
+ selector:
+ matchLabels:
+ app: piko
+ serviceName: "piko"
+ replicas: 3
+ template:
+ metadata:
+ labels:
+ app: piko
+ spec:
+ terminationGracePeriodSeconds: 60
+ containers:
+ - name: piko
+ image: my-repo/piko:latest
+ ports:
+ - containerPort: 8000
+ name: proxy
+ - containerPort: 8001
+ name: upstream
+ - containerPort: 8002
+ name: admin
+ - containerPort: 8003
+ name: gossip
+ args:
+ - server
+ - --config.path
+ - /config/server.yaml
+ - --config.expand-env
+ resources:
+ limits:
+ cpu: 250m
+ ephemeral-storage: 1Gi
+ memory: 1Gi
+ requests:
+ cpu: 250m
+ ephemeral-storage: 1Gi
+ memory: 1Gi
+ env:
+ - name: POD_NAME
+ valueFrom:
+ fieldRef:
+ fieldPath: metadata.name
+ volumeMounts:
+ - name: config
+ mountPath: "/config"
+ readOnly: true
+ volumes:
+ - name: config
+ configMap:
+ name: server-config
+ items:
+ - key: "server.yaml"
+ path: "server.yaml"
+{{ end }}
diff --git a/charts/fp/templates/postgres.yaml b/charts/fp/templates/postgres.yaml
new file mode 100644
index 0000000..9a88904
--- /dev/null
+++ b/charts/fp/templates/postgres.yaml
@@ -0,0 +1,70 @@
+apiVersion: v1
+kind: PersistentVolumeClaim
+metadata:
+ namespace: futureporn
+ name: postgres
+annotations:
+ tilt.dev/down-policy: keep
+spec:
+ accessModes:
+ - ReadWriteOnce
+ persistentVolumeReclaimPolicy: Retain
+ resources:
+ requests:
+ storage: 40Gi
+ storageClassName: {{ .Values.storageClassName }}
+
+
+---
+apiVersion: v1
+kind: Service
+metadata:
+ namespace: futureporn
+ name: postgres
+annotations:
+ tilt.dev/down-policy: keep
+spec:
+ selector:
+ app.kubernetes.io/name: postgres
+ ports:
+ - name: db
+ protocol: TCP
+ port: 5432
+ targetPort: 5432
+status:
+ loadBalancer: {}
+
+---
+apiVersion: v1
+kind: Pod
+metadata:
+ namespace: futureporn
+ name: postgres
+ labels:
+ app.kubernetes.io/name: postgres
+annotations:
+ tilt.dev/down-policy: keep
+spec:
+ containers:
+ - name: postgres
+ image: postgres:16.0
+ env:
+ - name: POSTGRES_PASSWORD
+ valueFrom:
+ secretKeyRef:
+ name: postgres
+ key: password
+ ports:
+ - containerPort: 5432
+ resources:
+ limits:
+ cpu: 500m
+ memory: 1Gi
+ volumeMounts:
+ - name: postgres
+ mountPath: /data/postgres
+ restartPolicy: OnFailure
+ volumes:
+ - name: postgres
+ persistentVolumeClaim:
+ claimName: postgres
\ No newline at end of file
diff --git a/charts/fp/templates/roles.yaml b/charts/fp/templates/roles.yaml
index 69a432d..f0e4fb8 100644
--- a/charts/fp/templates/roles.yaml
+++ b/charts/fp/templates/roles.yaml
@@ -1,3 +1,5 @@
+{{ if eq .Values.managedBy "Helm" }}
+
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
@@ -23,3 +25,4 @@ roleRef:
name: cert-manager-webhook-vultr-secret-reader
apiGroup: rbac.authorization.k8s.io
+{{ end }}
\ No newline at end of file
diff --git a/charts/fp/templates/scout.yaml b/charts/fp/templates/scout.yaml
new file mode 100644
index 0000000..c3749d9
--- /dev/null
+++ b/charts/fp/templates/scout.yaml
@@ -0,0 +1,108 @@
+apiVersion: v1
+kind: Service
+metadata:
+ name: scout
+ namespace: futureporn
+spec:
+ selector:
+ app.kubernetes.io/name: scout
+ ports:
+ - name: web
+ port: 3000
+ targetPort: 3000
+
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: scout
+ namespace: futureporn
+ labels:
+ app: scout
+spec:
+ replicas: 1
+ selector:
+ matchLabels:
+ app: scout
+ template:
+ metadata:
+ labels:
+ app: scout
+ spec:
+ containers:
+ - name: scout
+ image: "{{ .Values.scout.containerName }}"
+ ports:
+ - containerPort: 5000
+ env:
+ - name: POSTGRES_REALTIME_CONNECTION_STRING
+ valueFrom:
+ secretKeyRef:
+ name: realtime
+ key: postgresRealtimeConnectionString
+ - name: STRAPI_URL
+ value: https://strapi.futureporn.svc.cluster.local
+ - name: SCOUT_RECENTS_TOKEN
+ valueFrom:
+ secretKeyRef:
+ name: scout
+ key: recentsToken
+ - name: SCOUT_IMAP_SERVER
+ valueFrom:
+ secretKeyRef:
+ name: scout
+ key: imapServer
+ - name: SCOUT_IMAP_PORT
+ valueFrom:
+ secretKeyRef:
+ name: scout
+ key: imapPort
+ - name: SCOUT_IMAP_USERNAME
+ valueFrom:
+ secretKeyRef:
+ name: scout
+ key: imapUsername
+ - name: SCOUT_IMAP_PASSWORD
+ valueFrom:
+ secretKeyRef:
+ name: scout
+ key: imapPassword
+ - name: SCOUT_IMAP_ACCESS_TOKEN
+ valueFrom:
+ secretKeyRef:
+ name: scout
+ key: imapAccessToken
+ - name: SCOUT_STRAPI_API_KEY
+ valueFrom:
+ secretKeyRef:
+ name: scout
+ key: strapiApiKey
+
+
+{{ if eq .Values.managedBy "Helm" }}
+---
+apiVersion: networking.k8s.io/v1
+kind: Ingress
+metadata:
+ name: scout
+ namespace: futureporn
+ annotations:
+ kubernetes.io/ingress.class: nginx
+ cert-manager.io/cluster-issuer: letsencrypt-staging
+spec:
+tls:
+ - secretName: scout-tls
+ hosts:
+ - scout.sbtp.xyz
+rules:
+ - host: scout.sbtp.xyz
+ http:
+ paths:
+ - path: /
+ pathType: Prefix
+ backend:
+ service:
+ name: scout
+ port:
+ number: 3000
+{{ end }}
\ No newline at end of file
diff --git a/charts/fp/templates/strapi.yaml b/charts/fp/templates/strapi.yaml
new file mode 100644
index 0000000..121aba1
--- /dev/null
+++ b/charts/fp/templates/strapi.yaml
@@ -0,0 +1,182 @@
+apiVersion: v1
+kind: Service
+metadata:
+ name: strapi
+ namespace: futureporn
+spec:
+ selector:
+ app.kubernetes.io/name: strapi
+ ports:
+ - name: http
+ port: 1339
+ targetPort: http
+ protocol: TCP
+
+---
+apiVersion: v1
+kind: Pod
+metadata:
+ name: strapi
+ namespace: futureporn
+ labels:
+ app.kubernetes.io/name: strapi
+spec:
+ containers:
+ - name: strapi
+ image: "{{ .Values.strapi.containerName }}"
+ ports:
+ - name: http
+ containerPort: 1339
+ env:
+ - name: ADMIN_JWT_SECRET
+ valueFrom:
+ secretKeyRef:
+ name: strapi
+ key: adminJwtSecret
+ - name: API_TOKEN_SALT
+ valueFrom:
+ secretKeyRef:
+ name: strapi
+ key: apiTokenSalt
+ - name: APP_KEYS
+ valueFrom:
+ secretKeyRef:
+ name: strapi
+ key: appKeys
+ - name: DATABASE_URL
+ valueFrom:
+ secretKeyRef:
+ name: strapi
+ key: databaseUrl
+ - name: CDN_BUCKET_USC_URL
+ valueFrom:
+ secretKeyRef:
+ name: strapi
+ key: cdnBucketUscUrl
+ - name: DATABASE_CLIENT
+ value: postgres
+ - name: DATABASE_HOST
+ value: postgres.futureporn.svc.cluster.local
+ - name: DATABASE_NAME
+ value: futureporn-strapi
+ - name: JWT_SECRET
+ valueFrom:
+ secretKeyRef:
+ name: strapi
+ key: jwtSecret
+ - name: MUX_PLAYBACK_RESTRICTION_ID
+ valueFrom:
+ secretKeyRef:
+ name: strapi
+ key: muxPlaybackRestrictionId
+ - name: MUX_SIGNING_KEY_ID
+ valueFrom:
+ secretKeyRef:
+ name: strapi
+ key: muxSigningKeyId
+ - name: MUX_SIGNING_KEY_PRIVATE_KEY
+ valueFrom:
+ secretKeyRef:
+ name: strapi
+ key: muxSigningKeyPrivateKey
+ - name: NODE_ENV
+ value: production
+ - name: S3_USC_BUCKET_APPLICATION_KEY
+ valueFrom:
+ secretKeyRef:
+ name: strapi
+ key: s3UscBucketApplicationKey
+ - name: S3_USC_BUCKET_ENDPOINT
+ valueFrom:
+ secretKeyRef:
+ name: strapi
+ key: s3UscBucketEndpoint
+ - name: S3_USC_BUCKET_KEY_ID
+ valueFrom:
+ secretKeyRef:
+ name: strapi
+ key: s3UscBucketKeyId
+ - name: S3_USC_BUCKET_NAME
+ valueFrom:
+ secretKeyRef:
+ name: strapi
+ key: s3UscBucketName
+ - name: S3_USC_BUCKET_REGION
+ valueFrom:
+ secretKeyRef:
+ name: strapi
+ key: s3UscBucketRegion
+ - name: SENDGRID_API_KEY
+ valueFrom:
+ secretKeyRef:
+ name: strapi
+ key: sendgridApiKey
+ - name: STRAPI_URL
+ value: "{{ .Values.strapi.url }}"
+ - name: TRANSFER_TOKEN_SALT
+ valueFrom:
+ secretKeyRef:
+ name: strapi
+ key: transferTokenSalt
+ - name: PORT
+ value: "{{ .Values.strapi.port }}"
+ resources:
+ limits:
+ cpu: 1000m
+ memory: 2Gi
+ restartPolicy: Always
+
+
+# ---
+# apiVersion: v1
+# kind: PersistentVolumeClaim
+# metadata:
+# name: strapi
+# namespace: futureporn
+# annotations:
+# meta.helm.sh/release-name: fp
+# meta.helm.sh/release-namespace: futureporn
+# labels:
+# app.kubernetes.io/managed-by: {{ .Values.managedBy }}
+# spec:
+# accessModes:
+# - ReadWriteOnce
+# resources:
+# requests:
+# storage: 100Gi
+# storageClassName: {{ .Values.storageClassName }}
+
+
+{{ if eq .Values.managedBy "Helm" }}
+---
+apiVersion: networking.k8s.io/v1
+kind: Ingress
+metadata:
+ name: strapi
+ namespace: futureporn
+ annotations:
+ sbtp.xyz/managed-by: "{{ .Values.managedBy }}"
+ kubernetes.io/ingress.class: nginx
+ cert-manager.io/cluster-issuer: "{{ .Values.strapi.certIssuer }}"
+spec:
+ ingressClassName: "{{ .Values.strapi.ingressClassName }}"
+ backend:
+ serviceName: strapi
+ servicePort: 1339
+ tls:
+ - secretName: strapi-tls
+ hosts:
+ - "{{ .Values.strapi.hostname }}"
+ rules:
+ - host: "{{ .Values.strapi.hostname }}"
+ http:
+ paths:
+ - path: /
+ pathType: Prefix
+ backend:
+ service:
+ name: strapi
+ port:
+ number: 1339
+
+{{ end }}
diff --git a/charts/fp/templates/windmill-ingress.yaml b/charts/fp/templates/windmill-ingress.yaml
index 77a6130..4ebaaad 100644
--- a/charts/fp/templates/windmill-ingress.yaml
+++ b/charts/fp/templates/windmill-ingress.yaml
@@ -1,3 +1,5 @@
+{{ if eq .Values.managedBy "Helm" }}
+
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
@@ -25,4 +27,6 @@ spec:
tls:
- hosts:
- windmill2.sbtp.xyz
- secretName: windmill-tls
\ No newline at end of file
+ secretName: windmill-tls
+
+{{ end }}
\ No newline at end of file
diff --git a/charts/fp/values-dev.yaml b/charts/fp/values-dev.yaml
index 40c9cc4..98c52de 100644
--- a/charts/fp/values-dev.yaml
+++ b/charts/fp/values-dev.yaml
@@ -1,12 +1,26 @@
# storageClassName: csi-hostpath-sc # used by minikube
storageClassName: standard # used by Kind
+managedBy: tilt
link2cid:
containerName: fp/link2cid
next:
containerName: fp/next
+ certIssuer: letsencrypt-staging
+ hostname: next.futureporn.svc.cluster.local
+capture:
+ containerName: fp/capture
+scout:
+ containerName: fp/scout
+ pubsubServerUrl: https://realtime.futureporn.svc.cluster.local/faye
strapi:
containerName: fp/strapi
- port: 1337
- url: http://localhost:1337
-managedBy: Dildo
+ port: 1339
+ url: http://localhost:1339
+ certIssuer: letsencrypt-staging
+ hostname: strapi.futureporn.svc.cluster.local
+ ingressClassName: ngrok
+ngrok:
+ hostname: grateful-engaging-cicada.ngrok-free.app
+realtime:
+ containerName: fp/realtime
adminEmail: cj@futureporn.net
\ No newline at end of file
diff --git a/charts/fp/values-prod.yaml b/charts/fp/values-prod.yaml
index a1f01e6..5ac9c09 100644
--- a/charts/fp/values-prod.yaml
+++ b/charts/fp/values-prod.yaml
@@ -1,12 +1,22 @@
storageClassName: vultr-block-storage-hdd
link2cid:
containerName: gitea.futureporn.net/futureporn/link2cid:latest
+scout:
+ containerName: gitea.futureporn.net/futureporn/scout:latest
+ pubsubServerUrl: https://realtime.futureporn.net/faye
next:
- containerName: sjc.vultrcr.com/fpcontainers/next
+ containerName: gitea.futureporn.net/futureporn/next:latest
+ certIssuer: letsencrypt-staging
+ hostname: next.sbtp.xyz
+capture:
+ containerName: gitea.futureporn.net/futureporn/capture:latest
strapi:
containerName: sjc.vultrcr.com/fpcontainers/strapi
- port: 1337
+ port: 1339
url: https://portal.futureporn.net
+ certIssuer: letsencrypt-prod
+ hostname: strapi.sbtp.xyz
+ ingressClassName: nginx
managedBy: Helm
adminEmail: cj@futureporn.net
extraArgs:
diff --git a/d.capture.dockerfile b/d.capture.dockerfile
new file mode 100644
index 0000000..4bcd39c
--- /dev/null
+++ b/d.capture.dockerfile
@@ -0,0 +1,35 @@
+FROM node:18-alpine
+# Install dependencies only when needed
+# Check https://github.com/nodejs/docker-node/tree/b4117f9333da4138b03a546ec926ef50a31506c3#nodealpine to understand why libc6-compat might be needed.
+RUN apk add --no-cache libc6-compat
+RUN corepack enable && corepack prepare pnpm@latest --activate
+
+# Enable `pnpm add --global` on Alpine Linux by setting
+# home location environment variable to a location already in $PATH
+# https://github.com/pnpm/pnpm/issues/784#issuecomment-1518582235
+ENV PNPM_HOME=/usr/local/bin
+
+# update and install latest dependencies, add dumb-init package
+# add a non root user
+RUN apk update && apk upgrade && apk add dumb-init ffmpeg make gcc g++ python3
+
+WORKDIR /app
+# Copy and install the dependencies for the project
+COPY ./packages/capture/package.json ./packages/capture/pnpm-lock.yaml ./
+
+# Copy all other project files to working directory
+COPY ./packages/capture .
+# Run the next build process and generate the artifacts
+RUN pnpm i;
+
+
+# expose 3000 on container
+EXPOSE 3000
+
+# set app host ,port and node env
+ENV HOSTNAME=0.0.0.0 PORT=3000 NODE_ENV=production
+# start the app with dumb init to spawn the Node.js runtime process
+# with signal support
+CMD [ "dumb-init", "node", "index.js" ]
+
+
diff --git a/link2cid.dockerfile b/d.link2cid.dockerfile
similarity index 100%
rename from link2cid.dockerfile
rename to d.link2cid.dockerfile
diff --git a/next.dockerfile b/d.next.dockerfile
similarity index 100%
rename from next.dockerfile
rename to d.next.dockerfile
diff --git a/d.realtime.dockerfile b/d.realtime.dockerfile
new file mode 100644
index 0000000..0368a93
--- /dev/null
+++ b/d.realtime.dockerfile
@@ -0,0 +1,14 @@
+FROM node:20-alpine
+WORKDIR /app
+ENV PNPM_HOME="/pnpm"
+ENV PATH="$PNPM_HOME:$PATH"
+RUN corepack enable
+RUN apk update
+
+ENV NODE_ENV=production
+COPY pnpm-lock.yaml ./
+RUN pnpm fetch
+COPY ./packages/realtime /app
+
+ENTRYPOINT ["pnpm"]
+CMD ["run", "start"]
diff --git a/d.scout.dockerfile b/d.scout.dockerfile
new file mode 100644
index 0000000..fdf04ff
--- /dev/null
+++ b/d.scout.dockerfile
@@ -0,0 +1,26 @@
+FROM node:20-alpine AS base
+ENV PNPM_HOME="/pnpm"
+ENV PATH="$PNPM_HOME:$PATH"
+RUN corepack enable
+RUN apk update
+
+
+FROM base AS build
+ENV NODE_ENV=production
+COPY . /usr/src/app
+WORKDIR /usr/src/app
+RUN mkdir -p /prod/scout
+RUN --mount=type=cache,id=pnpm,target=/pnpm/store pnpm install --frozen-lockfile
+RUN ls -la ./packages
+RUN pnpm deploy --filter=@futureporn/scout --prod /prod/scout
+# COPY pnpm-lock.yaml ./
+# RUN pnpm fetch
+# COPY ./packages/scout /app
+
+
+FROM base AS scout
+COPY --from=build /prod/scout /app
+WORKDIR /app
+RUN ls -la
+ENTRYPOINT ["pnpm"]
+CMD ["run", "start"]
diff --git a/d.strapi-app.dockerfile b/d.strapi-app.dockerfile
new file mode 100644
index 0000000..335c6d8
--- /dev/null
+++ b/d.strapi-app.dockerfile
@@ -0,0 +1,19 @@
+FROM node:18-alpine3.18
+# 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 ./packages/strapi-app/package.json ./packages/strapi-app/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 ./packages/strapi-app/ .
+RUN chown -R node:node /opt/app
+USER node
+RUN ["yarn", "build"]
+EXPOSE 1338
+CMD ["yarn", "develop", "--debug"]
\ No newline at end of file
diff --git a/d.strapi.dockerfile b/d.strapi.dockerfile
new file mode 100644
index 0000000..8b692f4
--- /dev/null
+++ b/d.strapi.dockerfile
@@ -0,0 +1,24 @@
+FROM node:18-alpine AS base
+ENV PNPM_HOME="/pnpm"
+ENV PATH="$PNPM_HOME:$PATH"
+RUN corepack enable
+# 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}
+
+FROM base AS build
+WORKDIR /usr/src/app/
+COPY ./packages/strapi/package.json ./packages/strapi/pnpm-lock.yaml .
+RUN --mount=type=cache,id=pnpm,target=/pnpm/store pnpm install --frozen-lockfile
+COPY ./packages/strapi/ .
+
+FROM build AS dev
+WORKDIR /app
+ENV PATH /app/node_modules/.bin:$PATH
+COPY --from=build /usr/src/app/ .
+RUN chown -R node:node /app
+USER node
+RUN ["pnpm", "run", "build"]
+EXPOSE 1339
+CMD ["pnpm", "run", "dev"]
\ No newline at end of file
diff --git a/packages/bot/pnpm-lock.yaml b/packages/bot/pnpm-lock.yaml
index e12d5c8..a530c5e 100644
--- a/packages/bot/pnpm-lock.yaml
+++ b/packages/bot/pnpm-lock.yaml
@@ -1,52 +1,561 @@
-lockfileVersion: '6.0'
+lockfileVersion: '9.0'
settings:
autoInstallPeers: true
excludeLinksFromLockfile: false
-dependencies:
- '@types/express':
- specifier: ^4.17.21
- version: 4.17.21
- '@types/node':
- specifier: ^20.12.6
- version: 20.12.6
- discordeno:
- specifier: ^18.0.1
- version: 18.0.1
- express:
- specifier: ^4.19.2
- version: 4.19.2
- oceanic.js:
- specifier: ^1.10.0
- version: 1.10.0
+importers:
-devDependencies:
- tsx:
- specifier: ^4.7.2
- version: 4.7.2
+ .:
+ dependencies:
+ '@types/express':
+ specifier: ^4.17.21
+ version: 4.17.21
+ '@types/node':
+ specifier: ^20.12.6
+ version: 20.12.6
+ discordeno:
+ specifier: ^18.0.1
+ version: 18.0.1
+ express:
+ specifier: ^4.19.2
+ version: 4.19.2
+ oceanic.js:
+ specifier: ^1.10.0
+ version: 1.10.0
+ devDependencies:
+ tsx:
+ specifier: ^4.7.2
+ version: 4.7.2
packages:
- /@deno/shim-deno-test@0.3.3:
+ '@deno/shim-deno-test@0.3.3':
resolution: {integrity: sha512-Ge0Tnl7zZY0VvEfgsyLhjid8DzI1d0La0dgm+3m0/A8gZXgp5xwlyIyue5e4SCUuVB/3AH/0lun9LcJhhTwmbg==}
- dev: false
- /@deno/shim-deno@0.9.0:
+ '@deno/shim-deno@0.9.0':
resolution: {integrity: sha512-iP+qdI4Oy/Mw9yv40TqdjNKL+stpKDo8drki2cKisTXgZf+GoIdMhIuODxSypRyv6wxIuHNx7ZiKE3Sl3kAHuw==}
+
+ '@deno/shim-timers@0.1.0':
+ resolution: {integrity: sha512-XFRnB5Rtbkd5RiYHwhugNK9gvDgYXmFTUOT5dmhWCKG7WnOWZggbJMnH1NcyYS3QgHvmaTOaHCyNFNSv57j3Dg==}
+
+ '@discordjs/voice@0.16.1':
+ resolution: {integrity: sha512-uiWiW0Ta6K473yf8zs13RfKuPqm/xU4m4dAidMkIdwqgy1CztbbZBtPLfDkVSKzpW7s6m072C+uQcs4LwF3FhA==}
+ engines: {node: '>=16.11.0'}
+
+ '@esbuild/aix-ppc64@0.19.12':
+ resolution: {integrity: sha512-bmoCYyWdEL3wDQIVbcyzRyeKLgk2WtWLTWz1ZIAZF/EGbNOwSA6ew3PftJ1PqMiOOGu0OyFMzG53L0zqIpPeNA==}
+ engines: {node: '>=12'}
+ cpu: [ppc64]
+ os: [aix]
+
+ '@esbuild/android-arm64@0.19.12':
+ resolution: {integrity: sha512-P0UVNGIienjZv3f5zq0DP3Nt2IE/3plFzuaS96vihvD0Hd6H/q4WXUGpCxD/E8YrSXfNyRPbpTq+T8ZQioSuPA==}
+ engines: {node: '>=12'}
+ cpu: [arm64]
+ os: [android]
+
+ '@esbuild/android-arm@0.19.12':
+ resolution: {integrity: sha512-qg/Lj1mu3CdQlDEEiWrlC4eaPZ1KztwGJ9B6J+/6G+/4ewxJg7gqj8eVYWvao1bXrqGiW2rsBZFSX3q2lcW05w==}
+ engines: {node: '>=12'}
+ cpu: [arm]
+ os: [android]
+
+ '@esbuild/android-x64@0.19.12':
+ resolution: {integrity: sha512-3k7ZoUW6Q6YqhdhIaq/WZ7HwBpnFBlW905Fa4s4qWJyiNOgT1dOqDiVAQFwBH7gBRZr17gLrlFCRzF6jFh7Kew==}
+ engines: {node: '>=12'}
+ cpu: [x64]
+ os: [android]
+
+ '@esbuild/darwin-arm64@0.19.12':
+ resolution: {integrity: sha512-B6IeSgZgtEzGC42jsI+YYu9Z3HKRxp8ZT3cqhvliEHovq8HSX2YX8lNocDn79gCKJXOSaEot9MVYky7AKjCs8g==}
+ engines: {node: '>=12'}
+ cpu: [arm64]
+ os: [darwin]
+
+ '@esbuild/darwin-x64@0.19.12':
+ resolution: {integrity: sha512-hKoVkKzFiToTgn+41qGhsUJXFlIjxI/jSYeZf3ugemDYZldIXIxhvwN6erJGlX4t5h417iFuheZ7l+YVn05N3A==}
+ engines: {node: '>=12'}
+ cpu: [x64]
+ os: [darwin]
+
+ '@esbuild/freebsd-arm64@0.19.12':
+ resolution: {integrity: sha512-4aRvFIXmwAcDBw9AueDQ2YnGmz5L6obe5kmPT8Vd+/+x/JMVKCgdcRwH6APrbpNXsPz+K653Qg8HB/oXvXVukA==}
+ engines: {node: '>=12'}
+ cpu: [arm64]
+ os: [freebsd]
+
+ '@esbuild/freebsd-x64@0.19.12':
+ resolution: {integrity: sha512-EYoXZ4d8xtBoVN7CEwWY2IN4ho76xjYXqSXMNccFSx2lgqOG/1TBPW0yPx1bJZk94qu3tX0fycJeeQsKovA8gg==}
+ engines: {node: '>=12'}
+ cpu: [x64]
+ os: [freebsd]
+
+ '@esbuild/linux-arm64@0.19.12':
+ resolution: {integrity: sha512-EoTjyYyLuVPfdPLsGVVVC8a0p1BFFvtpQDB/YLEhaXyf/5bczaGeN15QkR+O4S5LeJ92Tqotve7i1jn35qwvdA==}
+ engines: {node: '>=12'}
+ cpu: [arm64]
+ os: [linux]
+
+ '@esbuild/linux-arm@0.19.12':
+ resolution: {integrity: sha512-J5jPms//KhSNv+LO1S1TX1UWp1ucM6N6XuL6ITdKWElCu8wXP72l9MM0zDTzzeikVyqFE6U8YAV9/tFyj0ti+w==}
+ engines: {node: '>=12'}
+ cpu: [arm]
+ os: [linux]
+
+ '@esbuild/linux-ia32@0.19.12':
+ resolution: {integrity: sha512-Thsa42rrP1+UIGaWz47uydHSBOgTUnwBwNq59khgIwktK6x60Hivfbux9iNR0eHCHzOLjLMLfUMLCypBkZXMHA==}
+ engines: {node: '>=12'}
+ cpu: [ia32]
+ os: [linux]
+
+ '@esbuild/linux-loong64@0.19.12':
+ resolution: {integrity: sha512-LiXdXA0s3IqRRjm6rV6XaWATScKAXjI4R4LoDlvO7+yQqFdlr1Bax62sRwkVvRIrwXxvtYEHHI4dm50jAXkuAA==}
+ engines: {node: '>=12'}
+ cpu: [loong64]
+ os: [linux]
+
+ '@esbuild/linux-mips64el@0.19.12':
+ resolution: {integrity: sha512-fEnAuj5VGTanfJ07ff0gOA6IPsvrVHLVb6Lyd1g2/ed67oU1eFzL0r9WL7ZzscD+/N6i3dWumGE1Un4f7Amf+w==}
+ engines: {node: '>=12'}
+ cpu: [mips64el]
+ os: [linux]
+
+ '@esbuild/linux-ppc64@0.19.12':
+ resolution: {integrity: sha512-nYJA2/QPimDQOh1rKWedNOe3Gfc8PabU7HT3iXWtNUbRzXS9+vgB0Fjaqr//XNbd82mCxHzik2qotuI89cfixg==}
+ engines: {node: '>=12'}
+ cpu: [ppc64]
+ os: [linux]
+
+ '@esbuild/linux-riscv64@0.19.12':
+ resolution: {integrity: sha512-2MueBrlPQCw5dVJJpQdUYgeqIzDQgw3QtiAHUC4RBz9FXPrskyyU3VI1hw7C0BSKB9OduwSJ79FTCqtGMWqJHg==}
+ engines: {node: '>=12'}
+ cpu: [riscv64]
+ os: [linux]
+
+ '@esbuild/linux-s390x@0.19.12':
+ resolution: {integrity: sha512-+Pil1Nv3Umes4m3AZKqA2anfhJiVmNCYkPchwFJNEJN5QxmTs1uzyy4TvmDrCRNT2ApwSari7ZIgrPeUx4UZDg==}
+ engines: {node: '>=12'}
+ cpu: [s390x]
+ os: [linux]
+
+ '@esbuild/linux-x64@0.19.12':
+ resolution: {integrity: sha512-B71g1QpxfwBvNrfyJdVDexenDIt1CiDN1TIXLbhOw0KhJzE78KIFGX6OJ9MrtC0oOqMWf+0xop4qEU8JrJTwCg==}
+ engines: {node: '>=12'}
+ cpu: [x64]
+ os: [linux]
+
+ '@esbuild/netbsd-x64@0.19.12':
+ resolution: {integrity: sha512-3ltjQ7n1owJgFbuC61Oj++XhtzmymoCihNFgT84UAmJnxJfm4sYCiSLTXZtE00VWYpPMYc+ZQmB6xbSdVh0JWA==}
+ engines: {node: '>=12'}
+ cpu: [x64]
+ os: [netbsd]
+
+ '@esbuild/openbsd-x64@0.19.12':
+ resolution: {integrity: sha512-RbrfTB9SWsr0kWmb9srfF+L933uMDdu9BIzdA7os2t0TXhCRjrQyCeOt6wVxr79CKD4c+p+YhCj31HBkYcXebw==}
+ engines: {node: '>=12'}
+ cpu: [x64]
+ os: [openbsd]
+
+ '@esbuild/sunos-x64@0.19.12':
+ resolution: {integrity: sha512-HKjJwRrW8uWtCQnQOz9qcU3mUZhTUQvi56Q8DPTLLB+DawoiQdjsYq+j+D3s9I8VFtDr+F9CjgXKKC4ss89IeA==}
+ engines: {node: '>=12'}
+ cpu: [x64]
+ os: [sunos]
+
+ '@esbuild/win32-arm64@0.19.12':
+ resolution: {integrity: sha512-URgtR1dJnmGvX864pn1B2YUYNzjmXkuJOIqG2HdU62MVS4EHpU2946OZoTMnRUHklGtJdJZ33QfzdjGACXhn1A==}
+ engines: {node: '>=12'}
+ cpu: [arm64]
+ os: [win32]
+
+ '@esbuild/win32-ia32@0.19.12':
+ resolution: {integrity: sha512-+ZOE6pUkMOJfmxmBZElNOx72NKpIa/HFOMGzu8fqzQJ5kgf6aTGrcJaFsNiVMH4JKpMipyK+7k0n2UXN7a8YKQ==}
+ engines: {node: '>=12'}
+ cpu: [ia32]
+ os: [win32]
+
+ '@esbuild/win32-x64@0.19.12':
+ resolution: {integrity: sha512-T1QyPSDCyMXaO3pzBkF96E8xMkiRYbUEZADd29SyPGabqxMViNoii+NcK7eWJAEoU6RZyEm5lVSIjTmcdoB9HA==}
+ engines: {node: '>=12'}
+ cpu: [x64]
+ os: [win32]
+
+ '@fastify/busboy@2.1.1':
+ resolution: {integrity: sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA==}
+ engines: {node: '>=14'}
+
+ '@types/body-parser@1.19.5':
+ resolution: {integrity: sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==}
+
+ '@types/connect@3.4.38':
+ resolution: {integrity: sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==}
+
+ '@types/express-serve-static-core@4.19.0':
+ resolution: {integrity: sha512-bGyep3JqPCRry1wq+O5n7oiBgGWmeIJXPjXXCo8EK0u8duZGSYar7cGqd3ML2JUsLGeB7fmc06KYo9fLGWqPvQ==}
+
+ '@types/express@4.17.21':
+ resolution: {integrity: sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ==}
+
+ '@types/http-errors@2.0.4':
+ resolution: {integrity: sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==}
+
+ '@types/mime@1.3.5':
+ resolution: {integrity: sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==}
+
+ '@types/node@20.12.6':
+ resolution: {integrity: sha512-3KurE8taB8GCvZBPngVbp0lk5CKi8M9f9k1rsADh0Evdz5SzJ+Q+Hx9uHoFGsLnLnd1xmkDQr2hVhlA0Mn0lKQ==}
+
+ '@types/qs@6.9.14':
+ resolution: {integrity: sha512-5khscbd3SwWMhFqylJBLQ0zIu7c1K6Vz0uBIt915BI3zV0q1nfjRQD3RqSBcPaO6PHEF4ov/t9y89fSiyThlPA==}
+
+ '@types/range-parser@1.2.7':
+ resolution: {integrity: sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==}
+
+ '@types/send@0.17.4':
+ resolution: {integrity: sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA==}
+
+ '@types/serve-static@1.15.7':
+ resolution: {integrity: sha512-W8Ym+h8nhuRwaKPaDw34QUkwsGi6Rc4yYqvKFo5rm2FUEhCFbzVWrxXUxuKK8TASjWsysJY0nsmNCGhCOIsrOw==}
+
+ '@types/ws@8.5.10':
+ resolution: {integrity: sha512-vmQSUcfalpIq0R9q7uTo2lXs6eGIpt9wtnLdMv9LVpIjCA/+ufZRozlVoVelIYixx1ugCBKDhn89vnsEGOCx9A==}
+
+ accepts@1.3.8:
+ resolution: {integrity: sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==}
+ engines: {node: '>= 0.6'}
+
+ array-flatten@1.1.1:
+ resolution: {integrity: sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==}
+
+ body-parser@1.20.2:
+ resolution: {integrity: sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==}
+ engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16}
+
+ bytes@3.1.2:
+ resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==}
+ engines: {node: '>= 0.8'}
+
+ call-bind@1.0.7:
+ resolution: {integrity: sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==}
+ engines: {node: '>= 0.4'}
+
+ content-disposition@0.5.4:
+ resolution: {integrity: sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==}
+ engines: {node: '>= 0.6'}
+
+ content-type@1.0.5:
+ resolution: {integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==}
+ engines: {node: '>= 0.6'}
+
+ cookie-signature@1.0.6:
+ resolution: {integrity: sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==}
+
+ cookie@0.6.0:
+ resolution: {integrity: sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==}
+ engines: {node: '>= 0.6'}
+
+ debug@2.6.9:
+ resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==}
+ peerDependencies:
+ supports-color: '*'
+ peerDependenciesMeta:
+ supports-color:
+ optional: true
+
+ define-data-property@1.1.4:
+ resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==}
+ engines: {node: '>= 0.4'}
+
+ depd@2.0.0:
+ resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==}
+ engines: {node: '>= 0.8'}
+
+ destroy@1.2.0:
+ resolution: {integrity: sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==}
+ engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16}
+
+ discord-api-types@0.37.61:
+ resolution: {integrity: sha512-o/dXNFfhBpYHpQFdT6FWzeO7pKc838QeeZ9d91CfVAtpr5XLK4B/zYxQbYgPdoMiTDvJfzcsLW5naXgmHGDNXw==}
+
+ discordeno@18.0.1:
+ resolution: {integrity: sha512-d3D/HpC39YGInmxy2HK90kPpMMu2gYYsWuwtEEFPWpq2hlR9dvad4ihvLursPz5bj4Ob1NWOgPv3kz/bwMSIpw==}
+
+ ee-first@1.1.1:
+ resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==}
+
+ encodeurl@1.0.2:
+ resolution: {integrity: sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==}
+ engines: {node: '>= 0.8'}
+
+ es-define-property@1.0.0:
+ resolution: {integrity: sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==}
+ engines: {node: '>= 0.4'}
+
+ es-errors@1.3.0:
+ resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==}
+ engines: {node: '>= 0.4'}
+
+ esbuild@0.19.12:
+ resolution: {integrity: sha512-aARqgq8roFBj054KvQr5f1sFu0D65G+miZRCuJyJ0G13Zwx7vRar5Zhn2tkQNzIXcBrNVsv/8stehpj+GAjgbg==}
+ engines: {node: '>=12'}
+ hasBin: true
+
+ escape-html@1.0.3:
+ resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==}
+
+ etag@1.8.1:
+ resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==}
+ engines: {node: '>= 0.6'}
+
+ express@4.19.2:
+ resolution: {integrity: sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==}
+ engines: {node: '>= 0.10.0'}
+
+ finalhandler@1.2.0:
+ resolution: {integrity: sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==}
+ engines: {node: '>= 0.8'}
+
+ forwarded@0.2.0:
+ resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==}
+ engines: {node: '>= 0.6'}
+
+ fresh@0.5.2:
+ resolution: {integrity: sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==}
+ engines: {node: '>= 0.6'}
+
+ fsevents@2.3.3:
+ resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==}
+ engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
+ os: [darwin]
+
+ function-bind@1.1.2:
+ resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==}
+
+ get-intrinsic@1.2.4:
+ resolution: {integrity: sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==}
+ engines: {node: '>= 0.4'}
+
+ get-tsconfig@4.7.3:
+ resolution: {integrity: sha512-ZvkrzoUA0PQZM6fy6+/Hce561s+faD1rsNwhnO5FelNjyy7EMGJ3Rz1AQ8GYDWjhRs/7dBLOEJvhK8MiEJOAFg==}
+
+ gopd@1.0.1:
+ resolution: {integrity: sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==}
+
+ has-property-descriptors@1.0.2:
+ resolution: {integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==}
+
+ has-proto@1.0.3:
+ resolution: {integrity: sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==}
+ engines: {node: '>= 0.4'}
+
+ has-symbols@1.0.3:
+ resolution: {integrity: sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==}
+ engines: {node: '>= 0.4'}
+
+ hasown@2.0.2:
+ resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==}
+ engines: {node: '>= 0.4'}
+
+ http-errors@2.0.0:
+ resolution: {integrity: sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==}
+ engines: {node: '>= 0.8'}
+
+ iconv-lite@0.4.24:
+ resolution: {integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==}
+ engines: {node: '>=0.10.0'}
+
+ inherits@2.0.4:
+ resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==}
+
+ ipaddr.js@1.9.1:
+ resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==}
+ engines: {node: '>= 0.10'}
+
+ isexe@2.0.0:
+ resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==}
+
+ media-typer@0.3.0:
+ resolution: {integrity: sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==}
+ engines: {node: '>= 0.6'}
+
+ merge-descriptors@1.0.1:
+ resolution: {integrity: sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==}
+
+ methods@1.1.2:
+ resolution: {integrity: sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==}
+ engines: {node: '>= 0.6'}
+
+ mime-db@1.52.0:
+ resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==}
+ engines: {node: '>= 0.6'}
+
+ mime-types@2.1.35:
+ resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==}
+ engines: {node: '>= 0.6'}
+
+ mime@1.6.0:
+ resolution: {integrity: sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==}
+ engines: {node: '>=4'}
+ hasBin: true
+
+ ms@2.0.0:
+ resolution: {integrity: sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==}
+
+ ms@2.1.3:
+ resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==}
+
+ negotiator@0.6.3:
+ resolution: {integrity: sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==}
+ engines: {node: '>= 0.6'}
+
+ object-inspect@1.13.1:
+ resolution: {integrity: sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==}
+
+ oceanic.js@1.10.0:
+ resolution: {integrity: sha512-WYgtdBHBSVX/2kCycU64WA0c2b4BOsAREXek06dOz1cqfX8464HFRamSJir6pOiTQvnW/nk/WN8r3Bq6Yt9lrQ==}
+ engines: {node: '>=18.13.0'}
+
+ on-finished@2.4.1:
+ resolution: {integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==}
+ engines: {node: '>= 0.8'}
+
+ parseurl@1.3.3:
+ resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==}
+ engines: {node: '>= 0.8'}
+
+ path-to-regexp@0.1.7:
+ resolution: {integrity: sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==}
+
+ prism-media@1.3.5:
+ resolution: {integrity: sha512-IQdl0Q01m4LrkN1EGIE9lphov5Hy7WWlH6ulf5QdGePLlPas9p2mhgddTEHrlaXYjjFToM1/rWuwF37VF4taaA==}
+ peerDependencies:
+ '@discordjs/opus': '>=0.8.0 <1.0.0'
+ ffmpeg-static: ^5.0.2 || ^4.2.7 || ^3.0.0 || ^2.4.0
+ node-opus: ^0.3.3
+ opusscript: ^0.0.8
+ peerDependenciesMeta:
+ '@discordjs/opus':
+ optional: true
+ ffmpeg-static:
+ optional: true
+ node-opus:
+ optional: true
+ opusscript:
+ optional: true
+
+ proxy-addr@2.0.7:
+ resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==}
+ engines: {node: '>= 0.10'}
+
+ qs@6.11.0:
+ resolution: {integrity: sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==}
+ engines: {node: '>=0.6'}
+
+ range-parser@1.2.1:
+ resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==}
+ engines: {node: '>= 0.6'}
+
+ raw-body@2.5.2:
+ resolution: {integrity: sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==}
+ engines: {node: '>= 0.8'}
+
+ resolve-pkg-maps@1.0.0:
+ resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==}
+
+ safe-buffer@5.2.1:
+ resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==}
+
+ safer-buffer@2.1.2:
+ resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==}
+
+ send@0.18.0:
+ resolution: {integrity: sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==}
+ engines: {node: '>= 0.8.0'}
+
+ serve-static@1.15.0:
+ resolution: {integrity: sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==}
+ engines: {node: '>= 0.8.0'}
+
+ set-function-length@1.2.2:
+ resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==}
+ engines: {node: '>= 0.4'}
+
+ setprototypeof@1.2.0:
+ resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==}
+
+ side-channel@1.0.6:
+ resolution: {integrity: sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==}
+ engines: {node: '>= 0.4'}
+
+ statuses@2.0.1:
+ resolution: {integrity: sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==}
+ engines: {node: '>= 0.8'}
+
+ toidentifier@1.0.1:
+ resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==}
+ engines: {node: '>=0.6'}
+
+ tslib@2.6.2:
+ resolution: {integrity: sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==}
+
+ tsx@4.7.2:
+ resolution: {integrity: sha512-BCNd4kz6fz12fyrgCTEdZHGJ9fWTGeUzXmQysh0RVocDY3h4frk05ZNCXSy4kIenF7y/QnrdiVpTsyNRn6vlAw==}
+ engines: {node: '>=18.0.0'}
+ hasBin: true
+
+ type-is@1.6.18:
+ resolution: {integrity: sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==}
+ engines: {node: '>= 0.6'}
+
+ undici-types@5.26.5:
+ resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==}
+
+ undici@5.28.4:
+ resolution: {integrity: sha512-72RFADWFqKmUb2hmmvNODKL3p9hcB6Gt2DOQMis1SEBaV6a4MH8soBvzg+95CYhCKPFedut2JY9bMfrDl9D23g==}
+ engines: {node: '>=14.0'}
+
+ unpipe@1.0.0:
+ resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==}
+ engines: {node: '>= 0.8'}
+
+ utils-merge@1.0.1:
+ resolution: {integrity: sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==}
+ engines: {node: '>= 0.4.0'}
+
+ vary@1.1.2:
+ resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==}
+ engines: {node: '>= 0.8'}
+
+ which@2.0.2:
+ resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==}
+ engines: {node: '>= 8'}
+ hasBin: true
+
+ ws@8.16.0:
+ resolution: {integrity: sha512-HS0c//TP7Ina87TfiPUz1rQzMhHrl/SG2guqRcTOIUYD2q8uhUdNHZYJUaQ8aTGPzCh+c6oawMKW35nFl1dxyQ==}
+ 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
+
+snapshots:
+
+ '@deno/shim-deno-test@0.3.3': {}
+
+ '@deno/shim-deno@0.9.0':
dependencies:
'@deno/shim-deno-test': 0.3.3
which: 2.0.2
- dev: false
- /@deno/shim-timers@0.1.0:
- resolution: {integrity: sha512-XFRnB5Rtbkd5RiYHwhugNK9gvDgYXmFTUOT5dmhWCKG7WnOWZggbJMnH1NcyYS3QgHvmaTOaHCyNFNSv57j3Dg==}
- dev: false
+ '@deno/shim-timers@0.1.0': {}
- /@discordjs/voice@0.16.1:
- resolution: {integrity: sha512-uiWiW0Ta6K473yf8zs13RfKuPqm/xU4m4dAidMkIdwqgy1CztbbZBtPLfDkVSKzpW7s6m072C+uQcs4LwF3FhA==}
- engines: {node: '>=16.11.0'}
- requiresBuild: true
+ '@discordjs/voice@0.16.1':
dependencies:
'@types/ws': 8.5.10
discord-api-types: 0.37.61
@@ -60,312 +569,138 @@ packages:
- node-opus
- opusscript
- utf-8-validate
- dev: false
optional: true
- /@esbuild/aix-ppc64@0.19.12:
- resolution: {integrity: sha512-bmoCYyWdEL3wDQIVbcyzRyeKLgk2WtWLTWz1ZIAZF/EGbNOwSA6ew3PftJ1PqMiOOGu0OyFMzG53L0zqIpPeNA==}
- engines: {node: '>=12'}
- cpu: [ppc64]
- os: [aix]
- requiresBuild: true
- dev: true
+ '@esbuild/aix-ppc64@0.19.12':
optional: true
- /@esbuild/android-arm64@0.19.12:
- resolution: {integrity: sha512-P0UVNGIienjZv3f5zq0DP3Nt2IE/3plFzuaS96vihvD0Hd6H/q4WXUGpCxD/E8YrSXfNyRPbpTq+T8ZQioSuPA==}
- engines: {node: '>=12'}
- cpu: [arm64]
- os: [android]
- requiresBuild: true
- dev: true
+ '@esbuild/android-arm64@0.19.12':
optional: true
- /@esbuild/android-arm@0.19.12:
- resolution: {integrity: sha512-qg/Lj1mu3CdQlDEEiWrlC4eaPZ1KztwGJ9B6J+/6G+/4ewxJg7gqj8eVYWvao1bXrqGiW2rsBZFSX3q2lcW05w==}
- engines: {node: '>=12'}
- cpu: [arm]
- os: [android]
- requiresBuild: true
- dev: true
+ '@esbuild/android-arm@0.19.12':
optional: true
- /@esbuild/android-x64@0.19.12:
- resolution: {integrity: sha512-3k7ZoUW6Q6YqhdhIaq/WZ7HwBpnFBlW905Fa4s4qWJyiNOgT1dOqDiVAQFwBH7gBRZr17gLrlFCRzF6jFh7Kew==}
- engines: {node: '>=12'}
- cpu: [x64]
- os: [android]
- requiresBuild: true
- dev: true
+ '@esbuild/android-x64@0.19.12':
optional: true
- /@esbuild/darwin-arm64@0.19.12:
- resolution: {integrity: sha512-B6IeSgZgtEzGC42jsI+YYu9Z3HKRxp8ZT3cqhvliEHovq8HSX2YX8lNocDn79gCKJXOSaEot9MVYky7AKjCs8g==}
- engines: {node: '>=12'}
- cpu: [arm64]
- os: [darwin]
- requiresBuild: true
- dev: true
+ '@esbuild/darwin-arm64@0.19.12':
optional: true
- /@esbuild/darwin-x64@0.19.12:
- resolution: {integrity: sha512-hKoVkKzFiToTgn+41qGhsUJXFlIjxI/jSYeZf3ugemDYZldIXIxhvwN6erJGlX4t5h417iFuheZ7l+YVn05N3A==}
- engines: {node: '>=12'}
- cpu: [x64]
- os: [darwin]
- requiresBuild: true
- dev: true
+ '@esbuild/darwin-x64@0.19.12':
optional: true
- /@esbuild/freebsd-arm64@0.19.12:
- resolution: {integrity: sha512-4aRvFIXmwAcDBw9AueDQ2YnGmz5L6obe5kmPT8Vd+/+x/JMVKCgdcRwH6APrbpNXsPz+K653Qg8HB/oXvXVukA==}
- engines: {node: '>=12'}
- cpu: [arm64]
- os: [freebsd]
- requiresBuild: true
- dev: true
+ '@esbuild/freebsd-arm64@0.19.12':
optional: true
- /@esbuild/freebsd-x64@0.19.12:
- resolution: {integrity: sha512-EYoXZ4d8xtBoVN7CEwWY2IN4ho76xjYXqSXMNccFSx2lgqOG/1TBPW0yPx1bJZk94qu3tX0fycJeeQsKovA8gg==}
- engines: {node: '>=12'}
- cpu: [x64]
- os: [freebsd]
- requiresBuild: true
- dev: true
+ '@esbuild/freebsd-x64@0.19.12':
optional: true
- /@esbuild/linux-arm64@0.19.12:
- resolution: {integrity: sha512-EoTjyYyLuVPfdPLsGVVVC8a0p1BFFvtpQDB/YLEhaXyf/5bczaGeN15QkR+O4S5LeJ92Tqotve7i1jn35qwvdA==}
- engines: {node: '>=12'}
- cpu: [arm64]
- os: [linux]
- requiresBuild: true
- dev: true
+ '@esbuild/linux-arm64@0.19.12':
optional: true
- /@esbuild/linux-arm@0.19.12:
- resolution: {integrity: sha512-J5jPms//KhSNv+LO1S1TX1UWp1ucM6N6XuL6ITdKWElCu8wXP72l9MM0zDTzzeikVyqFE6U8YAV9/tFyj0ti+w==}
- engines: {node: '>=12'}
- cpu: [arm]
- os: [linux]
- requiresBuild: true
- dev: true
+ '@esbuild/linux-arm@0.19.12':
optional: true
- /@esbuild/linux-ia32@0.19.12:
- resolution: {integrity: sha512-Thsa42rrP1+UIGaWz47uydHSBOgTUnwBwNq59khgIwktK6x60Hivfbux9iNR0eHCHzOLjLMLfUMLCypBkZXMHA==}
- engines: {node: '>=12'}
- cpu: [ia32]
- os: [linux]
- requiresBuild: true
- dev: true
+ '@esbuild/linux-ia32@0.19.12':
optional: true
- /@esbuild/linux-loong64@0.19.12:
- resolution: {integrity: sha512-LiXdXA0s3IqRRjm6rV6XaWATScKAXjI4R4LoDlvO7+yQqFdlr1Bax62sRwkVvRIrwXxvtYEHHI4dm50jAXkuAA==}
- engines: {node: '>=12'}
- cpu: [loong64]
- os: [linux]
- requiresBuild: true
- dev: true
+ '@esbuild/linux-loong64@0.19.12':
optional: true
- /@esbuild/linux-mips64el@0.19.12:
- resolution: {integrity: sha512-fEnAuj5VGTanfJ07ff0gOA6IPsvrVHLVb6Lyd1g2/ed67oU1eFzL0r9WL7ZzscD+/N6i3dWumGE1Un4f7Amf+w==}
- engines: {node: '>=12'}
- cpu: [mips64el]
- os: [linux]
- requiresBuild: true
- dev: true
+ '@esbuild/linux-mips64el@0.19.12':
optional: true
- /@esbuild/linux-ppc64@0.19.12:
- resolution: {integrity: sha512-nYJA2/QPimDQOh1rKWedNOe3Gfc8PabU7HT3iXWtNUbRzXS9+vgB0Fjaqr//XNbd82mCxHzik2qotuI89cfixg==}
- engines: {node: '>=12'}
- cpu: [ppc64]
- os: [linux]
- requiresBuild: true
- dev: true
+ '@esbuild/linux-ppc64@0.19.12':
optional: true
- /@esbuild/linux-riscv64@0.19.12:
- resolution: {integrity: sha512-2MueBrlPQCw5dVJJpQdUYgeqIzDQgw3QtiAHUC4RBz9FXPrskyyU3VI1hw7C0BSKB9OduwSJ79FTCqtGMWqJHg==}
- engines: {node: '>=12'}
- cpu: [riscv64]
- os: [linux]
- requiresBuild: true
- dev: true
+ '@esbuild/linux-riscv64@0.19.12':
optional: true
- /@esbuild/linux-s390x@0.19.12:
- resolution: {integrity: sha512-+Pil1Nv3Umes4m3AZKqA2anfhJiVmNCYkPchwFJNEJN5QxmTs1uzyy4TvmDrCRNT2ApwSari7ZIgrPeUx4UZDg==}
- engines: {node: '>=12'}
- cpu: [s390x]
- os: [linux]
- requiresBuild: true
- dev: true
+ '@esbuild/linux-s390x@0.19.12':
optional: true
- /@esbuild/linux-x64@0.19.12:
- resolution: {integrity: sha512-B71g1QpxfwBvNrfyJdVDexenDIt1CiDN1TIXLbhOw0KhJzE78KIFGX6OJ9MrtC0oOqMWf+0xop4qEU8JrJTwCg==}
- engines: {node: '>=12'}
- cpu: [x64]
- os: [linux]
- requiresBuild: true
- dev: true
+ '@esbuild/linux-x64@0.19.12':
optional: true
- /@esbuild/netbsd-x64@0.19.12:
- resolution: {integrity: sha512-3ltjQ7n1owJgFbuC61Oj++XhtzmymoCihNFgT84UAmJnxJfm4sYCiSLTXZtE00VWYpPMYc+ZQmB6xbSdVh0JWA==}
- engines: {node: '>=12'}
- cpu: [x64]
- os: [netbsd]
- requiresBuild: true
- dev: true
+ '@esbuild/netbsd-x64@0.19.12':
optional: true
- /@esbuild/openbsd-x64@0.19.12:
- resolution: {integrity: sha512-RbrfTB9SWsr0kWmb9srfF+L933uMDdu9BIzdA7os2t0TXhCRjrQyCeOt6wVxr79CKD4c+p+YhCj31HBkYcXebw==}
- engines: {node: '>=12'}
- cpu: [x64]
- os: [openbsd]
- requiresBuild: true
- dev: true
+ '@esbuild/openbsd-x64@0.19.12':
optional: true
- /@esbuild/sunos-x64@0.19.12:
- resolution: {integrity: sha512-HKjJwRrW8uWtCQnQOz9qcU3mUZhTUQvi56Q8DPTLLB+DawoiQdjsYq+j+D3s9I8VFtDr+F9CjgXKKC4ss89IeA==}
- engines: {node: '>=12'}
- cpu: [x64]
- os: [sunos]
- requiresBuild: true
- dev: true
+ '@esbuild/sunos-x64@0.19.12':
optional: true
- /@esbuild/win32-arm64@0.19.12:
- resolution: {integrity: sha512-URgtR1dJnmGvX864pn1B2YUYNzjmXkuJOIqG2HdU62MVS4EHpU2946OZoTMnRUHklGtJdJZ33QfzdjGACXhn1A==}
- engines: {node: '>=12'}
- cpu: [arm64]
- os: [win32]
- requiresBuild: true
- dev: true
+ '@esbuild/win32-arm64@0.19.12':
optional: true
- /@esbuild/win32-ia32@0.19.12:
- resolution: {integrity: sha512-+ZOE6pUkMOJfmxmBZElNOx72NKpIa/HFOMGzu8fqzQJ5kgf6aTGrcJaFsNiVMH4JKpMipyK+7k0n2UXN7a8YKQ==}
- engines: {node: '>=12'}
- cpu: [ia32]
- os: [win32]
- requiresBuild: true
- dev: true
+ '@esbuild/win32-ia32@0.19.12':
optional: true
- /@esbuild/win32-x64@0.19.12:
- resolution: {integrity: sha512-T1QyPSDCyMXaO3pzBkF96E8xMkiRYbUEZADd29SyPGabqxMViNoii+NcK7eWJAEoU6RZyEm5lVSIjTmcdoB9HA==}
- engines: {node: '>=12'}
- cpu: [x64]
- os: [win32]
- requiresBuild: true
- dev: true
+ '@esbuild/win32-x64@0.19.12':
optional: true
- /@fastify/busboy@2.1.1:
- resolution: {integrity: sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA==}
- engines: {node: '>=14'}
- dev: false
+ '@fastify/busboy@2.1.1': {}
- /@types/body-parser@1.19.5:
- resolution: {integrity: sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==}
+ '@types/body-parser@1.19.5':
dependencies:
'@types/connect': 3.4.38
'@types/node': 20.12.6
- dev: false
- /@types/connect@3.4.38:
- resolution: {integrity: sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==}
+ '@types/connect@3.4.38':
dependencies:
'@types/node': 20.12.6
- dev: false
- /@types/express-serve-static-core@4.19.0:
- resolution: {integrity: sha512-bGyep3JqPCRry1wq+O5n7oiBgGWmeIJXPjXXCo8EK0u8duZGSYar7cGqd3ML2JUsLGeB7fmc06KYo9fLGWqPvQ==}
+ '@types/express-serve-static-core@4.19.0':
dependencies:
'@types/node': 20.12.6
'@types/qs': 6.9.14
'@types/range-parser': 1.2.7
'@types/send': 0.17.4
- dev: false
- /@types/express@4.17.21:
- resolution: {integrity: sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ==}
+ '@types/express@4.17.21':
dependencies:
'@types/body-parser': 1.19.5
'@types/express-serve-static-core': 4.19.0
'@types/qs': 6.9.14
'@types/serve-static': 1.15.7
- dev: false
- /@types/http-errors@2.0.4:
- resolution: {integrity: sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==}
- dev: false
+ '@types/http-errors@2.0.4': {}
- /@types/mime@1.3.5:
- resolution: {integrity: sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==}
- dev: false
+ '@types/mime@1.3.5': {}
- /@types/node@20.12.6:
- resolution: {integrity: sha512-3KurE8taB8GCvZBPngVbp0lk5CKi8M9f9k1rsADh0Evdz5SzJ+Q+Hx9uHoFGsLnLnd1xmkDQr2hVhlA0Mn0lKQ==}
+ '@types/node@20.12.6':
dependencies:
undici-types: 5.26.5
- dev: false
- /@types/qs@6.9.14:
- resolution: {integrity: sha512-5khscbd3SwWMhFqylJBLQ0zIu7c1K6Vz0uBIt915BI3zV0q1nfjRQD3RqSBcPaO6PHEF4ov/t9y89fSiyThlPA==}
- dev: false
+ '@types/qs@6.9.14': {}
- /@types/range-parser@1.2.7:
- resolution: {integrity: sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==}
- dev: false
+ '@types/range-parser@1.2.7': {}
- /@types/send@0.17.4:
- resolution: {integrity: sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA==}
+ '@types/send@0.17.4':
dependencies:
'@types/mime': 1.3.5
'@types/node': 20.12.6
- dev: false
- /@types/serve-static@1.15.7:
- resolution: {integrity: sha512-W8Ym+h8nhuRwaKPaDw34QUkwsGi6Rc4yYqvKFo5rm2FUEhCFbzVWrxXUxuKK8TASjWsysJY0nsmNCGhCOIsrOw==}
+ '@types/serve-static@1.15.7':
dependencies:
'@types/http-errors': 2.0.4
'@types/node': 20.12.6
'@types/send': 0.17.4
- dev: false
- /@types/ws@8.5.10:
- resolution: {integrity: sha512-vmQSUcfalpIq0R9q7uTo2lXs6eGIpt9wtnLdMv9LVpIjCA/+ufZRozlVoVelIYixx1ugCBKDhn89vnsEGOCx9A==}
- requiresBuild: true
+ '@types/ws@8.5.10':
dependencies:
'@types/node': 20.12.6
- dev: false
optional: true
- /accepts@1.3.8:
- resolution: {integrity: sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==}
- engines: {node: '>= 0.6'}
+ accepts@1.3.8:
dependencies:
mime-types: 2.1.35
negotiator: 0.6.3
- dev: false
- /array-flatten@1.1.1:
- resolution: {integrity: sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==}
- dev: false
+ array-flatten@1.1.1: {}
- /body-parser@1.20.2:
- resolution: {integrity: sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==}
- engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16}
+ body-parser@1.20.2:
dependencies:
bytes: 3.1.2
content-type: 1.0.5
@@ -381,83 +716,45 @@ packages:
unpipe: 1.0.0
transitivePeerDependencies:
- supports-color
- dev: false
- /bytes@3.1.2:
- resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==}
- engines: {node: '>= 0.8'}
- dev: false
+ bytes@3.1.2: {}
- /call-bind@1.0.7:
- resolution: {integrity: sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==}
- engines: {node: '>= 0.4'}
+ call-bind@1.0.7:
dependencies:
es-define-property: 1.0.0
es-errors: 1.3.0
function-bind: 1.1.2
get-intrinsic: 1.2.4
set-function-length: 1.2.2
- dev: false
- /content-disposition@0.5.4:
- resolution: {integrity: sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==}
- engines: {node: '>= 0.6'}
+ content-disposition@0.5.4:
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
+ content-type@1.0.5: {}
- /cookie-signature@1.0.6:
- resolution: {integrity: sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==}
- dev: false
+ cookie-signature@1.0.6: {}
- /cookie@0.6.0:
- resolution: {integrity: sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==}
- engines: {node: '>= 0.6'}
- dev: false
+ cookie@0.6.0: {}
- /debug@2.6.9:
- resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==}
- peerDependencies:
- supports-color: '*'
- peerDependenciesMeta:
- supports-color:
- optional: true
+ debug@2.6.9:
dependencies:
ms: 2.0.0
- dev: false
- /define-data-property@1.1.4:
- resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==}
- engines: {node: '>= 0.4'}
+ define-data-property@1.1.4:
dependencies:
es-define-property: 1.0.0
es-errors: 1.3.0
gopd: 1.0.1
- dev: false
- /depd@2.0.0:
- resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==}
- engines: {node: '>= 0.8'}
- dev: false
+ depd@2.0.0: {}
- /destroy@1.2.0:
- resolution: {integrity: sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==}
- engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16}
- dev: false
+ destroy@1.2.0: {}
- /discord-api-types@0.37.61:
- resolution: {integrity: sha512-o/dXNFfhBpYHpQFdT6FWzeO7pKc838QeeZ9d91CfVAtpr5XLK4B/zYxQbYgPdoMiTDvJfzcsLW5naXgmHGDNXw==}
- requiresBuild: true
- dev: false
+ discord-api-types@0.37.61:
optional: true
- /discordeno@18.0.1:
- resolution: {integrity: sha512-d3D/HpC39YGInmxy2HK90kPpMMu2gYYsWuwtEEFPWpq2hlR9dvad4ihvLursPz5bj4Ob1NWOgPv3kz/bwMSIpw==}
+ discordeno@18.0.1:
dependencies:
'@deno/shim-deno': 0.9.0
'@deno/shim-timers': 0.1.0
@@ -466,34 +763,18 @@ packages:
transitivePeerDependencies:
- bufferutil
- utf-8-validate
- dev: false
- /ee-first@1.1.1:
- resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==}
- dev: false
+ ee-first@1.1.1: {}
- /encodeurl@1.0.2:
- resolution: {integrity: sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==}
- engines: {node: '>= 0.8'}
- dev: false
+ encodeurl@1.0.2: {}
- /es-define-property@1.0.0:
- resolution: {integrity: sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==}
- engines: {node: '>= 0.4'}
+ es-define-property@1.0.0:
dependencies:
get-intrinsic: 1.2.4
- dev: false
- /es-errors@1.3.0:
- resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==}
- engines: {node: '>= 0.4'}
- dev: false
+ es-errors@1.3.0: {}
- /esbuild@0.19.12:
- resolution: {integrity: sha512-aARqgq8roFBj054KvQr5f1sFu0D65G+miZRCuJyJ0G13Zwx7vRar5Zhn2tkQNzIXcBrNVsv/8stehpj+GAjgbg==}
- engines: {node: '>=12'}
- hasBin: true
- requiresBuild: true
+ esbuild@0.19.12:
optionalDependencies:
'@esbuild/aix-ppc64': 0.19.12
'@esbuild/android-arm': 0.19.12
@@ -518,20 +799,12 @@ packages:
'@esbuild/win32-arm64': 0.19.12
'@esbuild/win32-ia32': 0.19.12
'@esbuild/win32-x64': 0.19.12
- dev: true
- /escape-html@1.0.3:
- resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==}
- dev: false
+ escape-html@1.0.3: {}
- /etag@1.8.1:
- resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==}
- engines: {node: '>= 0.6'}
- dev: false
+ etag@1.8.1: {}
- /express@4.19.2:
- resolution: {integrity: sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==}
- engines: {node: '>= 0.10.0'}
+ express@4.19.2:
dependencies:
accepts: 1.3.8
array-flatten: 1.1.1
@@ -566,11 +839,8 @@ packages:
vary: 1.1.2
transitivePeerDependencies:
- supports-color
- dev: false
- /finalhandler@1.2.0:
- resolution: {integrity: sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==}
- engines: {node: '>= 0.8'}
+ finalhandler@1.2.0:
dependencies:
debug: 2.6.9
encodeurl: 1.0.2
@@ -581,159 +851,85 @@ packages:
unpipe: 1.0.0
transitivePeerDependencies:
- supports-color
- dev: false
- /forwarded@0.2.0:
- resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==}
- engines: {node: '>= 0.6'}
- dev: false
+ forwarded@0.2.0: {}
- /fresh@0.5.2:
- resolution: {integrity: sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==}
- engines: {node: '>= 0.6'}
- dev: false
+ fresh@0.5.2: {}
- /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
- dev: true
+ fsevents@2.3.3:
optional: true
- /function-bind@1.1.2:
- resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==}
- dev: false
+ function-bind@1.1.2: {}
- /get-intrinsic@1.2.4:
- resolution: {integrity: sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==}
- engines: {node: '>= 0.4'}
+ get-intrinsic@1.2.4:
dependencies:
es-errors: 1.3.0
function-bind: 1.1.2
has-proto: 1.0.3
has-symbols: 1.0.3
hasown: 2.0.2
- dev: false
- /get-tsconfig@4.7.3:
- resolution: {integrity: sha512-ZvkrzoUA0PQZM6fy6+/Hce561s+faD1rsNwhnO5FelNjyy7EMGJ3Rz1AQ8GYDWjhRs/7dBLOEJvhK8MiEJOAFg==}
+ get-tsconfig@4.7.3:
dependencies:
resolve-pkg-maps: 1.0.0
- dev: true
- /gopd@1.0.1:
- resolution: {integrity: sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==}
+ gopd@1.0.1:
dependencies:
get-intrinsic: 1.2.4
- dev: false
- /has-property-descriptors@1.0.2:
- resolution: {integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==}
+ has-property-descriptors@1.0.2:
dependencies:
es-define-property: 1.0.0
- dev: false
- /has-proto@1.0.3:
- resolution: {integrity: sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==}
- engines: {node: '>= 0.4'}
- dev: false
+ has-proto@1.0.3: {}
- /has-symbols@1.0.3:
- resolution: {integrity: sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==}
- engines: {node: '>= 0.4'}
- dev: false
+ has-symbols@1.0.3: {}
- /hasown@2.0.2:
- resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==}
- engines: {node: '>= 0.4'}
+ hasown@2.0.2:
dependencies:
function-bind: 1.1.2
- dev: false
- /http-errors@2.0.0:
- resolution: {integrity: sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==}
- engines: {node: '>= 0.8'}
+ http-errors@2.0.0:
dependencies:
depd: 2.0.0
inherits: 2.0.4
setprototypeof: 1.2.0
statuses: 2.0.1
toidentifier: 1.0.1
- dev: false
- /iconv-lite@0.4.24:
- resolution: {integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==}
- engines: {node: '>=0.10.0'}
+ iconv-lite@0.4.24:
dependencies:
safer-buffer: 2.1.2
- dev: false
- /inherits@2.0.4:
- resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==}
- dev: false
+ inherits@2.0.4: {}
- /ipaddr.js@1.9.1:
- resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==}
- engines: {node: '>= 0.10'}
- dev: false
+ ipaddr.js@1.9.1: {}
- /isexe@2.0.0:
- resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==}
- dev: false
+ isexe@2.0.0: {}
- /media-typer@0.3.0:
- resolution: {integrity: sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==}
- engines: {node: '>= 0.6'}
- dev: false
+ media-typer@0.3.0: {}
- /merge-descriptors@1.0.1:
- resolution: {integrity: sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==}
- dev: false
+ merge-descriptors@1.0.1: {}
- /methods@1.1.2:
- resolution: {integrity: sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==}
- engines: {node: '>= 0.6'}
- dev: false
+ methods@1.1.2: {}
- /mime-db@1.52.0:
- resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==}
- engines: {node: '>= 0.6'}
- dev: false
+ mime-db@1.52.0: {}
- /mime-types@2.1.35:
- resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==}
- engines: {node: '>= 0.6'}
+ mime-types@2.1.35:
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
+ mime@1.6.0: {}
- /ms@2.0.0:
- resolution: {integrity: sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==}
- dev: false
+ ms@2.0.0: {}
- /ms@2.1.3:
- resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==}
- dev: false
+ ms@2.1.3: {}
- /negotiator@0.6.3:
- resolution: {integrity: sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==}
- engines: {node: '>= 0.6'}
- dev: false
+ negotiator@0.6.3: {}
- /object-inspect@1.13.1:
- resolution: {integrity: sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==}
- dev: false
+ object-inspect@1.13.1: {}
- /oceanic.js@1.10.0:
- resolution: {integrity: sha512-WYgtdBHBSVX/2kCycU64WA0c2b4BOsAREXek06dOz1cqfX8464HFRamSJir6pOiTQvnW/nk/WN8r3Bq6Yt9lrQ==}
- engines: {node: '>=18.13.0'}
+ oceanic.js@1.10.0:
dependencies:
tslib: 2.6.2
ws: 8.16.0
@@ -746,89 +942,43 @@ packages:
- node-opus
- opusscript
- utf-8-validate
- dev: false
- /on-finished@2.4.1:
- resolution: {integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==}
- engines: {node: '>= 0.8'}
+ on-finished@2.4.1:
dependencies:
ee-first: 1.1.1
- dev: false
- /parseurl@1.3.3:
- resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==}
- engines: {node: '>= 0.8'}
- dev: false
+ parseurl@1.3.3: {}
- /path-to-regexp@0.1.7:
- resolution: {integrity: sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==}
- dev: false
+ path-to-regexp@0.1.7: {}
- /prism-media@1.3.5:
- resolution: {integrity: sha512-IQdl0Q01m4LrkN1EGIE9lphov5Hy7WWlH6ulf5QdGePLlPas9p2mhgddTEHrlaXYjjFToM1/rWuwF37VF4taaA==}
- requiresBuild: true
- peerDependencies:
- '@discordjs/opus': '>=0.8.0 <1.0.0'
- ffmpeg-static: ^5.0.2 || ^4.2.7 || ^3.0.0 || ^2.4.0
- node-opus: ^0.3.3
- opusscript: ^0.0.8
- peerDependenciesMeta:
- '@discordjs/opus':
- optional: true
- ffmpeg-static:
- optional: true
- node-opus:
- optional: true
- opusscript:
- optional: true
- dev: false
+ prism-media@1.3.5:
optional: true
- /proxy-addr@2.0.7:
- resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==}
- engines: {node: '>= 0.10'}
+ proxy-addr@2.0.7:
dependencies:
forwarded: 0.2.0
ipaddr.js: 1.9.1
- dev: false
- /qs@6.11.0:
- resolution: {integrity: sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==}
- engines: {node: '>=0.6'}
+ qs@6.11.0:
dependencies:
side-channel: 1.0.6
- dev: false
- /range-parser@1.2.1:
- resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==}
- engines: {node: '>= 0.6'}
- dev: false
+ range-parser@1.2.1: {}
- /raw-body@2.5.2:
- resolution: {integrity: sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==}
- engines: {node: '>= 0.8'}
+ raw-body@2.5.2:
dependencies:
bytes: 3.1.2
http-errors: 2.0.0
iconv-lite: 0.4.24
unpipe: 1.0.0
- dev: false
- /resolve-pkg-maps@1.0.0:
- resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==}
- dev: true
+ resolve-pkg-maps@1.0.0: {}
- /safe-buffer@5.2.1:
- resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==}
- dev: false
+ safe-buffer@5.2.1: {}
- /safer-buffer@2.1.2:
- resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==}
- dev: false
+ safer-buffer@2.1.2: {}
- /send@0.18.0:
- resolution: {integrity: sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==}
- engines: {node: '>= 0.8.0'}
+ send@0.18.0:
dependencies:
debug: 2.6.9
depd: 2.0.0
@@ -845,11 +995,8 @@ packages:
statuses: 2.0.1
transitivePeerDependencies:
- supports-color
- dev: false
- /serve-static@1.15.0:
- resolution: {integrity: sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==}
- engines: {node: '>= 0.8.0'}
+ serve-static@1.15.0:
dependencies:
encodeurl: 1.0.2
escape-html: 1.0.3
@@ -857,11 +1004,8 @@ packages:
send: 0.18.0
transitivePeerDependencies:
- supports-color
- dev: false
- /set-function-length@1.2.2:
- resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==}
- engines: {node: '>= 0.4'}
+ set-function-length@1.2.2:
dependencies:
define-data-property: 1.1.4
es-errors: 1.3.0
@@ -869,98 +1013,48 @@ packages:
get-intrinsic: 1.2.4
gopd: 1.0.1
has-property-descriptors: 1.0.2
- dev: false
- /setprototypeof@1.2.0:
- resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==}
- dev: false
+ setprototypeof@1.2.0: {}
- /side-channel@1.0.6:
- resolution: {integrity: sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==}
- engines: {node: '>= 0.4'}
+ side-channel@1.0.6:
dependencies:
call-bind: 1.0.7
es-errors: 1.3.0
get-intrinsic: 1.2.4
object-inspect: 1.13.1
- dev: false
- /statuses@2.0.1:
- resolution: {integrity: sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==}
- engines: {node: '>= 0.8'}
- dev: false
+ statuses@2.0.1: {}
- /toidentifier@1.0.1:
- resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==}
- engines: {node: '>=0.6'}
- dev: false
+ toidentifier@1.0.1: {}
- /tslib@2.6.2:
- resolution: {integrity: sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==}
- dev: false
+ tslib@2.6.2: {}
- /tsx@4.7.2:
- resolution: {integrity: sha512-BCNd4kz6fz12fyrgCTEdZHGJ9fWTGeUzXmQysh0RVocDY3h4frk05ZNCXSy4kIenF7y/QnrdiVpTsyNRn6vlAw==}
- engines: {node: '>=18.0.0'}
- hasBin: true
+ tsx@4.7.2:
dependencies:
esbuild: 0.19.12
get-tsconfig: 4.7.3
optionalDependencies:
fsevents: 2.3.3
- dev: true
- /type-is@1.6.18:
- resolution: {integrity: sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==}
- engines: {node: '>= 0.6'}
+ type-is@1.6.18:
dependencies:
media-typer: 0.3.0
mime-types: 2.1.35
- dev: false
- /undici-types@5.26.5:
- resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==}
- dev: false
+ undici-types@5.26.5: {}
- /undici@5.28.4:
- resolution: {integrity: sha512-72RFADWFqKmUb2hmmvNODKL3p9hcB6Gt2DOQMis1SEBaV6a4MH8soBvzg+95CYhCKPFedut2JY9bMfrDl9D23g==}
- engines: {node: '>=14.0'}
+ undici@5.28.4:
dependencies:
'@fastify/busboy': 2.1.1
- dev: false
- /unpipe@1.0.0:
- resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==}
- engines: {node: '>= 0.8'}
- dev: false
+ unpipe@1.0.0: {}
- /utils-merge@1.0.1:
- resolution: {integrity: sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==}
- engines: {node: '>= 0.4.0'}
- dev: false
+ utils-merge@1.0.1: {}
- /vary@1.1.2:
- resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==}
- engines: {node: '>= 0.8'}
- dev: false
+ vary@1.1.2: {}
- /which@2.0.2:
- resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==}
- engines: {node: '>= 8'}
- hasBin: true
+ which@2.0.2:
dependencies:
isexe: 2.0.0
- dev: false
- /ws@8.16.0:
- resolution: {integrity: sha512-HS0c//TP7Ina87TfiPUz1rQzMhHrl/SG2guqRcTOIUYD2q8uhUdNHZYJUaQ8aTGPzCh+c6oawMKW35nFl1dxyQ==}
- 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
+ ws@8.16.0: {}
diff --git a/packages/capture/.gitignore b/packages/capture/.gitignore
new file mode 100644
index 0000000..c4273d6
--- /dev/null
+++ b/packages/capture/.gitignore
@@ -0,0 +1,153 @@
+.pnp.*
+.yarn/*
+!.yarn/patches
+!.yarn/plugins
+!.yarn/releases
+!.yarn/sdks
+!.yarn/versions
+
+
+# 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/capture/README.md b/packages/capture/README.md
new file mode 100644
index 0000000..d6fd503
--- /dev/null
+++ b/packages/capture/README.md
@@ -0,0 +1,25 @@
+# Capture
+
+## Dev notes
+
+### youtube-dl end of stream output
+
+```
+[https @ 0x5646887f1580] Opening 'https://edge11-lax.live.mmcdn.com/live-hls/amlst:hotfallingdevil-sd-fdf87e5b6c880e52d38e8c94f8ebf8728c980a91d56fb4ace13748ba59012336_trns_h264/chunklist_w881713853_b5128000_t64RlBTOjMwLjA=.m3u8' for reading
+[hls @ 0x564687dd0980] Skip ('#EXT-X-VERSION:4')
+[hls @ 0x564687dd0980] Skip ('#EXT-X-DISCONTINUITY-SEQUENCE:0')
+[hls @ 0x564687dd0980] Skip ('#EXT-X-PROGRAM-DATE-TIME:2023-01-31T17:48:45.947+00:00')
+[https @ 0x5646880bf880] Opening 'https://edge11-lax.live.mmcdn.com/live-hls/amlst:hotfallingdevil-sd-fdf87e5b6c880e52d38e8c94f8ebf8728c980a91d56fb4ace13748ba59012336_trns_h264/media_w881713853_b5128000_t64RlBTOjMwLjA=_18912.ts' for reading
+[https @ 0x564688097d00] Opening 'https://edge11-lax.live.mmcdn.com/live-hls/amlst:hotfallingdevil-sd-fdf87e5b6c880e52d38e8c94f8ebf8728c980a91d56fb4ace13748ba59012336_trns_h264/media_w881713853_b5128000_t64RlBTOjMwLjA=_18913.ts' for reading
+[https @ 0x5646887f1580] Opening 'https://edge11-lax.live.mmcdn.com/live-hls/amlst:hotfallingdevil-sd-fdf87e5b6c880e52d38e8c94f8ebf8728c980a91d56fb4ace13748ba59012336_trns_h264/chunklist_w881713853_b5128000_t64RlBTOjMwLjA=.m3u8' for reading
+[https @ 0x5646886e8580] HTTP error 403 Forbidden
+[hls @ 0x564687dd0980] keepalive request failed for 'https://edge11-lax.live.mmcdn.com/live-hls/amlst:hotfallingdevil-sd-fdf87e5b6c880e52d38e8c94f8ebf8728c980a91d56fb4ace13748ba59012336_trns_h264/chunklist_w881713853_b5128000_t64RlBTOjMwLjA=.m3u8' with error: 'Server returned 403 Forbidden (access denied)' when parsing playlist
+[https @ 0x5646886ccfc0] HTTP error 403 Forbidden
+[hls @ 0x564687dd0980] Failed to reload playlist 0
+[https @ 0x5646886bf680] HTTP error 403 Forbidden
+[hls @ 0x564687dd0980] Failed to reload playlist 0
+frame= 5355 fps= 31 q=-1.0 Lsize= 71404kB time=00:02:58.50 bitrate=3277.0kbits/s speed=1.02x
+video:68484kB audio:2790kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: 0.181873%
+[ffmpeg] Downloaded 73117881 bytes
+[download] 100% of 69.73MiB in 02:57
+```
\ No newline at end of file
diff --git a/packages/capture/index.js b/packages/capture/index.js
new file mode 100755
index 0000000..949bc16
--- /dev/null
+++ b/packages/capture/index.js
@@ -0,0 +1,155 @@
+#!/usr/bin/env node
+
+// import Capture from './src/Capture.js'
+// import Video from './src/Video.js'
+
+import dotenv from 'dotenv'
+dotenv.config()
+import { createId } from '@paralleldrive/cuid2'
+import os from 'os'
+import fs from 'node:fs'
+import { loggerFactory } from "./src/logger.js"
+import { verifyStorage } from './src/disk.js'
+import faye from 'faye'
+import { record, assertDependencyDirectory, checkFFmpeg } from './src/record.js'
+import fastq from 'fastq'
+import pRetry from 'p-retry';
+import Fastify from 'fastify';
+
+
+
+// Create a map to store the work queues
+const workQueues = new Map();
+
+
+
+async function captureTask (args, cb) {
+ const { appContext, playlistUrl, roomName } = args;
+
+ try {
+ const downloadStream = async () => {
+ const rc = await record(appContext, playlistUrl, roomName)
+ if (rc !== 0) throw new Error('ffmpeg exited irregularly (return code was other than zero)')
+ }
+ await pRetry(downloadStream, {
+ retries: 3,
+ onFailedAttempt: error => {
+ appContext.logger.log({ level: 'error', message: `downloadStream attempt ${error.attemptNumber} failed. There are ${error.retriesLeft} retries left.` });
+ },
+ })
+ } catch (e) {
+ // we can get here if all retries are exhausted.
+ // this could be that the stream is over, the playlistUrl might be different, etc.
+ // we might have queued tasks so we don't want to crash.
+ appContext.logger.log({ level: 'error', message: `downloadStream exhausted all retries.` })
+ appContext.logger.log({ level: 'error', message: e })
+ }
+
+ verifyStorage(appContext)
+
+ appContext.logger.log({ level: 'info', message: 'Capture task complete'})
+ cb(null, null)
+}
+
+/**
+ *
+ * Fastify is used to facilitate Docker health checks
+ *
+ */
+async function initFastify(appContext) {
+ appContext.fastify = Fastify({
+ logger: true
+ })
+
+ // Declare a route
+ appContext.fastify.get('/health', function (_, reply) {
+ reply.send({ message: 'futureporn-capture sneed' });
+ })
+
+ // Run the server!
+ appContext.fastify.listen({ port: appContext.env.PORT }, function (err, address) {
+ if (err) {
+ appContext.fastify.log.error(err)
+ process.exit(1)
+ }
+ })
+}
+
+async function init () {
+
+ const appEnv = new Array(
+ 'FUTUREPORN_WORKDIR',
+ 'DOWNLOADER_UA',
+ 'PORT'
+ )
+
+ const logger = loggerFactory({
+ service: 'futureporn/capture'
+ })
+
+
+ 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;
+ }, {}),
+ logger,
+ pkg: JSON.parse(fs.readFileSync('./package.json', { encoding: 'utf-8'})),
+ workerId: `${os.hostname}-${createId()}`,
+ };
+
+ await initFastify(appContext);
+
+ assertDependencyDirectory(appContext)
+ await checkFFmpeg(appContext)
+ verifyStorage(appContext)
+
+ return appContext
+}
+
+
+async function main () {
+
+ const appContext = await init()
+
+
+
+ appContext.logger.log({ level: 'info', message: `capture version: ${appContext.pkg.version}` })
+ appContext.logger.log({ level: 'info', message: `my capture directory is ${appContext.env.FUTUREPORN_WORKDIR}` })
+
+
+ // connect to realtime server
+ appContext.pubsub.subscribe('/signals', (message) => {
+ appContext.logger.log({ level: 'debug', message: JSON.stringify(message) })
+
+ if (
+ (message?.signal === 'start') &&
+ (message?.room) &&
+ (message?.url.startsWith('https://'))
+ ) {
+
+ const roomName = message.room;
+ const playlistUrl = message.url;
+
+ // Check if a work queue for the room already exists, otherwise create a new one
+ if (!workQueues.has(roomName)) {
+ workQueues.set(roomName, fastq(captureTask, 1));
+ }
+
+
+ // Push the task to the corresponding work queue
+ workQueues.get(roomName).push({ appContext, playlistUrl, roomName });
+ }
+
+ })
+
+
+
+}
+
+main()
+
+
+
+
diff --git a/packages/capture/package.json b/packages/capture/package.json
new file mode 100644
index 0000000..4d397c3
--- /dev/null
+++ b/packages/capture/package.json
@@ -0,0 +1,46 @@
+{
+ "name": "futureporn-capture",
+ "version": "0.1.12",
+ "main": "index.js",
+ "license": "Unlicense",
+ "private": true,
+ "type": "module",
+ "scripts": {
+ "start": "node --trace-warnings index",
+ "test": "FUTUREPORN_WORKDIR=/home/chris/Downloads mocha",
+ "integration": "FUTUREPORN_WORKDIR=/home/chris/Downloads mocha ./integration/**/*.test.js",
+ "dev": "FUTUREPORN_WORKDIR=/home/chris/Downloads nodemon index"
+ },
+ "dependencies": {
+ "@paralleldrive/cuid2": "^2.1.8",
+ "diskusage": "^1.1.3",
+ "dotenv": "^16.0.3",
+ "execa": "^6.1.0",
+ "fastify": "^4.12.0",
+ "fastq": "^1.15.0",
+ "faye": "^1.4.0",
+ "faye-websocket": "^0.11.4",
+ "fluent-ffmpeg": "^2.1.2",
+ "https": "^1.0.0",
+ "ioredis": "^5.2.4",
+ "minimatch": "^5.1.1",
+ "p-retry": "^5.1.2",
+ "postgres": "^3.3.3",
+ "rxjs": "^7.8.0",
+ "sql": "^0.78.0",
+ "winston": "^3.9.0",
+ "youtube-dl-wrap": "git+https://github.com/insanity54/youtube-dl-wrap.git"
+ },
+ "devDependencies": {
+ "chai": "^4.3.7",
+ "cheerio": "^1.0.0-rc.12",
+ "mocha": "^10.2.0",
+ "multiformats": "^11.0.1",
+ "node-abort-controller": "^3.0.1",
+ "node-fetch": "^3.3.0",
+ "nodemon": "^2.0.20",
+ "sinon": "^15.0.1",
+ "sinon-chai": "^3.7.0",
+ "sinon-test": "^3.1.5"
+ }
+}
diff --git a/packages/capture/pnpm-lock.yaml b/packages/capture/pnpm-lock.yaml
new file mode 100644
index 0000000..b6200e1
--- /dev/null
+++ b/packages/capture/pnpm-lock.yaml
@@ -0,0 +1,2139 @@
+lockfileVersion: '9.0'
+
+settings:
+ autoInstallPeers: true
+ excludeLinksFromLockfile: false
+
+importers:
+
+ .:
+ dependencies:
+ '@paralleldrive/cuid2':
+ specifier: ^2.1.8
+ version: 2.2.2
+ diskusage:
+ specifier: ^1.1.3
+ version: 1.2.0
+ dotenv:
+ specifier: ^16.0.3
+ version: 16.4.5
+ execa:
+ specifier: ^6.1.0
+ version: 6.1.0
+ fastify:
+ specifier: ^4.12.0
+ version: 4.27.0
+ fastq:
+ specifier: ^1.15.0
+ version: 1.17.1
+ faye:
+ specifier: ^1.4.0
+ version: 1.4.0
+ faye-websocket:
+ specifier: ^0.11.4
+ version: 0.11.4
+ fluent-ffmpeg:
+ specifier: ^2.1.2
+ version: 2.1.3
+ https:
+ specifier: ^1.0.0
+ version: 1.0.0
+ ioredis:
+ specifier: ^5.2.4
+ version: 5.4.1
+ minimatch:
+ specifier: ^5.1.1
+ version: 5.1.6
+ p-retry:
+ specifier: ^5.1.2
+ version: 5.1.2
+ postgres:
+ specifier: ^3.3.3
+ version: 3.4.4
+ rxjs:
+ specifier: ^7.8.0
+ version: 7.8.1
+ sql:
+ specifier: ^0.78.0
+ version: 0.78.0
+ winston:
+ specifier: ^3.9.0
+ version: 3.13.0
+ youtube-dl-wrap:
+ specifier: git+https://github.com/insanity54/youtube-dl-wrap.git
+ version: https://codeload.github.com/insanity54/youtube-dl-wrap/tar.gz/b47e9388063b4ef516624112ef59b7d11f7775d9
+ devDependencies:
+ chai:
+ specifier: ^4.3.7
+ version: 4.4.1
+ cheerio:
+ specifier: ^1.0.0-rc.12
+ version: 1.0.0-rc.12
+ mocha:
+ specifier: ^10.2.0
+ version: 10.4.0
+ multiformats:
+ specifier: ^11.0.1
+ version: 11.0.2
+ node-abort-controller:
+ specifier: ^3.0.1
+ version: 3.1.1
+ node-fetch:
+ specifier: ^3.3.0
+ version: 3.3.2
+ nodemon:
+ specifier: ^2.0.20
+ version: 2.0.22
+ sinon:
+ specifier: ^15.0.1
+ version: 15.2.0
+ sinon-chai:
+ specifier: ^3.7.0
+ version: 3.7.0(chai@4.4.1)(sinon@15.2.0)
+ sinon-test:
+ specifier: ^3.1.5
+ version: 3.1.6(sinon@15.2.0)
+
+packages:
+
+ '@colors/colors@1.6.0':
+ resolution: {integrity: sha512-Ir+AOibqzrIsL6ajt3Rz3LskB7OiMVHqltZmspbW/TJuTVuyOMirVqAkjfY6JISiLHgyNqicAC8AyHHGzNd/dA==}
+ engines: {node: '>=0.1.90'}
+
+ '@dabh/diagnostics@2.0.3':
+ resolution: {integrity: sha512-hrlQOIi7hAfzsMqlGSFyVucrx38O+j6wiGOf//H2ecvIEqYN4ADBSS2iLMh5UFyDunCNniUIPk/q3riFv45xRA==}
+
+ '@fastify/ajv-compiler@3.5.0':
+ resolution: {integrity: sha512-ebbEtlI7dxXF5ziNdr05mOY8NnDiPB1XvAlLHctRt/Rc+C3LCOVW5imUVX+mhvUhnNzmPBHewUkOFgGlCxgdAA==}
+
+ '@fastify/error@3.4.1':
+ resolution: {integrity: sha512-wWSvph+29GR783IhmvdwWnN4bUxTD01Vm5Xad4i7i1VuAOItLvbPAb69sb0IQ2N57yprvhNIwAP5B6xfKTmjmQ==}
+
+ '@fastify/fast-json-stringify-compiler@4.3.0':
+ resolution: {integrity: sha512-aZAXGYo6m22Fk1zZzEUKBvut/CIIQe/BapEORnxiD5Qr0kPHqqI69NtEMCme74h+at72sPhbkb4ZrLd1W3KRLA==}
+
+ '@fastify/merge-json-schemas@0.1.1':
+ resolution: {integrity: sha512-fERDVz7topgNjtXsJTTW1JKLy0rhuLRcquYqNR9rF7OcVpCa2OVW49ZPDIhaRRCaUuvVxI+N416xUoF76HNSXA==}
+
+ '@ioredis/commands@1.2.0':
+ resolution: {integrity: sha512-Sx1pU8EM64o2BrqNpEO1CNLtKQwyhuXuqyfH7oGKCk+1a33d2r5saW8zNwm3j6BTExtjrv2BxTgzzkMwts6vGg==}
+
+ '@noble/hashes@1.4.0':
+ resolution: {integrity: sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg==}
+ engines: {node: '>= 16'}
+
+ '@paralleldrive/cuid2@2.2.2':
+ resolution: {integrity: sha512-ZOBkgDwEdoYVlSeRbYYXs0S9MejQofiVYoTbKzy/6GQa39/q5tQU2IX46+shYnUkpEl3wc+J6wRlar7r2EK2xA==}
+
+ '@sinonjs/commons@2.0.0':
+ resolution: {integrity: sha512-uLa0j859mMrg2slwQYdO/AkrOfmH+X6LTVmNTS9CqexuE2IvVORIkSpJLqePAbEnKJ77aMmCwr1NUZ57120Xcg==}
+
+ '@sinonjs/commons@3.0.1':
+ resolution: {integrity: sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==}
+
+ '@sinonjs/fake-timers@10.3.0':
+ resolution: {integrity: sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==}
+
+ '@sinonjs/fake-timers@11.2.2':
+ resolution: {integrity: sha512-G2piCSxQ7oWOxwGSAyFHfPIsyeJGXYtc6mFbnFA+kRXkiEnTl8c/8jul2S329iFBnDI9HGoeWWAZvuvOkZccgw==}
+
+ '@sinonjs/samsam@8.0.0':
+ resolution: {integrity: sha512-Bp8KUVlLp8ibJZrnvq2foVhP0IVX2CIprMJPK0vqGqgrDa0OHVKeZyBykqskkrdxV6yKBPmGasO8LVjAKR3Gew==}
+
+ '@sinonjs/text-encoding@0.7.2':
+ resolution: {integrity: sha512-sXXKG+uL9IrKqViTtao2Ws6dy0znu9sOaP1di/jKGW1M6VssO8vlpXCQcpZ+jisQ1tTFAC5Jo/EOzFbggBagFQ==}
+
+ '@types/retry@0.12.1':
+ resolution: {integrity: sha512-xoDlM2S4ortawSWORYqsdU+2rxdh4LRW9ytc3zmT37RIKQh6IHyKwwtKhKis9ah8ol07DCkZxPt8BBvPjC6v4g==}
+
+ '@types/triple-beam@1.3.5':
+ resolution: {integrity: sha512-6WaYesThRMCl19iryMYP7/x2OVgCtbIVflDGFpWnb9irXI3UjYE4AzmYuiUKY1AJstGijoY+MgUszMgRxIYTYw==}
+
+ abort-controller@3.0.0:
+ resolution: {integrity: sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==}
+ engines: {node: '>=6.5'}
+
+ abstract-logging@2.0.1:
+ resolution: {integrity: sha512-2BjRTZxTPvheOvGbBslFSYOUkr+SjPtOnrLP33f+VIWLzezQpZcqVg7ja3L4dBXmzzgwT+a029jRx5PCi3JuiA==}
+
+ ajv-formats@2.1.1:
+ resolution: {integrity: sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==}
+ peerDependencies:
+ ajv: ^8.0.0
+ peerDependenciesMeta:
+ ajv:
+ optional: true
+
+ ajv-formats@3.0.1:
+ resolution: {integrity: sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==}
+ peerDependencies:
+ ajv: ^8.0.0
+ peerDependenciesMeta:
+ ajv:
+ optional: true
+
+ ajv@8.13.0:
+ resolution: {integrity: sha512-PRA911Blj99jR5RMeTunVbNXMF6Lp4vZXnk5GQjcnUWUTsrXtekg/pnmFFI2u/I36Y/2bITGS30GZCXei6uNkA==}
+
+ ansi-colors@4.1.1:
+ resolution: {integrity: sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==}
+ engines: {node: '>=6'}
+
+ ansi-regex@5.0.1:
+ resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==}
+ engines: {node: '>=8'}
+
+ ansi-styles@4.3.0:
+ resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==}
+ engines: {node: '>=8'}
+
+ anymatch@3.1.3:
+ resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==}
+ engines: {node: '>= 8'}
+
+ argparse@2.0.1:
+ resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==}
+
+ asap@2.0.6:
+ resolution: {integrity: sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==}
+
+ assertion-error@1.1.0:
+ resolution: {integrity: sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==}
+
+ async@0.2.10:
+ resolution: {integrity: sha512-eAkdoKxU6/LkKDBzLpT+t6Ff5EtfSF4wx1WfJiPEEV7WNLnDaRXk0oVysiEPm262roaachGexwUv94WhSgN5TQ==}
+
+ async@3.2.5:
+ resolution: {integrity: sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg==}
+
+ atomic-sleep@1.0.0:
+ resolution: {integrity: sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ==}
+ engines: {node: '>=8.0.0'}
+
+ avvio@8.3.2:
+ resolution: {integrity: sha512-st8e519GWHa/azv8S87mcJvZs4WsgTBjOw/Ih1CP6u+8SZvcOeAYNG6JbsIrAUUJJ7JfmrnOkR8ipDS+u9SIRQ==}
+
+ balanced-match@1.0.2:
+ resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
+
+ base64-js@1.5.1:
+ resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==}
+
+ binary-extensions@2.3.0:
+ resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==}
+ engines: {node: '>=8'}
+
+ boolbase@1.0.0:
+ resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==}
+
+ brace-expansion@1.1.11:
+ resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==}
+
+ brace-expansion@2.0.1:
+ resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==}
+
+ braces@3.0.3:
+ resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==}
+ engines: {node: '>=8'}
+
+ browser-stdout@1.3.1:
+ resolution: {integrity: sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==}
+
+ buffer@6.0.3:
+ resolution: {integrity: sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==}
+
+ camelcase@6.3.0:
+ resolution: {integrity: sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==}
+ engines: {node: '>=10'}
+
+ chai@4.4.1:
+ resolution: {integrity: sha512-13sOfMv2+DWduEU+/xbun3LScLoqN17nBeTLUsmDfKdoiC1fr0n9PU4guu4AhRcOVFk/sW8LyZWHuhWtQZiF+g==}
+ engines: {node: '>=4'}
+
+ chalk@4.1.2:
+ resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==}
+ engines: {node: '>=10'}
+
+ check-error@1.0.3:
+ resolution: {integrity: sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==}
+
+ cheerio-select@2.1.0:
+ resolution: {integrity: sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g==}
+
+ cheerio@1.0.0-rc.12:
+ resolution: {integrity: sha512-VqR8m68vM46BNnuZ5NtnGBKIE/DfN0cRIzg9n40EIq9NOv90ayxLBXA8fXC5gquFRGJSTRqBq25Jt2ECLR431Q==}
+ engines: {node: '>= 6'}
+
+ chokidar@3.5.3:
+ resolution: {integrity: sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==}
+ engines: {node: '>= 8.10.0'}
+
+ chokidar@3.6.0:
+ resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==}
+ engines: {node: '>= 8.10.0'}
+
+ cliui@7.0.4:
+ resolution: {integrity: sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==}
+
+ cluster-key-slot@1.1.2:
+ resolution: {integrity: sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA==}
+ engines: {node: '>=0.10.0'}
+
+ color-convert@1.9.3:
+ resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==}
+
+ color-convert@2.0.1:
+ resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==}
+ engines: {node: '>=7.0.0'}
+
+ color-name@1.1.3:
+ resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==}
+
+ 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==}
+
+ color@3.2.1:
+ resolution: {integrity: sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA==}
+
+ colorspace@1.1.4:
+ resolution: {integrity: sha512-BgvKJiuVu1igBUF2kEjRCZXol6wiiGbY5ipL/oVPwm0BL9sIpMIzM8IK7vwuxIIzOXMV3Ey5w+vxhm0rR/TN8w==}
+
+ concat-map@0.0.1:
+ resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==}
+
+ cookie@0.6.0:
+ resolution: {integrity: sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==}
+ engines: {node: '>= 0.6'}
+
+ cross-spawn@7.0.3:
+ resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==}
+ engines: {node: '>= 8'}
+
+ csprng@0.1.2:
+ resolution: {integrity: sha512-D3WAbvvgUVIqSxUfdvLeGjuotsB32bvfVPd+AaaTWMtyUeC9zgCnw5xs94no89yFLVsafvY9dMZEhTwsY/ZecA==}
+ engines: {node: '>=0.6.0'}
+
+ css-select@5.1.0:
+ resolution: {integrity: sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==}
+
+ css-what@6.1.0:
+ resolution: {integrity: sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==}
+ engines: {node: '>= 6'}
+
+ data-uri-to-buffer@4.0.1:
+ resolution: {integrity: sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==}
+ engines: {node: '>= 12'}
+
+ debug@3.2.7:
+ resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==}
+ peerDependencies:
+ supports-color: '*'
+ peerDependenciesMeta:
+ supports-color:
+ optional: true
+
+ debug@4.3.4:
+ resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==}
+ engines: {node: '>=6.0'}
+ peerDependencies:
+ supports-color: '*'
+ peerDependenciesMeta:
+ supports-color:
+ optional: true
+
+ decamelize@4.0.0:
+ resolution: {integrity: sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==}
+ engines: {node: '>=10'}
+
+ deep-eql@4.1.3:
+ resolution: {integrity: sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw==}
+ engines: {node: '>=6'}
+
+ denque@2.1.0:
+ resolution: {integrity: sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==}
+ engines: {node: '>=0.10'}
+
+ diff@5.0.0:
+ resolution: {integrity: sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==}
+ engines: {node: '>=0.3.1'}
+
+ diff@5.2.0:
+ resolution: {integrity: sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A==}
+ engines: {node: '>=0.3.1'}
+
+ diskusage@1.2.0:
+ resolution: {integrity: sha512-2u3OG3xuf5MFyzc4MctNRUKjjwK+UkovRYdD2ed/NZNZPrt0lqHnLKxGhlFVvAb4/oufIgQG3nWgwmeTbHOvXA==}
+
+ dom-serializer@2.0.0:
+ resolution: {integrity: sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==}
+
+ domelementtype@2.3.0:
+ resolution: {integrity: sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==}
+
+ domhandler@5.0.3:
+ resolution: {integrity: sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==}
+ engines: {node: '>= 4'}
+
+ domutils@3.1.0:
+ resolution: {integrity: sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==}
+
+ dotenv@16.4.5:
+ resolution: {integrity: sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==}
+ engines: {node: '>=12'}
+
+ emoji-regex@8.0.0:
+ resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==}
+
+ enabled@2.0.0:
+ resolution: {integrity: sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ==}
+
+ entities@4.5.0:
+ resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==}
+ engines: {node: '>=0.12'}
+
+ es6-promise@4.2.8:
+ resolution: {integrity: sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==}
+
+ escalade@3.1.2:
+ resolution: {integrity: sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==}
+ engines: {node: '>=6'}
+
+ escape-string-regexp@4.0.0:
+ resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==}
+ engines: {node: '>=10'}
+
+ event-target-shim@5.0.1:
+ resolution: {integrity: sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==}
+ engines: {node: '>=6'}
+
+ events@3.3.0:
+ resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==}
+ engines: {node: '>=0.8.x'}
+
+ execa@6.1.0:
+ resolution: {integrity: sha512-QVWlX2e50heYJcCPG0iWtf8r0xjEYfz/OYLGDYH+IyjWezzPNxz63qNFOu0l4YftGWuizFVZHHs8PrLU5p2IDA==}
+ engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
+
+ fast-content-type-parse@1.1.0:
+ resolution: {integrity: sha512-fBHHqSTFLVnR61C+gltJuE5GkVQMV0S2nqUO8TJ+5Z3qAKG8vAx4FKai1s5jq/inV1+sREynIWSuQ6HgoSXpDQ==}
+
+ fast-decode-uri-component@1.0.1:
+ resolution: {integrity: sha512-WKgKWg5eUxvRZGwW8FvfbaH7AXSh2cL+3j5fMGzUMCxWBJ3dV3a7Wz8y2f/uQ0e3B6WmodD3oS54jTQ9HVTIIg==}
+
+ fast-deep-equal@3.1.3:
+ resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==}
+
+ fast-json-stringify@5.16.0:
+ resolution: {integrity: sha512-A4bg6E15QrkuVO3f0SwIASgzMzR6XC4qTyTqhf3hYXy0iazbAdZKwkE+ox4WgzKyzM6ygvbdq3r134UjOaaAnA==}
+
+ fast-querystring@1.1.2:
+ resolution: {integrity: sha512-g6KuKWmFXc0fID8WWH0jit4g0AGBoJhCkJMb1RmbsSEUNvQ+ZC8D6CUZ+GtF8nMzSPXnhiePyyqqipzNNEnHjg==}
+
+ fast-redact@3.5.0:
+ resolution: {integrity: sha512-dwsoQlS7h9hMeYUq1W++23NDcBLV4KqONnITDV9DjfS3q1SgDGVrBdvvTLUotWtPSD7asWDV9/CmsZPy8Hf70A==}
+ engines: {node: '>=6'}
+
+ fast-uri@2.3.0:
+ resolution: {integrity: sha512-eel5UKGn369gGEWOqBShmFJWfq/xSJvsgDzgLYC845GneayWvXBf0lJCBn5qTABfewy1ZDPoaR5OZCP+kssfuw==}
+
+ fastify@4.27.0:
+ resolution: {integrity: sha512-ci9IXzbigB8dyi0mSy3faa3Bsj0xWAPb9JeT4KRzubdSb6pNhcADRUaXCBml6V1Ss/a05kbtQls5LBmhHydoTA==}
+
+ fastq@1.17.1:
+ resolution: {integrity: sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==}
+
+ faye-websocket@0.11.4:
+ resolution: {integrity: sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==}
+ engines: {node: '>=0.8.0'}
+
+ faye@1.4.0:
+ resolution: {integrity: sha512-kRrIg4be8VNYhycS2PY//hpBJSzZPr/DBbcy9VWelhZMW3KhyLkQR0HL0k0MNpmVoNFF4EdfMFkNAWjTP65g6w==}
+ engines: {node: '>=0.8.0'}
+
+ fecha@4.2.3:
+ resolution: {integrity: sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw==}
+
+ fetch-blob@3.2.0:
+ resolution: {integrity: sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==}
+ engines: {node: ^12.20 || >= 14.13}
+
+ fill-range@7.1.1:
+ resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==}
+ engines: {node: '>=8'}
+
+ find-my-way@8.2.0:
+ resolution: {integrity: sha512-HdWXgFYc6b1BJcOBDBwjqWuHJj1WYiqrxSh25qtU4DabpMFdj/gSunNBQb83t+8Zt67D7CXEzJWTkxaShMTMOA==}
+ engines: {node: '>=14'}
+
+ find-up@5.0.0:
+ resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==}
+ engines: {node: '>=10'}
+
+ flat@5.0.2:
+ resolution: {integrity: sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==}
+ hasBin: true
+
+ fluent-ffmpeg@2.1.3:
+ resolution: {integrity: sha512-Be3narBNt2s6bsaqP6Jzq91heDgOEaDCJAXcE3qcma/EJBSy5FB4cvO31XBInuAuKBx8Kptf8dkhjK0IOru39Q==}
+ engines: {node: '>=18'}
+
+ fn.name@1.1.0:
+ resolution: {integrity: sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==}
+
+ formdata-polyfill@4.0.10:
+ resolution: {integrity: sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==}
+ engines: {node: '>=12.20.0'}
+
+ forwarded@0.2.0:
+ resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==}
+ engines: {node: '>= 0.6'}
+
+ fs.realpath@1.0.0:
+ resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==}
+
+ fsevents@2.3.3:
+ resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==}
+ engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
+ os: [darwin]
+
+ get-caller-file@2.0.5:
+ resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==}
+ engines: {node: 6.* || 8.* || >= 10.*}
+
+ get-func-name@2.0.2:
+ resolution: {integrity: sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==}
+
+ get-stream@6.0.1:
+ resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==}
+ engines: {node: '>=10'}
+
+ glob-parent@5.1.2:
+ resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==}
+ engines: {node: '>= 6'}
+
+ glob@8.1.0:
+ resolution: {integrity: sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==}
+ engines: {node: '>=12'}
+
+ 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'}
+
+ he@1.2.0:
+ resolution: {integrity: sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==}
+ hasBin: true
+
+ htmlparser2@8.0.2:
+ resolution: {integrity: sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==}
+
+ http-parser-js@0.5.8:
+ resolution: {integrity: sha512-SGeBX54F94Wgu5RH3X5jsDtf4eHyRogWX1XGT3b4HuW3tQPM4AaBzoUji/4AAJNXCEOWZ5O0DgZmJw1947gD5Q==}
+
+ https@1.0.0:
+ resolution: {integrity: sha512-4EC57ddXrkaF0x83Oj8sM6SLQHAWXw90Skqu2M4AEWENZ3F02dFJE/GARA8igO79tcgYqGrD7ae4f5L3um2lgg==}
+
+ human-signals@3.0.1:
+ resolution: {integrity: sha512-rQLskxnM/5OCldHo+wNXbpVgDn5A17CUoKX+7Sokwaknlq7CdSnphy0W39GU8dw59XiCXmFXDg4fRuckQRKewQ==}
+ engines: {node: '>=12.20.0'}
+
+ ieee754@1.2.1:
+ resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==}
+
+ ignore-by-default@1.0.1:
+ resolution: {integrity: sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==}
+
+ inflight@1.0.6:
+ resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==}
+ deprecated: This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.
+
+ inherits@2.0.4:
+ resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==}
+
+ ioredis@5.4.1:
+ resolution: {integrity: sha512-2YZsvl7jopIa1gaePkeMtd9rAcSjOOjPtpcLlOeusyO+XH2SK5ZcT+UCrElPP+WVIInh2TzeI4XW9ENaSLVVHA==}
+ engines: {node: '>=12.22.0'}
+
+ ipaddr.js@1.9.1:
+ resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==}
+ engines: {node: '>= 0.10'}
+
+ is-arrayish@0.3.2:
+ resolution: {integrity: sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==}
+
+ is-binary-path@2.1.0:
+ resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==}
+ engines: {node: '>=8'}
+
+ is-extglob@2.1.1:
+ resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==}
+ engines: {node: '>=0.10.0'}
+
+ is-fullwidth-code-point@3.0.0:
+ resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==}
+ engines: {node: '>=8'}
+
+ is-glob@4.0.3:
+ resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==}
+ engines: {node: '>=0.10.0'}
+
+ is-number@7.0.0:
+ resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==}
+ engines: {node: '>=0.12.0'}
+
+ is-plain-obj@2.1.0:
+ resolution: {integrity: sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==}
+ engines: {node: '>=8'}
+
+ is-stream@2.0.1:
+ resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==}
+ engines: {node: '>=8'}
+
+ is-stream@3.0.0:
+ resolution: {integrity: sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==}
+ engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
+
+ is-unicode-supported@0.1.0:
+ resolution: {integrity: sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==}
+ engines: {node: '>=10'}
+
+ isexe@2.0.0:
+ resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==}
+
+ js-yaml@4.1.0:
+ resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==}
+ hasBin: true
+
+ json-schema-ref-resolver@1.0.1:
+ resolution: {integrity: sha512-EJAj1pgHc1hxF6vo2Z3s69fMjO1INq6eGHXZ8Z6wCQeldCuwxGK9Sxf4/cScGn3FZubCVUehfWtcDM/PLteCQw==}
+
+ json-schema-traverse@1.0.0:
+ resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==}
+
+ just-extend@6.2.0:
+ resolution: {integrity: sha512-cYofQu2Xpom82S6qD778jBDpwvvy39s1l/hrYij2u9AMdQcGRpaBu6kY4mVhuno5kJVi1DAz4aiphA2WI1/OAw==}
+
+ kuler@2.0.0:
+ resolution: {integrity: sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A==}
+
+ light-my-request@5.13.0:
+ resolution: {integrity: sha512-9IjUN9ZyCS9pTG+KqTDEQo68Sui2lHsYBrfMyVUTTZ3XhH8PMZq7xO94Kr+eP9dhi/kcKsx4N41p2IXEBil1pQ==}
+
+ locate-path@6.0.0:
+ resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==}
+ engines: {node: '>=10'}
+
+ lodash.defaults@4.2.0:
+ resolution: {integrity: sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ==}
+
+ lodash.get@4.4.2:
+ resolution: {integrity: sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==}
+
+ lodash.isarguments@3.1.0:
+ resolution: {integrity: sha512-chi4NHZlZqZD18a0imDHnZPrDeBbTtVN7GXMwuGdRH9qotxAjYs3aVLKc7zNOG9eddR5Ksd8rvFEBc9SsggPpg==}
+
+ lodash@4.1.0:
+ resolution: {integrity: sha512-B9sgtKUlz0xe7lkYb80BcOpwwJJw5iOiz4HkBDzF0+i5nJLiwfBnL08m7bBkCOPBfi+0aqvrJDMdZDfAvs8vYg==}
+
+ log-symbols@4.1.0:
+ resolution: {integrity: sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==}
+ engines: {node: '>=10'}
+
+ logform@2.6.0:
+ resolution: {integrity: sha512-1ulHeNPp6k/LD8H91o7VYFBng5i1BDE7HoKxVbZiGFidS1Rj65qcywLxX+pVfAPoQJEjRdvKcusKwOupHCVOVQ==}
+ engines: {node: '>= 12.0.0'}
+
+ loupe@2.3.7:
+ resolution: {integrity: sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA==}
+
+ merge-stream@2.0.0:
+ resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==}
+
+ mimic-fn@4.0.0:
+ resolution: {integrity: sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==}
+ engines: {node: '>=12'}
+
+ minimatch@3.1.2:
+ resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==}
+
+ minimatch@5.0.1:
+ resolution: {integrity: sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==}
+ engines: {node: '>=10'}
+
+ minimatch@5.1.6:
+ resolution: {integrity: sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==}
+ engines: {node: '>=10'}
+
+ mocha@10.4.0:
+ resolution: {integrity: sha512-eqhGB8JKapEYcC4ytX/xrzKforgEc3j1pGlAXVy3eRwrtAy5/nIfT1SvgGzfN0XZZxeLq0aQWkOUAmqIJiv+bA==}
+ engines: {node: '>= 14.0.0'}
+ hasBin: true
+
+ 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@11.0.2:
+ resolution: {integrity: sha512-b5mYMkOkARIuVZCpvijFj9a6m5wMVLC7cf/jIPd5D/ARDOfLC5+IFkbgDXQgcU2goIsTD/O9NY4DI/Mt4OGvlg==}
+ engines: {node: '>=16.0.0', npm: '>=7.0.0'}
+
+ nan@2.19.0:
+ resolution: {integrity: sha512-nO1xXxfh/RWNxfd/XPfbIfFk5vgLsAxUR9y5O0cHMJu/AW9U95JLXqthYHjEp+8gQ5p96K9jUp8nbVOxCdRbtw==}
+
+ nise@5.1.9:
+ resolution: {integrity: sha512-qOnoujW4SV6e40dYxJOb3uvuoPHtmLzIk4TFo+j0jPJoC+5Z9xja5qH5JZobEPsa8+YYphMrOSwnrshEhG2qww==}
+
+ node-abort-controller@3.1.1:
+ resolution: {integrity: sha512-AGK2yQKIjRuqnc6VkX2Xj5d+QW8xZ87pa1UK6yA6ouUyuxfHuMP6umE5QK7UmTeOAymo+Zx1Fxiuw9rVx8taHQ==}
+
+ node-domexception@1.0.0:
+ resolution: {integrity: sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==}
+ engines: {node: '>=10.5.0'}
+
+ node-fetch@3.3.2:
+ resolution: {integrity: sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==}
+ engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
+
+ nodemon@2.0.22:
+ resolution: {integrity: sha512-B8YqaKMmyuCO7BowF1Z1/mkPqLk6cs/l63Ojtd6otKjMx47Dq1utxfRxcavH1I7VSaL8n5BUaoutadnsX3AAVQ==}
+ engines: {node: '>=8.10.0'}
+ hasBin: true
+
+ normalize-path@3.0.0:
+ resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==}
+ engines: {node: '>=0.10.0'}
+
+ npm-run-path@5.3.0:
+ resolution: {integrity: sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==}
+ engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
+
+ nth-check@2.1.1:
+ resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==}
+
+ on-exit-leak-free@2.1.2:
+ resolution: {integrity: sha512-0eJJY6hXLGf1udHwfNftBqH+g73EU4B504nZeKpz1sYRKafAghwxEJunB2O7rDZkL4PGfsMVnTXZ2EjibbqcsA==}
+ engines: {node: '>=14.0.0'}
+
+ once@1.4.0:
+ resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==}
+
+ one-time@1.0.0:
+ resolution: {integrity: sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g==}
+
+ onetime@6.0.0:
+ resolution: {integrity: sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==}
+ engines: {node: '>=12'}
+
+ p-limit@3.1.0:
+ resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==}
+ engines: {node: '>=10'}
+
+ p-locate@5.0.0:
+ resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==}
+ engines: {node: '>=10'}
+
+ p-retry@5.1.2:
+ resolution: {integrity: sha512-couX95waDu98NfNZV+i/iLt+fdVxmI7CbrrdC2uDWfPdUAApyxT4wmDlyOtR5KtTDmkDO0zDScDjDou9YHhd9g==}
+ engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
+
+ parse5-htmlparser2-tree-adapter@7.0.0:
+ resolution: {integrity: sha512-B77tOZrqqfUfnVcOrUvfdLbz4pu4RopLD/4vmu3HUPswwTA8OH0EMW9BlWR2B0RCoiZRAHEUu7IxeP1Pd1UU+g==}
+
+ parse5@7.1.2:
+ resolution: {integrity: sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==}
+
+ path-exists@4.0.0:
+ resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==}
+ engines: {node: '>=8'}
+
+ path-key@3.1.1:
+ resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==}
+ engines: {node: '>=8'}
+
+ path-key@4.0.0:
+ resolution: {integrity: sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==}
+ engines: {node: '>=12'}
+
+ path-to-regexp@6.2.2:
+ resolution: {integrity: sha512-GQX3SSMokngb36+whdpRXE+3f9V8UzyAorlYvOGx87ufGHehNTn5lCxrKtLyZ4Yl/wEKnNnr98ZzOwwDZV5ogw==}
+
+ pathval@1.1.1:
+ resolution: {integrity: sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==}
+
+ picomatch@2.3.1:
+ resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==}
+ engines: {node: '>=8.6'}
+
+ pino-abstract-transport@1.2.0:
+ resolution: {integrity: sha512-Guhh8EZfPCfH+PMXAb6rKOjGQEoy0xlAIn+irODG5kgfYV+BQ0rGYYWTIel3P5mmyXqkYkPmdIkywsn6QKUR1Q==}
+
+ pino-std-serializers@7.0.0:
+ resolution: {integrity: sha512-e906FRY0+tV27iq4juKzSYPbUj2do2X2JX4EzSca1631EB2QJQUqGbDuERal7LCtOpxl6x3+nvo9NPZcmjkiFA==}
+
+ pino@9.1.0:
+ resolution: {integrity: sha512-qUcgfrlyOtjwhNLdbhoL7NR4NkHjzykAPw0V2QLFbvu/zss29h4NkRnibyFzBrNCbzCOY3WZ9hhKSwfOkNggYA==}
+ hasBin: true
+
+ postgres@3.4.4:
+ resolution: {integrity: sha512-IbyN+9KslkqcXa8AO9fxpk97PA4pzewvpi2B3Dwy9u4zpV32QicaEdgmF3eSQUzdRk7ttDHQejNgAEr4XoeH4A==}
+ engines: {node: '>=12'}
+
+ process-warning@3.0.0:
+ resolution: {integrity: sha512-mqn0kFRl0EoqhnL0GQ0veqFHyIN1yig9RHh/InzORTUiZHFRAur+aMtRkELNwGs9aNwKS6tg/An4NYBPGwvtzQ==}
+
+ process@0.11.10:
+ resolution: {integrity: sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==}
+ engines: {node: '>= 0.6.0'}
+
+ proxy-addr@2.0.7:
+ resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==}
+ engines: {node: '>= 0.10'}
+
+ psl@1.9.0:
+ resolution: {integrity: sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==}
+
+ pstree.remy@1.1.8:
+ resolution: {integrity: sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==}
+
+ punycode@2.3.1:
+ resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==}
+ engines: {node: '>=6'}
+
+ querystringify@2.2.0:
+ resolution: {integrity: sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==}
+
+ quick-format-unescaped@4.0.4:
+ resolution: {integrity: sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==}
+
+ randombytes@2.1.0:
+ resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==}
+
+ readable-stream@3.6.2:
+ resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==}
+ engines: {node: '>= 6'}
+
+ readable-stream@4.5.2:
+ resolution: {integrity: sha512-yjavECdqeZ3GLXNgRXgeQEdz9fvDDkNKyHnbHRFtOr7/LcfgBcmct7t/ET+HaCTqfh06OzoAxrkN/IfjJBVe+g==}
+ engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+
+ readdirp@3.6.0:
+ resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==}
+ engines: {node: '>=8.10.0'}
+
+ real-require@0.2.0:
+ resolution: {integrity: sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg==}
+ engines: {node: '>= 12.13.0'}
+
+ redis-errors@1.2.0:
+ resolution: {integrity: sha512-1qny3OExCf0UvUV/5wpYKf2YwPcOqXzkwKKSmKHiE6ZMQs5heeE/c8eXK+PNllPvmjgAbfnsbpkGZWy8cBpn9w==}
+ engines: {node: '>=4'}
+
+ redis-parser@3.0.0:
+ resolution: {integrity: sha512-DJnGAeenTdpMEH6uAJRK/uiyEIH9WVsUmoLwzudwGJUwZPp80PDBWPHXSAGNPwNvIXAbe7MSUB1zQFugFml66A==}
+ engines: {node: '>=4'}
+
+ require-directory@2.1.1:
+ resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==}
+ engines: {node: '>=0.10.0'}
+
+ require-from-string@2.0.2:
+ resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==}
+ engines: {node: '>=0.10.0'}
+
+ requires-port@1.0.0:
+ resolution: {integrity: sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==}
+
+ ret@0.4.3:
+ resolution: {integrity: sha512-0f4Memo5QP7WQyUEAYUO3esD/XjOc3Zjjg5CPsAq1p8sIu0XPeMbHJemKA0BO7tV0X7+A0FoEpbmHXWxPyD3wQ==}
+ engines: {node: '>=10'}
+
+ retry@0.13.1:
+ resolution: {integrity: sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==}
+ engines: {node: '>= 4'}
+
+ reusify@1.0.4:
+ resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==}
+ engines: {iojs: '>=1.0.0', node: '>=0.10.0'}
+
+ rfdc@1.3.1:
+ resolution: {integrity: sha512-r5a3l5HzYlIC68TpmYKlxWjmOP6wiPJ1vWv2HeLhNsRZMrCkxeqxiHlQ21oXmQ4F3SiryXBHhAD7JZqvOJjFmg==}
+
+ rxjs@7.8.1:
+ resolution: {integrity: sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==}
+
+ safe-buffer@5.2.1:
+ resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==}
+
+ safe-regex2@3.1.0:
+ resolution: {integrity: sha512-RAAZAGbap2kBfbVhvmnTFv73NWLMvDGOITFYTZBAaY8eR+Ir4ef7Up/e7amo+y1+AH+3PtLkrt9mvcTsG9LXug==}
+
+ safe-stable-stringify@2.4.3:
+ resolution: {integrity: sha512-e2bDA2WJT0wxseVd4lsDP4+3ONX6HpMXQa1ZhFQ7SU+GjvORCmShbCMltrtIDfkYhVHrOcPtj+KhmDBdPdZD1g==}
+ engines: {node: '>=10'}
+
+ secure-json-parse@2.7.0:
+ resolution: {integrity: sha512-6aU+Rwsezw7VR8/nyvKTx8QpWH9FrcYiXXlqC4z5d5XQBDRqtbfsRjnwGyqbi3gddNtWHuEk9OANUotL26qKUw==}
+
+ semver@5.7.2:
+ resolution: {integrity: sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==}
+ hasBin: true
+
+ semver@7.0.0:
+ resolution: {integrity: sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==}
+ hasBin: true
+
+ semver@7.6.2:
+ resolution: {integrity: sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==}
+ engines: {node: '>=10'}
+ hasBin: true
+
+ sequin@0.1.1:
+ resolution: {integrity: sha512-hJWMZRwP75ocoBM+1/YaCsvS0j5MTPeBHJkS2/wruehl9xwtX30HlDF1Gt6UZ8HHHY8SJa2/IL+jo+JJCd59rA==}
+ engines: {node: '>=0.4.0'}
+
+ serialize-javascript@6.0.0:
+ resolution: {integrity: sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==}
+
+ set-cookie-parser@2.6.0:
+ resolution: {integrity: sha512-RVnVQxTXuerk653XfuliOxBP81Sf0+qfQE73LIYKcyMYHG94AuH0kgrQpRDuTZnSmjpysHmzxJXKNfa6PjFhyQ==}
+
+ shebang-command@2.0.0:
+ resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==}
+ engines: {node: '>=8'}
+
+ shebang-regex@3.0.0:
+ resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==}
+ engines: {node: '>=8'}
+
+ signal-exit@3.0.7:
+ resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==}
+
+ simple-swizzle@0.2.2:
+ resolution: {integrity: sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==}
+
+ simple-update-notifier@1.1.0:
+ resolution: {integrity: sha512-VpsrsJSUcJEseSbMHkrsrAVSdvVS5I96Qo1QAQ4FxQ9wXFcB+pjj7FB7/us9+GcgfW4ziHtYMc1J0PLczb55mg==}
+ engines: {node: '>=8.10.0'}
+
+ sinon-chai@3.7.0:
+ resolution: {integrity: sha512-mf5NURdUaSdnatJx3uhoBOrY9dtL19fiOtAdT1Azxg3+lNJFiuN0uzaU3xX1LeAfL17kHQhTAJgpsfhbMJMY2g==}
+ peerDependencies:
+ chai: ^4.0.0
+ sinon: '>=4.0.0'
+
+ sinon-test@3.1.6:
+ resolution: {integrity: sha512-3jBJGf61sS2EN3M+YuIiIbeutKrubP6SFolceTcJrubG+4s+zq3rey/y0huSEwU2ECKOcyCs7EkzANnwqHWPjA==}
+ peerDependencies:
+ sinon: '>= 2.x'
+
+ sinon@15.2.0:
+ resolution: {integrity: sha512-nPS85arNqwBXaIsFCkolHjGIkFo+Oxu9vbgmBJizLAhqe6P2o3Qmj3KCUoRkfhHtvgDhZdWD3risLHAUJ8npjw==}
+ deprecated: 16.1.1
+
+ sliced@0.0.5:
+ resolution: {integrity: sha512-9bYT917D6H3+q8GlQBJmLVz3bc4OeVGfZ2BB12wvLnluTGfG6/8UdOUbKJDW1EEx9SZMDbjnatkau5/XcUeyOw==}
+
+ sonic-boom@4.0.1:
+ resolution: {integrity: sha512-hTSD/6JMLyT4r9zeof6UtuBDpjJ9sO08/nmS5djaA9eozT9oOlNdpXSnzcgj4FTqpk3nkLrs61l4gip9r1HCrQ==}
+
+ split2@4.2.0:
+ resolution: {integrity: sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==}
+ engines: {node: '>= 10.x'}
+
+ sql@0.78.0:
+ resolution: {integrity: sha512-+If27aF3UQxmnuF5JgTJKd/X6TiELa1f58Zo5TX9ULbPnqs1fBDODwwbtU0WwM5H3lSiwx2En4m2lB1rCoIhvQ==}
+
+ stack-trace@0.0.10:
+ resolution: {integrity: sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg==}
+
+ standard-as-callback@2.1.0:
+ resolution: {integrity: sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A==}
+
+ string-width@4.2.3:
+ resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==}
+ engines: {node: '>=8'}
+
+ string_decoder@1.3.0:
+ resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==}
+
+ strip-ansi@6.0.1:
+ resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==}
+ engines: {node: '>=8'}
+
+ strip-final-newline@3.0.0:
+ resolution: {integrity: sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==}
+ engines: {node: '>=12'}
+
+ strip-json-comments@3.1.1:
+ resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==}
+ engines: {node: '>=8'}
+
+ supports-color@5.5.0:
+ resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==}
+ engines: {node: '>=4'}
+
+ supports-color@7.2.0:
+ resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==}
+ engines: {node: '>=8'}
+
+ supports-color@8.1.1:
+ resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==}
+ engines: {node: '>=10'}
+
+ text-hex@1.0.0:
+ resolution: {integrity: sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==}
+
+ thread-stream@3.0.1:
+ resolution: {integrity: sha512-O5O/RbdV3CjhtwFa4slXvrb/26lzsf4/NMts3QFIRniIsi+584QSneJXaHXasqcZO+B7pWZkr+4h9knhnAQevg==}
+
+ to-regex-range@5.0.1:
+ resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==}
+ engines: {node: '>=8.0'}
+
+ toad-cache@3.7.0:
+ resolution: {integrity: sha512-/m8M+2BJUpoJdgAHoG+baCwBT+tf2VraSfkBgl0Y00qIWt41DJ8R5B8nsEw0I58YwF5IZH6z24/2TobDKnqSWw==}
+ engines: {node: '>=12'}
+
+ touch@3.1.1:
+ resolution: {integrity: sha512-r0eojU4bI8MnHr8c5bNo7lJDdI2qXlWWJk6a9EAFG7vbhTjElYhBVS3/miuE0uOuoLdb8Mc/rVfsmm6eo5o9GA==}
+ hasBin: true
+
+ tough-cookie@4.1.4:
+ resolution: {integrity: sha512-Loo5UUvLD9ScZ6jh8beX1T6sO1w2/MpCRpEP7V280GKMVUQ0Jzar2U3UJPsrdbziLEMMhu3Ujnq//rhiFuIeag==}
+ engines: {node: '>=6'}
+
+ triple-beam@1.4.1:
+ resolution: {integrity: sha512-aZbgViZrg1QNcG+LULa7nhZpJTZSLm/mXnHXnbAbjmN5aSa0y7V+wvv6+4WaBtpISJzThKy+PIPxc1Nq1EJ9mg==}
+ engines: {node: '>= 14.0.0'}
+
+ tslib@2.6.2:
+ resolution: {integrity: sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==}
+
+ tunnel-agent@0.6.0:
+ resolution: {integrity: sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==}
+
+ type-detect@4.0.8:
+ resolution: {integrity: sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==}
+ engines: {node: '>=4'}
+
+ undefsafe@2.0.5:
+ resolution: {integrity: sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==}
+
+ universalify@0.2.0:
+ resolution: {integrity: sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==}
+ engines: {node: '>= 4.0.0'}
+
+ uri-js@4.4.1:
+ resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==}
+
+ url-parse@1.5.10:
+ resolution: {integrity: sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==}
+
+ util-deprecate@1.0.2:
+ resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==}
+
+ web-streams-polyfill@3.3.3:
+ resolution: {integrity: sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==}
+ engines: {node: '>= 8'}
+
+ websocket-driver@0.7.4:
+ resolution: {integrity: sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==}
+ engines: {node: '>=0.8.0'}
+
+ websocket-extensions@0.1.4:
+ resolution: {integrity: sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==}
+ engines: {node: '>=0.8.0'}
+
+ which@1.3.1:
+ resolution: {integrity: sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==}
+ hasBin: true
+
+ which@2.0.2:
+ resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==}
+ engines: {node: '>= 8'}
+ hasBin: true
+
+ winston-transport@4.7.0:
+ resolution: {integrity: sha512-ajBj65K5I7denzer2IYW6+2bNIVqLGDHqDw3Ow8Ohh+vdW+rv4MZ6eiDvHoKhfJFZ2auyN8byXieDDJ96ViONg==}
+ engines: {node: '>= 12.0.0'}
+
+ winston@3.13.0:
+ resolution: {integrity: sha512-rwidmA1w3SE4j0E5MuIufFhyJPBDG7Nu71RkZor1p2+qHvJSZ9GYDA81AyleQcZbh/+V6HjeBdfnTZJm9rSeQQ==}
+ engines: {node: '>= 12.0.0'}
+
+ workerpool@6.2.1:
+ resolution: {integrity: sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw==}
+
+ wrap-ansi@7.0.0:
+ resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==}
+ engines: {node: '>=10'}
+
+ wrappy@1.0.2:
+ resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==}
+
+ y18n@5.0.8:
+ resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==}
+ engines: {node: '>=10'}
+
+ yargs-parser@20.2.4:
+ resolution: {integrity: sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==}
+ engines: {node: '>=10'}
+
+ yargs-unparser@2.0.0:
+ resolution: {integrity: sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==}
+ engines: {node: '>=10'}
+
+ yargs@16.2.0:
+ resolution: {integrity: sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==}
+ engines: {node: '>=10'}
+
+ yocto-queue@0.1.0:
+ resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==}
+ engines: {node: '>=10'}
+
+ youtube-dl-wrap@https://codeload.github.com/insanity54/youtube-dl-wrap/tar.gz/b47e9388063b4ef516624112ef59b7d11f7775d9:
+ resolution: {tarball: https://codeload.github.com/insanity54/youtube-dl-wrap/tar.gz/b47e9388063b4ef516624112ef59b7d11f7775d9}
+ version: 2.1.1
+
+snapshots:
+
+ '@colors/colors@1.6.0': {}
+
+ '@dabh/diagnostics@2.0.3':
+ dependencies:
+ colorspace: 1.1.4
+ enabled: 2.0.0
+ kuler: 2.0.0
+
+ '@fastify/ajv-compiler@3.5.0':
+ dependencies:
+ ajv: 8.13.0
+ ajv-formats: 2.1.1(ajv@8.13.0)
+ fast-uri: 2.3.0
+
+ '@fastify/error@3.4.1': {}
+
+ '@fastify/fast-json-stringify-compiler@4.3.0':
+ dependencies:
+ fast-json-stringify: 5.16.0
+
+ '@fastify/merge-json-schemas@0.1.1':
+ dependencies:
+ fast-deep-equal: 3.1.3
+
+ '@ioredis/commands@1.2.0': {}
+
+ '@noble/hashes@1.4.0': {}
+
+ '@paralleldrive/cuid2@2.2.2':
+ dependencies:
+ '@noble/hashes': 1.4.0
+
+ '@sinonjs/commons@2.0.0':
+ dependencies:
+ type-detect: 4.0.8
+
+ '@sinonjs/commons@3.0.1':
+ dependencies:
+ type-detect: 4.0.8
+
+ '@sinonjs/fake-timers@10.3.0':
+ dependencies:
+ '@sinonjs/commons': 3.0.1
+
+ '@sinonjs/fake-timers@11.2.2':
+ dependencies:
+ '@sinonjs/commons': 3.0.1
+
+ '@sinonjs/samsam@8.0.0':
+ dependencies:
+ '@sinonjs/commons': 2.0.0
+ lodash.get: 4.4.2
+ type-detect: 4.0.8
+
+ '@sinonjs/text-encoding@0.7.2': {}
+
+ '@types/retry@0.12.1': {}
+
+ '@types/triple-beam@1.3.5': {}
+
+ abort-controller@3.0.0:
+ dependencies:
+ event-target-shim: 5.0.1
+
+ abstract-logging@2.0.1: {}
+
+ ajv-formats@2.1.1(ajv@8.13.0):
+ optionalDependencies:
+ ajv: 8.13.0
+
+ ajv-formats@3.0.1(ajv@8.13.0):
+ optionalDependencies:
+ ajv: 8.13.0
+
+ ajv@8.13.0:
+ dependencies:
+ fast-deep-equal: 3.1.3
+ json-schema-traverse: 1.0.0
+ require-from-string: 2.0.2
+ uri-js: 4.4.1
+
+ ansi-colors@4.1.1: {}
+
+ ansi-regex@5.0.1: {}
+
+ ansi-styles@4.3.0:
+ dependencies:
+ color-convert: 2.0.1
+
+ anymatch@3.1.3:
+ dependencies:
+ normalize-path: 3.0.0
+ picomatch: 2.3.1
+
+ argparse@2.0.1: {}
+
+ asap@2.0.6: {}
+
+ assertion-error@1.1.0: {}
+
+ async@0.2.10: {}
+
+ async@3.2.5: {}
+
+ atomic-sleep@1.0.0: {}
+
+ avvio@8.3.2:
+ dependencies:
+ '@fastify/error': 3.4.1
+ fastq: 1.17.1
+
+ balanced-match@1.0.2: {}
+
+ base64-js@1.5.1: {}
+
+ binary-extensions@2.3.0: {}
+
+ boolbase@1.0.0: {}
+
+ brace-expansion@1.1.11:
+ dependencies:
+ balanced-match: 1.0.2
+ concat-map: 0.0.1
+
+ brace-expansion@2.0.1:
+ dependencies:
+ balanced-match: 1.0.2
+
+ braces@3.0.3:
+ dependencies:
+ fill-range: 7.1.1
+
+ browser-stdout@1.3.1: {}
+
+ buffer@6.0.3:
+ dependencies:
+ base64-js: 1.5.1
+ ieee754: 1.2.1
+
+ camelcase@6.3.0: {}
+
+ chai@4.4.1:
+ dependencies:
+ assertion-error: 1.1.0
+ check-error: 1.0.3
+ deep-eql: 4.1.3
+ get-func-name: 2.0.2
+ loupe: 2.3.7
+ pathval: 1.1.1
+ type-detect: 4.0.8
+
+ chalk@4.1.2:
+ dependencies:
+ ansi-styles: 4.3.0
+ supports-color: 7.2.0
+
+ check-error@1.0.3:
+ dependencies:
+ get-func-name: 2.0.2
+
+ cheerio-select@2.1.0:
+ dependencies:
+ boolbase: 1.0.0
+ css-select: 5.1.0
+ css-what: 6.1.0
+ domelementtype: 2.3.0
+ domhandler: 5.0.3
+ domutils: 3.1.0
+
+ cheerio@1.0.0-rc.12:
+ dependencies:
+ cheerio-select: 2.1.0
+ dom-serializer: 2.0.0
+ domhandler: 5.0.3
+ domutils: 3.1.0
+ htmlparser2: 8.0.2
+ parse5: 7.1.2
+ parse5-htmlparser2-tree-adapter: 7.0.0
+
+ chokidar@3.5.3:
+ dependencies:
+ anymatch: 3.1.3
+ braces: 3.0.3
+ 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
+
+ chokidar@3.6.0:
+ dependencies:
+ anymatch: 3.1.3
+ braces: 3.0.3
+ 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
+
+ cliui@7.0.4:
+ dependencies:
+ string-width: 4.2.3
+ strip-ansi: 6.0.1
+ wrap-ansi: 7.0.0
+
+ cluster-key-slot@1.1.2: {}
+
+ color-convert@1.9.3:
+ dependencies:
+ color-name: 1.1.3
+
+ color-convert@2.0.1:
+ dependencies:
+ color-name: 1.1.4
+
+ color-name@1.1.3: {}
+
+ color-name@1.1.4: {}
+
+ color-string@1.9.1:
+ dependencies:
+ color-name: 1.1.4
+ simple-swizzle: 0.2.2
+
+ color@3.2.1:
+ dependencies:
+ color-convert: 1.9.3
+ color-string: 1.9.1
+
+ colorspace@1.1.4:
+ dependencies:
+ color: 3.2.1
+ text-hex: 1.0.0
+
+ concat-map@0.0.1: {}
+
+ cookie@0.6.0: {}
+
+ cross-spawn@7.0.3:
+ dependencies:
+ path-key: 3.1.1
+ shebang-command: 2.0.0
+ which: 2.0.2
+
+ csprng@0.1.2:
+ dependencies:
+ sequin: 0.1.1
+
+ css-select@5.1.0:
+ dependencies:
+ boolbase: 1.0.0
+ css-what: 6.1.0
+ domhandler: 5.0.3
+ domutils: 3.1.0
+ nth-check: 2.1.1
+
+ css-what@6.1.0: {}
+
+ data-uri-to-buffer@4.0.1: {}
+
+ debug@3.2.7(supports-color@5.5.0):
+ dependencies:
+ ms: 2.1.3
+ optionalDependencies:
+ supports-color: 5.5.0
+
+ debug@4.3.4(supports-color@8.1.1):
+ dependencies:
+ ms: 2.1.2
+ optionalDependencies:
+ supports-color: 8.1.1
+
+ decamelize@4.0.0: {}
+
+ deep-eql@4.1.3:
+ dependencies:
+ type-detect: 4.0.8
+
+ denque@2.1.0: {}
+
+ diff@5.0.0: {}
+
+ diff@5.2.0: {}
+
+ diskusage@1.2.0:
+ dependencies:
+ es6-promise: 4.2.8
+ nan: 2.19.0
+
+ dom-serializer@2.0.0:
+ dependencies:
+ domelementtype: 2.3.0
+ domhandler: 5.0.3
+ entities: 4.5.0
+
+ domelementtype@2.3.0: {}
+
+ domhandler@5.0.3:
+ dependencies:
+ domelementtype: 2.3.0
+
+ domutils@3.1.0:
+ dependencies:
+ dom-serializer: 2.0.0
+ domelementtype: 2.3.0
+ domhandler: 5.0.3
+
+ dotenv@16.4.5: {}
+
+ emoji-regex@8.0.0: {}
+
+ enabled@2.0.0: {}
+
+ entities@4.5.0: {}
+
+ es6-promise@4.2.8: {}
+
+ escalade@3.1.2: {}
+
+ escape-string-regexp@4.0.0: {}
+
+ event-target-shim@5.0.1: {}
+
+ events@3.3.0: {}
+
+ execa@6.1.0:
+ dependencies:
+ cross-spawn: 7.0.3
+ get-stream: 6.0.1
+ human-signals: 3.0.1
+ is-stream: 3.0.0
+ merge-stream: 2.0.0
+ npm-run-path: 5.3.0
+ onetime: 6.0.0
+ signal-exit: 3.0.7
+ strip-final-newline: 3.0.0
+
+ fast-content-type-parse@1.1.0: {}
+
+ fast-decode-uri-component@1.0.1: {}
+
+ fast-deep-equal@3.1.3: {}
+
+ fast-json-stringify@5.16.0:
+ dependencies:
+ '@fastify/merge-json-schemas': 0.1.1
+ ajv: 8.13.0
+ ajv-formats: 3.0.1(ajv@8.13.0)
+ fast-deep-equal: 3.1.3
+ fast-uri: 2.3.0
+ json-schema-ref-resolver: 1.0.1
+ rfdc: 1.3.1
+
+ fast-querystring@1.1.2:
+ dependencies:
+ fast-decode-uri-component: 1.0.1
+
+ fast-redact@3.5.0: {}
+
+ fast-uri@2.3.0: {}
+
+ fastify@4.27.0:
+ dependencies:
+ '@fastify/ajv-compiler': 3.5.0
+ '@fastify/error': 3.4.1
+ '@fastify/fast-json-stringify-compiler': 4.3.0
+ abstract-logging: 2.0.1
+ avvio: 8.3.2
+ fast-content-type-parse: 1.1.0
+ fast-json-stringify: 5.16.0
+ find-my-way: 8.2.0
+ light-my-request: 5.13.0
+ pino: 9.1.0
+ process-warning: 3.0.0
+ proxy-addr: 2.0.7
+ rfdc: 1.3.1
+ secure-json-parse: 2.7.0
+ semver: 7.6.2
+ toad-cache: 3.7.0
+
+ fastq@1.17.1:
+ dependencies:
+ reusify: 1.0.4
+
+ faye-websocket@0.11.4:
+ dependencies:
+ websocket-driver: 0.7.4
+
+ faye@1.4.0:
+ dependencies:
+ asap: 2.0.6
+ csprng: 0.1.2
+ faye-websocket: 0.11.4
+ safe-buffer: 5.2.1
+ tough-cookie: 4.1.4
+ tunnel-agent: 0.6.0
+
+ fecha@4.2.3: {}
+
+ fetch-blob@3.2.0:
+ dependencies:
+ node-domexception: 1.0.0
+ web-streams-polyfill: 3.3.3
+
+ fill-range@7.1.1:
+ dependencies:
+ to-regex-range: 5.0.1
+
+ find-my-way@8.2.0:
+ dependencies:
+ fast-deep-equal: 3.1.3
+ fast-querystring: 1.1.2
+ safe-regex2: 3.1.0
+
+ find-up@5.0.0:
+ dependencies:
+ locate-path: 6.0.0
+ path-exists: 4.0.0
+
+ flat@5.0.2: {}
+
+ fluent-ffmpeg@2.1.3:
+ dependencies:
+ async: 0.2.10
+ which: 1.3.1
+
+ fn.name@1.1.0: {}
+
+ formdata-polyfill@4.0.10:
+ dependencies:
+ fetch-blob: 3.2.0
+
+ forwarded@0.2.0: {}
+
+ fs.realpath@1.0.0: {}
+
+ fsevents@2.3.3:
+ optional: true
+
+ get-caller-file@2.0.5: {}
+
+ get-func-name@2.0.2: {}
+
+ get-stream@6.0.1: {}
+
+ glob-parent@5.1.2:
+ dependencies:
+ is-glob: 4.0.3
+
+ glob@8.1.0:
+ dependencies:
+ fs.realpath: 1.0.0
+ inflight: 1.0.6
+ inherits: 2.0.4
+ minimatch: 5.1.6
+ once: 1.4.0
+
+ has-flag@3.0.0: {}
+
+ has-flag@4.0.0: {}
+
+ he@1.2.0: {}
+
+ htmlparser2@8.0.2:
+ dependencies:
+ domelementtype: 2.3.0
+ domhandler: 5.0.3
+ domutils: 3.1.0
+ entities: 4.5.0
+
+ http-parser-js@0.5.8: {}
+
+ https@1.0.0: {}
+
+ human-signals@3.0.1: {}
+
+ ieee754@1.2.1: {}
+
+ ignore-by-default@1.0.1: {}
+
+ inflight@1.0.6:
+ dependencies:
+ once: 1.4.0
+ wrappy: 1.0.2
+
+ inherits@2.0.4: {}
+
+ ioredis@5.4.1:
+ dependencies:
+ '@ioredis/commands': 1.2.0
+ cluster-key-slot: 1.1.2
+ debug: 4.3.4(supports-color@8.1.1)
+ denque: 2.1.0
+ lodash.defaults: 4.2.0
+ lodash.isarguments: 3.1.0
+ redis-errors: 1.2.0
+ redis-parser: 3.0.0
+ standard-as-callback: 2.1.0
+ transitivePeerDependencies:
+ - supports-color
+
+ ipaddr.js@1.9.1: {}
+
+ is-arrayish@0.3.2: {}
+
+ is-binary-path@2.1.0:
+ dependencies:
+ binary-extensions: 2.3.0
+
+ is-extglob@2.1.1: {}
+
+ is-fullwidth-code-point@3.0.0: {}
+
+ is-glob@4.0.3:
+ dependencies:
+ is-extglob: 2.1.1
+
+ is-number@7.0.0: {}
+
+ is-plain-obj@2.1.0: {}
+
+ is-stream@2.0.1: {}
+
+ is-stream@3.0.0: {}
+
+ is-unicode-supported@0.1.0: {}
+
+ isexe@2.0.0: {}
+
+ js-yaml@4.1.0:
+ dependencies:
+ argparse: 2.0.1
+
+ json-schema-ref-resolver@1.0.1:
+ dependencies:
+ fast-deep-equal: 3.1.3
+
+ json-schema-traverse@1.0.0: {}
+
+ just-extend@6.2.0: {}
+
+ kuler@2.0.0: {}
+
+ light-my-request@5.13.0:
+ dependencies:
+ cookie: 0.6.0
+ process-warning: 3.0.0
+ set-cookie-parser: 2.6.0
+
+ locate-path@6.0.0:
+ dependencies:
+ p-locate: 5.0.0
+
+ lodash.defaults@4.2.0: {}
+
+ lodash.get@4.4.2: {}
+
+ lodash.isarguments@3.1.0: {}
+
+ lodash@4.1.0: {}
+
+ log-symbols@4.1.0:
+ dependencies:
+ chalk: 4.1.2
+ is-unicode-supported: 0.1.0
+
+ logform@2.6.0:
+ dependencies:
+ '@colors/colors': 1.6.0
+ '@types/triple-beam': 1.3.5
+ fecha: 4.2.3
+ ms: 2.1.3
+ safe-stable-stringify: 2.4.3
+ triple-beam: 1.4.1
+
+ loupe@2.3.7:
+ dependencies:
+ get-func-name: 2.0.2
+
+ merge-stream@2.0.0: {}
+
+ mimic-fn@4.0.0: {}
+
+ minimatch@3.1.2:
+ dependencies:
+ brace-expansion: 1.1.11
+
+ minimatch@5.0.1:
+ dependencies:
+ brace-expansion: 2.0.1
+
+ minimatch@5.1.6:
+ dependencies:
+ brace-expansion: 2.0.1
+
+ mocha@10.4.0:
+ dependencies:
+ ansi-colors: 4.1.1
+ browser-stdout: 1.3.1
+ chokidar: 3.5.3
+ debug: 4.3.4(supports-color@8.1.1)
+ diff: 5.0.0
+ escape-string-regexp: 4.0.0
+ find-up: 5.0.0
+ glob: 8.1.0
+ he: 1.2.0
+ js-yaml: 4.1.0
+ log-symbols: 4.1.0
+ minimatch: 5.0.1
+ ms: 2.1.3
+ serialize-javascript: 6.0.0
+ strip-json-comments: 3.1.1
+ supports-color: 8.1.1
+ workerpool: 6.2.1
+ yargs: 16.2.0
+ yargs-parser: 20.2.4
+ yargs-unparser: 2.0.0
+
+ ms@2.1.2: {}
+
+ ms@2.1.3: {}
+
+ multiformats@11.0.2: {}
+
+ nan@2.19.0: {}
+
+ nise@5.1.9:
+ dependencies:
+ '@sinonjs/commons': 3.0.1
+ '@sinonjs/fake-timers': 11.2.2
+ '@sinonjs/text-encoding': 0.7.2
+ just-extend: 6.2.0
+ path-to-regexp: 6.2.2
+
+ node-abort-controller@3.1.1: {}
+
+ node-domexception@1.0.0: {}
+
+ node-fetch@3.3.2:
+ dependencies:
+ data-uri-to-buffer: 4.0.1
+ fetch-blob: 3.2.0
+ formdata-polyfill: 4.0.10
+
+ nodemon@2.0.22:
+ dependencies:
+ chokidar: 3.6.0
+ debug: 3.2.7(supports-color@5.5.0)
+ ignore-by-default: 1.0.1
+ minimatch: 3.1.2
+ pstree.remy: 1.1.8
+ semver: 5.7.2
+ simple-update-notifier: 1.1.0
+ supports-color: 5.5.0
+ touch: 3.1.1
+ undefsafe: 2.0.5
+
+ normalize-path@3.0.0: {}
+
+ npm-run-path@5.3.0:
+ dependencies:
+ path-key: 4.0.0
+
+ nth-check@2.1.1:
+ dependencies:
+ boolbase: 1.0.0
+
+ on-exit-leak-free@2.1.2: {}
+
+ once@1.4.0:
+ dependencies:
+ wrappy: 1.0.2
+
+ one-time@1.0.0:
+ dependencies:
+ fn.name: 1.1.0
+
+ onetime@6.0.0:
+ dependencies:
+ mimic-fn: 4.0.0
+
+ p-limit@3.1.0:
+ dependencies:
+ yocto-queue: 0.1.0
+
+ p-locate@5.0.0:
+ dependencies:
+ p-limit: 3.1.0
+
+ p-retry@5.1.2:
+ dependencies:
+ '@types/retry': 0.12.1
+ retry: 0.13.1
+
+ parse5-htmlparser2-tree-adapter@7.0.0:
+ dependencies:
+ domhandler: 5.0.3
+ parse5: 7.1.2
+
+ parse5@7.1.2:
+ dependencies:
+ entities: 4.5.0
+
+ path-exists@4.0.0: {}
+
+ path-key@3.1.1: {}
+
+ path-key@4.0.0: {}
+
+ path-to-regexp@6.2.2: {}
+
+ pathval@1.1.1: {}
+
+ picomatch@2.3.1: {}
+
+ pino-abstract-transport@1.2.0:
+ dependencies:
+ readable-stream: 4.5.2
+ split2: 4.2.0
+
+ pino-std-serializers@7.0.0: {}
+
+ pino@9.1.0:
+ dependencies:
+ atomic-sleep: 1.0.0
+ fast-redact: 3.5.0
+ on-exit-leak-free: 2.1.2
+ pino-abstract-transport: 1.2.0
+ pino-std-serializers: 7.0.0
+ process-warning: 3.0.0
+ quick-format-unescaped: 4.0.4
+ real-require: 0.2.0
+ safe-stable-stringify: 2.4.3
+ sonic-boom: 4.0.1
+ thread-stream: 3.0.1
+
+ postgres@3.4.4: {}
+
+ process-warning@3.0.0: {}
+
+ process@0.11.10: {}
+
+ proxy-addr@2.0.7:
+ dependencies:
+ forwarded: 0.2.0
+ ipaddr.js: 1.9.1
+
+ psl@1.9.0: {}
+
+ pstree.remy@1.1.8: {}
+
+ punycode@2.3.1: {}
+
+ querystringify@2.2.0: {}
+
+ quick-format-unescaped@4.0.4: {}
+
+ randombytes@2.1.0:
+ dependencies:
+ safe-buffer: 5.2.1
+
+ readable-stream@3.6.2:
+ dependencies:
+ inherits: 2.0.4
+ string_decoder: 1.3.0
+ util-deprecate: 1.0.2
+
+ readable-stream@4.5.2:
+ dependencies:
+ abort-controller: 3.0.0
+ buffer: 6.0.3
+ events: 3.3.0
+ process: 0.11.10
+ string_decoder: 1.3.0
+
+ readdirp@3.6.0:
+ dependencies:
+ picomatch: 2.3.1
+
+ real-require@0.2.0: {}
+
+ redis-errors@1.2.0: {}
+
+ redis-parser@3.0.0:
+ dependencies:
+ redis-errors: 1.2.0
+
+ require-directory@2.1.1: {}
+
+ require-from-string@2.0.2: {}
+
+ requires-port@1.0.0: {}
+
+ ret@0.4.3: {}
+
+ retry@0.13.1: {}
+
+ reusify@1.0.4: {}
+
+ rfdc@1.3.1: {}
+
+ rxjs@7.8.1:
+ dependencies:
+ tslib: 2.6.2
+
+ safe-buffer@5.2.1: {}
+
+ safe-regex2@3.1.0:
+ dependencies:
+ ret: 0.4.3
+
+ safe-stable-stringify@2.4.3: {}
+
+ secure-json-parse@2.7.0: {}
+
+ semver@5.7.2: {}
+
+ semver@7.0.0: {}
+
+ semver@7.6.2: {}
+
+ sequin@0.1.1: {}
+
+ serialize-javascript@6.0.0:
+ dependencies:
+ randombytes: 2.1.0
+
+ set-cookie-parser@2.6.0: {}
+
+ shebang-command@2.0.0:
+ dependencies:
+ shebang-regex: 3.0.0
+
+ shebang-regex@3.0.0: {}
+
+ signal-exit@3.0.7: {}
+
+ simple-swizzle@0.2.2:
+ dependencies:
+ is-arrayish: 0.3.2
+
+ simple-update-notifier@1.1.0:
+ dependencies:
+ semver: 7.0.0
+
+ sinon-chai@3.7.0(chai@4.4.1)(sinon@15.2.0):
+ dependencies:
+ chai: 4.4.1
+ sinon: 15.2.0
+
+ sinon-test@3.1.6(sinon@15.2.0):
+ dependencies:
+ sinon: 15.2.0
+
+ sinon@15.2.0:
+ dependencies:
+ '@sinonjs/commons': 3.0.1
+ '@sinonjs/fake-timers': 10.3.0
+ '@sinonjs/samsam': 8.0.0
+ diff: 5.2.0
+ nise: 5.1.9
+ supports-color: 7.2.0
+
+ sliced@0.0.5: {}
+
+ sonic-boom@4.0.1:
+ dependencies:
+ atomic-sleep: 1.0.0
+
+ split2@4.2.0: {}
+
+ sql@0.78.0:
+ dependencies:
+ lodash: 4.1.0
+ sliced: 0.0.5
+
+ stack-trace@0.0.10: {}
+
+ standard-as-callback@2.1.0: {}
+
+ string-width@4.2.3:
+ dependencies:
+ emoji-regex: 8.0.0
+ is-fullwidth-code-point: 3.0.0
+ strip-ansi: 6.0.1
+
+ string_decoder@1.3.0:
+ dependencies:
+ safe-buffer: 5.2.1
+
+ strip-ansi@6.0.1:
+ dependencies:
+ ansi-regex: 5.0.1
+
+ strip-final-newline@3.0.0: {}
+
+ strip-json-comments@3.1.1: {}
+
+ supports-color@5.5.0:
+ dependencies:
+ has-flag: 3.0.0
+
+ supports-color@7.2.0:
+ dependencies:
+ has-flag: 4.0.0
+
+ supports-color@8.1.1:
+ dependencies:
+ has-flag: 4.0.0
+
+ text-hex@1.0.0: {}
+
+ thread-stream@3.0.1:
+ dependencies:
+ real-require: 0.2.0
+
+ to-regex-range@5.0.1:
+ dependencies:
+ is-number: 7.0.0
+
+ toad-cache@3.7.0: {}
+
+ touch@3.1.1: {}
+
+ tough-cookie@4.1.4:
+ dependencies:
+ psl: 1.9.0
+ punycode: 2.3.1
+ universalify: 0.2.0
+ url-parse: 1.5.10
+
+ triple-beam@1.4.1: {}
+
+ tslib@2.6.2: {}
+
+ tunnel-agent@0.6.0:
+ dependencies:
+ safe-buffer: 5.2.1
+
+ type-detect@4.0.8: {}
+
+ undefsafe@2.0.5: {}
+
+ universalify@0.2.0: {}
+
+ uri-js@4.4.1:
+ dependencies:
+ punycode: 2.3.1
+
+ url-parse@1.5.10:
+ dependencies:
+ querystringify: 2.2.0
+ requires-port: 1.0.0
+
+ util-deprecate@1.0.2: {}
+
+ web-streams-polyfill@3.3.3: {}
+
+ websocket-driver@0.7.4:
+ dependencies:
+ http-parser-js: 0.5.8
+ safe-buffer: 5.2.1
+ websocket-extensions: 0.1.4
+
+ websocket-extensions@0.1.4: {}
+
+ which@1.3.1:
+ dependencies:
+ isexe: 2.0.0
+
+ which@2.0.2:
+ dependencies:
+ isexe: 2.0.0
+
+ winston-transport@4.7.0:
+ dependencies:
+ logform: 2.6.0
+ readable-stream: 3.6.2
+ triple-beam: 1.4.1
+
+ winston@3.13.0:
+ dependencies:
+ '@colors/colors': 1.6.0
+ '@dabh/diagnostics': 2.0.3
+ async: 3.2.5
+ is-stream: 2.0.1
+ logform: 2.6.0
+ one-time: 1.0.0
+ readable-stream: 3.6.2
+ safe-stable-stringify: 2.4.3
+ stack-trace: 0.0.10
+ triple-beam: 1.4.1
+ winston-transport: 4.7.0
+
+ workerpool@6.2.1: {}
+
+ wrap-ansi@7.0.0:
+ dependencies:
+ ansi-styles: 4.3.0
+ string-width: 4.2.3
+ strip-ansi: 6.0.1
+
+ wrappy@1.0.2: {}
+
+ y18n@5.0.8: {}
+
+ yargs-parser@20.2.4: {}
+
+ yargs-unparser@2.0.0:
+ dependencies:
+ camelcase: 6.3.0
+ decamelize: 4.0.0
+ flat: 5.0.2
+ is-plain-obj: 2.1.0
+
+ yargs@16.2.0:
+ dependencies:
+ cliui: 7.0.4
+ escalade: 3.1.2
+ get-caller-file: 2.0.5
+ require-directory: 2.1.1
+ string-width: 4.2.3
+ y18n: 5.0.8
+ yargs-parser: 20.2.4
+
+ yocto-queue@0.1.0: {}
+
+ youtube-dl-wrap@https://codeload.github.com/insanity54/youtube-dl-wrap/tar.gz/b47e9388063b4ef516624112ef59b7d11f7775d9: {}
diff --git a/packages/capture/src/Capture.js b/packages/capture/src/Capture.js
new file mode 100644
index 0000000..d21cc84
--- /dev/null
+++ b/packages/capture/src/Capture.js
@@ -0,0 +1,125 @@
+
+import Voddo from './Voddo.js'
+import {loggerFactory} from 'common/logger'
+
+const logger = loggerFactory({
+ service: 'futureporn/capture'
+})
+
+export default class Capture {
+
+ constructor(opts) {
+ this.date = opts?.date
+ this.sql = opts.sql
+ this.ipfs = opts.ipfs
+ this.idleTimeout = opts.idleTimeout || 1000*60*15
+ this.video = opts.video
+ this.voddo = opts.voddo
+ this.workerId = opts.workerId
+ return this
+ }
+
+
+ /**
+ * upload VOD to ipfs
+ *
+ * @return {Promise}
+ * @resolves {String} cid
+ */
+ async upload (filename) {
+ const cid = await this.ipfs.upload(filename)
+ return cid
+ }
+
+
+
+ /**
+ * save Vod data to db
+ */
+ async save (cid, timestamp) {
+ logger.log({ level: 'debug', message: `saving ${cid} \n w/ captureDate ${timestamp}` })
+ this.date = timestamp
+ return await this.sql`INSERT INTO vod ( "videoSrcHash", "captureDate" ) values (${cid}, ${timestamp}) returning *`
+ }
+
+
+ /**
+ * advertise the vod segment(s) we captured.
+ * futureporn/commander uses this data to elect one worker to upload the VOD
+ */
+ async advertise () {
+ const segments = await this.voddo.getRecordedSegments()
+ const streams = Voddo.groupStreamSegments(segments)
+ const workerId = this.workerId
+ logger.log({ level: 'debug', message: `Advertising our VOD streams(s) ${JSON.stringify({segments, streams, workerId})}` })
+ this.sql.notify('capture/vod/advertisement', JSON.stringify({segments, streams, workerId}))
+ }
+
+
+ listen () {
+ this.sql.listen('scout/stream/stop', (data) => {
+ logger.log({ level: 'debug', message: 'Scout said the stream has stopped. I will advertise the vod segment(s) I have.' })
+ this.advertise()
+ })
+
+ this.sql.listen('commander/vod/election', async (data) => {
+ if (data.workerId === this.workerId) {
+ logger.log({ level: 'debug', message: 'Commander elected me to process/upload' })
+ this.process(await this.voddo.getFilenames())
+ } else {
+ logger.log({ level: 'debug', message: `Commander elected ${data.workerId} to process/upload their vod segment(s)` })
+ }
+ })
+
+ return this
+ }
+
+
+ /**
+ * process video(s) after end of stream
+ *
+ * @param {String[]} filenames
+ * @returns {void}
+ */
+ async process (filenames) {
+ this.date = filenames[0].timestamp
+
+ logger.log({ level: 'debug', message: 'concatenation in progress...' })
+ const file = await this.video.concat(filenames)
+
+ logger.log({ level: 'debug', message: `uploading ${file}` })
+ const cid = await this.ipfs.upload(file)
+
+ logger.log({ level: 'debug', message: 'db save in progress' })
+ await this.save(cid, this.date)
+
+ }
+
+
+
+ /**
+ * download a livestream
+ *
+ * - initializes Voddo
+ * - invokes this.process() as side effect
+ *
+ * @return {void}
+ */
+ async download () {
+ this.voddo.on('start', (data) => {
+ logger.log({ level: 'debug', message: 'voddo started' })
+ logger.log({ level: 'debug', message: data })
+ this.sql.notify('capture/file', JSON.stringify(data))
+ })
+ this.voddo.on('stop', (report) => {
+ logger.log({ level: 'debug', message: `Got a stop event from Voddo` })
+ })
+ logger.log({ level: 'debug', message: 'starting voddo' })
+ this.voddo.start()
+ }
+
+}
+
+
+
+
diff --git a/packages/capture/src/Ipfs.js b/packages/capture/src/Ipfs.js
new file mode 100644
index 0000000..7d20638
--- /dev/null
+++ b/packages/capture/src/Ipfs.js
@@ -0,0 +1,57 @@
+
+import {execa} from 'execa'
+import {loggerFactory} from 'common/logger'
+
+const logger = loggerFactory({
+ service: 'futureporn/capture'
+})
+
+export default class Ipfs {
+ constructor(opts) {
+ this.multiaddr = opts?.IPFS_CLUSTER_HTTP_API_MULTIADDR
+ this.username = opts?.IPFS_CLUSTER_HTTP_API_USERNAME
+ this.password = opts?.IPFS_CLUSTER_HTTP_API_PASSWORD
+ this.ctlExecutable = opts?.ctlExecutable || '/usr/local/bin/ipfs-cluster-ctl'
+ this.ipfsExecutable = opts?.ipfsExecutable || '/usr/local/bin/ipfs'
+ }
+ getArgs () {
+ let args = [
+ '--no-check-certificate',
+ '--host', this.multiaddr,
+ '--basic-auth', `${this.username}:${this.password}`
+ ]
+ return args
+ }
+ async upload (filename, expiryDuration = false) {
+ try {
+ let args = getArgs()
+
+ args = args.concat([
+ 'add',
+ '--quieter',
+ '--cid-version', 1
+ ])
+
+ if (expiryDuration) {
+ args = args.concat(['--expire-in', expiryDuration])
+ }
+
+ args.push(filename)
+
+ const { stdout } = await execa(this.ctlExecutable, args)
+ return stdout
+ } catch (e) {
+ logger.log({ level: 'error', message: 'Error while adding file to ipfs' })
+ logger.log({ level: 'error', message: e })
+ }
+ }
+ async hash (filename) {
+ try {
+ const { stdout } = await execa(this.ipfsExecutable, ['add', '--quiet', '--cid-version=1', '--only-hash', filename])
+ return stdout
+ } catch (e) {
+ logger.log({ level: 'error', message: 'Error while hashing file' })
+ logger.log({ level: 'error', message: e })
+ }
+ }
+}
\ No newline at end of file
diff --git a/packages/capture/src/Video.js b/packages/capture/src/Video.js
new file mode 100644
index 0000000..253ae28
--- /dev/null
+++ b/packages/capture/src/Video.js
@@ -0,0 +1,68 @@
+
+import { execa } from 'execa'
+import { tmpdir } from 'os'
+import path from 'node:path'
+import fs from 'node:fs'
+import os from 'node:os'
+
+export class VideoConcatError extends Error {
+ constructor (msg) {
+ super(msg || 'Failed to concatenate video')
+ this.name = 'VideoConcatError'
+ }
+}
+
+
+
+export default class Video {
+ constructor (opts) {
+ if (typeof opts.filePaths === 'undefined') throw new Error('Video must be called with opts.filePaths');
+ if (typeof opts.cwd === 'undefined') throw new Error('Video must be called with opts.cwd');
+ this.filePaths = opts.filePaths
+ this.cwd = opts.cwd
+ this.room = opts.room || 'projektmelody'
+ this.execa = opts.execa || execa
+ }
+
+
+
+ getFilesTxt () {
+ return this.filePaths
+ .sort((a, b) => a.timestamp - b.timestamp)
+ .map((d) => `file '${d.file}'`)
+ .join('\n')
+ .concat('\n')
+ }
+
+
+ getFilesFile () {
+ const p = path.join(this.cwd, 'files.txt')
+ fs.writeFileSync(
+ p,
+ this.getFilesTxt(this.filePaths),
+ { encoding: 'utf-8' }
+ )
+ return p
+ }
+
+ async concat () {
+ const target = path.join(this.cwd, `${this.room}-chaturbate-${new Date().valueOf()}.mp4`)
+
+ const { exitCode, killed, stdout, stderr } = await this.execa('ffmpeg', [
+ '-y',
+ '-f', 'concat',
+ '-safe', '0',
+ '-i', this.getFilesFile(this.filePaths),
+ '-c', 'copy',
+ target
+ ], {
+ cwd: this.cwd
+ });
+
+ if (exitCode !== 0 || killed !== false) {
+ throw new VideoConcatError(`exitCode:${exitCode}, killed:${killed}, stdout:${stdout}, stderr:${stderr}`);
+ }
+
+ return target
+ }
+}
diff --git a/packages/capture/src/Voddo.js b/packages/capture/src/Voddo.js
new file mode 100644
index 0000000..6e1a75e
--- /dev/null
+++ b/packages/capture/src/Voddo.js
@@ -0,0 +1,243 @@
+import 'dotenv/config'
+import YoutubeDlWrap from "youtube-dl-wrap";
+import { EventEmitter } from 'node:events';
+import { AbortController } from "node-abort-controller";
+import { readdir, stat } from 'node:fs/promises';
+import { join } from 'node:path'
+import ffmpeg from 'fluent-ffmpeg'
+import { loggerFactory } from 'common/logger'
+
+const logger = loggerFactory({
+ service: 'futureporn/capture'
+})
+const defaultStats = {segments:[],lastUpdatedAt:null}
+
+export default class Voddo extends EventEmitter {
+ constructor(opts) {
+ super()
+ this.courtesyTimer = setTimeout(() => {}, 0);
+ this.retryCount = 0;
+ this.url = opts.url;
+ this.format = opts.format || 'best';
+ this.cwd = opts.cwd;
+ this.ytdlee; // event emitter for ytdlwrap
+ this.stats = Object.assign({}, defaultStats);
+ this.abortController = new AbortController();
+ this.ytdl = opts.ytdl || new YoutubeDlWrap();
+ if (process.env.YOUTUBE_DL_BINARY) this.ytdl.setBinaryPath(process.env.YOUTUBE_DL_BINARY);
+ }
+
+ static async getVideoLength (filePath) {
+ return new Promise((resolve, reject) => {
+ ffmpeg.ffprobe(filePath, function(err, metadata) {
+ if (err) reject(err)
+ resolve(Math.floor(metadata.format.duration*1000))
+ });
+ })
+ }
+
+ // greets ChatGPT
+ static groupStreamSegments(segments, threshold = 1000*60*60) {
+ segments.sort((a, b) => a.startTime - b.startTime);
+ const streams = [];
+ let currentStream = [];
+
+ for (let i = 0; i < segments.length; i++) {
+ const currentSegment = segments[i];
+ const previousSegment = currentStream[currentStream.length - 1];
+
+ if (!previousSegment || currentSegment.startTime - previousSegment.endTime <= threshold) {
+ currentStream.push(currentSegment);
+ } else {
+ streams.push(currentStream);
+ currentStream = [currentSegment];
+ }
+ }
+
+ streams.push(currentStream);
+ return streams;
+ }
+
+
+
+
+
+
+
+ /**
+ * getRecordedStreams
+ *
+ * get the metadata of the videos captured
+ */
+ async getRecordedSegments() {
+ let f = []
+ const files = await readdir(this.cwd).then((raw) => raw.filter((f) => /\.mp4$/.test(f) ))
+ for (const file of files) {
+ const filePath = join(this.cwd, file)
+ const s = await stat(filePath)
+ const videoDuration = await Voddo.getVideoLength(filePath)
+ const startTime = parseInt(s.ctimeMs)
+ const endTime = startTime+videoDuration
+ const size = s.size
+ f.push({
+ startTime,
+ endTime,
+ file,
+ size
+ })
+ }
+ this.stats.segments = f
+
+
+ return this.stats.segments
+ }
+
+ isDownloading() {
+ // if there are event emitter listeners for the progress event,
+ // we are probably downloading.
+ return (
+ this.ytdlee?.listeners('progress').length !== undefined
+ )
+ }
+
+ delayedStart() {
+ // only for testing
+ this.retryCount = 500
+ this.courtesyTimer = this.getCourtesyTimer(() => this.download())
+ }
+
+
+ start() {
+ // if download is in progress, do nothing
+ if (this.isDownloading()) {
+ logger.log({ level: 'debug', message: 'Doing nothing because a download is in progress.' })
+ return;
+ }
+
+ // if download is not in progress, start download immediately
+ // reset the retryCount so the backoff timer resets to 1s between attempts
+ this.retryCount = 0
+ clearTimeout(this.courtesyTimer)
+
+ // create new abort controller
+ //this.abortController = new AbortController() // @todo do i need this? Can't I reuse the existing this.abortController?
+
+ this.download()
+ }
+
+ stop() {
+ logger.log({ level: 'info', message: 'Received stop(). Stopping.' })
+ clearTimeout(this.courtesyTimer)
+ this.abortController.abort()
+ }
+
+ /** generate a report **/
+ getReport(errorMessage) {
+ let report = {}
+ report.stats = Object.assign({}, this.stats)
+ report.error = errorMessage
+ report.reason = (() => {
+ if (errorMessage) return 'error';
+ else if (this.abortController.signal.aborted) return 'aborted';
+ else return 'close';
+ })()
+ // clear stats to prepare for next run
+ this.stats = Object.assign({}, defaultStats)
+ return report
+ }
+
+ emitReport(report) {
+ logger.log({ level: 'debug', message: 'EMITTING REPORT' })
+ this.emit('stop', report)
+ }
+
+ getCourtesyTimer(callback) {
+ // 600000ms = 10m
+ const waitTime = Math.min(600000, (Math.pow(2, this.retryCount) * 1000));
+ this.retryCount += 1;
+ logger.log({ level: 'debug', message: `courtesyWait for ${waitTime/1000} seconds. (retryCount: ${this.retryCount})` })
+ return setTimeout(callback, waitTime)
+ }
+
+ download() {
+ const handleProgress = (progress) => {
+ logger.log({ level: 'debug', message:` [*] progress event` })
+ this.stats.lastUpdatedAt = Date.now(),
+ this.stats.totalSize = progress.totalSize
+ }
+
+ const handleError = (error) => {
+ if (error?.message !== undefined && error.message.includes('Room is currently offline')) {
+ logger.log({ level: 'debug', message: 'Handled an expected \'Room is offline\' error' })
+
+ } else {
+ logger.log({ level: 'error', message: 'ytdl error' })
+ logger.log({ level: 'error', message: error.message })
+ }
+ this.ytdlee.off('progress', handleProgress)
+ this.ytdlee.off('handleYtdlEvent', handleYtdlEvent)
+
+ // restart the download after the courtesyTimeout
+ this.courtesyTimer = this.getCourtesyTimer(() => this.download())
+ this.emitReport(this.getReport(error.message))
+ }
+
+
+ const handleYtdlEvent = (type, data) => {
+ logger.log({ level: 'debug', message: `handleYtdlEvent type: ${type}, data: ${data}` })
+ logger.log({ level: 'debug', message: `handleYtdlEvent type: ${type}, data: ${data}` })
+ if (type === 'download' && data.includes('Destination:')) {
+ let filePath = /Destination:\s(.*)$/.exec(data)[1]
+ logger.log({ level: 'debug', message: `Destination file detected: ${filePath}` })
+ let datum = { file: filePath, timestamp: new Date().valueOf() }
+ let segments = this.stats.segments
+ segments.push(datum) && segments.length > 64 && segments.shift(); // limit the size of the segments array
+ this.emit('start', datum)
+ } else if (type === 'ffmpeg' && data.includes('bytes')) {
+ const bytes = /(\d*)\sbytes/.exec(data)[1]
+ logger.log({ level: 'debug', message: `ffmpeg reports ${bytes}`})
+ let mostRecentFile = this.stats.segments[this.stats.segments.length-1]
+ mostRecentFile['size'] = bytes
+ logger.log({ level: 'debug', message: mostRecentFile })
+ }
+ }
+
+ const handleClose = () => {
+ logger.log({ level: 'debug', message: 'got a close event. handling!' });
+
+ this.ytdlee.off('progress', handleProgress)
+ this.ytdlee.off('handleYtdlEvent', handleYtdlEvent)
+
+ // restart Voddo only if the close was not due to stop()
+ if (!this.abortController.signal.aborted) {
+ // restart the download after the courtesyTimeout
+ this.courtesyTimer = this.getCourtesyTimer(() => this.download())
+ }
+
+ this.emitReport(this.getReport())
+ }
+
+ logger.log({ level: 'debug', message: `Downloading url:${this.url} format:${this.format}` })
+ logger.log({ level: 'debug', message: JSON.stringify(this.ytdl) })
+
+ // sanity check. ensure cwd exists
+ stat(this.cwd, (err) => {
+ if (err) logger.log({ level: 'error', message: `Error while getting cwd stats of ${this.cwd} Does it exist?` })
+ })
+
+ this.ytdlee = this.ytdl.exec(
+ [this.url, '-f', this.format],
+ {
+ cwd: this.cwd
+ },
+ this.abortController.signal
+ );
+ this.ytdlee.on('progress', handleProgress);
+ this.ytdlee.on('youtubeDlEvent', handleYtdlEvent);
+ this.ytdlee.once('error', handleError);
+ this.ytdlee.once('close', handleClose);
+ }
+
+
+
+}
\ No newline at end of file
diff --git a/packages/capture/src/cb.js b/packages/capture/src/cb.js
new file mode 100644
index 0000000..24125a3
--- /dev/null
+++ b/packages/capture/src/cb.js
@@ -0,0 +1,17 @@
+import cheerio from 'cheerio'
+import fetch from 'node-fetch'
+
+export async function getRandomRoom () {
+ const res = await fetch('https://chaturbate.com/')
+ const body = await res.text()
+ const $ = cheerio.load(body)
+ let roomsRaw = $('a[data-room]')
+ let rooms = []
+ $(roomsRaw).each((_, e) => {
+ rooms.push($(e).attr('href'))
+ })
+
+ // greets https://stackoverflow.com/a/4435017/1004931
+ var randomIndex = Math.floor(Math.random() * rooms.length);
+ return rooms[randomIndex].replaceAll('/', '')
+}
\ No newline at end of file
diff --git a/packages/capture/src/disk.js b/packages/capture/src/disk.js
new file mode 100644
index 0000000..2d18c5b
--- /dev/null
+++ b/packages/capture/src/disk.js
@@ -0,0 +1,33 @@
+import disk from 'diskusage';
+
+
+export function verifyStorage (appContext) {
+ const mountPath = appContext.env.FUTUREPORN_WORKDIR
+ disk.check(mountPath, (err, info) => {
+ if (err) {
+ appContext.logger.log({ level: 'error', message: `Error retrieving disk usage for ${mountPath}: ${err}` });
+ return;
+ }
+
+ const totalSize = info.total;
+ const availableSize = info.available;
+ const freeSize = info.free;
+
+ appContext.logger.log({ 'level': 'info', message: `${mountPath} Disk Usage:` });
+ appContext.logger.log({ 'level': 'info', message: `Total: ${bytesToSize(totalSize)}` });
+ appContext.logger.log({ 'level': 'info', message: `Free: ${bytesToSize(freeSize)}` });
+ appContext.logger.log({ 'level': 'info', message: `Available: ${bytesToSize(availableSize)}` });
+
+ if (availableSize < 85899345920) appContext.logger.log({ 'level': 'warn', message: `⚠️ Available disk is getting low! ${bytesToSize(availableSize)}` });
+ else if (availableSize < 42949672960) appContext.logger.log({ 'level': 'error', message: `⚠️☠️ AVAILABLE DISK IS TOO LOW! ${bytesToSize(availableSize)}` });
+ });
+}
+
+
+// Helper function to convert bytes to human-readable format
+export function bytesToSize(bytes) {
+ const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB'];
+ if (bytes === 0) return '0 Bytes';
+ const i = Math.floor(Math.log2(bytes) / 10);
+ return `${(bytes / Math.pow(1024, i)).toFixed(2)} ${sizes[i]}`;
+}
\ No newline at end of file
diff --git a/packages/capture/src/logger.js b/packages/capture/src/logger.js
new file mode 100644
index 0000000..84c387f
--- /dev/null
+++ b/packages/capture/src/logger.js
@@ -0,0 +1,25 @@
+import winston from 'winston'
+
+export const loggerFactory = (options) => {
+ const mergedOptions = Object.assign({}, {
+ level: 'info',
+ defaultMeta: { service: 'futureporn' },
+ format: winston.format.timestamp()
+ }, options)
+ const logger = winston.createLogger(mergedOptions);
+
+ if (process.env.NODE_ENV !== 'production') {
+ logger.add(new winston.transports.Console({
+ level: 'debug',
+ format: winston.format.simple()
+ }))
+ } else {
+ logger.add(new winston.transports.Console({
+ level: 'info',
+ format: winston.format.json()
+ }))
+ }
+
+ return logger
+}
+
diff --git a/packages/capture/src/record.js b/packages/capture/src/record.js
new file mode 100644
index 0000000..5c799eb
--- /dev/null
+++ b/packages/capture/src/record.js
@@ -0,0 +1,117 @@
+import { join } from 'path';
+import { spawn } from 'child_process';
+import fs from 'node:fs';
+
+export const getFilename = (appContext, roomName) => {
+ const name = `${roomName}_${new Date().toISOString()}.ts`
+ return join(appContext.env.FUTUREPORN_WORKDIR, 'recordings', name);
+}
+
+
+export const assertDirectory = (directoryPath) => {
+ if (fs.statSync(directoryPath, { throwIfNoEntry: false }) === undefined) fs.mkdirSync(directoryPath);
+}
+
+export const checkFFmpeg = async (appContext) => {
+ return new Promise((resolve, reject) => {
+ const childProcess = spawn('ffmpeg', ['-version']);
+
+ childProcess.on('error', (err) => {
+ appContext.logger.log({
+ level: 'error',
+ message: `ffmpeg -version failed, which likely means ffmpeg is not installed or not on $PATH`,
+ });
+ throw new Error('ffmpeg is missing')
+ });
+
+ childProcess.on('exit', (code) => {
+ if (code !== 0) reject(`'ffmpeg -version' exited with code ${code}`)
+ if (code === 0) {
+ appContext.logger.log({ level: 'info', message: `ffmpeg PRESENT.` });
+ resolve()
+ }
+ });
+ })
+};
+
+export const assertDependencyDirectory = (appContext) => {
+ // Extract the directory path from the filename
+ const directoryPath = join(appContext.env.FUTUREPORN_WORKDIR, 'recordings');
+ console.log(`asserting ${directoryPath} exists`)
+
+ // Check if the directory exists, and create it if it doesn't
+ if (!fs.existsSync(directoryPath)) {
+ fs.mkdirSync(directoryPath, { recursive: true });
+ console.log(`Created directory: ${directoryPath}`);
+ }
+}
+
+export const record = async (appContext, playlistUrl, roomName) => {
+ if (appContext === undefined) throw new Error('appContext undef');
+ if (playlistUrl === undefined) throw new Error('playlistUrl undef');
+ if (roomName === undefined) throw new Error('roomName undef');
+
+ const filename = getFilename(appContext, roomName);
+ console.log(`downloading to ${filename}`)
+
+ // example: `ffmpeg -headers "User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:105.0) Gecko/20100101 Firefox/105.0"
+ // -i ${chunkPlaylist}
+ // -c:v copy
+ // -c:a copy
+ // -movflags faststart
+ // -y
+ // -f mpegts
+ // ./my-recording.ts`
+ const ffmpegProcess = spawn('ffmpeg', [
+ '-headers', `"User-Agent: ${appContext.env.DOWNLOADER_UA}"`,
+ '-i', playlistUrl,
+ '-c:v', 'copy',
+ '-c:a', 'copy',
+ '-movflags', 'faststart',
+ '-y',
+ '-f', 'mpegts',
+ filename
+ ], {
+ stdio: 'inherit'
+ });
+
+
+
+ return new Promise((resolve, reject) => {
+ ffmpegProcess.once('exit', (code) => {
+ resolve(code)
+ })
+ })
+
+ // ffmpegProcess.on('data', (data) => {
+ // console.log(data.toString());
+ // });
+
+
+ // Optional: Handle other events such as 'error', 'close', etc.
+ // @todo this needs to be handled outside this function
+ // otherwise this function is not testable
+ // ffmpegProcess.on('exit', (code, signal) => {
+ // // Retry the download using exponential backoff if the process exits for any reason
+ // console.log(`ffmpeg exited with code ${code} and signal ${signal}`)
+ // retryDownload(appContext, playlistUrl, roomName);
+ // });
+
+ // return ffmpegProcess;
+}
+
+
+const calculateExponentialBackoffDelay = (attemptNumber) => {
+ return Math.pow(2, attemptNumber) * 1000;
+};
+
+const retryDownload = (appContext, playlistUrl, roomName, attemptNumber = 1, maxAttempts = 3) => {
+ const delay = calculateExponentialBackoffDelay(attemptNumber);
+
+ appContext.logger.log({ level: 'debug', message: `Retrying download in ${delay / 1000} seconds...` });
+
+ setTimeout(() => {
+ console.log('Retrying download...');
+ record(appContext, playlistUrl, roomName, attemptNumber + 1);
+ }, delay);
+};
diff --git a/packages/capture/test/Capture.test.js b/packages/capture/test/Capture.test.js
new file mode 100644
index 0000000..c9f0606
--- /dev/null
+++ b/packages/capture/test/Capture.test.js
@@ -0,0 +1,147 @@
+
+import Video from '../src/Video.js'
+import Capture from '../src/Capture.js'
+import Ipfs from '../src/Ipfs.js'
+import chai, { expect } from 'chai'
+import { dirname } from 'path';
+import { fileURLToPath } from 'url';
+import path from 'node:path'
+import sinon from 'sinon'
+import sinonChai from 'sinon-chai'
+import { CID } from 'multiformats/cid'
+import Voddo from '../src/Voddo.js'
+import EventEmitter from 'node:events'
+import postgres from 'postgres'
+
+chai.use(sinonChai)
+
+const Timer = setTimeout(()=>{},0).constructor
+const fixtureDate = 1581117660000
+const cidFixture = 'bafybeid3mg5lzrvnmpfi5ftwhiupp7i5bgkmdo7dnlwrvklbv33telrrry'
+const __dirname = dirname(fileURLToPath(import.meta.url));
+
+describe('Capture', function () {
+
+ let clock
+
+ const sandbox = sinon.createSandbox()
+
+ beforeEach(() => {
+
+ clock = sandbox.useFakeTimers({
+ toFake: ["setTimeout", "setInterval"],
+ shouldAdvanceTime: false
+ });
+
+ // // const sql = postgres({
+ // // idle_timeout: 1
+ // // })
+
+ // let pgStub = (opts) => {
+ // let sql = (args) => {}
+ // return sql
+ // }
+ const sqlRaw = postgres()
+ const sql = sandbox.stub(sqlRaw)
+ // sql.listen.resolves(fixtureDate)
+ // sql.notify.resolves(92834)
+ // sinon.stub(postgres, 'notify')
+ // sinon.createStubInstance(postgres)
+ // sql
+ // .withArgs('INSERT INTO vod ( videoSrcHash, captureDate ) values (bafybeid3mg5lzrvnmpfi5ftwhiupp7i5bgkmdo7dnlwrvklbv33telrrry, 1581117660000) returning *')
+ // .resolves({ msg: 'idk' })
+ // sinon.stub(sql, 'notify').returns()
+
+
+
+
+ // const ipfs = sandbox.createStubInstance(Ipfs)
+ // ipfs.upload.withArgs('/tmp/mycoolfile.mp4').resolves(cidFixture)
+ // capture = new Capture({
+ // sql,
+ // ipfs,
+ // video,
+ // voddo
+ // })
+ // sandbox.stub(capture, 'process').resolves()
+ })
+
+ afterEach(() => {
+ sandbox.restore()
+ clock.restore()
+ })
+
+
+
+ describe('upload', function () {
+ it('should upload a video to ipfs', async function () {
+
+ const sqlRaw = postgres()
+ const sql = sandbox.stub(sqlRaw)
+
+ const video = sandbox.stub()
+ const voddo = sandbox.createStubInstance(Voddo)
+ voddo.on.callThrough()
+ voddo.emit.callThrough()
+ voddo.listeners.callThrough()
+ voddo.listenerCount.callThrough()
+
+
+ voddo.start.callsFake(() => {
+ voddo.emit('start', { file: '/tmp/burrito.mp4', timestamp: 1 })
+ })
+
+ const ipfs = sandbox.createStubInstance(Ipfs)
+ ipfs.upload.withArgs('/tmp/mycoolfile.mp4').resolves(cidFixture)
+ const capture = new Capture({
+ sql,
+ ipfs,
+ video,
+ voddo
+ })
+
+ const cid = await capture.upload('/tmp/mycoolfile.mp4')
+ expect(() => CID.parse(cid), `The IPFS CID '${cid}' is invalid.`).to.not.throw()
+ expect(capture.ipfs.upload).calledOnce
+ })
+ })
+ describe('save', function () {
+ it('should save to db', async function () {
+
+ const sqlRaw = postgres()
+ const sql = sandbox.stub(sqlRaw)
+
+ const video = sandbox.stub()
+ const voddo = sandbox.createStubInstance(Voddo)
+ voddo.on.callThrough()
+ voddo.emit.callThrough()
+ voddo.listeners.callThrough()
+ voddo.listenerCount.callThrough()
+
+
+ voddo.start.callsFake(() => {
+ voddo.emit('start', { file: '/tmp/burrito.mp4', timestamp: 1 })
+ })
+
+ const ipfs = sandbox.createStubInstance(Ipfs)
+ ipfs.upload.withArgs('/tmp/mycoolfile.mp4').resolves(cidFixture)
+ const capture = new Capture({
+ sql,
+ ipfs,
+ video,
+ voddo
+ })
+
+ // I can't stub sql`` because of that template string override so i'm just stubbing capture.save
+ // I think this is an evergreen test ¯\_(ツ)_/¯
+ sandbox.stub(capture, 'save').resolves([
+ { id: 1, cid: cidFixture, captureDate: fixtureDate }
+ ])
+ const vod = await capture.save(cidFixture, fixtureDate)
+ })
+ })
+
+
+
+
+})
\ No newline at end of file
diff --git a/packages/capture/test/Video.test.js b/packages/capture/test/Video.test.js
new file mode 100644
index 0000000..c9305a3
--- /dev/null
+++ b/packages/capture/test/Video.test.js
@@ -0,0 +1,86 @@
+
+import 'dotenv/config'
+import Video from '../src/Video.js'
+import { dirname } from 'path';
+import { fileURLToPath } from 'url';
+import path from 'node:path'
+import os from 'node:os'
+import fs from 'node:fs'
+import sinon from 'sinon'
+import sinonChai from 'sinon-chai'
+import chai, { expect } from 'chai'
+
+chai.use(sinonChai);
+
+const __dirname = dirname(fileURLToPath(import.meta.url));
+
+
+
+const dataFixture = [
+ {
+ timestamp: 1,
+ file: 'mock-stream0.mp4'
+ }, {
+ timestamp: 2,
+ file: 'mock-stream1.mp4'
+ }, {
+ timestamp: 3,
+ file: 'mock-stream2.mp4'
+ }
+]
+
+describe('Video', function () {
+
+ let video
+
+ before(() => {
+ // copy files to /tmp so we dont clutter the fixtures dir
+ // and simulate cwd being process.env.FUTUREPORN_TMP
+ dataFixture.forEach((d) => {
+ fs.copyFileSync(
+ path.join(__dirname, 'fixtures', d.file),
+ path.join(os.tmpdir(), d.file)
+ )
+ })
+ })
+
+
+
+ beforeEach(() => {
+ video = new Video({
+ cwd: os.tmpdir(),
+ filePaths: dataFixture,
+ execa: sinon.fake.resolves({ exitCode: 0, killed: false, stdout: "i am so horni rn", stderr: null })
+ })
+ })
+
+ afterEach(function() {
+ console.log('>> sinon.restore! (afterEach)')
+ sinon.restore();
+ })
+
+
+ describe('getFilesTxt', function () {
+ it('should generate contents suitable for input to `ffmpeg -f concat`', function () {
+ const txt = video.getFilesTxt()
+ expect(txt).to.deep.equal("file 'mock-stream0.mp4'\nfile 'mock-stream1.mp4'\nfile 'mock-stream2.mp4'\n")
+ })
+ })
+
+ describe('concat', function () {
+ it('should join multiple videos into one', async function () {
+ const file = await video.concat()
+ expect(typeof file === 'string').to.be.true
+ expect(video.execa).calledOnce
+ expect(file).to.match(/\.mp4$/)
+ })
+ })
+
+ describe('getFilesFile', function () {
+ it('should create a files.txt and return the path', async function () {
+ const file = await video.getFilesFile()
+ expect(typeof file === 'string').to.be.true
+ expect(file).to.equal(path.join(os.tmpdir(), 'files.txt'))
+ })
+ })
+})
\ No newline at end of file
diff --git a/packages/capture/test/Voddo.test.js b/packages/capture/test/Voddo.test.js
new file mode 100644
index 0000000..28afddf
--- /dev/null
+++ b/packages/capture/test/Voddo.test.js
@@ -0,0 +1,491 @@
+import 'dotenv/config'
+import Voddo from '../src/Voddo.js'
+import chai, { expect } from 'chai'
+import sinon from 'sinon'
+import YoutubeDlWrap from 'youtube-dl-wrap'
+import {
+ AbortController
+} from "node-abort-controller";
+import {
+ EventEmitter
+} from 'events'
+import debugFactory from 'debug'
+import { join, dirname } from 'path';
+import { fileURLToPath } from 'url';
+import sinonChai from 'sinon-chai'
+import sinonTest from "sinon-test";
+import path from 'path'
+
+chai.use(sinonChai);
+
+const test = sinonTest(sinon, {
+ toFake: ["setTimeout", "setInterval"],
+ shouldAdvanceTime: false
+});
+const debug = debugFactory('voddo')
+const __dirname = dirname(fileURLToPath(import.meta.url));
+
+
+
+
+
+describe('Voddo', function() {
+
+
+ describe('groupStreamSegments', function () {
+ it('should separate two stream data objects', function () {
+ const fixture = [{
+ "startTime": 1675386000000,
+ "file": "projektmelody 2023-02-02 17_00-projektmelody.mp4",
+ "size": 550799038,
+ "endTime": 1675391400000,
+ }, {
+ "startTime": 1675391405000,
+ "file": "projektmelody 2023-02-02 18_30-projektmelody.mp4",
+ "size": 6556534941,
+ "endTime": 1675396800000
+ }, {
+ "startTime": 1675368000000,
+ "file": "projektmelody 2023-02-02 12_00-projektmelody.mp4",
+ "size": 6556534941,
+ "endTime": 1675378800000
+ }]
+
+ const streams = Voddo.groupStreamSegments(fixture)
+ expect(streams).to.deep.equal([
+ [
+ {
+ "startTime": 1675368000000,
+ "file": "projektmelody 2023-02-02 12_00-projektmelody.mp4",
+ "size": 6556534941,
+ "endTime": 1675378800000
+ }
+ ],
+ [
+ {
+ "startTime": 1675386000000,
+ "file": "projektmelody 2023-02-02 17_00-projektmelody.mp4",
+ "size": 550799038,
+ "endTime": 1675391400000,
+ }, {
+ "startTime": 1675391405000,
+ "file": "projektmelody 2023-02-02 18_30-projektmelody.mp4",
+ "size": 6556534941,
+ "endTime": 1675396800000
+ }
+ ]
+ ])
+ })
+ })
+
+
+ // let clock;
+
+ // beforeEach(function() {
+ // clock = sinon.useFakeTimers({
+ // toFake: ["setTimeout", "setInterval"],
+ // shouldAdvanceTime: false
+ // });
+ // })
+
+ // afterEach(() => {
+ // sinon.restore()
+ // })
+
+
+
+ // Something faulty with Voddo or sinon or mocha, not sure.
+ // When running by itself, test succeeds. When running with 'should start and stop stream download',
+ // voddo.stats gets set to whatever that test sets it to. So bizarre, it's like the same Voddo class instance
+ // exists in two different tests even though they are named differently.
+ // Even though they are not in global scope. Even though each was called with `new Voddo(...)`
+ // Doesn't matter if I wrap both in sinon-test. Same leaky problem.
+ // Doesn't matter if I sinon.restore() afterEach. Same leaky problem.
+ // Doesn't matter if I manually set up a sinon sandbox. Same leaky problem.
+ // Fuck event emitters. I love their utility but I don't know how the fuck they are supposed to be tested.
+ // Solution might just call for a rewrite of Voddo, or perhaps deleting Voddo in favor of Capture
+ // For now, I'm moving forward because Voddo works even though this test does not.
+ describe('getRecordedSegments', function() {
+ xit('should populate it\'s log if log is empty', async function () {
+ const voddo = new Voddo({
+ url: 'https://example.com',
+ cwd: join(__dirname, 'fixtures')
+ })
+ const streams = await voddo.getRecordedSegments()
+ console.log(streams)
+ expect(streams.length).to.equal(3)
+ expect(streams[0]).to.have.property('startTime')
+ expect(streams[0]).to.have.property('file')
+ expect(streams[0]).to.have.property('size')
+ })
+ xit('should use Voddo\'s stats history to get filenames of only the most recent stream', async function() {
+ const sb = sinon.createSandbox()
+ const viddo = new Voddo({
+ url: 'https://example.com',
+ cwd: '~/Downloads'
+ })
+ sb.stub(viddo, 'stats').value({
+ segments: [{
+ startTime: 1674147647000,
+ size: 192627,
+ file: 'projektmelody 2023-01-19 17_00-projektmelody.mp4'
+ }, {
+ startTime: 1674151247000,
+ size: 192627,
+ file: 'projektmelody 2023-01-19 18_00-projektmelody.mp4'
+ }, {
+ startTime: 1674154847000,
+ size: 192627,
+ file: 'projektmelody 2023-01-19 19_00-projektmelody.mp4'
+ }, {
+ file: 'projektmelody 2023-01-20 20_10-projektmelody.mp4',
+ size: 192627,
+ startTime: 1674245400000,
+ }, {
+ file: 'projektmelody 2023-01-20 21_10-projektmelody.mp4',
+ size: 192627,
+ startTime: 1674249000000,
+ }, {
+ file: 'projektmelody 2023-01-20 22_10-projektmelody.mp4',
+ size: 192627,
+ startTime: 1674252600000,
+ }]
+ })
+
+ const filenames = await viddo.getRecordedSegments()
+ sb.restore()
+ expect(filenames).to.have.lengthOf(3)
+ expect(filenames).to.deep.equal([{
+ file: 'projektmelody 2023-01-20 20_10-projektmelody.mp4',
+ size: 192627,
+ startTime: 1674245400000,
+ }, {
+ file: 'projektmelody 2023-01-20 21_10-projektmelody.mp4',
+ size: 192627,
+ startTime: 1674249000000,
+ }, {
+ file: 'projektmelody 2023-01-20 22_10-projektmelody.mp4',
+ size: 192627,
+ startTime: 1674252600000,
+ }])
+ })
+ })
+
+
+ xit('should keep a log of the files downloaded', function(done) {
+ const ee = new EventEmitter()
+
+
+ const ytdl = sinon.createStubInstance(YoutubeDlWrap)
+ ytdl.exec.returns(ee)
+
+
+ const times = [
+ 1000, // start
+ 1000 * 60 * 60 * 1, // stop
+ 1000 * 60 * 60 * 1 + 1, // start
+ 1000 * 60 * 60 * 2, // stop
+ 1000 * 60 * 60 * 3 + 1, // start
+ 1000 * 60 * 60 * 4 // stop
+ ]
+
+ clock.setTimeout(() => {
+ ee.emit('youtubeDlEvent', 'download', ' Destination: projektmelody 2023-01-18 21_10-projektmelody.mp4')
+ }, times[0])
+
+ clock.setTimeout(() => {
+ ee.emit('close')
+ }, times[1])
+
+ clock.setTimeout(() => {
+ ee.emit('youtubeDlEvent', 'download', ' Destination: projektmelody 2023-01-18 22_10-projektmelody.mp4')
+ }, times[2])
+
+ clock.setTimeout(() => {
+ ee.emit('close')
+ }, times[3])
+
+ clock.setTimeout(() => {
+ ee.emit('youtubeDlEvent', 'download', ' Destination: projektmelody 2023-01-18 23_10-projektmelody.mp4')
+ }, times[4])
+
+ clock.setTimeout(() => {
+ ee.emit('close')
+ }, times[5])
+
+
+ let url = `https://chaturbate.com/projektmelody`
+ let cwd = process.env.FUTUREPORN_WORKDIR || '/tmp'
+ const voddo = new Voddo({
+ url: url,
+ format: 'best',
+ cwd: cwd,
+ ytdl
+ })
+
+ voddo.once('start', (data) => {
+ expect(data).to.have.property('file')
+ expect(data).to.have.property('timestamp')
+
+ voddo.once('start', (data) => {
+ expect(data).to.have.property('file')
+ expect(data).to.have.property('timestamp')
+
+ voddo.once('start', (data) => {
+ expect(data).to.have.property('file')
+ expect(data).to.have.property('timestamp')
+
+ voddo.once('stop', function(report) {
+ debug(report)
+ expect(report).to.have.property('stats')
+ expect(report.stats).to.have.property('files')
+ expect(report.stats.files).to.have.lengthOf(3)
+ debug(report.stats.files)
+ expect(report.stats.files[0]).to.include({
+ file: 'projektmelody 2023-01-18 21_10-projektmelody.mp4'
+ })
+
+ expect(ytdl.exec).calledThrice
+
+ console.log('>>WE ARE DONE')
+ expect(this.clock.countTimers()).to.equal(0)
+ done()
+ })
+ clock.tick(times[5]) // stop
+
+ })
+ clock.tick(times[3]) // stop
+ clock.tick(times[4]) // start
+
+ })
+ clock.tick(times[1]) // stop
+ clock.tick(times[2]) // start
+
+ })
+
+
+ voddo.start()
+ expect(ytdl.exec).calledOnce
+
+ clock.tick(times[0])
+
+
+
+
+ })
+
+ xit('should keep a log of the files downloaded', function(done) {
+ this.timeout(5000)
+ // https://github.com/insanity54/futureporn/issues/13
+ const ytdlStub = sinon.createStubInstance(YoutubeDlWrap)
+ ytdlStub.exec
+ .onCall(0)
+ .callsFake(function(args, opts, aborter) {
+ let ee = new EventEmitter()
+ clock.setTimeout(() => {
+ ee.emit('youtubeDlEvent', 'download', ' Destination: projektmelody 2023-01-18 21_10-projektmelody.mp4')
+ }, 50)
+ clock.setTimeout(() => {
+ ee.emit('close')
+ }, 100)
+ return ee
+ })
+ .onCall(1)
+ .callsFake(function(args, opts, aborter) {
+ let ee = new EventEmitter()
+ clock.setTimeout(() => {
+ ee.emit('youtubeDlEvent', 'download', ' Destination: projektmelody 2023-01-18 22_10-projektmelody.mp4')
+ }, 50)
+ clock.setTimeout(() => {
+ ee.emit('close')
+ }, 100)
+ return ee
+ })
+ .onCall(2)
+ .callsFake(function(args, opts, aborter) {
+ let ee = new EventEmitter()
+ clock.setTimeout(() => {
+ ee.emit('youtubeDlEvent', 'download', ' Destination: projektmelody 2023-01-18 23_10-projektmelody.mp4')
+ }, 50)
+ clock.setTimeout(() => {
+ ee.emit('close')
+ }, 100)
+ return ee
+ })
+ let url = `https://chaturbate.com/projektmelody`
+ let cwd = process.env.FUTUREPORN_WORKDIR || '/tmp'
+
+ const voddo = new Voddo({
+ url: url,
+ format: 'best',
+ cwd: cwd,
+ ytdl: ytdlStub
+ })
+
+ // expect(clock.countTimers()).to.equal(0)
+ voddo.once('start', function(data) {
+ expect(data).to.have.property('file')
+ expect(data).to.have.property('timestamp')
+
+ clock.next()
+ clock.next()
+ voddo.once('start', function(data) {
+ expect(data).to.have.property('file')
+ expect(data).to.have.property('timestamp')
+
+ voddo.once('start', function(data) {
+ debug('fake start?')
+ expect(data).to.have.property('file')
+ expect(data).to.have.property('timestamp')
+
+ voddo.once('stop', function(report) {
+ debug(report)
+ expect(report).to.have.property('stats')
+ expect(report.stats).to.have.property('files')
+ expect(report.stats.files).to.have.lengthOf(3)
+ debug(report.stats.files)
+ expect(report.stats.files[0]).to.include({
+ file: 'projektmelody 2023-01-18 21_10-projektmelody.mp4'
+ })
+
+ sinon.assert.calledThrice(ytdlStub.exec)
+ expect(this.clock.countTimers()).to.equal(0)
+ done()
+ })
+
+
+ })
+ })
+ })
+
+ voddo.start()
+ })
+
+
+ it('should start and stop stream download', test(function(done) {
+
+ const sandbox = this
+
+ const ee = new EventEmitter()
+
+ const ytdl = this.createStubInstance(YoutubeDlWrap);
+ ytdl.exec.returns(ee)
+
+
+ const url = 'https://chaturbate.com/projektmelody'
+ const format = 'best'
+ const cwd = '/tmp'
+ const v = new Voddo({
+ url,
+ format,
+ cwd,
+ ytdl
+ })
+ console.log(v.stats)
+
+ v.once('stop', function(data) {
+ console.log('ffffff')
+ console.log(this)
+ expect(this.abortController.signal.aborted, 'abortController did not abort').to.be.true
+ expect(sandbox.clock.countTimers()).to.equal(0)
+ done()
+ })
+ v.once('start', function(data) {
+ console.log('STARRRRRT')
+ expect(data).to.have.property('file')
+ expect(data).to.have.property('timestamp')
+ expect(this).to.have.property('abortController')
+ console.log('ey cool, voddo started')
+ })
+ v.start()
+
+ const times = [
+ 500,
+ 1000,
+ 2000
+ ]
+
+ this.clock.setTimeout(() => {
+ ee.emit('youtubeDlEvent', 'download', ' Destination: projektmelody 2023-01-18 21_10-projektmelody.mp4')
+ }, times[0])
+
+ this.clock.setTimeout(() => {
+ v.stop()
+ }, times[1])
+
+ this.clock.setTimeout(() => {
+ ee.emit('close')
+ }, times[2])
+
+ this.clock.tick(times[0]) // start
+ this.clock.tick(times[1]) // stop
+ this.clock.tick(times[2]) // close
+
+ }))
+
+
+ xit('should retry when a stream closes', function(done) {
+
+ const ytdlStub = sinon.createStubInstance(YoutubeDlWrap);
+ ytdlStub.exec
+ .onCall(0)
+ .callsFake(function(args, opts, aborter) {
+ debug(' [test] callsFake 0')
+ let ee = new EventEmitter()
+ setTimeout(() => {
+ console.log('should retry when a stream closes -- emission')
+ ee.emit('youtubeDlEvent', 'download', ' Destination: projektmelody 2023-01-17 19_39-projektmelody.mp4')
+ }, 100)
+ setTimeout(() => {
+ console.log('should retry when a stream closes -- emission')
+ // this simulates youtube-dl closing
+ // (NOT Voddo closing)
+ ee.emit('close')
+ }, 550)
+ return ee
+ })
+ .onCall(1)
+ .callsFake(function(args, opts, aborter) {
+ debug(' [test] callsFake 1')
+ let ee = new EventEmitter()
+ setTimeout(() => {
+ ee.emit('youtubeDlEvent', 'download', ' Destination: projektmelody 2023-01-17 19_45-projektmelody.mp4')
+ }, 100)
+ return ee
+ })
+ let url = `https://chaturbate.com/projektmelody`
+ let cwd = process.env.FUTUREPORN_WORKDIR || '/tmp'
+ let abortController = new AbortController()
+
+ const voddo = new Voddo({
+ url: url,
+ format: 'best',
+ cwd: cwd,
+ ytdl: ytdlStub
+ })
+
+ voddo.once('start', function(data) {
+ debug(' [test] voddo <<<<<-----')
+ expect(data).to.have.property('file')
+ expect(data).to.have.property('timestamp')
+
+ voddo.once('start', function(data) {
+ debug(' [test] restarted after dl close! (expected) <<<<<-----')
+
+ sinon.assert.calledTwice(ytdlStub.exec)
+ expect(this.clock.countTimers()).to.equal(0)
+ done()
+ })
+ })
+
+ voddo.start()
+
+ clock.next()
+ clock.next()
+ clock.next()
+ clock.next()
+ clock.next()
+
+ })
+
+})
\ No newline at end of file
diff --git a/packages/helloworld/go.mod b/packages/capture/test/fixtures/just-a-text-file.txt
similarity index 100%
rename from packages/helloworld/go.mod
rename to packages/capture/test/fixtures/just-a-text-file.txt
diff --git a/packages/capture/test/fixtures/mock-stream0.mp4 b/packages/capture/test/fixtures/mock-stream0.mp4
new file mode 100644
index 0000000..d857323
Binary files /dev/null and b/packages/capture/test/fixtures/mock-stream0.mp4 differ
diff --git a/packages/capture/test/fixtures/mock-stream1.mp4 b/packages/capture/test/fixtures/mock-stream1.mp4
new file mode 100644
index 0000000..86a7548
Binary files /dev/null and b/packages/capture/test/fixtures/mock-stream1.mp4 differ
diff --git a/packages/capture/test/fixtures/mock-stream2.mp4 b/packages/capture/test/fixtures/mock-stream2.mp4
new file mode 100644
index 0000000..0e9dc7f
Binary files /dev/null and b/packages/capture/test/fixtures/mock-stream2.mp4 differ
diff --git a/packages/capture/test/integration/Capture.test.js b/packages/capture/test/integration/Capture.test.js
new file mode 100644
index 0000000..a946d53
--- /dev/null
+++ b/packages/capture/test/integration/Capture.test.js
@@ -0,0 +1,123 @@
+import 'dotenv/config'
+import chai, { expect } from 'chai'
+import sinon from 'sinon'
+import sinonChai from 'sinon-chai'
+import { CID } from 'multiformats/cid'
+import EventEmitter from 'node:events'
+import { fileURLToPath } from 'url';
+import path from 'node:path'
+import postgres from 'postgres'
+import Capture from '../src/Capture.js'
+import Voddo from '../src/Voddo.js'
+import Video from '../src/Video.js'
+
+chai.use(sinonChai)
+
+if (typeof process.env.POSTGRES_PASSWORD === 'undefined') throw new Error('missing POSTGRES_PASSWORD');
+if (typeof process.env.POSTGRES_USERNAME === 'undefined') throw new Error('missing POSTGRES_USERNAME');
+
+
+const cidFixture = 'bafybeid3mg5lzrvnmpfi5ftwhiupp7i5bgkmdo7dnlwrvklbv33telrrry'
+const inputFixture = 'projektmelody 3021-10-16 06-16.mp4'
+const outputFixture = 'projektmelody-chaturbate-30211016T000000Z.mp4'
+const timestampFixture = 33191316900000
+
+describe('Capture integration', function () {
+
+ let clock
+
+ beforeEach(() => {
+ clock = sinon.useFakeTimers({
+ toFake: ["setTimeout", "setInterval"],
+ shouldAdvanceTime: false
+ });
+ })
+
+ afterEach(() => {
+ sinon.restore()
+ clock.restore()
+ })
+
+ it('end of stream behavior', async function() {
+ const ipfsClusterUpload = sinon.mock()
+ .withExactArgs(outputFixture)
+ .resolves(cidFixture)
+
+ const sql = postgres({
+ username: process.env.POSTGRES_USERNAME,
+ password: process.env.POSTGRES_PASSWORD,
+ host: process.env.POSTGRES_HOST,
+ database: 'futureporn',
+ idle_timeout: 1
+ })
+
+
+ const voddo = sinon.createStubInstance(Voddo)
+ voddo.on.callThrough()
+ voddo.off.callThrough()
+ voddo.emit.callThrough()
+ voddo.listeners.callThrough()
+ voddo.listenerCount.callThrough()
+ voddo.getFilenames.returns([{
+ timestamp: timestampFixture,
+ filename: inputFixture
+ }])
+
+ const video = sinon.createStubInstance(Video)
+ video.concat.resolves(outputFixture)
+
+ const capture = new Capture({
+ voddo,
+ sql,
+ ipfsClusterUpload,
+ video
+ })
+
+ capture.download()
+ voddo.emit('stop', {
+ reason: 'close',
+ stats: {
+ filenames: [
+ inputFixture
+ ]
+ }
+ })
+
+ clock.next() // actionTimer elapse
+
+
+ expect(clock.countTimers()).to.equal(0)
+ clock.restore()
+
+ // gotta wait to verify otherwise verification
+ // occurs before ipfsClusterUpload has a chance
+ // to be invoked.
+ //
+ // (not sure why)
+ //
+ // maybe we're waiting for the
+ // concat promise to resolve?
+
+ await Promise.resolve(() => {
+ expect(ipfsClusterUpload).calledOnce
+ })
+
+ // Capture.save is called as a side effect
+ // of Capture.process
+ // which is called as a side effect of Capture.download
+ // so we have to wait for it to complete
+ // this is not ideal because there is potential
+ // to not wait long enough
+ await new Promise((resolve) => {
+ setTimeout(resolve, 1000)
+ })
+
+ const rows = await sql`SELECT "videoSrcHash" FROM vod WHERE "videoSrcHash" = ${cidFixture}`
+
+ expect(rows[0]).to.exist
+ expect(rows[0]).to.have.property('videoSrcHash', cidFixture)
+
+
+
+ })
+})
\ No newline at end of file
diff --git a/packages/capture/test/integration/Ipfs.test.js b/packages/capture/test/integration/Ipfs.test.js
new file mode 100644
index 0000000..0b23477
--- /dev/null
+++ b/packages/capture/test/integration/Ipfs.test.js
@@ -0,0 +1,18 @@
+
+import Ipfs from '../src/Ipfs.js'
+import { expect } from 'chai'
+import path, { dirname } from 'path';
+import { fileURLToPath } from 'url';
+const __dirname = dirname(fileURLToPath(import.meta.url));
+
+const ipfsExecutable = '/home/chris/.local/bin/ipfs'
+
+describe('Ipfs', function() {
+ describe('hash', function () {
+ it('should hash a file and return the v1 CID', async function () {
+ const ipfs = new Ipfs({ ipfsExecutable })
+ const cid = await ipfs.hash(path.join(__dirname, '../test/fixtures/mock-stream0.mp4'))
+ expect(cid).to.equal('bafkreihfbftehabfrakhr6tmbx72inewwpayw6cypwgm6lbhbf7mxm7wni')
+ })
+ })
+})
\ No newline at end of file
diff --git a/packages/capture/test/integration/Voddo.test.js b/packages/capture/test/integration/Voddo.test.js
new file mode 100644
index 0000000..7cc3742
--- /dev/null
+++ b/packages/capture/test/integration/Voddo.test.js
@@ -0,0 +1,62 @@
+import 'dotenv/config'
+import Voddo from '../src/Voddo.js'
+import {
+ expect
+} from 'chai'
+import sinon from 'sinon'
+import YoutubeDlWrap from 'youtube-dl-wrap'
+import {
+ EventEmitter
+} from 'events'
+import { getRandomRoom } from '../src/cb.js'
+import path, { dirname } from 'path';
+import { fileURLToPath } from 'url';
+const __dirname = dirname(fileURLToPath(import.meta.url));
+
+
+describe('voddo', function() {
+
+
+ describe('getVideoLength', function () {
+ it('should return the video length in ms', async function () {
+ const fixtureFile = path.join(__dirname, '..', 'test', 'fixtures', 'mock-stream0.mp4')
+ const length = await Voddo.getVideoLength(fixtureFile)
+ expect(length).to.equal(3819)
+ })
+ })
+
+ it('aborted stream', function(done) {
+ this.timeout(10000)
+
+ getRandomRoom().then((room) => {
+ console.log(room)
+ const abortController = new AbortController()
+
+ const url = `https://chaturbate.com/${room}`
+ const format = 'best'
+ const cwd = '/tmp'
+ const voddo = new Voddo({
+ url,
+ format,
+ cwd
+ })
+
+
+ voddo.once('stop', function(data) {
+ console.log('f in chat')
+ expect(voddo.stats.files[0]).to.have.property('size')
+ done()
+ })
+
+ voddo.start()
+
+ setTimeout(() => {
+ voddo.stop()
+ }, 5000)
+ })
+
+
+ })
+
+
+})
\ No newline at end of file
diff --git a/packages/capture/test/integration/record.test.js b/packages/capture/test/integration/record.test.js
new file mode 100644
index 0000000..c0de476
--- /dev/null
+++ b/packages/capture/test/integration/record.test.js
@@ -0,0 +1,35 @@
+import { record, assertDependencyDirectory } from '../../src/record.js'
+import { getRandomRoom } from '../../src/cb.js'
+import path from 'node:path'
+import os from 'node:os'
+import { execa } from 'execa'
+
+describe('record', function() {
+ it('should record a file to disk', async function () {
+ this.timeout(1000*60)
+ const roomName = await getRandomRoom()
+ console.log(`roomName:${roomName}`)
+ const appContext = {
+ env: {
+ FUTUREPORN_WORKDIR: os.tmpdir(),
+ DOWNLOADER_UA: "Mozilla/5.0 (X11; Linux x86_64; rv:105.0) Gecko/20100101 Firefox/105.0"
+ },
+ logger: {
+ log: (msg) => { console.log(JSON.stringify(msg)) }
+ }
+ }
+ console.log(appContext)
+ const { stdout } = await execa('yt-dlp', ['-g', `https://chaturbate.com/${roomName}`])
+ const playlistUrl = stdout.trim()
+ console.log(`playlistUrl:${playlistUrl}`)
+ assertDependencyDirectory(appContext)
+ const ffmpegProc = record(appContext, playlistUrl, roomName)
+ // console.log(ffmpegProc)
+ return new Promise((resolve) => {
+ setTimeout(() => {
+ ffmpegProc.kill('SIGINT')
+ resolve()
+ }, 1000*10)
+ })
+ })
+})
\ No newline at end of file
diff --git a/packages/capture/test/integration/video.test.js b/packages/capture/test/integration/video.test.js
new file mode 100644
index 0000000..b3b7f3f
--- /dev/null
+++ b/packages/capture/test/integration/video.test.js
@@ -0,0 +1,33 @@
+
+import 'dotenv/config'
+import Video from '../src/Video.js'
+import { expect } from 'chai'
+import { dirname } from 'path';
+import { fileURLToPath } from 'url';
+import path from 'node:path'
+
+const __dirname = dirname(fileURLToPath(import.meta.url));
+
+const dataFixture = [
+ {
+ timestamp: 1,
+ file: 'mock-stream0.mp4'
+ }, {
+ timestamp: 2,
+ file: 'mock-stream1.mp4'
+ }, {
+ timestamp: 3,
+ file: 'mock-stream2.mp4'
+ }
+]
+
+xdescribe('video', function () {
+ describe('concat', function () {
+ it('should combine several videos into one', async function() {
+ const cwd = path.join(__dirname, './fixtures')
+ const outputFile = await concat(dataFixture, {
+ cwd
+ })
+ })
+ })
+})
\ No newline at end of file
diff --git a/packages/helloworld/Dockerfile b/packages/helloworld/Dockerfile
deleted file mode 100644
index 13766bd..0000000
--- a/packages/helloworld/Dockerfile
+++ /dev/null
@@ -1,20 +0,0 @@
-# Base Image
-FROM golang:latest
-
-# Set the Current Working Directory inside the container
-WORKDIR /app
-
-# Copy everything from the current directory to the PWD(Present Working Directory) inside the container
-COPY . .
-
-# Download all the dependencies
-RUN go mod download
-
-# Build the Go app
-RUN go build -o main .
-
-# Expose port 8080 to the outside world
-EXPOSE 8080
-
-# Command to run the executable
-CMD ["./main"]
\ No newline at end of file
diff --git a/packages/helloworld/main.go b/packages/helloworld/main.go
deleted file mode 100644
index f298b34..0000000
--- a/packages/helloworld/main.go
+++ /dev/null
@@ -1,13 +0,0 @@
-package main
-
-import "net/http"
-
-func main() {
- http.HandleFunc("/", hellowordhandler)
-
- http.ListenAndServe(":9000", nil)
-}
-
-func hellowordhandler(w http.ResponseWriter, r *http.Request) {
- w.Write([]byte("Hello World"))
-}
\ No newline at end of file
diff --git a/packages/helloworldy/.dockerignore b/packages/helloworldy/.dockerignore
deleted file mode 100644
index 4400aea..0000000
--- a/packages/helloworldy/.dockerignore
+++ /dev/null
@@ -1,2 +0,0 @@
-node_modules
-README.md
\ No newline at end of file
diff --git a/packages/helloworldy/.gitignore b/packages/helloworldy/.gitignore
deleted file mode 100644
index fd3dbb5..0000000
--- a/packages/helloworldy/.gitignore
+++ /dev/null
@@ -1,36 +0,0 @@
-# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
-
-# dependencies
-/node_modules
-/.pnp
-.pnp.js
-.yarn/install-state.gz
-
-# testing
-/coverage
-
-# next.js
-/.next/
-/out/
-
-# production
-/build
-
-# misc
-.DS_Store
-*.pem
-
-# debug
-npm-debug.log*
-yarn-debug.log*
-yarn-error.log*
-
-# local env files
-.env*.local
-
-# vercel
-.vercel
-
-# typescript
-*.tsbuildinfo
-next-env.d.ts
diff --git a/packages/helloworldy/Dockerfile b/packages/helloworldy/Dockerfile
deleted file mode 100644
index 7519fbd..0000000
--- a/packages/helloworldy/Dockerfile
+++ /dev/null
@@ -1,12 +0,0 @@
-FROM node:20
-
-RUN corepack enable
-WORKDIR /app
-
-ADD package.json .
-ADD package-lock.json .
-RUN pnpm install
-
-ADD . .
-
-ENTRYPOINT [ "pnpm", "next", "dev" ]
\ No newline at end of file
diff --git a/packages/helloworldy/README.md b/packages/helloworldy/README.md
deleted file mode 100644
index 0dc9ea2..0000000
--- a/packages/helloworldy/README.md
+++ /dev/null
@@ -1,36 +0,0 @@
-This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app).
-
-## Getting Started
-
-First, run the development server:
-
-```bash
-npm run dev
-# or
-yarn dev
-# or
-pnpm dev
-# or
-bun dev
-```
-
-Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
-
-You can start editing the page by modifying `app/page.js`. The page auto-updates as you edit the file.
-
-This project uses [`next/font`](https://nextjs.org/docs/basic-features/font-optimization) to automatically optimize and load Inter, a custom Google Font.
-
-## Learn More
-
-To learn more about Next.js, take a look at the following resources:
-
-- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
-- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
-
-You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome!
-
-## Deploy on Vercel
-
-The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.
-
-Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details.
diff --git a/packages/helloworldy/app/favicon.ico b/packages/helloworldy/app/favicon.ico
deleted file mode 100644
index 718d6fe..0000000
Binary files a/packages/helloworldy/app/favicon.ico and /dev/null differ
diff --git a/packages/helloworldy/app/globals.css b/packages/helloworldy/app/globals.css
deleted file mode 100644
index f4bd77c..0000000
--- a/packages/helloworldy/app/globals.css
+++ /dev/null
@@ -1,107 +0,0 @@
-:root {
- --max-width: 1100px;
- --border-radius: 12px;
- --font-mono: ui-monospace, Menlo, Monaco, "Cascadia Mono", "Segoe UI Mono",
- "Roboto Mono", "Oxygen Mono", "Ubuntu Monospace", "Source Code Pro",
- "Fira Mono", "Droid Sans Mono", "Courier New", monospace;
-
- --foreground-rgb: 0, 0, 0;
- --background-start-rgb: 214, 219, 220;
- --background-end-rgb: 255, 255, 255;
-
- --primary-glow: conic-gradient(
- from 180deg at 50% 50%,
- #16abff33 0deg,
- #0885ff33 55deg,
- #54d6ff33 120deg,
- #0071ff33 160deg,
- transparent 360deg
- );
- --secondary-glow: radial-gradient(
- rgba(255, 255, 255, 1),
- rgba(255, 255, 255, 0)
- );
-
- --tile-start-rgb: 239, 245, 249;
- --tile-end-rgb: 228, 232, 233;
- --tile-border: conic-gradient(
- #00000080,
- #00000040,
- #00000030,
- #00000020,
- #00000010,
- #00000010,
- #00000080
- );
-
- --callout-rgb: 238, 240, 241;
- --callout-border-rgb: 172, 175, 176;
- --card-rgb: 180, 185, 188;
- --card-border-rgb: 131, 134, 135;
-}
-
-@media (prefers-color-scheme: dark) {
- :root {
- --foreground-rgb: 255, 255, 255;
- --background-start-rgb: 0, 0, 0;
- --background-end-rgb: 0, 0, 0;
-
- --primary-glow: radial-gradient(rgba(1, 65, 255, 0.4), rgba(1, 65, 255, 0));
- --secondary-glow: linear-gradient(
- to bottom right,
- rgba(1, 65, 255, 0),
- rgba(1, 65, 255, 0),
- rgba(1, 65, 255, 0.3)
- );
-
- --tile-start-rgb: 2, 13, 46;
- --tile-end-rgb: 2, 5, 19;
- --tile-border: conic-gradient(
- #ffffff80,
- #ffffff40,
- #ffffff30,
- #ffffff20,
- #ffffff10,
- #ffffff10,
- #ffffff80
- );
-
- --callout-rgb: 20, 20, 20;
- --callout-border-rgb: 108, 108, 108;
- --card-rgb: 100, 100, 100;
- --card-border-rgb: 200, 200, 200;
- }
-}
-
-* {
- box-sizing: border-box;
- padding: 0;
- margin: 0;
-}
-
-html,
-body {
- max-width: 100vw;
- overflow-x: hidden;
-}
-
-body {
- color: rgb(var(--foreground-rgb));
- background: linear-gradient(
- to bottom,
- transparent,
- rgb(var(--background-end-rgb))
- )
- rgb(var(--background-start-rgb));
-}
-
-a {
- color: inherit;
- text-decoration: none;
-}
-
-@media (prefers-color-scheme: dark) {
- html {
- color-scheme: dark;
- }
-}
diff --git a/packages/helloworldy/app/layout.js b/packages/helloworldy/app/layout.js
deleted file mode 100644
index 9aef1df..0000000
--- a/packages/helloworldy/app/layout.js
+++ /dev/null
@@ -1,17 +0,0 @@
-import { Inter } from "next/font/google";
-import "./globals.css";
-
-const inter = Inter({ subsets: ["latin"] });
-
-export const metadata = {
- title: "Create Next App",
- description: "Generated by create next app",
-};
-
-export default function RootLayout({ children }) {
- return (
-
-
{children}
-
- );
-}
diff --git a/packages/helloworldy/app/page.js b/packages/helloworldy/app/page.js
deleted file mode 100644
index 6f71460..0000000
--- a/packages/helloworldy/app/page.js
+++ /dev/null
@@ -1,95 +0,0 @@
-import Image from "next/image";
-import styles from "./page.module.css";
-
-export default function Home() {
- return (
-
-
-
- Get started by editing
- app/page.js
-
-
-
-
-
-
-
-
-
-
- );
-}
diff --git a/packages/helloworldy/app/page.module.css b/packages/helloworldy/app/page.module.css
deleted file mode 100644
index 5c4b1e6..0000000
--- a/packages/helloworldy/app/page.module.css
+++ /dev/null
@@ -1,230 +0,0 @@
-.main {
- display: flex;
- flex-direction: column;
- justify-content: space-between;
- align-items: center;
- padding: 6rem;
- min-height: 100vh;
-}
-
-.description {
- display: inherit;
- justify-content: inherit;
- align-items: inherit;
- font-size: 0.85rem;
- max-width: var(--max-width);
- width: 100%;
- z-index: 2;
- font-family: var(--font-mono);
-}
-
-.description a {
- display: flex;
- justify-content: center;
- align-items: center;
- gap: 0.5rem;
-}
-
-.description p {
- position: relative;
- margin: 0;
- padding: 1rem;
- background-color: rgba(var(--callout-rgb), 0.5);
- border: 1px solid rgba(var(--callout-border-rgb), 0.3);
- border-radius: var(--border-radius);
-}
-
-.code {
- font-weight: 700;
- font-family: var(--font-mono);
-}
-
-.grid {
- display: grid;
- grid-template-columns: repeat(4, minmax(25%, auto));
- max-width: 100%;
- width: var(--max-width);
-}
-
-.card {
- padding: 1rem 1.2rem;
- border-radius: var(--border-radius);
- background: rgba(var(--card-rgb), 0);
- border: 1px solid rgba(var(--card-border-rgb), 0);
- transition: background 200ms, border 200ms;
-}
-
-.card span {
- display: inline-block;
- transition: transform 200ms;
-}
-
-.card h2 {
- font-weight: 600;
- margin-bottom: 0.7rem;
-}
-
-.card p {
- margin: 0;
- opacity: 0.6;
- font-size: 0.9rem;
- line-height: 1.5;
- max-width: 30ch;
- text-wrap: balance;
-}
-
-.center {
- display: flex;
- justify-content: center;
- align-items: center;
- position: relative;
- padding: 4rem 0;
-}
-
-.center::before {
- background: var(--secondary-glow);
- border-radius: 50%;
- width: 480px;
- height: 360px;
- margin-left: -400px;
-}
-
-.center::after {
- background: var(--primary-glow);
- width: 240px;
- height: 180px;
- z-index: -1;
-}
-
-.center::before,
-.center::after {
- content: "";
- left: 50%;
- position: absolute;
- filter: blur(45px);
- transform: translateZ(0);
-}
-
-.logo {
- position: relative;
-}
-/* Enable hover only on non-touch devices */
-@media (hover: hover) and (pointer: fine) {
- .card:hover {
- background: rgba(var(--card-rgb), 0.1);
- border: 1px solid rgba(var(--card-border-rgb), 0.15);
- }
-
- .card:hover span {
- transform: translateX(4px);
- }
-}
-
-@media (prefers-reduced-motion) {
- .card:hover span {
- transform: none;
- }
-}
-
-/* Mobile */
-@media (max-width: 700px) {
- .content {
- padding: 4rem;
- }
-
- .grid {
- grid-template-columns: 1fr;
- margin-bottom: 120px;
- max-width: 320px;
- text-align: center;
- }
-
- .card {
- padding: 1rem 2.5rem;
- }
-
- .card h2 {
- margin-bottom: 0.5rem;
- }
-
- .center {
- padding: 8rem 0 6rem;
- }
-
- .center::before {
- transform: none;
- height: 300px;
- }
-
- .description {
- font-size: 0.8rem;
- }
-
- .description a {
- padding: 1rem;
- }
-
- .description p,
- .description div {
- display: flex;
- justify-content: center;
- position: fixed;
- width: 100%;
- }
-
- .description p {
- align-items: center;
- inset: 0 0 auto;
- padding: 2rem 1rem 1.4rem;
- border-radius: 0;
- border: none;
- border-bottom: 1px solid rgba(var(--callout-border-rgb), 0.25);
- background: linear-gradient(
- to bottom,
- rgba(var(--background-start-rgb), 1),
- rgba(var(--callout-rgb), 0.5)
- );
- background-clip: padding-box;
- backdrop-filter: blur(24px);
- }
-
- .description div {
- align-items: flex-end;
- pointer-events: none;
- inset: auto 0 0;
- padding: 2rem;
- height: 200px;
- background: linear-gradient(
- to bottom,
- transparent 0%,
- rgb(var(--background-end-rgb)) 40%
- );
- z-index: 1;
- }
-}
-
-/* Tablet and Smaller Desktop */
-@media (min-width: 701px) and (max-width: 1120px) {
- .grid {
- grid-template-columns: repeat(2, 50%);
- }
-}
-
-@media (prefers-color-scheme: dark) {
- .vercelLogo {
- filter: invert(1);
- }
-
- .logo {
- filter: invert(1) drop-shadow(0 0 0.3rem #ffffff70);
- }
-}
-
-@keyframes rotate {
- from {
- transform: rotate(360deg);
- }
- to {
- transform: rotate(0deg);
- }
-}
diff --git a/packages/helloworldy/jsconfig.json b/packages/helloworldy/jsconfig.json
deleted file mode 100644
index 2a2e4b3..0000000
--- a/packages/helloworldy/jsconfig.json
+++ /dev/null
@@ -1,7 +0,0 @@
-{
- "compilerOptions": {
- "paths": {
- "@/*": ["./*"]
- }
- }
-}
diff --git a/packages/helloworldy/next.config.mjs b/packages/helloworldy/next.config.mjs
deleted file mode 100644
index 4678774..0000000
--- a/packages/helloworldy/next.config.mjs
+++ /dev/null
@@ -1,4 +0,0 @@
-/** @type {import('next').NextConfig} */
-const nextConfig = {};
-
-export default nextConfig;
diff --git a/packages/helloworldy/package-lock.json b/packages/helloworldy/package-lock.json
deleted file mode 100644
index 8867e0b..0000000
--- a/packages/helloworldy/package-lock.json
+++ /dev/null
@@ -1,389 +0,0 @@
-{
- "name": "helloworldy",
- "version": "0.1.0",
- "lockfileVersion": 3,
- "requires": true,
- "packages": {
- "": {
- "name": "helloworldy",
- "version": "0.1.0",
- "dependencies": {
- "next": "14.1.3",
- "react": "^18",
- "react-dom": "^18"
- }
- },
- "node_modules/@next/env": {
- "version": "14.1.3",
- "resolved": "https://registry.npmjs.org/@next/env/-/env-14.1.3.tgz",
- "integrity": "sha512-VhgXTvrgeBRxNPjyfBsDIMvgsKDxjlpw4IAUsHCX8Gjl1vtHUYRT3+xfQ/wwvLPDd/6kqfLqk9Pt4+7gysuCKQ=="
- },
- "node_modules/@next/swc-darwin-arm64": {
- "version": "14.1.3",
- "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-14.1.3.tgz",
- "integrity": "sha512-LALu0yIBPRiG9ANrD5ncB3pjpO0Gli9ZLhxdOu6ZUNf3x1r3ea1rd9Q+4xxUkGrUXLqKVK9/lDkpYIJaCJ6AHQ==",
- "cpu": [
- "arm64"
- ],
- "optional": true,
- "os": [
- "darwin"
- ],
- "engines": {
- "node": ">= 10"
- }
- },
- "node_modules/@next/swc-darwin-x64": {
- "version": "14.1.3",
- "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-14.1.3.tgz",
- "integrity": "sha512-E/9WQeXxkqw2dfcn5UcjApFgUq73jqNKaE5bysDm58hEUdUGedVrnRhblhJM7HbCZNhtVl0j+6TXsK0PuzXTCg==",
- "cpu": [
- "x64"
- ],
- "optional": true,
- "os": [
- "darwin"
- ],
- "engines": {
- "node": ">= 10"
- }
- },
- "node_modules/@next/swc-linux-arm64-gnu": {
- "version": "14.1.3",
- "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-14.1.3.tgz",
- "integrity": "sha512-USArX9B+3rZSXYLFvgy0NVWQgqh6LHWDmMt38O4lmiJNQcwazeI6xRvSsliDLKt+78KChVacNiwvOMbl6g6BBw==",
- "cpu": [
- "arm64"
- ],
- "optional": true,
- "os": [
- "linux"
- ],
- "engines": {
- "node": ">= 10"
- }
- },
- "node_modules/@next/swc-linux-arm64-musl": {
- "version": "14.1.3",
- "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-14.1.3.tgz",
- "integrity": "sha512-esk1RkRBLSIEp1qaQXv1+s6ZdYzuVCnDAZySpa62iFTMGTisCyNQmqyCTL9P+cLJ4N9FKCI3ojtSfsyPHJDQNw==",
- "cpu": [
- "arm64"
- ],
- "optional": true,
- "os": [
- "linux"
- ],
- "engines": {
- "node": ">= 10"
- }
- },
- "node_modules/@next/swc-linux-x64-gnu": {
- "version": "14.1.3",
- "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-14.1.3.tgz",
- "integrity": "sha512-8uOgRlYEYiKo0L8YGeS+3TudHVDWDjPVDUcST+z+dUzgBbTEwSSIaSgF/vkcC1T/iwl4QX9iuUyUdQEl0Kxalg==",
- "cpu": [
- "x64"
- ],
- "optional": true,
- "os": [
- "linux"
- ],
- "engines": {
- "node": ">= 10"
- }
- },
- "node_modules/@next/swc-linux-x64-musl": {
- "version": "14.1.3",
- "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-14.1.3.tgz",
- "integrity": "sha512-DX2zqz05ziElLoxskgHasaJBREC5Y9TJcbR2LYqu4r7naff25B4iXkfXWfcp69uD75/0URmmoSgT8JclJtrBoQ==",
- "cpu": [
- "x64"
- ],
- "optional": true,
- "os": [
- "linux"
- ],
- "engines": {
- "node": ">= 10"
- }
- },
- "node_modules/@next/swc-win32-arm64-msvc": {
- "version": "14.1.3",
- "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-14.1.3.tgz",
- "integrity": "sha512-HjssFsCdsD4GHstXSQxsi2l70F/5FsRTRQp8xNgmQs15SxUfUJRvSI9qKny/jLkY3gLgiCR3+6A7wzzK0DBlfA==",
- "cpu": [
- "arm64"
- ],
- "optional": true,
- "os": [
- "win32"
- ],
- "engines": {
- "node": ">= 10"
- }
- },
- "node_modules/@next/swc-win32-ia32-msvc": {
- "version": "14.1.3",
- "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-14.1.3.tgz",
- "integrity": "sha512-DRuxD5axfDM1/Ue4VahwSxl1O5rn61hX8/sF0HY8y0iCbpqdxw3rB3QasdHn/LJ6Wb2y5DoWzXcz3L1Cr+Thrw==",
- "cpu": [
- "ia32"
- ],
- "optional": true,
- "os": [
- "win32"
- ],
- "engines": {
- "node": ">= 10"
- }
- },
- "node_modules/@next/swc-win32-x64-msvc": {
- "version": "14.1.3",
- "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-14.1.3.tgz",
- "integrity": "sha512-uC2DaDoWH7h1P/aJ4Fok3Xiw6P0Lo4ez7NbowW2VGNXw/Xv6tOuLUcxhBYZxsSUJtpeknCi8/fvnSpyCFp4Rcg==",
- "cpu": [
- "x64"
- ],
- "optional": true,
- "os": [
- "win32"
- ],
- "engines": {
- "node": ">= 10"
- }
- },
- "node_modules/@swc/helpers": {
- "version": "0.5.2",
- "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.2.tgz",
- "integrity": "sha512-E4KcWTpoLHqwPHLxidpOqQbcrZVgi0rsmmZXUle1jXmJfuIf/UWpczUJ7MZZ5tlxytgJXyp0w4PGkkeLiuIdZw==",
- "dependencies": {
- "tslib": "^2.4.0"
- }
- },
- "node_modules/busboy": {
- "version": "1.6.0",
- "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz",
- "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==",
- "dependencies": {
- "streamsearch": "^1.1.0"
- },
- "engines": {
- "node": ">=10.16.0"
- }
- },
- "node_modules/caniuse-lite": {
- "version": "1.0.30001599",
- "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001599.tgz",
- "integrity": "sha512-LRAQHZ4yT1+f9LemSMeqdMpMxZcc4RMWdj4tiFe3G8tNkWK+E58g+/tzotb5cU6TbcVJLr4fySiAW7XmxQvZQA==",
- "funding": [
- {
- "type": "opencollective",
- "url": "https://opencollective.com/browserslist"
- },
- {
- "type": "tidelift",
- "url": "https://tidelift.com/funding/github/npm/caniuse-lite"
- },
- {
- "type": "github",
- "url": "https://github.com/sponsors/ai"
- }
- ]
- },
- "node_modules/client-only": {
- "version": "0.0.1",
- "resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz",
- "integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA=="
- },
- "node_modules/graceful-fs": {
- "version": "4.2.11",
- "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
- "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="
- },
- "node_modules/js-tokens": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
- "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="
- },
- "node_modules/loose-envify": {
- "version": "1.4.0",
- "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
- "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
- "dependencies": {
- "js-tokens": "^3.0.0 || ^4.0.0"
- },
- "bin": {
- "loose-envify": "cli.js"
- }
- },
- "node_modules/nanoid": {
- "version": "3.3.7",
- "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz",
- "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==",
- "funding": [
- {
- "type": "github",
- "url": "https://github.com/sponsors/ai"
- }
- ],
- "bin": {
- "nanoid": "bin/nanoid.cjs"
- },
- "engines": {
- "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
- }
- },
- "node_modules/next": {
- "version": "14.1.3",
- "resolved": "https://registry.npmjs.org/next/-/next-14.1.3.tgz",
- "integrity": "sha512-oexgMV2MapI0UIWiXKkixF8J8ORxpy64OuJ/J9oVUmIthXOUCcuVEZX+dtpgq7wIfIqtBwQsKEDXejcjTsan9g==",
- "dependencies": {
- "@next/env": "14.1.3",
- "@swc/helpers": "0.5.2",
- "busboy": "1.6.0",
- "caniuse-lite": "^1.0.30001579",
- "graceful-fs": "^4.2.11",
- "postcss": "8.4.31",
- "styled-jsx": "5.1.1"
- },
- "bin": {
- "next": "dist/bin/next"
- },
- "engines": {
- "node": ">=18.17.0"
- },
- "optionalDependencies": {
- "@next/swc-darwin-arm64": "14.1.3",
- "@next/swc-darwin-x64": "14.1.3",
- "@next/swc-linux-arm64-gnu": "14.1.3",
- "@next/swc-linux-arm64-musl": "14.1.3",
- "@next/swc-linux-x64-gnu": "14.1.3",
- "@next/swc-linux-x64-musl": "14.1.3",
- "@next/swc-win32-arm64-msvc": "14.1.3",
- "@next/swc-win32-ia32-msvc": "14.1.3",
- "@next/swc-win32-x64-msvc": "14.1.3"
- },
- "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
- }
- }
- },
- "node_modules/picocolors": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz",
- "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ=="
- },
- "node_modules/postcss": {
- "version": "8.4.31",
- "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz",
- "integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==",
- "funding": [
- {
- "type": "opencollective",
- "url": "https://opencollective.com/postcss/"
- },
- {
- "type": "tidelift",
- "url": "https://tidelift.com/funding/github/npm/postcss"
- },
- {
- "type": "github",
- "url": "https://github.com/sponsors/ai"
- }
- ],
- "dependencies": {
- "nanoid": "^3.3.6",
- "picocolors": "^1.0.0",
- "source-map-js": "^1.0.2"
- },
- "engines": {
- "node": "^10 || ^12 || >=14"
- }
- },
- "node_modules/react": {
- "version": "18.2.0",
- "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz",
- "integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==",
- "dependencies": {
- "loose-envify": "^1.1.0"
- },
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/react-dom": {
- "version": "18.2.0",
- "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz",
- "integrity": "sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==",
- "dependencies": {
- "loose-envify": "^1.1.0",
- "scheduler": "^0.23.0"
- },
- "peerDependencies": {
- "react": "^18.2.0"
- }
- },
- "node_modules/scheduler": {
- "version": "0.23.0",
- "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz",
- "integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==",
- "dependencies": {
- "loose-envify": "^1.1.0"
- }
- },
- "node_modules/source-map-js": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.1.0.tgz",
- "integrity": "sha512-9vC2SfsJzlej6MAaMPLu8HiBSHGdRAJ9hVFYN1ibZoNkeanmDmLUcIrj6G9DGL7XMJ54AKg/G75akXl1/izTOw==",
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/streamsearch": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz",
- "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==",
- "engines": {
- "node": ">=10.0.0"
- }
- },
- "node_modules/styled-jsx": {
- "version": "5.1.1",
- "resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.1.1.tgz",
- "integrity": "sha512-pW7uC1l4mBZ8ugbiZrcIsiIvVx1UmTfw7UkC3Um2tmfUq9Bhk8IiyEIPl6F8agHgjzku6j0xQEZbfA5uSgSaCw==",
- "dependencies": {
- "client-only": "0.0.1"
- },
- "engines": {
- "node": ">= 12.0.0"
- },
- "peerDependencies": {
- "react": ">= 16.8.0 || 17.x.x || ^18.0.0-0"
- },
- "peerDependenciesMeta": {
- "@babel/core": {
- "optional": true
- },
- "babel-plugin-macros": {
- "optional": true
- }
- }
- },
- "node_modules/tslib": {
- "version": "2.6.2",
- "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz",
- "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q=="
- }
- }
-}
diff --git a/packages/helloworldy/package.json b/packages/helloworldy/package.json
deleted file mode 100644
index 5509079..0000000
--- a/packages/helloworldy/package.json
+++ /dev/null
@@ -1,16 +0,0 @@
-{
- "name": "helloworldy",
- "version": "0.1.0",
- "private": true,
- "scripts": {
- "dev": "next dev",
- "build": "next build",
- "start": "next start",
- "lint": "next lint"
- },
- "dependencies": {
- "react": "^18",
- "react-dom": "^18",
- "next": "14.1.3"
- }
-}
diff --git a/packages/helloworldy/public/next.svg b/packages/helloworldy/public/next.svg
deleted file mode 100644
index 5174b28..0000000
--- a/packages/helloworldy/public/next.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/packages/helloworldy/public/vercel.svg b/packages/helloworldy/public/vercel.svg
deleted file mode 100644
index d2f8422..0000000
--- a/packages/helloworldy/public/vercel.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/packages/link2cid/pnpm-lock.yaml b/packages/link2cid/pnpm-lock.yaml
index a78265f..6c33f1b 100644
--- a/packages/link2cid/pnpm-lock.yaml
+++ b/packages/link2cid/pnpm-lock.yaml
@@ -1,165 +1,656 @@
-lockfileVersion: '6.0'
+lockfileVersion: '9.0'
settings:
autoInstallPeers: true
excludeLinksFromLockfile: false
-dependencies:
- '@paralleldrive/cuid2':
- specifier: ^2.2.2
- version: 2.2.2
- '@types/express':
- specifier: ^4.17.21
- version: 4.17.21
- better-queue:
- specifier: ^3.8.12
- version: 3.8.12
- 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
+importers:
-devDependencies:
- chai:
- specifier: ^5.1.0
- version: 5.1.0
- supertest:
- specifier: ^6.3.4
- version: 6.3.4
+ .:
+ dependencies:
+ '@paralleldrive/cuid2':
+ specifier: ^2.2.2
+ version: 2.2.2
+ '@types/express':
+ specifier: ^4.17.21
+ version: 4.17.21
+ better-queue:
+ specifier: ^3.8.12
+ version: 3.8.12
+ 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
+ devDependencies:
+ chai:
+ specifier: ^5.1.0
+ version: 5.1.0
+ nodemon:
+ specifier: ^3.0.3
+ version: 3.1.0
+ supertest:
+ specifier: ^6.3.4
+ version: 6.3.4
packages:
- /@noble/hashes@1.4.0:
+ '@noble/hashes@1.4.0':
resolution: {integrity: sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg==}
engines: {node: '>= 16'}
- dev: false
- /@paralleldrive/cuid2@2.2.2:
+ '@paralleldrive/cuid2@2.2.2':
resolution: {integrity: sha512-ZOBkgDwEdoYVlSeRbYYXs0S9MejQofiVYoTbKzy/6GQa39/q5tQU2IX46+shYnUkpEl3wc+J6wRlar7r2EK2xA==}
+
+ '@types/body-parser@1.19.5':
+ resolution: {integrity: sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==}
+
+ '@types/connect@3.4.38':
+ resolution: {integrity: sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==}
+
+ '@types/express-serve-static-core@4.17.41':
+ resolution: {integrity: sha512-OaJ7XLaelTgrvlZD8/aa0vvvxZdUmlCn6MtWeB7TkiKW70BQLc9XEPpDLPdbo52ZhXUCrznlWdCHWxJWtdyajA==}
+
+ '@types/express@4.17.21':
+ resolution: {integrity: sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ==}
+
+ '@types/http-errors@2.0.4':
+ resolution: {integrity: sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==}
+
+ '@types/mime@1.3.5':
+ resolution: {integrity: sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==}
+
+ '@types/mime@3.0.4':
+ resolution: {integrity: sha512-iJt33IQnVRkqeqC7PzBHPTC6fDlRNRW8vjrgqtScAhrmMwe8c4Eo7+fUGTa+XdWrpEgpyKWMYmi2dIwMAYRzPw==}
+
+ '@types/node@20.10.5':
+ resolution: {integrity: sha512-nNPsNE65wjMxEKI93yOP+NPGGBJz/PoN3kZsVLee0XMiJolxSekEVD8wRwBUBqkwc7UWop0edW50yrCQW4CyRw==}
+
+ '@types/qs@6.9.10':
+ resolution: {integrity: sha512-3Gnx08Ns1sEoCrWssEgTSJs/rsT2vhGP+Ja9cnnk9k4ALxinORlQneLXFeFKOTJMOeZUFD1s7w+w2AphTpvzZw==}
+
+ '@types/range-parser@1.2.7':
+ resolution: {integrity: sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==}
+
+ '@types/send@0.17.4':
+ resolution: {integrity: sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA==}
+
+ '@types/serve-static@1.15.5':
+ resolution: {integrity: sha512-PDRk21MnK70hja/YF8AHfC7yIsiQHn1rcXx7ijCFBX/k+XQJhQT/gw3xekXKJvx+5SXaMMS8oqQy09Mzvz2TuQ==}
+
+ accepts@1.3.8:
+ resolution: {integrity: sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==}
+ engines: {node: '>= 0.6'}
+
+ anymatch@3.1.3:
+ resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==}
+ engines: {node: '>= 8'}
+
+ array-flatten@1.1.1:
+ resolution: {integrity: sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==}
+
+ asap@2.0.6:
+ resolution: {integrity: sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==}
+
+ assertion-error@2.0.1:
+ resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==}
+ engines: {node: '>=12'}
+
+ asynckit@0.4.0:
+ resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==}
+
+ balanced-match@1.0.2:
+ resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
+
+ better-queue-memory@1.0.4:
+ resolution: {integrity: sha512-SWg5wFIShYffEmJpI6LgbL8/3Dqhku7xI1oEiy6FroP9DbcZlG0ZDjxvPdP9t7hTGW40IpIcC6zVoGT1oxjOuA==}
+
+ better-queue@3.8.12:
+ resolution: {integrity: sha512-D9KZ+Us+2AyaCz693/9AyjTg0s8hEmkiM/MB3i09cs4MdK1KgTSGJluXRYmOulR69oLZVo2XDFtqsExDt8oiLA==}
+
+ binary-extensions@2.3.0:
+ resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==}
+ engines: {node: '>=8'}
+
+ body-parser@1.20.1:
+ resolution: {integrity: sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==}
+ engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16}
+
+ body-parser@1.20.2:
+ resolution: {integrity: sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==}
+ engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16}
+
+ brace-expansion@1.1.11:
+ resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==}
+
+ braces@3.0.3:
+ resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==}
+ engines: {node: '>=8'}
+
+ bytes@3.1.2:
+ resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==}
+ engines: {node: '>= 0.8'}
+
+ call-bind@1.0.5:
+ resolution: {integrity: sha512-C3nQxfFZxFRVoJoGKKI8y3MOEo129NQ+FgQ08iye+Mk4zNZZGdjfs06bVTr+DBSlA66Q2VEcMki/cUCP4SercQ==}
+
+ chai@5.1.0:
+ resolution: {integrity: sha512-kDZ7MZyM6Q1DhR9jy7dalKohXQ2yrlXkk59CR52aRKxJrobmlBNqnFQxX9xOX8w+4mz8SYlKJa/7D7ddltFXCw==}
+ engines: {node: '>=12'}
+
+ check-error@2.0.0:
+ resolution: {integrity: sha512-tjLAOBHKVxtPoHe/SA7kNOMvhCRdCJ3vETdeY0RuAc9popf+hyaSV6ZEg9hr4cpWF7jmo/JSWEnLDrnijS9Tog==}
+ engines: {node: '>= 16'}
+
+ chokidar@3.6.0:
+ resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==}
+ engines: {node: '>= 8.10.0'}
+
+ combined-stream@1.0.8:
+ resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==}
+ engines: {node: '>= 0.8'}
+
+ component-emitter@1.3.1:
+ resolution: {integrity: sha512-T0+barUSQRTUQASh8bx02dl+DhF54GtIDY13Y3m9oWTklKbb3Wv974meRpeZ3lp1JpLVECWWNHC4vaG2XHXouQ==}
+
+ concat-map@0.0.1:
+ resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==}
+
+ content-disposition@0.5.4:
+ resolution: {integrity: sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==}
+ engines: {node: '>= 0.6'}
+
+ content-type@1.0.5:
+ resolution: {integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==}
+ engines: {node: '>= 0.6'}
+
+ cookie-signature@1.0.6:
+ resolution: {integrity: sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==}
+
+ cookie@0.5.0:
+ resolution: {integrity: sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==}
+ engines: {node: '>= 0.6'}
+
+ cookiejar@2.1.4:
+ resolution: {integrity: sha512-LDx6oHrK+PhzLKJU9j5S7/Y3jM/mUHvD/DeI1WQmJn652iPC5Y4TBzC9l+5OMOXlyTTA+SmVUPm0HQUwpD5Jqw==}
+
+ cors@2.8.5:
+ resolution: {integrity: sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==}
+ engines: {node: '>= 0.10'}
+
+ debug@2.6.9:
+ resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==}
+ peerDependencies:
+ supports-color: '*'
+ peerDependenciesMeta:
+ supports-color:
+ optional: true
+
+ debug@4.3.4:
+ resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==}
+ engines: {node: '>=6.0'}
+ peerDependencies:
+ supports-color: '*'
+ peerDependenciesMeta:
+ supports-color:
+ optional: true
+
+ deep-eql@5.0.1:
+ resolution: {integrity: sha512-nwQCf6ne2gez3o1MxWifqkciwt0zhl0LO1/UwVu4uMBuPmflWM4oQ70XMqHqnBJA+nhzncaqL9HVL6KkHJ28lw==}
+ engines: {node: '>=6'}
+
+ define-data-property@1.1.1:
+ resolution: {integrity: sha512-E7uGkTzkk1d0ByLeSc6ZsFS79Axg+m1P/VsgYsxHgiuc3tFSj+MjMIwe90FC4lOAZzNBdY7kkO2P2wKdsQ1vgQ==}
+ engines: {node: '>= 0.4'}
+
+ delayed-stream@1.0.0:
+ resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==}
+ engines: {node: '>=0.4.0'}
+
+ depd@2.0.0:
+ resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==}
+ engines: {node: '>= 0.8'}
+
+ destroy@1.2.0:
+ resolution: {integrity: sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==}
+ engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16}
+
+ dezalgo@1.0.4:
+ resolution: {integrity: sha512-rXSP0bf+5n0Qonsb+SVVfNfIsimO4HEtmnIpPHY8Q1UCzKlQrDMfdobr8nJOOsRgWCyMRqeSBQzmWUMq7zvVig==}
+
+ dotenv@16.3.1:
+ resolution: {integrity: sha512-IPzF4w4/Rd94bA9imS68tZBaYyBWSCE47V1RGuMrB94iyTOIEwRmVL2x/4An+6mETpLrKJ5hQkB8W4kFAadeIQ==}
+ engines: {node: '>=12'}
+
+ ee-first@1.1.1:
+ resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==}
+
+ encodeurl@1.0.2:
+ resolution: {integrity: sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==}
+ engines: {node: '>= 0.8'}
+
+ escape-html@1.0.3:
+ resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==}
+
+ etag@1.8.1:
+ resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==}
+ engines: {node: '>= 0.6'}
+
+ express@4.18.2:
+ resolution: {integrity: sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==}
+ engines: {node: '>= 0.10.0'}
+
+ fast-safe-stringify@2.1.1:
+ resolution: {integrity: sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==}
+
+ fill-range@7.1.1:
+ resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==}
+ engines: {node: '>=8'}
+
+ finalhandler@1.2.0:
+ resolution: {integrity: sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==}
+ engines: {node: '>= 0.8'}
+
+ form-data@4.0.0:
+ resolution: {integrity: sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==}
+ engines: {node: '>= 6'}
+
+ formidable@2.1.2:
+ resolution: {integrity: sha512-CM3GuJ57US06mlpQ47YcunuUZ9jpm8Vx+P2CGt2j7HpgkKZO/DJYQ0Bobim8G6PFQmK5lOqOOdUXboU+h73A4g==}
+
+ forwarded@0.2.0:
+ resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==}
+ engines: {node: '>= 0.6'}
+
+ fresh@0.5.2:
+ resolution: {integrity: sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==}
+ engines: {node: '>= 0.6'}
+
+ fsevents@2.3.3:
+ resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==}
+ engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
+ os: [darwin]
+
+ function-bind@1.1.2:
+ resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==}
+
+ get-func-name@2.0.2:
+ resolution: {integrity: sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==}
+
+ get-intrinsic@1.2.2:
+ resolution: {integrity: sha512-0gSo4ml/0j98Y3lngkFEot/zhiCeWsbYIlZ+uZOVgzLyLaUw7wxUL+nCTP0XJvJg1AXulJRI3UJi8GsbDuxdGA==}
+
+ glob-parent@5.1.2:
+ resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==}
+ engines: {node: '>= 6'}
+
+ gopd@1.0.1:
+ resolution: {integrity: sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==}
+
+ has-flag@3.0.0:
+ resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==}
+ engines: {node: '>=4'}
+
+ has-property-descriptors@1.0.1:
+ resolution: {integrity: sha512-VsX8eaIewvas0xnvinAe9bw4WfIeODpGYikiWYLH+dma0Jw6KHYqWiWfhQlgOVK8D6PvjubK5Uc4P0iIhIcNVg==}
+
+ 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'}
+
+ hasown@2.0.0:
+ resolution: {integrity: sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==}
+ engines: {node: '>= 0.4'}
+
+ hexoid@1.0.0:
+ resolution: {integrity: sha512-QFLV0taWQOZtvIRIAdBChesmogZrtuXvVWsFHZTk2SU+anspqZ2vMnoLg7IE1+Uk16N19APic1BuF8bC8c2m5g==}
+ engines: {node: '>=8'}
+
+ http-errors@2.0.0:
+ resolution: {integrity: sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==}
+ engines: {node: '>= 0.8'}
+
+ iconv-lite@0.4.24:
+ resolution: {integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==}
+ engines: {node: '>=0.10.0'}
+
+ ignore-by-default@1.0.1:
+ resolution: {integrity: sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==}
+
+ inherits@2.0.4:
+ resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==}
+
+ ipaddr.js@1.9.1:
+ resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==}
+ engines: {node: '>= 0.10'}
+
+ is-binary-path@2.1.0:
+ resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==}
+ engines: {node: '>=8'}
+
+ is-extglob@2.1.1:
+ resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==}
+ engines: {node: '>=0.10.0'}
+
+ is-glob@4.0.3:
+ resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==}
+ engines: {node: '>=0.10.0'}
+
+ is-number@7.0.0:
+ resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==}
+ engines: {node: '>=0.12.0'}
+
+ loupe@3.1.0:
+ resolution: {integrity: sha512-qKl+FrLXUhFuHUoDJG7f8P8gEMHq9NFS0c6ghXG1J0rldmZFQZoNVv/vyirE9qwCIhWZDsvEFd1sbFu3GvRQFg==}
+
+ lru-cache@6.0.0:
+ resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==}
+ engines: {node: '>=10'}
+
+ media-typer@0.3.0:
+ resolution: {integrity: sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==}
+ engines: {node: '>= 0.6'}
+
+ merge-descriptors@1.0.1:
+ resolution: {integrity: sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==}
+
+ methods@1.1.2:
+ resolution: {integrity: sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==}
+ engines: {node: '>= 0.6'}
+
+ mime-db@1.52.0:
+ resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==}
+ engines: {node: '>= 0.6'}
+
+ mime-types@2.1.35:
+ resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==}
+ engines: {node: '>= 0.6'}
+
+ mime@1.6.0:
+ resolution: {integrity: sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==}
+ engines: {node: '>=4'}
+ hasBin: true
+
+ mime@2.6.0:
+ resolution: {integrity: sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==}
+ engines: {node: '>=4.0.0'}
+ hasBin: true
+
+ minimatch@3.1.2:
+ resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==}
+
+ ms@2.0.0:
+ resolution: {integrity: sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==}
+
+ ms@2.1.2:
+ resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==}
+
+ ms@2.1.3:
+ resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==}
+
+ negotiator@0.6.3:
+ resolution: {integrity: sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==}
+ engines: {node: '>= 0.6'}
+
+ node-eta@0.9.0:
+ resolution: {integrity: sha512-mTCTZk29tmX1OGfVkPt63H3c3VqXrI2Kvua98S7iUIB/Gbp0MNw05YtUomxQIxnnKMyRIIuY9izPcFixzhSBrA==}
+
+ nodemon@3.1.0:
+ resolution: {integrity: sha512-xqlktYlDMCepBJd43ZQhjWwMw2obW/JRvkrLxq5RCNcuDDX1DbcPT+qT1IlIIdf+DhnWs90JpTMe+Y5KxOchvA==}
+ engines: {node: '>=10'}
+ hasBin: true
+
+ normalize-path@3.0.0:
+ resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==}
+ engines: {node: '>=0.10.0'}
+
+ 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==}
+
+ on-finished@2.4.1:
+ resolution: {integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==}
+ engines: {node: '>= 0.8'}
+
+ once@1.4.0:
+ resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==}
+
+ parseurl@1.3.3:
+ resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==}
+ engines: {node: '>= 0.8'}
+
+ path-to-regexp@0.1.7:
+ resolution: {integrity: sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==}
+
+ pathval@2.0.0:
+ resolution: {integrity: sha512-vE7JKRyES09KiunauX7nd2Q9/L7lhok4smP9RZTDeD4MVs72Dp2qNFVz39Nz5a0FVEW0BJR6C0DYrq6unoziZA==}
+ engines: {node: '>= 14.16'}
+
+ picomatch@2.3.1:
+ resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==}
+ engines: {node: '>=8.6'}
+
+ proxy-addr@2.0.7:
+ resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==}
+ engines: {node: '>= 0.10'}
+
+ pstree.remy@1.1.8:
+ resolution: {integrity: sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==}
+
+ qs@6.11.0:
+ resolution: {integrity: sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==}
+ engines: {node: '>=0.6'}
+
+ range-parser@1.2.1:
+ resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==}
+ engines: {node: '>= 0.6'}
+
+ raw-body@2.5.1:
+ resolution: {integrity: sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==}
+ engines: {node: '>= 0.8'}
+
+ raw-body@2.5.2:
+ resolution: {integrity: sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==}
+ engines: {node: '>= 0.8'}
+
+ readdirp@3.6.0:
+ resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==}
+ engines: {node: '>=8.10.0'}
+
+ safe-buffer@5.2.1:
+ resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==}
+
+ safer-buffer@2.1.2:
+ resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==}
+
+ semver@7.5.4:
+ resolution: {integrity: sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==}
+ engines: {node: '>=10'}
+ hasBin: true
+
+ send@0.18.0:
+ resolution: {integrity: sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==}
+ engines: {node: '>= 0.8.0'}
+
+ serve-static@1.15.0:
+ resolution: {integrity: sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==}
+ engines: {node: '>= 0.8.0'}
+
+ set-function-length@1.1.1:
+ resolution: {integrity: sha512-VoaqjbBJKiWtg4yRcKBQ7g7wnGnLV3M8oLvVWwOk2PdYY6PEFegR1vezXR0tw6fZGF9csVakIRjrJiy2veSBFQ==}
+ engines: {node: '>= 0.4'}
+
+ setprototypeof@1.2.0:
+ resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==}
+
+ side-channel@1.0.4:
+ resolution: {integrity: sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==}
+
+ simple-update-notifier@2.0.0:
+ resolution: {integrity: sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==}
+ engines: {node: '>=10'}
+
+ statuses@2.0.1:
+ resolution: {integrity: sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==}
+ engines: {node: '>= 0.8'}
+
+ superagent@8.1.2:
+ resolution: {integrity: sha512-6WTxW1EB6yCxV5VFOIPQruWGHqc3yI7hEmZK6h+pyk69Lk/Ut7rLUY6W/ONF2MjBuGjvmMiIpsrVJ2vjrHlslA==}
+ engines: {node: '>=6.4.0 <13 || >=14'}
+
+ supertest@6.3.4:
+ resolution: {integrity: sha512-erY3HFDG0dPnhw4U+udPfrzXa4xhSG+n4rxfRuZWCUvjFWwKl+OxWf/7zk50s84/fAAs7vf5QAb9uRa0cCykxw==}
+ engines: {node: '>=6.4.0'}
+
+ supports-color@5.5.0:
+ resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==}
+ engines: {node: '>=4'}
+
+ to-regex-range@5.0.1:
+ resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==}
+ engines: {node: '>=8.0'}
+
+ toidentifier@1.0.1:
+ resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==}
+ engines: {node: '>=0.6'}
+
+ touch@3.1.1:
+ resolution: {integrity: sha512-r0eojU4bI8MnHr8c5bNo7lJDdI2qXlWWJk6a9EAFG7vbhTjElYhBVS3/miuE0uOuoLdb8Mc/rVfsmm6eo5o9GA==}
+ hasBin: true
+
+ type-is@1.6.18:
+ resolution: {integrity: sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==}
+ engines: {node: '>= 0.6'}
+
+ undefsafe@2.0.5:
+ resolution: {integrity: sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==}
+
+ 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'}
+
+ utils-merge@1.0.1:
+ resolution: {integrity: sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==}
+ engines: {node: '>= 0.4.0'}
+
+ uuid@9.0.1:
+ resolution: {integrity: sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==}
+ hasBin: true
+
+ vary@1.1.2:
+ resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==}
+ engines: {node: '>= 0.8'}
+
+ wrappy@1.0.2:
+ resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==}
+
+ yallist@4.0.0:
+ resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==}
+
+snapshots:
+
+ '@noble/hashes@1.4.0': {}
+
+ '@paralleldrive/cuid2@2.2.2':
dependencies:
'@noble/hashes': 1.4.0
- dev: false
- /@types/body-parser@1.19.5:
- resolution: {integrity: sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==}
+ '@types/body-parser@1.19.5':
dependencies:
'@types/connect': 3.4.38
'@types/node': 20.10.5
- dev: false
- /@types/connect@3.4.38:
- resolution: {integrity: sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==}
+ '@types/connect@3.4.38':
dependencies:
'@types/node': 20.10.5
- dev: false
- /@types/express-serve-static-core@4.17.41:
- resolution: {integrity: sha512-OaJ7XLaelTgrvlZD8/aa0vvvxZdUmlCn6MtWeB7TkiKW70BQLc9XEPpDLPdbo52ZhXUCrznlWdCHWxJWtdyajA==}
+ '@types/express-serve-static-core@4.17.41':
dependencies:
'@types/node': 20.10.5
'@types/qs': 6.9.10
'@types/range-parser': 1.2.7
'@types/send': 0.17.4
- dev: false
- /@types/express@4.17.21:
- resolution: {integrity: sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ==}
+ '@types/express@4.17.21':
dependencies:
'@types/body-parser': 1.19.5
'@types/express-serve-static-core': 4.17.41
'@types/qs': 6.9.10
'@types/serve-static': 1.15.5
- dev: false
- /@types/http-errors@2.0.4:
- resolution: {integrity: sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==}
- dev: false
+ '@types/http-errors@2.0.4': {}
- /@types/mime@1.3.5:
- resolution: {integrity: sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==}
- dev: false
+ '@types/mime@1.3.5': {}
- /@types/mime@3.0.4:
- resolution: {integrity: sha512-iJt33IQnVRkqeqC7PzBHPTC6fDlRNRW8vjrgqtScAhrmMwe8c4Eo7+fUGTa+XdWrpEgpyKWMYmi2dIwMAYRzPw==}
- dev: false
+ '@types/mime@3.0.4': {}
- /@types/node@20.10.5:
- resolution: {integrity: sha512-nNPsNE65wjMxEKI93yOP+NPGGBJz/PoN3kZsVLee0XMiJolxSekEVD8wRwBUBqkwc7UWop0edW50yrCQW4CyRw==}
+ '@types/node@20.10.5':
dependencies:
undici-types: 5.26.5
- dev: false
- /@types/qs@6.9.10:
- resolution: {integrity: sha512-3Gnx08Ns1sEoCrWssEgTSJs/rsT2vhGP+Ja9cnnk9k4ALxinORlQneLXFeFKOTJMOeZUFD1s7w+w2AphTpvzZw==}
- dev: false
+ '@types/qs@6.9.10': {}
- /@types/range-parser@1.2.7:
- resolution: {integrity: sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==}
- dev: false
+ '@types/range-parser@1.2.7': {}
- /@types/send@0.17.4:
- resolution: {integrity: sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA==}
+ '@types/send@0.17.4':
dependencies:
'@types/mime': 1.3.5
'@types/node': 20.10.5
- dev: false
- /@types/serve-static@1.15.5:
- resolution: {integrity: sha512-PDRk21MnK70hja/YF8AHfC7yIsiQHn1rcXx7ijCFBX/k+XQJhQT/gw3xekXKJvx+5SXaMMS8oqQy09Mzvz2TuQ==}
+ '@types/serve-static@1.15.5':
dependencies:
'@types/http-errors': 2.0.4
'@types/mime': 3.0.4
'@types/node': 20.10.5
- dev: false
- /accepts@1.3.8:
- resolution: {integrity: sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==}
- engines: {node: '>= 0.6'}
+ accepts@1.3.8:
dependencies:
mime-types: 2.1.35
negotiator: 0.6.3
- dev: false
- /array-flatten@1.1.1:
- resolution: {integrity: sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==}
- dev: false
+ anymatch@3.1.3:
+ dependencies:
+ normalize-path: 3.0.0
+ picomatch: 2.3.1
- /asap@2.0.6:
- resolution: {integrity: sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==}
- dev: true
+ array-flatten@1.1.1: {}
- /assertion-error@2.0.1:
- resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==}
- engines: {node: '>=12'}
- dev: true
+ asap@2.0.6: {}
- /asynckit@0.4.0:
- resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==}
- dev: true
+ assertion-error@2.0.1: {}
- /better-queue-memory@1.0.4:
- resolution: {integrity: sha512-SWg5wFIShYffEmJpI6LgbL8/3Dqhku7xI1oEiy6FroP9DbcZlG0ZDjxvPdP9t7hTGW40IpIcC6zVoGT1oxjOuA==}
- dev: false
+ asynckit@0.4.0: {}
- /better-queue@3.8.12:
- resolution: {integrity: sha512-D9KZ+Us+2AyaCz693/9AyjTg0s8hEmkiM/MB3i09cs4MdK1KgTSGJluXRYmOulR69oLZVo2XDFtqsExDt8oiLA==}
+ balanced-match@1.0.2: {}
+
+ better-queue-memory@1.0.4: {}
+
+ better-queue@3.8.12:
dependencies:
better-queue-memory: 1.0.4
node-eta: 0.9.0
uuid: 9.0.1
- 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}
+ binary-extensions@2.3.0: {}
+
+ body-parser@1.20.1:
dependencies:
bytes: 3.1.2
content-type: 1.0.5
@@ -175,11 +666,8 @@ packages:
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}
+ body-parser@1.20.2:
dependencies:
bytes: 3.1.2
content-type: 1.0.5
@@ -195,164 +683,111 @@ packages:
unpipe: 1.0.0
transitivePeerDependencies:
- supports-color
- dev: false
- /bytes@3.1.2:
- resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==}
- engines: {node: '>= 0.8'}
- dev: false
+ brace-expansion@1.1.11:
+ dependencies:
+ balanced-match: 1.0.2
+ concat-map: 0.0.1
- /call-bind@1.0.5:
- resolution: {integrity: sha512-C3nQxfFZxFRVoJoGKKI8y3MOEo129NQ+FgQ08iye+Mk4zNZZGdjfs06bVTr+DBSlA66Q2VEcMki/cUCP4SercQ==}
+ braces@3.0.3:
+ dependencies:
+ fill-range: 7.1.1
+
+ bytes@3.1.2: {}
+
+ call-bind@1.0.5:
dependencies:
function-bind: 1.1.2
get-intrinsic: 1.2.2
set-function-length: 1.1.1
- /chai@5.1.0:
- resolution: {integrity: sha512-kDZ7MZyM6Q1DhR9jy7dalKohXQ2yrlXkk59CR52aRKxJrobmlBNqnFQxX9xOX8w+4mz8SYlKJa/7D7ddltFXCw==}
- engines: {node: '>=12'}
+ chai@5.1.0:
dependencies:
assertion-error: 2.0.1
check-error: 2.0.0
deep-eql: 5.0.1
loupe: 3.1.0
pathval: 2.0.0
- dev: true
- /check-error@2.0.0:
- resolution: {integrity: sha512-tjLAOBHKVxtPoHe/SA7kNOMvhCRdCJ3vETdeY0RuAc9popf+hyaSV6ZEg9hr4cpWF7jmo/JSWEnLDrnijS9Tog==}
- engines: {node: '>= 16'}
- dev: true
+ check-error@2.0.0: {}
- /combined-stream@1.0.8:
- resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==}
- engines: {node: '>= 0.8'}
+ chokidar@3.6.0:
+ dependencies:
+ anymatch: 3.1.3
+ braces: 3.0.3
+ 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
+
+ combined-stream@1.0.8:
dependencies:
delayed-stream: 1.0.0
- dev: true
- /component-emitter@1.3.1:
- resolution: {integrity: sha512-T0+barUSQRTUQASh8bx02dl+DhF54GtIDY13Y3m9oWTklKbb3Wv974meRpeZ3lp1JpLVECWWNHC4vaG2XHXouQ==}
- dev: true
+ component-emitter@1.3.1: {}
- /content-disposition@0.5.4:
- resolution: {integrity: sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==}
- engines: {node: '>= 0.6'}
+ concat-map@0.0.1: {}
+
+ content-disposition@0.5.4:
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
+ content-type@1.0.5: {}
- /cookie-signature@1.0.6:
- resolution: {integrity: sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==}
- dev: false
+ cookie-signature@1.0.6: {}
- /cookie@0.5.0:
- resolution: {integrity: sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==}
- engines: {node: '>= 0.6'}
- dev: false
+ cookie@0.5.0: {}
- /cookiejar@2.1.4:
- resolution: {integrity: sha512-LDx6oHrK+PhzLKJU9j5S7/Y3jM/mUHvD/DeI1WQmJn652iPC5Y4TBzC9l+5OMOXlyTTA+SmVUPm0HQUwpD5Jqw==}
- dev: true
+ cookiejar@2.1.4: {}
- /cors@2.8.5:
- resolution: {integrity: sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==}
- engines: {node: '>= 0.10'}
+ cors@2.8.5:
dependencies:
object-assign: 4.1.1
vary: 1.1.2
- dev: false
- /debug@2.6.9:
- resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==}
- peerDependencies:
- supports-color: '*'
- peerDependenciesMeta:
- supports-color:
- optional: true
+ debug@2.6.9:
dependencies:
ms: 2.0.0
- dev: false
- /debug@4.3.4:
- resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==}
- engines: {node: '>=6.0'}
- peerDependencies:
- supports-color: '*'
- peerDependenciesMeta:
- supports-color:
- optional: true
+ debug@4.3.4(supports-color@5.5.0):
dependencies:
ms: 2.1.2
- dev: true
+ optionalDependencies:
+ supports-color: 5.5.0
- /deep-eql@5.0.1:
- resolution: {integrity: sha512-nwQCf6ne2gez3o1MxWifqkciwt0zhl0LO1/UwVu4uMBuPmflWM4oQ70XMqHqnBJA+nhzncaqL9HVL6KkHJ28lw==}
- engines: {node: '>=6'}
- dev: true
+ deep-eql@5.0.1: {}
- /define-data-property@1.1.1:
- resolution: {integrity: sha512-E7uGkTzkk1d0ByLeSc6ZsFS79Axg+m1P/VsgYsxHgiuc3tFSj+MjMIwe90FC4lOAZzNBdY7kkO2P2wKdsQ1vgQ==}
- engines: {node: '>= 0.4'}
+ define-data-property@1.1.1:
dependencies:
get-intrinsic: 1.2.2
gopd: 1.0.1
has-property-descriptors: 1.0.1
- /delayed-stream@1.0.0:
- resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==}
- engines: {node: '>=0.4.0'}
- dev: true
+ delayed-stream@1.0.0: {}
- /depd@2.0.0:
- resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==}
- engines: {node: '>= 0.8'}
- dev: false
+ depd@2.0.0: {}
- /destroy@1.2.0:
- resolution: {integrity: sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==}
- engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16}
- dev: false
+ destroy@1.2.0: {}
- /dezalgo@1.0.4:
- resolution: {integrity: sha512-rXSP0bf+5n0Qonsb+SVVfNfIsimO4HEtmnIpPHY8Q1UCzKlQrDMfdobr8nJOOsRgWCyMRqeSBQzmWUMq7zvVig==}
+ dezalgo@1.0.4:
dependencies:
asap: 2.0.6
wrappy: 1.0.2
- dev: true
- /dotenv@16.3.1:
- resolution: {integrity: sha512-IPzF4w4/Rd94bA9imS68tZBaYyBWSCE47V1RGuMrB94iyTOIEwRmVL2x/4An+6mETpLrKJ5hQkB8W4kFAadeIQ==}
- engines: {node: '>=12'}
- dev: false
+ dotenv@16.3.1: {}
- /ee-first@1.1.1:
- resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==}
- dev: false
+ ee-first@1.1.1: {}
- /encodeurl@1.0.2:
- resolution: {integrity: sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==}
- engines: {node: '>= 0.8'}
- dev: false
+ encodeurl@1.0.2: {}
- /escape-html@1.0.3:
- resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==}
- dev: false
+ escape-html@1.0.3: {}
- /etag@1.8.1:
- resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==}
- engines: {node: '>= 0.6'}
- dev: false
+ etag@1.8.1: {}
- /express@4.18.2:
- resolution: {integrity: sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==}
- engines: {node: '>= 0.10.0'}
+ express@4.18.2:
dependencies:
accepts: 1.3.8
array-flatten: 1.1.1
@@ -387,15 +822,14 @@ packages:
vary: 1.1.2
transitivePeerDependencies:
- supports-color
- dev: false
- /fast-safe-stringify@2.1.1:
- resolution: {integrity: sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==}
- dev: true
+ fast-safe-stringify@2.1.1: {}
- /finalhandler@1.2.0:
- resolution: {integrity: sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==}
- engines: {node: '>= 0.8'}
+ fill-range@7.1.1:
+ dependencies:
+ to-regex-range: 5.0.1
+
+ finalhandler@1.2.0:
dependencies:
debug: 2.6.9
encodeurl: 1.0.2
@@ -406,269 +840,205 @@ packages:
unpipe: 1.0.0
transitivePeerDependencies:
- supports-color
- dev: false
- /form-data@4.0.0:
- resolution: {integrity: sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==}
- engines: {node: '>= 6'}
+ form-data@4.0.0:
dependencies:
asynckit: 0.4.0
combined-stream: 1.0.8
mime-types: 2.1.35
- dev: true
- /formidable@2.1.2:
- resolution: {integrity: sha512-CM3GuJ57US06mlpQ47YcunuUZ9jpm8Vx+P2CGt2j7HpgkKZO/DJYQ0Bobim8G6PFQmK5lOqOOdUXboU+h73A4g==}
+ formidable@2.1.2:
dependencies:
dezalgo: 1.0.4
hexoid: 1.0.0
once: 1.4.0
qs: 6.11.0
- dev: true
- /forwarded@0.2.0:
- resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==}
- engines: {node: '>= 0.6'}
- dev: false
+ forwarded@0.2.0: {}
- /fresh@0.5.2:
- resolution: {integrity: sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==}
- engines: {node: '>= 0.6'}
- dev: false
+ fresh@0.5.2: {}
- /function-bind@1.1.2:
- resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==}
+ fsevents@2.3.3:
+ optional: true
- /get-func-name@2.0.2:
- resolution: {integrity: sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==}
- dev: true
+ function-bind@1.1.2: {}
- /get-intrinsic@1.2.2:
- resolution: {integrity: sha512-0gSo4ml/0j98Y3lngkFEot/zhiCeWsbYIlZ+uZOVgzLyLaUw7wxUL+nCTP0XJvJg1AXulJRI3UJi8GsbDuxdGA==}
+ get-func-name@2.0.2: {}
+
+ get-intrinsic@1.2.2:
dependencies:
function-bind: 1.1.2
has-proto: 1.0.1
has-symbols: 1.0.3
hasown: 2.0.0
- /gopd@1.0.1:
- resolution: {integrity: sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==}
+ glob-parent@5.1.2:
+ dependencies:
+ is-glob: 4.0.3
+
+ gopd@1.0.1:
dependencies:
get-intrinsic: 1.2.2
- /has-property-descriptors@1.0.1:
- resolution: {integrity: sha512-VsX8eaIewvas0xnvinAe9bw4WfIeODpGYikiWYLH+dma0Jw6KHYqWiWfhQlgOVK8D6PvjubK5Uc4P0iIhIcNVg==}
+ has-flag@3.0.0: {}
+
+ has-property-descriptors@1.0.1:
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-proto@1.0.1: {}
- /has-symbols@1.0.3:
- resolution: {integrity: sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==}
- engines: {node: '>= 0.4'}
+ has-symbols@1.0.3: {}
- /hasown@2.0.0:
- resolution: {integrity: sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==}
- engines: {node: '>= 0.4'}
+ hasown@2.0.0:
dependencies:
function-bind: 1.1.2
- /hexoid@1.0.0:
- resolution: {integrity: sha512-QFLV0taWQOZtvIRIAdBChesmogZrtuXvVWsFHZTk2SU+anspqZ2vMnoLg7IE1+Uk16N19APic1BuF8bC8c2m5g==}
- engines: {node: '>=8'}
- dev: true
+ hexoid@1.0.0: {}
- /http-errors@2.0.0:
- resolution: {integrity: sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==}
- engines: {node: '>= 0.8'}
+ http-errors@2.0.0:
dependencies:
depd: 2.0.0
inherits: 2.0.4
setprototypeof: 1.2.0
statuses: 2.0.1
toidentifier: 1.0.1
- dev: false
- /iconv-lite@0.4.24:
- resolution: {integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==}
- engines: {node: '>=0.10.0'}
+ iconv-lite@0.4.24:
dependencies:
safer-buffer: 2.1.2
- dev: false
- /inherits@2.0.4:
- resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==}
- dev: false
+ ignore-by-default@1.0.1: {}
- /ipaddr.js@1.9.1:
- resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==}
- engines: {node: '>= 0.10'}
- dev: false
+ inherits@2.0.4: {}
- /loupe@3.1.0:
- resolution: {integrity: sha512-qKl+FrLXUhFuHUoDJG7f8P8gEMHq9NFS0c6ghXG1J0rldmZFQZoNVv/vyirE9qwCIhWZDsvEFd1sbFu3GvRQFg==}
+ ipaddr.js@1.9.1: {}
+
+ is-binary-path@2.1.0:
+ dependencies:
+ binary-extensions: 2.3.0
+
+ is-extglob@2.1.1: {}
+
+ is-glob@4.0.3:
+ dependencies:
+ is-extglob: 2.1.1
+
+ is-number@7.0.0: {}
+
+ loupe@3.1.0:
dependencies:
get-func-name: 2.0.2
- dev: true
- /lru-cache@6.0.0:
- resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==}
- engines: {node: '>=10'}
+ lru-cache@6.0.0:
dependencies:
yallist: 4.0.0
- dev: true
- /media-typer@0.3.0:
- resolution: {integrity: sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==}
- engines: {node: '>= 0.6'}
- dev: false
+ media-typer@0.3.0: {}
- /merge-descriptors@1.0.1:
- resolution: {integrity: sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==}
- dev: false
+ merge-descriptors@1.0.1: {}
- /methods@1.1.2:
- resolution: {integrity: sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==}
- engines: {node: '>= 0.6'}
+ methods@1.1.2: {}
- /mime-db@1.52.0:
- resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==}
- engines: {node: '>= 0.6'}
+ mime-db@1.52.0: {}
- /mime-types@2.1.35:
- resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==}
- engines: {node: '>= 0.6'}
+ mime-types@2.1.35:
dependencies:
mime-db: 1.52.0
- /mime@1.6.0:
- resolution: {integrity: sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==}
- engines: {node: '>=4'}
- hasBin: true
- dev: false
+ mime@1.6.0: {}
- /mime@2.6.0:
- resolution: {integrity: sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==}
- engines: {node: '>=4.0.0'}
- hasBin: true
- dev: true
+ mime@2.6.0: {}
- /ms@2.0.0:
- resolution: {integrity: sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==}
- dev: false
+ minimatch@3.1.2:
+ dependencies:
+ brace-expansion: 1.1.11
- /ms@2.1.2:
- resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==}
- dev: true
+ ms@2.0.0: {}
- /ms@2.1.3:
- resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==}
- dev: false
+ ms@2.1.2: {}
- /negotiator@0.6.3:
- resolution: {integrity: sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==}
- engines: {node: '>= 0.6'}
- dev: false
+ ms@2.1.3: {}
- /node-eta@0.9.0:
- resolution: {integrity: sha512-mTCTZk29tmX1OGfVkPt63H3c3VqXrI2Kvua98S7iUIB/Gbp0MNw05YtUomxQIxnnKMyRIIuY9izPcFixzhSBrA==}
- dev: false
+ negotiator@0.6.3: {}
- /object-assign@4.1.1:
- resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==}
- engines: {node: '>=0.10.0'}
- dev: false
+ node-eta@0.9.0: {}
- /object-inspect@1.13.1:
- resolution: {integrity: sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==}
+ nodemon@3.1.0:
+ dependencies:
+ chokidar: 3.6.0
+ 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.1
+ undefsafe: 2.0.5
- /on-finished@2.4.1:
- resolution: {integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==}
- engines: {node: '>= 0.8'}
+ normalize-path@3.0.0: {}
+
+ object-assign@4.1.1: {}
+
+ object-inspect@1.13.1: {}
+
+ on-finished@2.4.1:
dependencies:
ee-first: 1.1.1
- dev: false
- /once@1.4.0:
- resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==}
+ once@1.4.0:
dependencies:
wrappy: 1.0.2
- dev: true
- /parseurl@1.3.3:
- resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==}
- engines: {node: '>= 0.8'}
- dev: false
+ parseurl@1.3.3: {}
- /path-to-regexp@0.1.7:
- resolution: {integrity: sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==}
- dev: false
+ path-to-regexp@0.1.7: {}
- /pathval@2.0.0:
- resolution: {integrity: sha512-vE7JKRyES09KiunauX7nd2Q9/L7lhok4smP9RZTDeD4MVs72Dp2qNFVz39Nz5a0FVEW0BJR6C0DYrq6unoziZA==}
- engines: {node: '>= 14.16'}
- dev: true
+ pathval@2.0.0: {}
- /proxy-addr@2.0.7:
- resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==}
- engines: {node: '>= 0.10'}
+ picomatch@2.3.1: {}
+
+ proxy-addr@2.0.7:
dependencies:
forwarded: 0.2.0
ipaddr.js: 1.9.1
- dev: false
- /qs@6.11.0:
- resolution: {integrity: sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==}
- engines: {node: '>=0.6'}
+ pstree.remy@1.1.8: {}
+
+ qs@6.11.0:
dependencies:
side-channel: 1.0.4
- /range-parser@1.2.1:
- resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==}
- engines: {node: '>= 0.6'}
- dev: false
+ range-parser@1.2.1: {}
- /raw-body@2.5.1:
- resolution: {integrity: sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==}
- engines: {node: '>= 0.8'}
+ raw-body@2.5.1:
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'}
+ raw-body@2.5.2:
dependencies:
bytes: 3.1.2
http-errors: 2.0.0
iconv-lite: 0.4.24
unpipe: 1.0.0
- dev: false
- /safe-buffer@5.2.1:
- resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==}
- dev: false
+ readdirp@3.6.0:
+ dependencies:
+ picomatch: 2.3.1
- /safer-buffer@2.1.2:
- resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==}
- dev: false
+ safe-buffer@5.2.1: {}
- /semver@7.5.4:
- resolution: {integrity: sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==}
- engines: {node: '>=10'}
- hasBin: true
+ safer-buffer@2.1.2: {}
+
+ semver@7.5.4:
dependencies:
lru-cache: 6.0.0
- dev: true
- /send@0.18.0:
- resolution: {integrity: sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==}
- engines: {node: '>= 0.8.0'}
+ send@0.18.0:
dependencies:
debug: 2.6.9
depd: 2.0.0
@@ -685,11 +1055,8 @@ packages:
statuses: 2.0.1
transitivePeerDependencies:
- supports-color
- dev: false
- /serve-static@1.15.0:
- resolution: {integrity: sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==}
- engines: {node: '>= 0.8.0'}
+ serve-static@1.15.0:
dependencies:
encodeurl: 1.0.2
escape-html: 1.0.3
@@ -697,40 +1064,33 @@ packages:
send: 0.18.0
transitivePeerDependencies:
- supports-color
- dev: false
- /set-function-length@1.1.1:
- resolution: {integrity: sha512-VoaqjbBJKiWtg4yRcKBQ7g7wnGnLV3M8oLvVWwOk2PdYY6PEFegR1vezXR0tw6fZGF9csVakIRjrJiy2veSBFQ==}
- engines: {node: '>= 0.4'}
+ set-function-length@1.1.1:
dependencies:
define-data-property: 1.1.1
get-intrinsic: 1.2.2
gopd: 1.0.1
has-property-descriptors: 1.0.1
- /setprototypeof@1.2.0:
- resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==}
- dev: false
+ setprototypeof@1.2.0: {}
- /side-channel@1.0.4:
- resolution: {integrity: sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==}
+ side-channel@1.0.4:
dependencies:
call-bind: 1.0.5
get-intrinsic: 1.2.2
object-inspect: 1.13.1
- /statuses@2.0.1:
- resolution: {integrity: sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==}
- engines: {node: '>= 0.8'}
- dev: false
+ simple-update-notifier@2.0.0:
+ dependencies:
+ semver: 7.5.4
- /superagent@8.1.2:
- resolution: {integrity: sha512-6WTxW1EB6yCxV5VFOIPQruWGHqc3yI7hEmZK6h+pyk69Lk/Ut7rLUY6W/ONF2MjBuGjvmMiIpsrVJ2vjrHlslA==}
- engines: {node: '>=6.4.0 <13 || >=14'}
+ statuses@2.0.1: {}
+
+ superagent@8.1.2:
dependencies:
component-emitter: 1.3.1
cookiejar: 2.1.4
- debug: 4.3.4
+ debug: 4.3.4(supports-color@5.5.0)
fast-safe-stringify: 2.1.1
form-data: 4.0.0
formidable: 2.1.2
@@ -740,59 +1100,43 @@ packages:
semver: 7.5.4
transitivePeerDependencies:
- supports-color
- dev: true
- /supertest@6.3.4:
- resolution: {integrity: sha512-erY3HFDG0dPnhw4U+udPfrzXa4xhSG+n4rxfRuZWCUvjFWwKl+OxWf/7zk50s84/fAAs7vf5QAb9uRa0cCykxw==}
- engines: {node: '>=6.4.0'}
+ supertest@6.3.4:
dependencies:
methods: 1.1.2
superagent: 8.1.2
transitivePeerDependencies:
- supports-color
- dev: true
- /toidentifier@1.0.1:
- resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==}
- engines: {node: '>=0.6'}
- dev: false
+ supports-color@5.5.0:
+ dependencies:
+ has-flag: 3.0.0
- /type-is@1.6.18:
- resolution: {integrity: sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==}
- engines: {node: '>= 0.6'}
+ to-regex-range@5.0.1:
+ dependencies:
+ is-number: 7.0.0
+
+ toidentifier@1.0.1: {}
+
+ touch@3.1.1: {}
+
+ type-is@1.6.18:
dependencies:
media-typer: 0.3.0
mime-types: 2.1.35
- dev: false
- /undici-types@5.26.5:
- resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==}
- dev: false
+ undefsafe@2.0.5: {}
- /unpipe@1.0.0:
- resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==}
- engines: {node: '>= 0.8'}
- dev: false
+ undici-types@5.26.5: {}
- /utils-merge@1.0.1:
- resolution: {integrity: sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==}
- engines: {node: '>= 0.4.0'}
- dev: false
+ unpipe@1.0.0: {}
- /uuid@9.0.1:
- resolution: {integrity: sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==}
- hasBin: true
- dev: false
+ utils-merge@1.0.1: {}
- /vary@1.1.2:
- resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==}
- engines: {node: '>= 0.8'}
- dev: false
+ uuid@9.0.1: {}
- /wrappy@1.0.2:
- resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==}
- dev: true
+ vary@1.1.2: {}
- /yallist@4.0.0:
- resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==}
- dev: true
+ wrappy@1.0.2: {}
+
+ yallist@4.0.0: {}
diff --git a/packages/next/app/streams/[cuid]/not-found.tsx b/packages/next/app/archive/[cuid]/not-found.tsx
similarity index 63%
rename from packages/next/app/streams/[cuid]/not-found.tsx
rename to packages/next/app/archive/[cuid]/not-found.tsx
index b9d167b..b58a3c8 100644
--- a/packages/next/app/streams/[cuid]/not-found.tsx
+++ b/packages/next/app/archive/[cuid]/not-found.tsx
@@ -4,9 +4,9 @@ export default function NotFound() {
return (
404 Not Found
-
Could not find that stream.
+
Could not find that stream archive.
-
Return to streams list
+
Return to archive list
)
}
\ No newline at end of file
diff --git a/packages/next/app/streams/[cuid]/page.tsx b/packages/next/app/archive/[cuid]/page.tsx
similarity index 86%
rename from packages/next/app/streams/[cuid]/page.tsx
rename to packages/next/app/archive/[cuid]/page.tsx
index e4971e0..15e1adf 100644
--- a/packages/next/app/streams/[cuid]/page.tsx
+++ b/packages/next/app/archive/[cuid]/page.tsx
@@ -12,6 +12,7 @@ interface IPageParams {
export default async function Page ({ params: { cuid } }: IPageParams) {
const stream = await getStreamByCuid(cuid);
+ console.log(`getting stream by cuid. cuid=${cuid}`)
return (
<>
diff --git a/packages/next/app/archive/page.tsx b/packages/next/app/archive/page.tsx
new file mode 100644
index 0000000..2f72e09
--- /dev/null
+++ b/packages/next/app/archive/page.tsx
@@ -0,0 +1,91 @@
+import Pager from "@/components/pager";
+import StreamsList from "@/components/streams-list";
+import StreamsTable from '@/components/streams-table';
+import { getAllStreams, getStreamsForVtuber } from "@/lib/streams";
+// import { getAllVtubers } from "@/lib/vtubers";
+import { notFound } from "next/navigation";
+
+
+
+export default async function Page() {
+ // const vtubers = await getAllVtubers();
+ // const streams = await getAllStreams();
+ // const streams = await getStreamsForVtuber(1)
+ // const pageSize = 100;
+ // const page = 1;
+
+
+ // export interface IStream {
+ // id: number;
+ // attributes: {
+ // date: string;
+ // archiveStatus: 'good' | 'issue' | 'missing';
+ // vods: IVodsResponse;
+ // cuid: string;
+ // vtuber: IVtuberResponse;
+ // tweet: ITweetResponse;
+ // isChaturbateStream: boolean;
+ // isFanslyStream: boolean;
+ // }
+ // }
+
+ // if (!vtubers) notFound();
+ // const streams = [
+ // {
+ // "firstName": "Tanner",
+ // "lastName": "Linsley",
+ // "age": 33,
+ // "visits": 100,
+ // "progress": 50,
+ // "status": "Married",
+ // "id": 5,
+ // "attributes": {
+ // date: '2023-10-10T15:18:20.003Z',
+ // archiveStatus: 'missing',
+ // isChaturbateStream: false,
+ // isFanslyStream: true,
+ // vods: {},
+ // cuid: '2983482932384',
+ // vtuber: {},
+ // tweet: '',
+ // }
+ // },
+ // {
+ // "firstName": "Kevin",
+ // "lastName": "Vandy",
+ // "age": 27,
+ // "visits": 200,
+ // "progress": 100,
+ // "status": "Single",
+ // "id": 3,
+ // "attributes": {
+ // date: '2023-10-10T15:18:20.003Z',
+ // archiveStatus: 'missing',
+ // isChaturbateStream: true,
+ // isFanslyStream: true,
+ // vods: {},
+ // cuid: '29823432384',
+ // vtuber: {},
+ // tweet: '',
+ // }
+ // }
+ // ]
+
+ return (
+
+ {/*
+ here are the streams object
+
+ {JSON.stringify(streams, null, 2)}
+
+ */}
+
+
+
+
Stream Archive
+
+ {/*
+
*/}
+
+ )
+}
\ No newline at end of file
diff --git a/packages/next/app/components/archive-progress.tsx b/packages/next/app/components/archive-progress.tsx
index 3f292e1..4b19d9a 100644
--- a/packages/next/app/components/archive-progress.tsx
+++ b/packages/next/app/components/archive-progress.tsx
@@ -7,7 +7,7 @@ export interface IArchiveProgressProps {
}
export default async function ArchiveProgress ({ vtuber }: IArchiveProgressProps) {
- const vods = await getVodsForVtuber(vtuber.id)
+ // const vods = await getVodsForVtuber(vtuber.id)
// const streams = await getAllStreamsForVtuber(vtuber.id);
// const goodStreams = await getAllStreamsForVtuber(vtuber.id, ['good']);
// const issueStreams = await getAllStreamsForVtuber(vtuber.id, ['issue']);
@@ -16,17 +16,21 @@ export default async function ArchiveProgress ({ vtuber }: IArchiveProgressProps
// // 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}%
- //
- // )
- // @todo
-
+ const completedPercentage = 50
+ const totalStreams = 500
+ const eligibleStreams = 50
return (
-
{(vods) ? vods.data.length : 0} vods
+
@todo
+
{eligibleStreams}/{totalStreams} Streams Archived ({completedPercentage}%)
+
{completedPercentage}%
)
+ // @todo
+
+ // return (
+ //
+ //
{(vods) ? vods.data.length : 0} vods
+ //
+ // )
}
\ No newline at end of file
diff --git a/packages/next/app/components/footer.tsx b/packages/next/app/components/footer.tsx
index 2727d0f..3f162f5 100644
--- a/packages/next/app/components/footer.tsx
+++ b/packages/next/app/components/footer.tsx
@@ -17,7 +17,7 @@ export default function Footer() {
↑ Top of page
Vtubers
- {/* Stream Archive */}
+ Archive
About
FAQ
Goals
diff --git a/packages/next/app/components/navbar.tsx b/packages/next/app/components/navbar.tsx
index 0dcf46a..e76d519 100644
--- a/packages/next/app/components/navbar.tsx
+++ b/packages/next/app/components/navbar.tsx
@@ -43,7 +43,7 @@ export default function Navbar() {