assert a vod CUID when updated
ci / build (push) Has been cancelled Details

This commit is contained in:
CJ_Clippy 2024-07-06 00:49:51 -08:00
parent 3a89a076d9
commit a60d0f0821
40 changed files with 729 additions and 773 deletions

View File

@ -10,7 +10,7 @@ Tested on VKE v1.30.0+1 (PVCs on other versions may not be fulfilled)
direnv for loading .envrc direnv for loading .envrc
Temporal for work queue Temporal for work queue, cron
Postgres for data storage Postgres for data storage

View File

@ -23,7 +23,7 @@ velero:
tilt: tilt:
kind get kubeconfig > ~/.kube/kind.yaml kind get kubeconfig > ~/.kube/kind.yaml
KUBECONFIG=~/.kube/kind.yaml tilt up -f ./t.wip.tiltfile KUBECONFIG=~/.kube/kind.yaml tilt up -f ./Tiltfile
exoscale: exoscale:
kubectl apply -f https://raw.githubusercontent.com/exoscale/cert-manager-webhook-exoscale/master/deploy/exoscale-webhook-kustomize/deploy.yaml kubectl apply -f https://raw.githubusercontent.com/exoscale/cert-manager-webhook-exoscale/master/deploy/exoscale-webhook-kustomize/deploy.yaml

View File

@ -4,6 +4,15 @@ Source Code for https://futureporn.net
See ./ARCHITECTURE.md for overview See ./ARCHITECTURE.md for overview
## Metrics Notes
Keeping track of metrics we want to scrape using Prometheus
### Uppy
https://uppy.fp.sbtp.xyz/metrics
## Development Mantras ## Development Mantras
### Move fast and break things ### Move fast and break things
@ -16,11 +25,14 @@ See ./ARCHITECTURE.md for overview
### If the way is long, the way is wrong ### If the way is long, the way is wrong
### Good, Fast, Cheap. Pick only two. ### Good, Fast, Cheap. Pick two but not all three.
### Organizations are fractals ### Organizations are fractals
### Focus on what moves the needle ### Focus on what moves the needle
### Alligator energy ### Alligator energy (move slow and preserve things)
### Code is run more than it is read
### The computer doesn't care

View File

@ -110,6 +110,7 @@ helm_remote(
# values=['./charts/nitter/values.yaml'], # values=['./charts/nitter/values.yaml'],
# )) # ))
k8s_yaml(helm( k8s_yaml(helm(
'./charts/fp', './charts/fp',
values=['./charts/fp/values-dev.yaml'], values=['./charts/fp/values-dev.yaml'],
@ -141,7 +142,6 @@ k8s_yaml(helm(
# ) # )
# docker_build('fp/link2cid', './packages/link2cid') # docker_build('fp/link2cid', './packages/link2cid')
docker_build( docker_build(
'fp/strapi', 'fp/strapi',
@ -153,6 +153,17 @@ docker_build(
] ]
) )
# docker_build(
# 'fp/bot',
# '.',
# only=['./packages/bot'],
# dockerfile='./d.bot.dockerfile',
# live_update=[
# sync('./packages/bot', '/app')
# ]
# )
@ -201,7 +212,7 @@ cmd_button('temporal-web:namespace',
docker_build( docker_build(
'fp/next', 'fp/next',
'.', '.',
only=['./pnpm-lock.yaml', './package.json', './packages/next'], only=['./pnpm-lock.yaml', './package.json', './packages/next', './ca/letsencrypt-stg-root-x1.pem'],
dockerfile='d.next.dockerfile', dockerfile='d.next.dockerfile',
target='dev', target='dev',
build_args={ build_args={
@ -216,9 +227,9 @@ docker_build(
docker_build( docker_build(
'fp/scout-manager', 'fp/scout-manager',
'.', '.',
only=['./pnpm-lock.yaml', './package.json', './packages/scout', './packages/next'], only=['./pnpm-lock.yaml', './package.json', './packages/scout', './packages/next', './ca/letsencrypt-stg-root-x1.pem'],
dockerfile='d.scout.dockerfile', dockerfile='d.packages.dockerfile',
target='manager', target='scout-manager',
live_update=[ live_update=[
sync('./packages/scout', '/app'), sync('./packages/scout', '/app'),
run('cd /app && pnpm i', trigger=['./packages/scout/package.json', './packages/scout/pnpm-lock.yaml']), run('cd /app && pnpm i', trigger=['./packages/scout/package.json', './packages/scout/pnpm-lock.yaml']),
@ -230,10 +241,10 @@ docker_build(
docker_build( docker_build(
'fp/scout-worker', 'fp/scout-worker',
'.', '.',
only=['./pnpm-lock.yaml', './package.json', './packages/scout', './packages/next'], only=['./pnpm-lock.yaml', './package.json', './packages/scout', './packages/next', './ca/letsencrypt-stg-root-x1.pem'],
# ignore=['./packages/next'], # I wish I could use this ignore to ignore file changes in this dir, but that's not how it works # ignore=['./packages/next'], # I wish I could use this ignore to ignore file changes in this dir, but that's not how it works
dockerfile='d.scout.dockerfile', dockerfile='d.packages.dockerfile',
target='worker', target='scout:worker',
live_update=[ live_update=[
# idk if this run() is effective # idk if this run() is effective
# run('cd /app && pnpm i', trigger=['./packages/scout/package.json', './packages/scout/pnpm-lock.yaml']), # run('cd /app && pnpm i', trigger=['./packages/scout/package.json', './packages/scout/pnpm-lock.yaml']),
@ -259,16 +270,24 @@ docker_build(
# workload='frp-operator-controller-manager', # workload='frp-operator-controller-manager',
# labels='tunnel' # labels='tunnel'
# ) # )
# k8s_resource(
# workload='echo',
# links=[
# link('https://echo.fp.sbtp.xyz'),
# link('http://echo.futureporn.svc.cluster.local:8001')
# ],
# labels='debug'
# )
k8s_resource( k8s_resource(
workload='echo', workload='uppy',
links=[ links=[
link('https://echo.fp.sbtp.xyz'), link('https://uppy.fp.sbtp.xyz'),
link('http://echo.futureporn.svc.cluster.local:8001')
], ],
labels='frontend' resource_deps=['redis-master'],
labels=['backend'],
) )
k8s_resource( k8s_resource(
workload='next', workload='next',
port_forwards=['3000'], port_forwards=['3000'],
@ -282,7 +301,7 @@ k8s_resource(
workload='strapi', workload='strapi',
port_forwards=['1339'], port_forwards=['1339'],
links=[ links=[
link('http://localhost:1339/admin'), link('https://strapi.fp.sbtp.xyz/admin'),
link('https://strapi.fp.sbtp.xyz'), link('https://strapi.fp.sbtp.xyz'),
], ],
resource_deps=['postgres'], resource_deps=['postgres'],
@ -307,13 +326,13 @@ k8s_resource(
k8s_resource( k8s_resource(
workload='scout-worker', workload='scout-worker',
resource_deps=['postgres', 'strapi', 'temporal-frontend', 'scout-manager'], resource_deps=['postgres', 'strapi', 'temporal-frontend'],
labels=['backend'], labels=['backend'],
) )
k8s_resource( k8s_resource(
workload='scout-manager', workload='scout-manager',
resource_deps=['postgres', 'strapi', 'temporal-frontend'], resource_deps=['postgres', 'strapi', 'temporal-frontend', 'scout-worker'],
labels=['backend'], labels=['backend'],
) )
@ -347,6 +366,20 @@ k8s_resource(
# ] # ]
# ) # )
helm_remote(
'redis',
repo_name='redis',
repo_url='https://charts.bitnami.com/bitnami',
namespace='futureporn',
version='19.6.1',
set=[
'auth.existingSecret=redis',
'auth.existingSecretPasswordKey=password',
'replica.persistence.enabled=false',
'architecture=standalone'
]
)
helm_remote( helm_remote(
'temporal', 'temporal',
repo_name='temporal', repo_name='temporal',
@ -445,6 +478,18 @@ k8s_resource(
workload='cert-manager-webhook-exoscale', workload='cert-manager-webhook-exoscale',
labels=['networking'], labels=['networking'],
) )
k8s_resource(
workload='redis-master',
labels=['backend']
)
# k8s_resource(
# workload='bot',
# labels=['backend']
# )
# k8s_resource( # k8s_resource(
# workload='cert-manager', # workload='cert-manager',
# labels='cert-manager' # labels='cert-manager'

View File

@ -0,0 +1,32 @@
-----BEGIN CERTIFICATE-----
MIIFmDCCA4CgAwIBAgIQU9C87nMpOIFKYpfvOHFHFDANBgkqhkiG9w0BAQsFADBm
MQswCQYDVQQGEwJVUzEzMDEGA1UEChMqKFNUQUdJTkcpIEludGVybmV0IFNlY3Vy
aXR5IFJlc2VhcmNoIEdyb3VwMSIwIAYDVQQDExkoU1RBR0lORykgUHJldGVuZCBQ
ZWFyIFgxMB4XDTE1MDYwNDExMDQzOFoXDTM1MDYwNDExMDQzOFowZjELMAkGA1UE
BhMCVVMxMzAxBgNVBAoTKihTVEFHSU5HKSBJbnRlcm5ldCBTZWN1cml0eSBSZXNl
YXJjaCBHcm91cDEiMCAGA1UEAxMZKFNUQUdJTkcpIFByZXRlbmQgUGVhciBYMTCC
AiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALbagEdDTa1QgGBWSYkyMhsc
ZXENOBaVRTMX1hceJENgsL0Ma49D3MilI4KS38mtkmdF6cPWnL++fgehT0FbRHZg
jOEr8UAN4jH6omjrbTD++VZneTsMVaGamQmDdFl5g1gYaigkkmx8OiCO68a4QXg4
wSyn6iDipKP8utsE+x1E28SA75HOYqpdrk4HGxuULvlr03wZGTIf/oRt2/c+dYmD
oaJhge+GOrLAEQByO7+8+vzOwpNAPEx6LW+crEEZ7eBXih6VP19sTGy3yfqK5tPt
TdXXCOQMKAp+gCj/VByhmIr+0iNDC540gtvV303WpcbwnkkLYC0Ft2cYUyHtkstO
fRcRO+K2cZozoSwVPyB8/J9RpcRK3jgnX9lujfwA/pAbP0J2UPQFxmWFRQnFjaq6
rkqbNEBgLy+kFL1NEsRbvFbKrRi5bYy2lNms2NJPZvdNQbT/2dBZKmJqxHkxCuOQ
FjhJQNeO+Njm1Z1iATS/3rts2yZlqXKsxQUzN6vNbD8KnXRMEeOXUYvbV4lqfCf8
mS14WEbSiMy87GB5S9ucSV1XUrlTG5UGcMSZOBcEUpisRPEmQWUOTWIoDQ5FOia/
GI+Ki523r2ruEmbmG37EBSBXdxIdndqrjy+QVAmCebyDx9eVEGOIpn26bW5LKeru
mJxa/CFBaKi4bRvmdJRLAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMB
Af8EBTADAQH/MB0GA1UdDgQWBBS182Xy/rAKkh/7PH3zRKCsYyXDFDANBgkqhkiG
9w0BAQsFAAOCAgEAncDZNytDbrrVe68UT6py1lfF2h6Tm2p8ro42i87WWyP2LK8Y
nLHC0hvNfWeWmjZQYBQfGC5c7aQRezak+tHLdmrNKHkn5kn+9E9LCjCaEsyIIn2j
qdHlAkepu/C3KnNtVx5tW07e5bvIjJScwkCDbP3akWQixPpRFAsnP+ULx7k0aO1x
qAeaAhQ2rgo1F58hcflgqKTXnpPM02intVfiVVkX5GXpJjK5EoQtLceyGOrkxlM/
sTPq4UrnypmsqSagWV3HcUlYtDinc+nukFk6eR4XkzXBbwKajl0YjztfrCIHOn5Q
CJL6TERVDbM/aAPly8kJ1sWGLuvvWYzMYgLzDul//rUF10gEMWaXVZV51KpS9DY/
5CunuvCXmEQJHo7kGcViT7sETn6Jz9KOhvYcXkJ7po6d93A/jy4GKPIPnsKKNEmR
xUuXY4xRdh45tMJnLTUDdC9FIU0flTeO9/vNpVA8OPU1i14vCz+MU8KX1bV3GXm/
fxlB7VBBjX9v5oUep0o/j68R/iDlCOM4VVfRa8gX6T2FU7fNdatvGro7uQzIvWof
gN9WUwCbEMBy/YhBSrXycKA8crgGg3x1mIsopn88JKwmMBa68oS7EHM9w7C4y71M
7DiA+/9Qdp9RBWJpTS9i/mDnJg1xvo8Xz49mrrgfmcAXTCJqXi24NatI3Oc=
-----END CERTIFICATE-----

View File

@ -0,0 +1,15 @@
-----BEGIN CERTIFICATE-----
MIICTjCCAdSgAwIBAgIRAIPgc3k5LlLVLtUUvs4K/QcwCgYIKoZIzj0EAwMwaDEL
MAkGA1UEBhMCVVMxMzAxBgNVBAoTKihTVEFHSU5HKSBJbnRlcm5ldCBTZWN1cml0
eSBSZXNlYXJjaCBHcm91cDEkMCIGA1UEAxMbKFNUQUdJTkcpIEJvZ3VzIEJyb2Nj
b2xpIFgyMB4XDTIwMDkwNDAwMDAwMFoXDTQwMDkxNzE2MDAwMFowaDELMAkGA1UE
BhMCVVMxMzAxBgNVBAoTKihTVEFHSU5HKSBJbnRlcm5ldCBTZWN1cml0eSBSZXNl
YXJjaCBHcm91cDEkMCIGA1UEAxMbKFNUQUdJTkcpIEJvZ3VzIEJyb2Njb2xpIFgy
MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEOvS+w1kCzAxYOJbA06Aw0HFP2tLBLKPo
FQqR9AMskl1nC2975eQqycR+ACvYelA8rfwFXObMHYXJ23XLB+dAjPJVOJ2OcsjT
VqO4dcDWu+rQ2VILdnJRYypnV1MMThVxo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYD
VR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU3tGjWWQOwZo2o0busBB2766XlWYwCgYI
KoZIzj0EAwMDaAAwZQIwRcp4ZKBsq9XkUuN8wfX+GEbY1N5nmCRc8e80kUkuAefo
uc2j3cICeXo1cOybQ1iWAjEA3Ooawl8eQyR4wrjCofUE8h44p0j7Yl/kBlJZT8+9
vbtH7QiVzeKCOTQPINyRql6P
-----END CERTIFICATE-----

View File

@ -1,138 +0,0 @@
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: echo
namespace: futureporn
spec:
selector:
matchLabels:
app: echo
template:
metadata:
labels:
app: echo
spec:
containers:
- image: hashicorp/http-echo
name: echo
ports:
- containerPort: 5678
args:
- -text="Hello, choom!"
{{ if eq .Values.environment "development" }}
---
apiVersion: chisel-operator.io/v1
kind: ExitNode
metadata:
name: echo-exit-node
namespace: futureporn
spec:
host: "{{ .Values.chisel.exitNodeIp }}"
port: 9090
auth: chisel
{{ end }}
# ---
# apiVersion: traefik.io/v1alpha1
# kind: IngressRoute
# metadata:
# name: echo
# namespace: futureporn
# spec:
# entryPoints:
# - web
# routes:
# - match: Host(`echo.fp.sbtp.xyz`) || PathPrefix(`/extra/echo`)
# kind: Rule
# services:
# - name: echo
# port: 8001
# # tls:
# # secretName: echo-cert
---
apiVersion: v1
kind: Service
metadata:
name: echo
namespace: futureporn
annotations:
external-dns.alpha.kubernetes.io/hostname: "{{ .Values.echo.hostname }}"
{{ if eq .Values.environment "development" }}
chisel-operator.io/exit-node-name: "echo-exit-node"
{{ end }}
spec:
type: LoadBalancer
selector:
app: echo
ports:
- name: web
protocol: TCP
port: 5678
targetPort: 5678
- name: websecure
protocol: TCP
port: 4443
targetPort: 5678
---
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: echo
namespace: futureporn
spec:
secretName: echo-tls
issuerRef:
name: "{{ .Values.certManager.issuer }}"
kind: ClusterIssuer
dnsNames:
- "{{ .Values.echo.hostname }}"
---
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
name: echo-http
namespace: futureporn
spec:
entryPoints:
- web
routes:
- match: Host(`echo.fp.sbtp.xyz`)
kind: Rule
middlewares:
- name: redirect
namespace: futureporn
services:
- name: echo
namespace: futureporn
port: 5678
---
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
name: echo-https
namespace: futureporn
annotations:
cert-manager.io/cluster-issuer: "{{ .Values.certManager.issuer }}"
spec:
entryPoints:
- websecure
routes:
- match: Host(`echo.fp.sbtp.xyz`)
kind: Rule
services:
- name: echo
namespace: futureporn
port: 5678
tls:
secretName: echo-tls

View File

@ -13,6 +13,8 @@ spec:
env: env:
- name: HOSTNAME - name: HOSTNAME
value: 0.0.0.0 value: 0.0.0.0
- name: NEXT_PUBLIC_UPPY_COMPANION_URL
value: "{{ .Values.uppy.hostname }}"
ports: ports:
- name: web - name: web
containerPort: 3000 containerPort: 3000

View File

@ -0,0 +1,219 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: uppy
namespace: futureporn
spec:
replicas: 2
minReadySeconds: 5
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 2
maxUnavailable: 1
selector:
matchLabels:
app: uppy
template:
metadata:
labels:
app: uppy
spec:
containers:
- name: uppy
image: docker.io/transloadit/companion:latest
imagePullPolicy: IfNotPresent
resources:
limits:
memory: 150Mi
requests:
memory: 100Mi
env:
- name: COMPANION_STREAMING_UPLOAD
value: "true"
- name: COMPANION_CLIENT_ORIGINS
value: "{{ .Values.uppy.clientOrigins }}"
- name: COMPANION_DATADIR
value: /tmp/
- name: COMPANION_DOMAIN
value: "{{ .Values.uppy.domain }}"
- name: COMPANION_PROTOCOL
value: https
- name: COMPANION_REDIS_URL
valueFrom:
secretKeyRef:
name: uppy
key: redisUrl
- name: COMPANION_SECRET
valueFrom:
secretKeyRef:
name: uppy
key: secret
- name: COMPANION_PREAUTH_SECRET
valueFrom:
secretKeyRef:
name: uppy
key: preAuthSecret
- name: COMPANION_DROPBOX_KEY
valueFrom:
secretKeyRef:
name: uppy
key: dropboxKey
- name: COMPANION_DROPBOX_SECRET
valueFrom:
secretKeyRef:
name: uppy
key: dropboxSecret
- name: COMPANION_BOX_KEY
valueFrom:
secretKeyRef:
name: uppy
key: boxKey
- name: COMPANION_BOX_SECRET
valueFrom:
secretKeyRef:
name: uppy
key: boxSecret
- name: COMPANION_GOOGLE_KEY
valueFrom:
secretKeyRef:
name: uppy
key: googleKey
- name: COMPANION_GOOGLE_SECRET
valueFrom:
secretKeyRef:
name: uppy
key: googleSecret
- name: COMPANION_AWS_KEY
valueFrom:
secretKeyRef:
name: uppy
key: awsKey
- name: COMPANION_AWS_SECRET
valueFrom:
secretKeyRef:
name: uppy
key: awsSecret
- name: COMPANION_AWS_BUCKET
value: "{{ .Values.uppy.s3.bucket }}"
- name: COMPANION_AWS_REGION
value: "{{ .Values.uppy.s3.region }}"
- name: COMPANION_AWS_PREFIX
value: "{{ .Values.uppy.s3.prefix }}"
## COMPANION_OAUTH_DOMAIN is only necessary if using a different domain per each uppy pod.
## We don't need this because we are load balancing the pods so they all use the same domain name.
## @see https://github.com/transloadit/uppy/blob/f4dd3d534ff4378f3a2f73fe327358bcbde74059/docs/companion.md#server
- name: COMPANION_OAUTH_DOMAIN
value: ''
- name: COMPANION_PATH
value: ''
- name: COMPANION_IMPLICIT_PATH
value: ''
- name: COMPANION_DOMAINS
value: ''
## https://uppy.io/docs/companion/#uploadurls-companion_upload_urls
- name: COMPANION_UPLOAD_URLS
value: "{{ .Values.uppy.uploadUrls }}"
ports:
- containerPort: 3020
volumeMounts:
- name: uppy-data
mountPath: /mnt/uppy-data
volumes:
- name: uppy-data
emptyDir: {}
---
apiVersion: v1
kind: Service
metadata:
name: uppy
namespace: futureporn
annotations:
external-dns.alpha.kubernetes.io/hostname: "{{ .Values.uppy.hostname }}"
chisel-operator.io/exit-node-name: "uppy-exit-node"
spec:
type: LoadBalancer
ports:
- port: 3020
targetPort: 3020
protocol: TCP
selector:
app: uppy
{{ if eq .Values.environment "development" }}
---
apiVersion: chisel-operator.io/v1
kind: ExitNode
metadata:
name: uppy-exit-node
namespace: futureporn
spec:
host: "{{ .Values.chisel.exitNodeIp }}"
port: 9090
auth: chisel
{{ end }}
---
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
name: uppy-http
namespace: futureporn
spec:
entryPoints:
- web
routes:
- match: Host(`uppy.fp.sbtp.xyz`)
kind: Rule
middlewares:
- name: redirect
namespace: futureporn
services:
- name: uppy
namespace: futureporn
port: 3020
---
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
name: uppy-https
namespace: futureporn
annotations:
cert-manager.io/cluster-issuer: "{{ .Values.certManager.issuer }}"
spec:
entryPoints:
- websecure
routes:
- match: Host(`uppy.fp.sbtp.xyz`)
kind: Rule
services:
- name: uppy
namespace: futureporn
port: 3020
tls:
secretName: uppy-tls
# Welcome to Companion v4.15.1
# ===================================
# Congratulations on setting up Companion! Thanks for joining our cause, you have taken
# the first step towards the future of file uploading! We
# hope you are as excited about this as we are!
# While you did an awesome job on getting Companion running, this is just the welcome
# message, so let's talk about the places that really matter:
# - Be sure to add the following URLs as your Oauth redirect uris on their corresponding developer interfaces:
# https://uppy.fp.sbtp.xyz/drive/redirect, https://uppy.fp.sbtp.xyz/googlephotos/redirect, https://uppy.fp.sbtp.xyz/dropbox/redirect, https://uppy.fp.sbtp.xyz/box/redirect, https://uppy.fp.sbtp.xyz/instagram/redirect, https://uppy.fp.sbtp.xyz/facebook/redirect, https://uppy.fp.sbtp.xyz/onedrive/redirect, https://uppy.fp.sbtp.xyz/zoom/redirect, https://uppy.fp.sbtp.xyz/unsplash/redirect
# - The URL https://uppy.fp.sbtp.xyz/metrics is available for statistics to keep Companion running smoothly
# - https://github.com/transloadit/uppy/issues - report your bugs here
# So quit lollygagging, start uploading and experience the future!

View File

@ -34,5 +34,16 @@ chisel:
exitNodeIp: "155.138.254.201" exitNodeIp: "155.138.254.201"
echo: echo:
hostname: echo.fp.sbtp.xyz hostname: echo.fp.sbtp.xyz
uppy:
hostname: uppy.fp.sbtp.xyz
imageName: fp/uppy
s3:
endpoint: s3.us-west-000.backblazeb2.com
bucket: futureporn-usc
region: us-west-000
prefix: s3
clientOrigins: next.fp.sbtp.xyz
domain: uppy.fp.sbtp.xyz
uploadUrls: https://uppy.fp.sbtp.xyz/files
certManager: certManager:
issuer: letsencrypt-staging issuer: letsencrypt-staging

View File

@ -5,22 +5,16 @@ RUN corepack enable
FROM base AS build FROM base AS build
ENV NODE_ENV=production ENV NODE_ENV=production
COPY . /usr/src/app COPY ./packages/bot /usr/src/app
WORKDIR /usr/src/app WORKDIR /usr/src/app
RUN mkdir -p /prod/scout RUN mkdir -p /prod/scout
RUN --mount=type=cache,id=pnpm,target=/pnpm/store pnpm install --frozen-lockfile RUN --mount=type=cache,id=pnpm,target=/pnpm/store pnpm install --frozen-lockfile
RUN pnpm deploy --filter=scout --prod /prod/scout RUN pnpm deploy --filter=bot --prod /prod/scout
FROM base AS manager FROM base AS bot
COPY --from=build /prod/scout /app COPY --from=build /prod/bot /app
WORKDIR /app WORKDIR /app
ENTRYPOINT ["pnpm"] ENTRYPOINT ["pnpm"]
CMD ["run", "start:manager"] CMD ["run", "start"]
FROM base AS worker
COPY --from=build /prod/scout /app
WORKDIR /app
ENTRYPOINT ["pnpm"]
CMD ["run", "start:worker"]

42
d.packages.dockerfile Normal file
View File

@ -0,0 +1,42 @@
## This dockerfile creates multiple docker images.
## Because we are using monorepo with pnpm workspaces, we have many npm packages in this single git repo.
## Some of these packages in the monorepo depend on other packages in the monorepo.
## In order to build these individual packages which inter-depend on eachother,
## all of the dependent code must be present in the build.
##
## Below, COPY . /usr/src/app copies all the app code into the build context.
## Because we use Tilt, only specific path directories are visible to docker. This helps with build performance.
## When a new package becomes a dependency, we need to update our Tiltfile to include the package directory.
## Tiltfile example of docker_build() args which include `scout` and `next` packages.
## `only=['./pnpm-lock.yaml', './package.json', './packages/scout', './packages/next'],`
##
##
FROM node:20 AS base
ENV PNPM_HOME="/pnpm"
ENV PATH="$PNPM_HOME:$PATH"
RUN corepack enable
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 pnpm deploy --filter=scout --prod /prod/scout
# RUN pnpm deploy --filter=bot --prod /prod/bot
FROM base AS scout-manager
COPY --from=build /prod/scout /app
WORKDIR /app
ENTRYPOINT ["pnpm"]
CMD ["run", "start:manager"]
FROM base AS scout-worker
COPY --from=build /prod/scout /app
COPY --from=build /usr/src/app/certs/letsencrypt-stg-root-x1.pem
ENV NODE_EXTRA_CA_CERTS "/app/certs/letsencrypt-stg-root-x1.pem"
WORKDIR /app
ENTRYPOINT ["pnpm"]
CMD ["run", "start:worker"]

View File

@ -5,9 +5,9 @@ WORKDIR /app
RUN corepack enable RUN corepack enable
FROM base as build FROM base as build
COPY ./packages/uppy/package.json ./ COPY ./packages/uppy/package.json ./packages/uppy/pnpm-lock.yaml /app
COPY ./packages/uppy/index.js ./ RUN --mount=type=cache,id=pnpm,target=/pnpm/store pnpm install --frozen-lockfile
RUN --mount=type=cache,id=pnpm,target=/pnpm/store pnpm install COPY ./packages/uppy/ .
FROM build as run FROM build as run
ENTRYPOINT ["pnpm"] ENTRYPOINT ["pnpm"]

View File

@ -1,5 +1,5 @@
# Futureporn node packages # Futureporn node packages
Each folder here is an individual node package, each of which can reference each other. Each folder here is an individual node package, each of which can reference each other. One reason we do this is to share utility functions between packages.
See https://pnpm.io/workspaces See https://pnpm.io/workspaces

View File

@ -1,3 +1,3 @@
# infra # infra
This module contains scripts that help with miscellaneous infrastructure tasks. This module contains scripts that help with miscellaneous infrastructure tasks like cleaning up unused resources on Vultr Kubernetes Engine.

View File

@ -1,5 +1,5 @@
{ {
"name": "scripts", "name": "infra",
"type": "module", "type": "module",
"version": "1.0.0", "version": "1.0.0",
"description": "", "description": "",

View File

@ -1,27 +1,2 @@
# futureporn-next # next
## Dev notes
When adding a new module via pnpm, docker compose needs to be restarted or something. I'm not sure the exact steps just yet, but I think it's something like the following.
```
pnpm add @uppy/react
docker compose build next
```
> fp-next | Module not found: Can't resolve '@uppy/react'
hmm... It looks like I'm missing something. Is the new package not getting into the container? Maybe it's something to do with the pnpm cache?
Must we build without cache?
docker compose build --no-cache next; docker compose up
YES. that solved the issue.
However, it's really slow to purge cache and download all packages once again. Is there a way we can speed this up?
* make it work
* make it right
* make it fast

View File

@ -8,47 +8,19 @@ export default async function Page() {
return ( return (
<> <>
<div className="content"> <div className="content">
<section className="hero"> <section className="hero">
<div className="hero-body"> <div className="hero-body">
<p className="title">About</p> <p className="title">About</p>
<p>Futureporn is a fanmade public archive of NSFW R18 vtuber livestreams.</p> <p>It's the worst feeling when a VOD disappears from the internet. It means you missed out, it's gone, and you may never experience what your peers got to take part in.</p>
<p>Futureporn is created by fans, for fans. Missed a stream? We got you, bro.</p>
<p>Together we can end 404s and create an everlasting archive of lewdtuber livestreams.</p>
</div> </div>
</section> </section>
<div className="section">
<h1>Mission</h1>
<p>It&apos;s a lofty goal, but Futureporn aims to become <b>the Galaxy&apos;s best VTuber hentai site.</b></p>
</div>
<div className="section">
<h2>How do we get there?</h2>
<h3>1. Solve the viewer&apos;s common problems</h3>
<p>Viewers want to watch livestream VODs on their own time. Futureporn collects vods from public streams, and caches them for later viewing.</p>
<p>Viewers want to find content that interests them. Futureporn enables vod tagging for easy browsing.</p>
</div>
<div className="section">
<h3>2. Solve the streamer&apos;s common problems</h3>
<p>Platforms like PH are not rising to the needs of VTubers. Instead of offering support and resources, they restrict and ban top talent.</p>
<p>Futureporn is different, embracing the medium and leveraging emerging technologies to amplify VTuber success.</p>
</div>
<div className="section">
<h3>3. Scale beyond Earth</h3>
<p>Piggybacking on <Link href="/faq#ipfs">IPFS</Link>&apos; content-addressable capabilities and potential to end 404s, VODs preserved here can withstand the test of time, and eventually persist <Link href="/goals">off-world</Link>.</p>
</div>
<div className="section"> <div className="section">

View File

@ -6,7 +6,7 @@ export default function NotFound() {
<h2 className='title is-2'>404 Not Found</h2> <h2 className='title is-2'>404 Not Found</h2>
<p>Could not find that stream archive.</p> <p>Could not find that stream archive.</p>
<Link href="/s">Return to archive list</Link> <Link href="/archive">Return to archive list</Link>
</div> </div>
) )
} }

View File

@ -63,7 +63,7 @@ export default function Navbar() {
</div> </div>
{/* <div className="navbar-item"> <div className="navbar-item">
<Link className="button " href="/upload"> <Link className="button " href="/upload">
<span className="mr-1">Upload</span> <span className="mr-1">Upload</span>
<FontAwesomeIcon <FontAwesomeIcon
@ -71,7 +71,7 @@ export default function Navbar() {
className="fas fa-upload" className="fas fa-upload"
></FontAwesomeIcon> ></FontAwesomeIcon>
</Link> </Link>
</div> */} </div>
<div className="navbar-item fp-profile-button"> <div className="navbar-item fp-profile-button">
{/* show the login button if user is anon */} {/* show the login button if user is anon */}

View File

@ -10,8 +10,6 @@ interface PatronsListProps {
export default async function PatronsList({ displayStyle }: PatronsListProps) { export default async function PatronsList({ displayStyle }: PatronsListProps) {
const patrons = await getPatrons() const patrons = await getPatrons()
console.log(`patrons are as follows`)
console.log(patrons)
if (!patrons) return ( if (!patrons) return (
<SkeletonTheme baseColor="#000" highlightColor="#000"> <SkeletonTheme baseColor="#000" highlightColor="#000">

View File

@ -11,6 +11,7 @@ import { faTriangleExclamation, faCircleInfo, faThumbsUp, IconDefinition, faO, f
import { Hemisphere, Moon } from "lunarphase-js"; import { Hemisphere, Moon } from "lunarphase-js";
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import { faXTwitter } from "@fortawesome/free-brands-svg-icons"; import { faXTwitter } from "@fortawesome/free-brands-svg-icons";
import { notFound } from "next/navigation";
export interface IStreamProps { export interface IStreamProps {
stream: IStream; stream: IStream;
@ -47,6 +48,7 @@ function determineStatus(stream: IStream): Status {
export default function StreamPage({ stream }: IStreamProps) { export default function StreamPage({ stream }: IStreamProps) {
console.log('StreamPage function has been invoked! stream as follows') console.log('StreamPage function has been invoked! stream as follows')
console.log(stream) console.log(stream)
if (!stream) notFound()
const displayName = stream.attributes.vtuber.data.attributes.displayName; const displayName = stream.attributes.vtuber.data.attributes.displayName;
const date = new Date(stream.attributes.date); const date = new Date(stream.attributes.date);
const [hemisphere, setHemisphere] = useState(Hemisphere.NORTHERN); const [hemisphere, setHemisphere] = useState(Hemisphere.NORTHERN);
@ -169,8 +171,7 @@ export default function StreamPage({ stream }: IStreamProps) {
<span className="title is-1"><FontAwesomeIcon icon={icon}></FontAwesomeIcon></span> <span className="title is-1"><FontAwesomeIcon icon={icon}></FontAwesomeIcon></span>
<p className="mt-3">{desc1}</p> <p className="mt-3">{desc1}</p>
<p className="mt-5">{desc2}<br /> <p className="mt-5">{desc2}<br />
{/* <Link href={`/upload?cuid=${stream.attributes.cuid}`}>Upload it here.</Link></p> */} <Link href={`/upload?cuid=${stream.attributes.cuid}`}>Upload it here.</Link></p>
<Link style={{ cursor: 'not-allowed' }} href={`/upload?cuid=${stream.attributes.cuid}`}><i>Uploads coming soon.</i></Link></p>
</div> </div>
</article> </article>
</div> </div>

View File

@ -16,7 +16,8 @@ import {
ColumnDef, ColumnDef,
flexRender, flexRender,
} from '@tanstack/react-table' } from '@tanstack/react-table'
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
import { faSpinner } from '@fortawesome/free-solid-svg-icons'
import { fetchStreamData, IStream } from '@/lib/streams' import { fetchStreamData, IStream } from '@/lib/streams'
@ -129,20 +130,20 @@ export default function StreamsTable() {
pageSize: 50, pageSize: 50,
}) })
const dataQuery = useQuery({ const { data, error, isPending } = useQuery({
queryKey: ['streams', pagination.pageIndex, pagination.pageSize], queryKey: ['streams', pagination.pageIndex, pagination.pageSize],
queryFn: () => fetchStreamData(pagination), queryFn: () => fetchStreamData(pagination),
placeholderData: keepPreviousData, // don't have 0 rows flash while changing pages/loading next page, placeholderData: keepPreviousData, // don't have 0 rows flash while changing pages/loading next page,
staleTime: 1000 staleTime: 1000,
}, queryClient) }, queryClient)
const defaultData = React.useMemo(() => [], []) const defaultData = React.useMemo(() => [], [])
const table = useReactTable({ const table = useReactTable({
data: dataQuery?.data?.rows ?? defaultData, data: data?.rows ?? defaultData,
columns, columns,
// pageCount: dataQuery.data?.pageCount ?? -1, //you can now pass in `rowCount` instead of pageCount and `pageCount` will be calculated internally (new in v8.13.0) // pageCount: dataQuery.data?.pageCount ?? -1, //you can now pass in `rowCount` instead of pageCount and `pageCount` will be calculated internally (new in v8.13.0)
rowCount: dataQuery.data?.rowCount, // new in v8.13.0 - alternatively, just pass in `pageCount` directly rowCount: data?.rowCount, // new in v8.13.0 - alternatively, just pass in `pageCount` directly
state: { state: {
pagination, pagination,
}, },
@ -156,49 +157,53 @@ export default function StreamsTable() {
return ( return (
<div className="p-2"> <div className="p-2">
<div className="h-2" /> <div className="h-2" />
<table className='table is-hoverable is-fullwidth'>
<thead> {isPending && <FontAwesomeIcon className="mt-5 fa-spin-pulse" icon={faSpinner} ></FontAwesomeIcon> }
{table.getHeaderGroups().map(headerGroup => ( {!isPending && <>
<tr key={headerGroup.id}> <table className='table is-hoverable is-fullwidth'>
{headerGroup.headers.map(header => { <thead>
return ( {table.getHeaderGroups().map(headerGroup => (
<th key={header.id} colSpan={header.colSpan}> <tr key={headerGroup.id}>
{header.isPlaceholder ? null : ( {headerGroup.headers.map(header => {
<div>
{flexRender(
header.column.columnDef.header,
header.getContext()
)}
</div>
)}
</th>
)
})}
</tr>
))}
</thead>
<tbody>
{table.getRowModel().rows.map(row => {
return (
<tr key={row.id}>
{row.getVisibleCells().map(cell => {
return ( return (
<td <th key={header.id} colSpan={header.colSpan}>
className={getStatusClass(cell.getValue() as string)} {header.isPlaceholder ? null : (
key={cell.id} <div>
> {flexRender(
{flexRender( header.column.columnDef.header,
cell.column.columnDef.cell, header.getContext()
cell.getContext() )}
</div>
)} )}
</td> </th>
) )
})} })}
</tr> </tr>
) ))}
})} </thead>
</tbody> <tbody>
</table> {table.getRowModel().rows.map(row => {
return (
<tr key={row.id}>
{row.getVisibleCells().map(cell => {
return (
<td
className={getStatusClass(cell.getValue() as string)}
key={cell.id}
>
{flexRender(
cell.column.columnDef.cell,
cell.getContext()
)}
</td>
)
})}
</tr>
)
})}
</tbody>
</table>
<div className="columns is-mobile is-vcentered"> <div className="columns is-mobile is-vcentered">
<div className='column is-half'> <div className='column is-half'>
@ -273,6 +278,7 @@ export default function StreamsTable() {
</div> </div>
</div> </div>
</div> </div>
</>}

View File

@ -159,235 +159,241 @@ export default function UploadForm({ vtubers }: IUploadFormProps) {
uppy.on('complete', async (result: any) => { uppy.on('complete', async (result: any) => {
console.log('uppy complete! ')
console.log(result)
for (const s of result.successful) {
if (!s?.s3Multipart) {
setError('root.serverError', {
type: 'remote',
message: 'file was missing s3Multipart'
})
// throw new Error('file was missing s3Multipart')
}
}
let files = result.successful.map((f: any) => ({ key: f.s3Multipart.key, uploadId: f.s3Multipart.uploadId })); let files = result.successful.map((f: any) => ({ key: f.s3Multipart.key, uploadId: f.s3Multipart.uploadId }));
setValue('files', files); setValue('files', files);
}); });
return (<div className="notification is-secondary">
<h1 className="title">VOD uploads</h1>
<p>
<i>coming soon!!</i>
</p>
<hr ></hr>
<p>Track progress on the <a href="/goals">Goals Page</a></p>
</div>)
// return ( return (
// <> <>
// <div className='section'> <div className='section'>
// <h2 className='title is-2'>Upload VOD</h2> <h2 className='title is-2'>Upload VOD</h2>
// <p className="mb-5"><i>Together we can archive all lewdtuber livestreams!</i></p> <p className="mb-5"><i>Together we can archive all lewdtuber livestreams!</i></p>
// {(!authData?.accessToken) {(!authData?.accessToken)
// ? ?
// <> <>
// <aside className='notification is-danger'><p>Please log in to upload VODs</p></aside> <aside className='notification is-danger'><p>Please log in to upload VODs</p></aside>
// <LoginButton /> <LoginButton />
// </> </>
// : ( : (
// <div className='columns is-multiline'> <div className='columns is-multiline'>
// <form id="vod-details" onSubmit={handleSubmit(createUSC)}> <form id="vod-details" onSubmit={handleSubmit(createUSC)}>
// {(!isSubmitSuccessful) && <div className='column is-full'> {(!isSubmitSuccessful) && <div className='column is-full'>
// <section className="hero is-info mb-3"> <section className="hero is-info mb-3">
// <div className="hero-body"> <div className="hero-body">
// <p className="title"> <p className="title">
// Step 1 Step 1
// </p> </p>
// <p className="subtitle"> <p className="subtitle">
// Upload the file Upload the file
// </p> </p>
// </div> </div>
// </section> </section>
// <section className="section mb-5"> <section className="section mb-5">
// <Dashboard <Dashboard
// uppy={uppy} uppy={uppy}
// theme='dark' theme='dark'
// proudlyDisplayPoweredByUppy={false} proudlyDisplayPoweredByUppy={true}
// />
showProgressDetails={true}
/>
// <input {/* This form is hidden. Why? */}
// required <input
// hidden={true} required
// style={{ display: 'none' }} hidden={false}
// className="input" type="text" style={{ display: 'block' }}
// {...register('files')} className="input" type="text"
// ></input> {...register('files')}
></input>
// {errors.files && <p className="help is-danger">{errors.files.message?.toString()}</p>} {errors.files && <p className="help is-danger">{errors.files.message?.toString()}</p>}
// </section> </section>
// </div>} </div>}
// {(!isSubmitSuccessful) && <div className='column is-full '> {(!isSubmitSuccessful) && <div className='column is-full '>
// {/* {(!cuid) && <aside className='notification is-info'>Hint: Some of these fields are filled out automatically when uploading from a <Link href="/streams">stream</Link> page.</aside>} */} {/* {(!cuid) && <aside className='notification is-info'>Hint: Some of these fields are filled out automatically when uploading from a <Link href="/streams">stream</Link> page.</aside>} */}
// <section className="hero is-info mb-3"> <section className="hero is-info mb-3">
// <div className="hero-body"> <div className="hero-body">
// <p className="title"> <p className="title">
// Step 2 Step 2
// </p> </p>
// <p className="subtitle"> <p className="subtitle">
// Tell us about the VOD Tell us about the VOD
// </p> </p>
// </div> </div>
// </section> </section>
// <section className="section"> <section className="section">
// {/* <input {/* <input
// required required
// // hidden={false} // hidden={false}
// // style={{ display: 'none' }} // style={{ display: 'none' }}
// className="input" type="text" className="input" type="text"
// {...register('streamCuid')} {...register('streamCuid')}
// ></input> */} ></input> */}
// <div className="field"> <div className="field">
// <label className="label">VTuber</label> <label className="label">VTuber</label>
// <div className="select"> <div className="select">
// <select <select
// required required
// // value={vtuber} // value={vtuber}
// // onChange={(evt) => setVtuber(parseInt(evt.target.value))} // onChange={(evt) => setVtuber(parseInt(evt.target.value))}
// {...register('vtuber')} {...register('vtuber')}
// > >
// {vtubers.map((vtuber: IVtuber) => ( {vtubers.map((vtuber: IVtuber) => (
// <option key={vtuber.id} value={vtuber.id}>{vtuber.attributes.displayName}</option> <option key={vtuber.id} value={vtuber.id}>{vtuber.attributes.displayName}</option>
// ))} ))}
// </select> </select>
// </div> </div>
// <p className="help is-info">Choose the VTuber this VOD belongs to. (More VTubers will be added when storage/bandwidth funding is secured.)</p> <p className="help is-info">Choose the VTuber this VOD belongs to. (More VTubers will be added when storage/bandwidth funding is secured.)</p>
// {errors.vtuber && <p className="help is-danger">vtuber error</p>} {errors.vtuber && <p className="help is-danger">vtuber error</p>}
// </div> </div>
// <div className="field"> <div className="field">
// <label className="label">Stream Date</label> <label className="label">Stream Date</label>
// <input <input
// required required
// className="input" type="date" className="input" type="date"
// {...register('date')} {...register('date')}
// // onChange={(evt) => setDate(evt.target.value)} // onChange={(evt) => setDate(evt.target.value)}
// ></input> ></input>
// <p className="help is-info">The date when the VOD was originally streamed.</p> <p className="help is-info">The date when the VOD was originally streamed.</p>
// {errors.date && <p className="help is-danger">{errors.date.message?.toString()}</p>} {errors.date && <p className="help is-danger">{errors.date.message?.toString()}</p>}
// </div> </div>
// <div className="field"> <div className="field">
// <label className="label">Notes</label> <label className="label">Notes</label>
// <textarea <textarea
// className="textarea" className="textarea"
// placeholder="e.g. Missing first 10 minutes of stream" placeholder="e.g. Missing first 10 minutes of stream"
// // onChange={(evt) => setNote(evt.target.value)} // onChange={(evt) => setNote(evt.target.value)}
// {...register('notes')} {...register('notes')}
// ></textarea> ></textarea>
// <p className="help is-info">If there are any issues with the VOD, put a note here. If there are no VOD issues, leave this field blank.</p> <p className="help is-info">If there are any issues with the VOD, put a note here. If there are no VOD issues, leave this field blank.</p>
// </div> </div>
// <div className="field"> <div className="field">
// <label className="label">Attribution</label> <label className="label">Attribution</label>
// <label className="checkbox"> <label className="checkbox">
// <input <input
// type="checkbox" type="checkbox"
// // onChange={(evt) => setAttribution(evt.target.checked)} // onChange={(evt) => setAttribution(evt.target.checked)}
// {...register('attribution')} {...register('attribution')}
// /> />
// <span className={`ml-2 ${styles.noselect}`}>Credit {authData.user?.username} for the upload.</span> <span className={`ml-2 ${styles.noselect}`}>Credit {authData.user?.username} for the upload.</span>
// <p className="help is-info">Check this box if you want your username displayed on the website. Thank you for uploading!</p> <p className="help is-info">Check this box if you want your username displayed on the website. Thank you for uploading!</p>
// </label> </label>
// </div> </div>
// </section> </section>
// </div>} </div>}
// <div className="column is-full"> <div className="column is-full">
// <section className="hero is-info"> <section className="hero is-info">
// <div className="hero-body"> <div className="hero-body">
// <p className="title"> <p className="title">
// Step 3 Step 3
// </p> </p>
// <p className="subtitle"> <p className="subtitle">
// Send the form Send the form
// </p> </p>
// </div> </div>
// </section> </section>
// <section className="section"> <section className="section">
// {errors.root?.serverError && ( {errors.root?.serverError && (
// <div className="notification"> <div className="notification">
// <button className="delete" onClick={() => clearErrors()}></button> <button className="delete" onClick={() => clearErrors()}></button>
// <ErrorMessage name="root" errors={errors} ></ErrorMessage> <ErrorMessage name="root" errors={errors} ></ErrorMessage>
// </div> </div>
// )} )}
// {!isSubmitSuccessful && ( {!isSubmitSuccessful && (
// <button className="button is-primary is-large mt-5"> <button className="button is-primary is-large mt-5">
// <span className="icon is-small"> <span className="icon is-small">
// <FontAwesomeIcon icon={faPaperPlane}></FontAwesomeIcon> <FontAwesomeIcon icon={faPaperPlane}></FontAwesomeIcon>
// </span> </span>
// <span>Send</span> <span>Send</span>
// </button> </button>
// )} )}
// {isSubmitting && ( {isSubmitting && (
// <p> <p>
// <FontAwesomeIcon className="mt-5 fa-spin-pulse" icon={faSpinner} ></FontAwesomeIcon> <FontAwesomeIcon className="mt-5 fa-spin-pulse" icon={faSpinner} ></FontAwesomeIcon>
// </p> </p>
// )} )}
// {isSubmitSuccessful && ( {isSubmitSuccessful && (
// <> <>
// <aside className="notification mt-5 is-success">Thank you for uploading! </aside> <aside className="notification mt-5 is-success">Thank you for uploading! </aside>
// <button onClick={() => { <button onClick={() => {
// reset(); // reset form reset(); // reset form
// const files = uppy.getFiles() const files = uppy.getFiles()
// for (const file of files) { for (const file of files) {
// uppy.removeFile(file.id); // reset uppy uppy.removeFile(file.id); // reset uppy
// } }
// }} className="button is-primary"> }} className="button is-primary">
// <span className="icon is-small"> <span className="icon is-small">
// <FontAwesomeIcon icon={faEraser}></FontAwesomeIcon> <FontAwesomeIcon icon={faEraser}></FontAwesomeIcon>
// </span> </span>
// <span>Reset form</span> <span>Reset form</span>
// </button> </button>
// </> </>
// )} )}
// </section> </section>
// </div> </div>
// </form> </form>
// </div> </div>
// ) )
// } }
// </div> </div>
// </> </>
// ) )
} }

View File

@ -340,14 +340,14 @@ export async function fetchStreamData({ pageIndex, pageSize }: { pageIndex: numb
}) })
const response = await fetch( const response = await fetch(
`${strapiUrl}/api/streams?${query}` `${strapiUrl}/api/streams?${query}`
); );
const json = await response.json(); const json = await response.json();
console.log(json) console.log(json)
const d = { const d = {
rows: json.data, rows: json.data,
pageCount: Math.ceil(json.meta.pagination.total / pageSize), pageCount: Math.ceil(json.meta.pagination.total / pageSize),
rowCount: json.meta.pagination.total, rowCount: json.meta.pagination.total,
} }
// console.log(`fetchStreamData with pageIndex=${pageIndex}, pageSize=${pageSize}\n\n${JSON.stringify(d, null, 2)}`) // console.log(`fetchStreamData with pageIndex=${pageIndex}, pageSize=${pageSize}\n\n${JSON.stringify(d, null, 2)}`)
return d; return d;
} }

View File

@ -8,6 +8,10 @@ import { useAuth } from './components/auth';
import { companionUrl } from '@/lib/constants'; import { companionUrl } from '@/lib/constants';
// Uppy is a challenging react integration. Following are some references
// @see https://github.com/transloadit/uppy/issues/4727#issuecomment-1761118428
export const UppyContext = createContext(new Uppy()); export const UppyContext = createContext(new Uppy());
export default function UppyProvider({ export default function UppyProvider({
@ -18,12 +22,17 @@ export default function UppyProvider({
const { authData } = useAuth(); const { authData } = useAuth();
const [uppy] = useState(() => new Uppy( const [uppy] = useState(() => new Uppy(
{ {
autoProceed: true autoProceed: false,
debug: true
} }
) )
.use(RemoteSources, { .use(RemoteSources, {
companionUrl, companionUrl,
sources: ['GoogleDrive'] sources: [
'GoogleDrive',
'Dropbox',
'Url'
]
}) })
.use(AwsS3, { .use(AwsS3, {
companionUrl, companionUrl,

View File

@ -1,4 +1,4 @@
{ {
"extension": ["js"], "extension": ["ts"],
"spec": "src/**/*.spec.js" "spec": "src/**/*.spec.ts"
} }

View File

@ -1,8 +1,3 @@
// export function blah(name) {
// return `Today is a blah kind of a day. amirite, ${name}?`;
// }
import fetch from "node-fetch" import fetch from "node-fetch"
import { NotificationData, processEmail } from "./workflows.js" import { NotificationData, processEmail } from "./workflows.js"
import qs from 'qs' import qs from 'qs'

View File

@ -19,7 +19,7 @@
"declarationMap": true, "declarationMap": true,
"sourceMap": true, "sourceMap": true,
"rootDir": "./src", "rootDir": "./src",
"outDir": "./lib" "outDir": "./dist"
}, },
"include": ["**/*.ts"], "include": ["**/*.ts"],
"ts-node": { "ts-node": {

View File

@ -1,6 +1,7 @@
module.exports = ({ env }) => ({ module.exports = ({ env }) => ({
host: env('HOST', '0.0.0.0'), host: env('HOST', '0.0.0.0'),
port: env.int('PORT', 1337), port: env.int('PORT', 1337),
proxy: true,
app: { app: {
keys: env.array('APP_KEYS'), keys: env.array('APP_KEYS'),
}, },

View File

@ -1,6 +1,7 @@
{ {
"compilerOptions": { "compilerOptions": {
"moduleResolution": "nodenext", "module": "NodeNext",
"moduleResolution": "NodeNext",
"target": "ES2021", "target": "ES2021",
"checkJs": true, "checkJs": true,
"allowJs": true "allowJs": true

View File

@ -11,10 +11,10 @@ function generateCuid(event) {
module.exports = { module.exports = {
async beforeUpdate(event) { async beforeUpdate(event) {
console.log(`>> beforeUpdate! We are generating a CUID`);
generateCuid(event); generateCuid(event);
}, },
async beforeCreate(event) { async beforeCreate(event) {
console.log(`>> beforeCreate! We are generating a CUID`);
console.log(`>> beforeCreate! We are generating a CUID`); console.log(`>> beforeCreate! We are generating a CUID`);
generateCuid(event); generateCuid(event);
}, },
@ -22,4 +22,6 @@ module.exports = {
console.log(`>> afterCreate! We are generating a CUID`); console.log(`>> afterCreate! We are generating a CUID`);
generateCuid(event); generateCuid(event);
} }
} }

View File

@ -1,30 +0,0 @@
SESSION_SECRET=a9834jjajfajfiojaoejfbitco####$#iniswhigjlbutoonlyifyour8asl
PORT=5000
FILEPATH=/tmp
HOST=http://localhost:5000
UPLOAD_URLS=http://localhost:5000
SECRET=afjafifjfjSHHHHHHdontdtouchtiafImS+____cared
SERVER_BASE_URL=http://localhost:5000
B2_ENDPOINT=s3.us-west-000.backblazeb2.com
B2_BUCKET=fp-usc-dev
B2_SECRET=K0004kP+ZfsINYsvWMGYdX66Gr5ZvIo
B2_KEY=000d37f13a933b80000000034
DRIVE_KEY=886031456924-jiuukhfte5n0cfkktevgojpum54dn6r3.apps.googleusercontent.com
DRIVE_SECRET=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
DROPBOX_KEY=zvaxniaf1gunns9
DROPBOX_SECRET=cclglkkjkoqqo3v
JWT_SECRET=GRYMjvirjfI6GxzkbNQMhg==
STRAPI_API_KEY=9ad1b224cb399219cae910569875aa76ff2bd408db7e799653d4317198e326f04694abbecb31efc2d5b845c39e348940bb548b07ecf1d3fff07535d92df001700ce8dfea96dd3fd8a720c49f366761537f0042a74b4e35100b783f54be28e13086c96a1d437ff31c80568618ef94ef7de7ba3f8396651f2797ff2eb6091e1a7f
STRAPI_URL=http://localhost:1337
#B2_ENDPOINT=s3.us-west-000.backblazeb2.com
#B2_BUCKET=futureporn-uppy
#B2_SECRET=K000NRFAHCIWBYOhXa1QlabBzi5Puvk
#B2_KEY=000d37f13a933b80000000025
#B2_BUCKET=0d53c79f31b3ead983030b18
#B2_KEY_ID=000d37f13a933b80000000025
#B2_KEY_NAME=futureporn-uppy-2023-05-05
#B2_APPLICATION_KEY=K000NRFAHCIWBYOhXa1QlabBzi5Puvk

View File

@ -1,17 +0,0 @@
SESSION_SECRET=a9834jjajfajfiojaoejfbitco####$#iniswhigjlbutoonlyifyour8asl
PORT=5000
FILEPATH=/tmp
HOST=https://uppy.futureporn.net
UPLOAD_URLS=https://uppy.futureporn.net
SECRET=afjafifjfjSHHHHHHdontdtouchtiafImS+____cared
SERVER_BASE_URL=http://uppy.futureporn.net
B2_ENDPOINT=s3.us-west-000.backblazeb2.com
B2_BUCKET=futureporn
B2_SECRET=K000euvnkS7IiMiCUQA3iCy/qxwwvLw
B2_KEY=000d37f13a933b8000000002a
DRIVE_KEY=886031456924-jiuukhfte5n0cfkktevgojpum54dn6r3.apps.googleusercontent.com
DRIVE_SECRET=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
DROPBOX_KEY=zvaxniaf1gunns9
DROPBOX_SECRET=cclglkkjkoqqo3v
JWT_SECRET=GRYMjvirjfI6GxzkbNQMhg==

View File

@ -1,6 +1,6 @@
# uppy # uppy
This is the server component which handles user uploads. This is the server-side component which handles user uploads. It is especially useful for allowing users to upload directly from their Dropbox, GoogleDrive, etc.
## B2 Bucket CORS configuration ## B2 Bucket CORS configuration

View File

@ -1,7 +1,6 @@
#!/usr/bin/env node #!/usr/bin/env node
import dotenv from 'dotenv' import 'dotenv/config'
dotenv.config()
import express from 'express' import express from 'express'
import bodyParser from 'body-parser' import bodyParser from 'body-parser'
import session from 'express-session' import session from 'express-session'
@ -12,6 +11,7 @@ import jwt from 'jsonwebtoken'
const appEnv = new Array( const appEnv = new Array(
'HOST',
'SESSION_SECRET', 'SESSION_SECRET',
'PORT', 'PORT',
'FILEPATH', 'FILEPATH',

View File

@ -1,19 +1,15 @@
{ {
"type": "module", "type": "module",
"name": "fp-uppy", "name": "uppy",
"version": "1.0.0", "version": "1.0.5",
"description": "", "description": "",
"main": "index.js", "main": "index.js",
"scripts": { "scripts": {
"start": "node index", "start": "node index"
"dev": "nodemon --watch **/*.js --watch .env --watch package.json index"
}, },
"keywords": [], "keywords": [],
"author": "", "author": "",
"license": "Unlicense", "license": "Unlicense",
"devDependencies": {
"nodemon": "^3.1.0"
},
"dependencies": { "dependencies": {
"@uppy/aws-s3-multipart": "^2.4.3", "@uppy/aws-s3-multipart": "^2.4.3",
"@uppy/companion": "4.12.0", "@uppy/companion": "4.12.0",

View File

@ -41,10 +41,6 @@ importers:
yup: yup:
specifier: link:@hookform/resolvers/yup specifier: link:@hookform/resolvers/yup
version: link:@hookform/resolvers/yup version: link:@hookform/resolvers/yup
devDependencies:
nodemon:
specifier: ^3.1.0
version: 3.1.0
packages: packages:
@ -501,9 +497,6 @@ packages:
'@uppy/utils@4.1.3': '@uppy/utils@4.1.3':
resolution: {integrity: sha512-nTuMvwWYobnJcytDO3t+D6IkVq/Qs4Xv3vyoEZ+Iaf8gegZP+rEyoaFT2CK5XLRMienPyqRqNbIfRuFaOWSIFw==} resolution: {integrity: sha512-nTuMvwWYobnJcytDO3t+D6IkVq/Qs4Xv3vyoEZ+Iaf8gegZP+rEyoaFT2CK5XLRMienPyqRqNbIfRuFaOWSIFw==}
abbrev@1.1.1:
resolution: {integrity: sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==}
accepts@1.3.8: accepts@1.3.8:
resolution: {integrity: sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==} resolution: {integrity: sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==}
engines: {node: '>= 0.6'} engines: {node: '>= 0.6'}
@ -512,10 +505,6 @@ packages:
resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==}
engines: {node: '>=8'} engines: {node: '>=8'}
anymatch@3.1.3:
resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==}
engines: {node: '>= 8'}
array-flatten@1.1.1: array-flatten@1.1.1:
resolution: {integrity: sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==} resolution: {integrity: sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==}
@ -530,9 +519,6 @@ packages:
engines: {node: '>= 4.5.0'} engines: {node: '>= 4.5.0'}
hasBin: true hasBin: true
balanced-match@1.0.2:
resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
base64-js@1.5.1: base64-js@1.5.1:
resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==}
@ -540,10 +526,6 @@ packages:
resolution: {integrity: sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg==} resolution: {integrity: sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg==}
engines: {node: '>= 0.8'} engines: {node: '>= 0.8'}
binary-extensions@2.3.0:
resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==}
engines: {node: '>=8'}
bintrees@1.0.2: bintrees@1.0.2:
resolution: {integrity: sha512-VOMgTMwjAaUG580SXn3LacVgjurrbMme7ZZNYGSSV7mmtY6QQRh0Eg3pwIcntQ77DErK1L0NxkbetjcoXzVwKw==} resolution: {integrity: sha512-VOMgTMwjAaUG580SXn3LacVgjurrbMme7ZZNYGSSV7mmtY6QQRh0Eg3pwIcntQ77DErK1L0NxkbetjcoXzVwKw==}
@ -561,13 +543,6 @@ packages:
bowser@2.11.0: bowser@2.11.0:
resolution: {integrity: sha512-AlcaJBi/pqqJBIQ8U9Mcpc9i8Aqxn88Skv5d+xBX006BY5u8N3mGLHa5Lgppa7L/HfwgwLgZ6NYs+Ag6uUmJRA==} resolution: {integrity: sha512-AlcaJBi/pqqJBIQ8U9Mcpc9i8Aqxn88Skv5d+xBX006BY5u8N3mGLHa5Lgppa7L/HfwgwLgZ6NYs+Ag6uUmJRA==}
brace-expansion@1.1.11:
resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==}
braces@3.0.2:
resolution: {integrity: sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==}
engines: {node: '>=8'}
brorand@1.1.0: brorand@1.1.0:
resolution: {integrity: sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==} resolution: {integrity: sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==}
@ -600,10 +575,6 @@ packages:
resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==}
engines: {node: '>=10'} engines: {node: '>=10'}
chokidar@3.6.0:
resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==}
engines: {node: '>= 8.10.0'}
clone-response@1.0.3: clone-response@1.0.3:
resolution: {integrity: sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA==} resolution: {integrity: sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA==}
@ -629,9 +600,6 @@ packages:
resolution: {integrity: sha512-gk/Z852D2Wtb//0I+kRFNKKE9dIIVirjoqPoA1wJU+XePVXZfGeBpk45+A1rKO4Q43prqWBNY/MiIeRLbPWUaA==} resolution: {integrity: sha512-gk/Z852D2Wtb//0I+kRFNKKE9dIIVirjoqPoA1wJU+XePVXZfGeBpk45+A1rKO4Q43prqWBNY/MiIeRLbPWUaA==}
engines: {node: '>=4.0.0'} engines: {node: '>=4.0.0'}
concat-map@0.0.1:
resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==}
connect-redis@7.1.0: connect-redis@7.1.0:
resolution: {integrity: sha512-UaqO1EirWjON2ENsyau7N5lbkrdYBpS6mYlXSeff/OYXsd6EGZ+SXSmNPoljL2PSua8fgjAEaldSA73PMZQ9Eg==} resolution: {integrity: sha512-UaqO1EirWjON2ENsyau7N5lbkrdYBpS6mYlXSeff/OYXsd6EGZ+SXSmNPoljL2PSua8fgjAEaldSA73PMZQ9Eg==}
engines: {node: '>=16'} engines: {node: '>=16'}
@ -811,10 +779,6 @@ packages:
resolution: {integrity: sha512-B9/wizE4WngqQftFPmdaMYlXoJlJOYxGQOanC77fq9k8+Z0v5dDSVh+3glErdIROP//s/jgb7ZuxKfB8nVyo0g==} resolution: {integrity: sha512-B9/wizE4WngqQftFPmdaMYlXoJlJOYxGQOanC77fq9k8+Z0v5dDSVh+3glErdIROP//s/jgb7ZuxKfB8nVyo0g==}
hasBin: true hasBin: true
fill-range@7.0.1:
resolution: {integrity: sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==}
engines: {node: '>=8'}
finalhandler@1.2.0: finalhandler@1.2.0:
resolution: {integrity: sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==} resolution: {integrity: sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==}
engines: {node: '>= 0.8'} engines: {node: '>= 0.8'}
@ -831,11 +795,6 @@ packages:
resolution: {integrity: sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==} resolution: {integrity: sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==}
engines: {node: '>= 0.6'} 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: function-bind@1.1.2:
resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==}
@ -851,10 +810,6 @@ packages:
resolution: {integrity: sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==} resolution: {integrity: sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==}
engines: {node: '>=8'} engines: {node: '>=8'}
glob-parent@5.1.2:
resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==}
engines: {node: '>= 6'}
gopd@1.0.1: gopd@1.0.1:
resolution: {integrity: sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==} resolution: {integrity: sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==}
@ -869,10 +824,6 @@ packages:
resolution: {integrity: sha512-QaoZudI9Gmh2W415gd71Iul6gpVH9sG1SkjfnGHtqYZopQDQ5PUVxRol5zFCrwGi9S0EbExbelHlZScgdChg2w==} resolution: {integrity: sha512-QaoZudI9Gmh2W415gd71Iul6gpVH9sG1SkjfnGHtqYZopQDQ5PUVxRol5zFCrwGi9S0EbExbelHlZScgdChg2w==}
engines: {node: '>=12.0.0'} engines: {node: '>=12.0.0'}
has-flag@3.0.0:
resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==}
engines: {node: '>=4'}
has-flag@4.0.0: has-flag@4.0.0:
resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==}
engines: {node: '>=8'} engines: {node: '>=8'}
@ -920,9 +871,6 @@ packages:
ieee754@1.2.1: ieee754@1.2.1:
resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==}
ignore-by-default@1.0.1:
resolution: {integrity: sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==}
inherits@2.0.4: inherits@2.0.4:
resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==}
@ -934,26 +882,10 @@ packages:
resolution: {integrity: sha512-LlbxQ7xKzfBusov6UMi4MFpEg0m+mAm9xyNGEduwXMEDuf4WfzB/RZwMVYEd7IKGvh4IUkEXYxtAVu9T3OelJQ==} resolution: {integrity: sha512-LlbxQ7xKzfBusov6UMi4MFpEg0m+mAm9xyNGEduwXMEDuf4WfzB/RZwMVYEd7IKGvh4IUkEXYxtAVu9T3OelJQ==}
engines: {node: '>= 10'} engines: {node: '>= 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-nan@1.3.2: is-nan@1.3.2:
resolution: {integrity: sha512-E+zBKpQ2t6MEo1VsonYmluk9NxGrbzpeeLC2xIViuO2EjU2xsXsBPwTr3Ykv9l08UYEVEdWeRZNouaZqF6RN0w==} resolution: {integrity: sha512-E+zBKpQ2t6MEo1VsonYmluk9NxGrbzpeeLC2xIViuO2EjU2xsXsBPwTr3Ykv9l08UYEVEdWeRZNouaZqF6RN0w==}
engines: {node: '>= 0.4'} engines: {node: '>= 0.4'}
is-number@7.0.0:
resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==}
engines: {node: '>=0.12.0'}
is-stream@2.0.1: is-stream@2.0.1:
resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==} resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==}
engines: {node: '>=8'} engines: {node: '>=8'}
@ -1107,9 +1039,6 @@ packages:
minimalistic-crypto-utils@1.0.1: minimalistic-crypto-utils@1.0.1:
resolution: {integrity: sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==} resolution: {integrity: sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==}
minimatch@3.1.2:
resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==}
moment-timezone@0.5.45: moment-timezone@0.5.45:
resolution: {integrity: sha512-HIWmqA86KcmCAhnMAN0wuDOARV/525R2+lOLotuGFzn4HO+FH+/645z2wx0Dt3iDv6/p61SIvKnDstISainhLQ==} resolution: {integrity: sha512-HIWmqA86KcmCAhnMAN0wuDOARV/525R2+lOLotuGFzn4HO+FH+/645z2wx0Dt3iDv6/p61SIvKnDstISainhLQ==}
@ -1145,19 +1074,6 @@ packages:
resolution: {integrity: sha512-nl4JTiZ7ZQDc97MmpTq9BQjYhq7gOtoh7SiPH069gBFBj0PzD8HI7zyFs6rzqL8Y5tTiEEYLxgtbx034YPrbyQ==} resolution: {integrity: sha512-nl4JTiZ7ZQDc97MmpTq9BQjYhq7gOtoh7SiPH069gBFBj0PzD8HI7zyFs6rzqL8Y5tTiEEYLxgtbx034YPrbyQ==}
engines: {node: '>=6'} engines: {node: '>=6'}
nodemon@3.1.0:
resolution: {integrity: sha512-xqlktYlDMCepBJd43ZQhjWwMw2obW/JRvkrLxq5RCNcuDDX1DbcPT+qT1IlIIdf+DhnWs90JpTMe+Y5KxOchvA==}
engines: {node: '>=10'}
hasBin: true
nopt@1.0.10:
resolution: {integrity: sha512-NWmpvLSqUrgrAC9HCuxEvb+PSloHpqVu+FqcO4eeF2h5qYRhA7ev6KvelyQAKtegUbC6RypJnlEOhd8vloNKYg==}
hasBin: true
normalize-path@3.0.0:
resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==}
engines: {node: '>=0.10.0'}
normalize-url@6.1.0: normalize-url@6.1.0:
resolution: {integrity: sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==} resolution: {integrity: sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==}
engines: {node: '>=10'} engines: {node: '>=10'}
@ -1202,10 +1118,6 @@ packages:
path-to-regexp@0.1.7: path-to-regexp@0.1.7:
resolution: {integrity: sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==} resolution: {integrity: sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==}
picomatch@2.3.1:
resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==}
engines: {node: '>=8.6'}
preact@10.20.2: preact@10.20.2:
resolution: {integrity: sha512-S1d1ernz3KQ+Y2awUxKakpfOg2CEmJmwOP+6igPx6dgr6pgDvenqYviyokWso2rhHvGtTlWWnJDa7RaPbQerTg==} resolution: {integrity: sha512-S1d1ernz3KQ+Y2awUxKakpfOg2CEmJmwOP+6igPx6dgr6pgDvenqYviyokWso2rhHvGtTlWWnJDa7RaPbQerTg==}
@ -1223,9 +1135,6 @@ packages:
pseudomap@1.0.2: pseudomap@1.0.2:
resolution: {integrity: sha512-b/YwNhb8lk1Zz2+bXXpS/LK9OisiZZ1SNsSLxN1x2OXVEhW2Ckr/7mWE5vrC1ZTiJlD9g19jWszTmJsB+oEpFQ==} resolution: {integrity: sha512-b/YwNhb8lk1Zz2+bXXpS/LK9OisiZZ1SNsSLxN1x2OXVEhW2Ckr/7mWE5vrC1ZTiJlD9g19jWszTmJsB+oEpFQ==}
pstree.remy@1.1.8:
resolution: {integrity: sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==}
pump@3.0.0: pump@3.0.0:
resolution: {integrity: sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==} resolution: {integrity: sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==}
@ -1281,10 +1190,6 @@ packages:
resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==} resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==}
engines: {node: '>= 6'} engines: {node: '>= 6'}
readdirp@3.6.0:
resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==}
engines: {node: '>=8.10.0'}
redis@4.2.0: redis@4.2.0:
resolution: {integrity: sha512-bCR0gKVhIXFg8zCQjXEANzgI01DDixtPZgIUZHBCmwqixnu+MK3Tb2yqGjh+HCLASQVVgApiwhNkv+FoedZOGQ==} resolution: {integrity: sha512-bCR0gKVhIXFg8zCQjXEANzgI01DDixtPZgIUZHBCmwqixnu+MK3Tb2yqGjh+HCLASQVVgApiwhNkv+FoedZOGQ==}
@ -1352,10 +1257,6 @@ packages:
signal-exit@3.0.7: signal-exit@3.0.7:
resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==}
simple-update-notifier@2.0.0:
resolution: {integrity: sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==}
engines: {node: '>=10'}
sorted-array-functions@1.3.0: sorted-array-functions@1.3.0:
resolution: {integrity: sha512-2sqgzeFlid6N4Z2fUQ1cvFmTOLRi/sEDzSQ0OKYchqgoPmQBVyM3959qYx3fpS6Esef80KjmpgPeEr028dP3OA==} resolution: {integrity: sha512-2sqgzeFlid6N4Z2fUQ1cvFmTOLRi/sEDzSQ0OKYchqgoPmQBVyM3959qYx3fpS6Esef80KjmpgPeEr028dP3OA==}
@ -1372,10 +1273,6 @@ packages:
strnum@1.0.5: strnum@1.0.5:
resolution: {integrity: sha512-J8bbNyKKXl5qYcR36TIO8W3mVGVHrmmxsd5PAItGkmyzwJvybiw2IVq5nqd0i4LSNSkB/sx9VHllbfFdr9k1JA==} resolution: {integrity: sha512-J8bbNyKKXl5qYcR36TIO8W3mVGVHrmmxsd5PAItGkmyzwJvybiw2IVq5nqd0i4LSNSkB/sx9VHllbfFdr9k1JA==}
supports-color@5.5.0:
resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==}
engines: {node: '>=4'}
supports-color@7.2.0: supports-color@7.2.0:
resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==}
engines: {node: '>=8'} engines: {node: '>=8'}
@ -1383,18 +1280,10 @@ packages:
tdigest@0.1.2: tdigest@0.1.2:
resolution: {integrity: sha512-+G0LLgjjo9BZX2MfdvPfH+MKLCrxlXSYec5DaPYP1fe6Iyhf0/fSmJ0bFiZ1F8BT6cGXl2LpltQptzjXKWEkKA==} resolution: {integrity: sha512-+G0LLgjjo9BZX2MfdvPfH+MKLCrxlXSYec5DaPYP1fe6Iyhf0/fSmJ0bFiZ1F8BT6cGXl2LpltQptzjXKWEkKA==}
to-regex-range@5.0.1:
resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==}
engines: {node: '>=8.0'}
toidentifier@1.0.1: toidentifier@1.0.1:
resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==} resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==}
engines: {node: '>=0.6'} engines: {node: '>=0.6'}
touch@3.1.0:
resolution: {integrity: sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA==}
hasBin: true
tslib@1.14.1: tslib@1.14.1:
resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==} resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==}
@ -1412,9 +1301,6 @@ packages:
resolution: {integrity: sha512-KPHm4VL5dDXKz01UuEd88Df+KzynaohSL9fBh096KWAxSKZQDI2uBrVqtvRM4rwrIrRRKsdLNML/lnaaVSRioA==} resolution: {integrity: sha512-KPHm4VL5dDXKz01UuEd88Df+KzynaohSL9fBh096KWAxSKZQDI2uBrVqtvRM4rwrIrRRKsdLNML/lnaaVSRioA==}
engines: {node: '>= 0.8'} engines: {node: '>= 0.8'}
undefsafe@2.0.5:
resolution: {integrity: sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==}
undici-types@5.26.5: undici-types@5.26.5:
resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==} resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==}
@ -2477,8 +2363,6 @@ snapshots:
dependencies: dependencies:
lodash.throttle: 4.1.1 lodash.throttle: 4.1.1
abbrev@1.1.1: {}
accepts@1.3.8: accepts@1.3.8:
dependencies: dependencies:
mime-types: 2.1.35 mime-types: 2.1.35
@ -2488,11 +2372,6 @@ snapshots:
dependencies: dependencies:
color-convert: 2.0.1 color-convert: 2.0.1
anymatch@3.1.3:
dependencies:
normalize-path: 3.0.0
picomatch: 2.3.1
array-flatten@1.1.1: {} array-flatten@1.1.1: {}
asn1.js@5.4.1: asn1.js@5.4.1:
@ -2507,16 +2386,12 @@ snapshots:
atob@2.1.2: {} atob@2.1.2: {}
balanced-match@1.0.2: {}
base64-js@1.5.1: {} base64-js@1.5.1: {}
basic-auth@2.0.1: basic-auth@2.0.1:
dependencies: dependencies:
safe-buffer: 5.1.2 safe-buffer: 5.1.2
binary-extensions@2.3.0: {}
bintrees@1.0.2: {} bintrees@1.0.2: {}
bn.js@4.12.0: bn.js@4.12.0:
@ -2558,15 +2433,6 @@ snapshots:
bowser@2.11.0: {} bowser@2.11.0: {}
brace-expansion@1.1.11:
dependencies:
balanced-match: 1.0.2
concat-map: 0.0.1
braces@3.0.2:
dependencies:
fill-range: 7.0.1
brorand@1.1.0: brorand@1.1.0:
optional: true optional: true
@ -2606,18 +2472,6 @@ snapshots:
ansi-styles: 4.3.0 ansi-styles: 4.3.0
supports-color: 7.2.0 supports-color: 7.2.0
chokidar@3.6.0:
dependencies:
anymatch: 3.1.3
braces: 3.0.2
glob-parent: 5.1.2
is-binary-path: 2.1.0
is-glob: 4.0.3
normalize-path: 3.0.0
readdirp: 3.6.0
optionalDependencies:
fsevents: 2.3.3
clone-response@1.0.3: clone-response@1.0.3:
dependencies: dependencies:
mimic-response: 1.0.1 mimic-response: 1.0.1
@ -2641,8 +2495,6 @@ snapshots:
common-tags@1.8.2: {} common-tags@1.8.2: {}
concat-map@0.0.1: {}
connect-redis@7.1.0(express-session@1.17.3): connect-redis@7.1.0(express-session@1.17.3):
dependencies: dependencies:
express-session: 1.17.3 express-session: 1.17.3
@ -2689,10 +2541,9 @@ snapshots:
dependencies: dependencies:
ms: 2.0.0 ms: 2.0.0
debug@4.3.4(supports-color@5.5.0): debug@4.3.4:
dependencies: dependencies:
ms: 2.1.2 ms: 2.1.2
supports-color: 5.5.0
decompress-response@6.0.0: decompress-response@6.0.0:
dependencies: dependencies:
@ -2877,10 +2728,6 @@ snapshots:
dependencies: dependencies:
strnum: 1.0.5 strnum: 1.0.5
fill-range@7.0.1:
dependencies:
to-regex-range: 5.0.1
finalhandler@1.2.0: finalhandler@1.2.0:
dependencies: dependencies:
debug: 2.6.9 debug: 2.6.9
@ -2903,9 +2750,6 @@ snapshots:
fresh@0.5.2: {} fresh@0.5.2: {}
fsevents@2.3.3:
optional: true
function-bind@1.1.2: {} function-bind@1.1.2: {}
generic-pool@3.8.2: {} generic-pool@3.8.2: {}
@ -2922,10 +2766,6 @@ snapshots:
dependencies: dependencies:
pump: 3.0.0 pump: 3.0.0
glob-parent@5.1.2:
dependencies:
is-glob: 4.0.3
gopd@1.0.1: gopd@1.0.1:
dependencies: dependencies:
get-intrinsic: 1.2.4 get-intrinsic: 1.2.4
@ -2957,8 +2797,6 @@ snapshots:
jwk-to-pem: 2.0.5 jwk-to-pem: 2.0.5
jws: 4.0.0 jws: 4.0.0
has-flag@3.0.0: {}
has-flag@4.0.0: {} has-flag@4.0.0: {}
has-property-descriptors@1.0.2: has-property-descriptors@1.0.2:
@ -3009,31 +2847,17 @@ snapshots:
ieee754@1.2.1: {} ieee754@1.2.1: {}
ignore-by-default@1.0.1: {}
inherits@2.0.4: {} inherits@2.0.4: {}
ipaddr.js@1.9.1: {} ipaddr.js@1.9.1: {}
ipaddr.js@2.1.0: {} ipaddr.js@2.1.0: {}
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-nan@1.3.2: is-nan@1.3.2:
dependencies: dependencies:
call-bind: 1.0.7 call-bind: 1.0.7
define-properties: 1.2.1 define-properties: 1.2.1
is-number@7.0.0: {}
is-stream@2.0.1: {} is-stream@2.0.1: {}
js-base64@3.7.7: {} js-base64@3.7.7: {}
@ -3162,7 +2986,7 @@ snapshots:
memorystore@1.6.7: memorystore@1.6.7:
dependencies: dependencies:
debug: 4.3.4(supports-color@5.5.0) debug: 4.3.4
lru-cache: 4.1.5 lru-cache: 4.1.5
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
@ -3193,10 +3017,6 @@ snapshots:
minimalistic-crypto-utils@1.0.1: minimalistic-crypto-utils@1.0.1:
optional: true optional: true
minimatch@3.1.2:
dependencies:
brace-expansion: 1.1.11
moment-timezone@0.5.45: moment-timezone@0.5.45:
dependencies: dependencies:
moment: 2.30.1 moment: 2.30.1
@ -3231,25 +3051,6 @@ snapshots:
long-timeout: 0.1.1 long-timeout: 0.1.1
sorted-array-functions: 1.3.0 sorted-array-functions: 1.3.0
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.6.0
simple-update-notifier: 2.0.0
supports-color: 5.5.0
touch: 3.1.0
undefsafe: 2.0.5
nopt@1.0.10:
dependencies:
abbrev: 1.1.1
normalize-path@3.0.0: {}
normalize-url@6.1.0: {} normalize-url@6.1.0: {}
oauth-sign@0.9.0: {} oauth-sign@0.9.0: {}
@ -3280,8 +3081,6 @@ snapshots:
path-to-regexp@0.1.7: {} path-to-regexp@0.1.7: {}
picomatch@2.3.1: {}
preact@10.20.2: {} preact@10.20.2: {}
prom-client@14.0.1: prom-client@14.0.1:
@ -3301,8 +3100,6 @@ snapshots:
pseudomap@1.0.2: {} pseudomap@1.0.2: {}
pstree.remy@1.1.8: {}
pump@3.0.0: pump@3.0.0:
dependencies: dependencies:
end-of-stream: 1.4.4 end-of-stream: 1.4.4
@ -3360,10 +3157,6 @@ snapshots:
string_decoder: 1.3.0 string_decoder: 1.3.0
util-deprecate: 1.0.2 util-deprecate: 1.0.2
readdirp@3.6.0:
dependencies:
picomatch: 2.3.1
redis@4.2.0: redis@4.2.0:
dependencies: dependencies:
'@redis/bloom': 1.0.2(@redis/client@1.2.0) '@redis/bloom': 1.0.2(@redis/client@1.2.0)
@ -3454,10 +3247,6 @@ snapshots:
signal-exit@3.0.7: {} signal-exit@3.0.7: {}
simple-update-notifier@2.0.0:
dependencies:
semver: 7.6.0
sorted-array-functions@1.3.0: {} sorted-array-functions@1.3.0: {}
statuses@2.0.1: {} statuses@2.0.1: {}
@ -3473,10 +3262,6 @@ snapshots:
strnum@1.0.5: {} strnum@1.0.5: {}
supports-color@5.5.0:
dependencies:
has-flag: 3.0.0
supports-color@7.2.0: supports-color@7.2.0:
dependencies: dependencies:
has-flag: 4.0.0 has-flag: 4.0.0
@ -3485,16 +3270,8 @@ snapshots:
dependencies: dependencies:
bintrees: 1.0.2 bintrees: 1.0.2
to-regex-range@5.0.1:
dependencies:
is-number: 7.0.0
toidentifier@1.0.1: {} toidentifier@1.0.1: {}
touch@3.1.0:
dependencies:
nopt: 1.0.10
tslib@1.14.1: {} tslib@1.14.1: {}
tslib@2.6.2: {} tslib@2.6.2: {}
@ -3518,8 +3295,6 @@ snapshots:
dependencies: dependencies:
random-bytes: 1.0.0 random-bytes: 1.0.0
undefsafe@2.0.5: {}
undici-types@5.26.5: {} undici-types@5.26.5: {}
unpipe@1.0.0: {} unpipe@1.0.0: {}

View File

@ -25,13 +25,45 @@ EOF
# --from-literal=username=${TRAEFIK_USERNAME} \ # --from-literal=username=${TRAEFIK_USERNAME} \
# --from-literal=password=${TRAEFIK_PASSWORD} # --from-literal=password=${TRAEFIK_PASSWORD}
# kubectl --namespace futureporn delete secret uppy --ignore-not-found
# kubectl --namespace futureporn create secret generic uppy \
# --from-literal=driveKey=${UPPY_DRIVE_KEY} \
# --from-literal=driveSecret=${UPPY_DRIVE_SECRET} \
# --from-literal=dropboxKey=${UPPY_DROPBOX_KEY} \
# --from-literal=dropboxSecret=${UPPY_DROPBOX_SECRET} \
# --from-literal=jwtSecret=${UPPY_JWT_SECRET} \
# --from-literal=secret=${UPPY_SECRET} \
# --from-literal=sessionSecret=${UPPY_SESSION_SECRET} \
# --from-literal=b2Key=${UPPY_B2_KEY} \
# --from-literal=b2Secret=${UPPY_B2_SECRET}\
kubectl --namespace futureporn delete secret redis --ignore-not-found
kubectl --namespace futureporn create secret generic redis \
--from-literal=password=${REDIS_PASSWORD}
kubectl --namespace futureporn delete secret uppy --ignore-not-found
kubectl --namespace futureporn create secret generic uppy \
--from-literal=redisUrl=${COMPANION_REDIS_URL} \
--from-literal=secret=${COMPANION_SECRET} \
--from-literal=preAuthSecret=${COMPANION_PREAUTH_SECRET} \
--from-literal=dropboxKey=${COMPANION_DROPBOX_KEY} \
--from-literal=dropboxSecret=${COMPANION_DROPBOX_SECRET} \
--from-literal=boxKey=${COMPANION_BOX_KEY} \
--from-literal=boxSecret=${COMPANION_BOX_SECRET} \
--from-literal=googleKey=${COMPANION_GOOGLE_KEY} \
--from-literal=googleSecret=${COMPANION_GOOGLE_SECRET} \
--from-literal=awsKey=${COMPANION_AWS_KEY} \
--from-literal=awsSecret=${COMPANION_AWS_SECRET} \
--from-literal=awsBucket=${COMPANION_AWS_BUCKET} \
--from-literal=oauthDomain=${COMPANION_OAUTH_DOMAIN} \
--from-literal=uploadUrls=${COMPANION_UPLOAD_URLS}
## @todo we need exoscale in two separate namespaces.
## Is it worth using secrets reflector?
kubectl --namespace cert-manager delete secret exoscale --ignore-not-found kubectl --namespace cert-manager delete secret exoscale --ignore-not-found
kubectl --namespace cert-manager create secret generic exoscale \ kubectl --namespace cert-manager create secret generic exoscale \
--from-literal=apiKey=${EXOSCALE_API_KEY} \ --from-literal=apiKey=${EXOSCALE_API_KEY} \
--from-literal=apiSecret=${EXOSCALE_API_SECRET} --from-literal=apiSecret=${EXOSCALE_API_SECRET}
## @todo we need exoscale in two separate namespaces.
## Is it worth using secrets reflector?
kubectl --namespace futureporn delete secret exoscale --ignore-not-found kubectl --namespace futureporn delete secret exoscale --ignore-not-found
kubectl --namespace futureporn create secret generic exoscale \ kubectl --namespace futureporn create secret generic exoscale \
--from-literal=apiKey=${EXOSCALE_API_KEY} \ --from-literal=apiKey=${EXOSCALE_API_KEY} \

View File

@ -1,6 +1,6 @@
#!/bin/bash #!/bin/bash
dbname=2024-06-19_22-24-03-futureporn-db.psql dbname=20240704T204659Z_development.psql
## drop futureporn_db ## drop futureporn_db
kubectl -n futureporn exec postgres -- psql -U postgres --command "DROP DATABASE futureporn_db;" kubectl -n futureporn exec postgres -- psql -U postgres --command "DROP DATABASE futureporn_db;"