mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-02-11 20:08:37 +00:00
build: affine Node.js server charts (#2895)
This commit is contained in:
2
.github/deployment/front/affine.nginx.conf
vendored
2
.github/deployment/front/affine.nginx.conf
vendored
@@ -3,7 +3,7 @@ server {
|
|||||||
root /app/dist;
|
root /app/dist;
|
||||||
|
|
||||||
location / {
|
location / {
|
||||||
try_files $uri $uri/index.html $uri.html =404;;
|
try_files $uri $uri/index.html $uri.html =404;
|
||||||
}
|
}
|
||||||
|
|
||||||
error_page 404 /404.html;
|
error_page 404 /404.html;
|
||||||
|
|||||||
23
.github/helm/affine/.helmignore
vendored
Normal file
23
.github/helm/affine/.helmignore
vendored
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
# Patterns to ignore when building packages.
|
||||||
|
# This supports shell glob matching, relative path matching, and
|
||||||
|
# negation (prefixed with !). Only one pattern per line.
|
||||||
|
.DS_Store
|
||||||
|
# Common VCS dirs
|
||||||
|
.git/
|
||||||
|
.gitignore
|
||||||
|
.bzr/
|
||||||
|
.bzrignore
|
||||||
|
.hg/
|
||||||
|
.hgignore
|
||||||
|
.svn/
|
||||||
|
# Common backup files
|
||||||
|
*.swp
|
||||||
|
*.bak
|
||||||
|
*.tmp
|
||||||
|
*.orig
|
||||||
|
*~
|
||||||
|
# Various IDEs
|
||||||
|
.project
|
||||||
|
.idea/
|
||||||
|
*.tmproj
|
||||||
|
.vscode/
|
||||||
6
.github/helm/affine/Chart.yaml
vendored
Normal file
6
.github/helm/affine/Chart.yaml
vendored
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
apiVersion: v2
|
||||||
|
name: affine
|
||||||
|
description: AFFiNE cloud chart
|
||||||
|
type: application
|
||||||
|
version: 0.0.0
|
||||||
|
appVersion: '0.7.0-canary.18'
|
||||||
6
.github/helm/affine/charts/graphql/Chart.yaml
vendored
Normal file
6
.github/helm/affine/charts/graphql/Chart.yaml
vendored
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
apiVersion: v2
|
||||||
|
name: graphql
|
||||||
|
description: AFFiNE GraphQL server
|
||||||
|
type: application
|
||||||
|
version: 0.0.0
|
||||||
|
appVersion: '0.7.0-canary.18'
|
||||||
16
.github/helm/affine/charts/graphql/templates/NOTES.txt
vendored
Normal file
16
.github/helm/affine/charts/graphql/templates/NOTES.txt
vendored
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
1. Get the application URL by running these commands:
|
||||||
|
{{- if contains "NodePort" .Values.service.type }}
|
||||||
|
export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include "graphql.fullname" . }})
|
||||||
|
export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}")
|
||||||
|
echo http://$NODE_IP:$NODE_PORT
|
||||||
|
{{- else if contains "LoadBalancer" .Values.service.type }}
|
||||||
|
NOTE: It may take a few minutes for the LoadBalancer IP to be available.
|
||||||
|
You can watch the status of by running 'kubectl get --namespace {{ .Release.Namespace }} svc -w {{ include "graphql.fullname" . }}'
|
||||||
|
export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include "graphql.fullname" . }} --template "{{"{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}"}}")
|
||||||
|
echo http://$SERVICE_IP:{{ .Values.service.port }}
|
||||||
|
{{- else if contains "ClusterIP" .Values.service.type }}
|
||||||
|
export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ include "graphql.name" . }},app.kubernetes.io/instance={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}")
|
||||||
|
export CONTAINER_PORT=$(kubectl get pod --namespace {{ .Release.Namespace }} $POD_NAME -o jsonpath="{.spec.containers[0].ports[0].containerPort}")
|
||||||
|
echo "Visit http://127.0.0.1:8080 to use your application"
|
||||||
|
kubectl --namespace {{ .Release.Namespace }} port-forward $POD_NAME 8080:$CONTAINER_PORT
|
||||||
|
{{- end }}
|
||||||
132
.github/helm/affine/charts/graphql/templates/_helpers.tpl
vendored
Normal file
132
.github/helm/affine/charts/graphql/templates/_helpers.tpl
vendored
Normal file
@@ -0,0 +1,132 @@
|
|||||||
|
{{/*
|
||||||
|
Expand the name of the chart.
|
||||||
|
*/}}
|
||||||
|
{{- define "graphql.name" -}}
|
||||||
|
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{/*
|
||||||
|
Create a default fully qualified app name.
|
||||||
|
We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
|
||||||
|
If release name contains chart name it will be used as a full name.
|
||||||
|
*/}}
|
||||||
|
{{- define "graphql.fullname" -}}
|
||||||
|
{{- if .Values.fullnameOverride }}
|
||||||
|
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }}
|
||||||
|
{{- else }}
|
||||||
|
{{- $name := default .Chart.Name .Values.nameOverride }}
|
||||||
|
{{- if contains $name .Release.Name }}
|
||||||
|
{{- .Release.Name | trunc 63 | trimSuffix "-" }}
|
||||||
|
{{- else }}
|
||||||
|
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{/*
|
||||||
|
Create chart name and version as used by the chart label.
|
||||||
|
*/}}
|
||||||
|
{{- define "graphql.chart" -}}
|
||||||
|
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{/*
|
||||||
|
Common labels
|
||||||
|
*/}}
|
||||||
|
{{- define "graphql.labels" -}}
|
||||||
|
helm.sh/chart: {{ include "graphql.chart" . }}
|
||||||
|
{{ include "graphql.selectorLabels" . }}
|
||||||
|
{{- if .Chart.AppVersion }}
|
||||||
|
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
|
||||||
|
{{- end }}
|
||||||
|
app.kubernetes.io/managed-by: {{ .Release.Service }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{/*
|
||||||
|
Selector labels
|
||||||
|
*/}}
|
||||||
|
{{- define "graphql.selectorLabels" -}}
|
||||||
|
app.kubernetes.io/name: {{ include "graphql.name" . }}
|
||||||
|
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{/*
|
||||||
|
Create the name of the service account to use
|
||||||
|
*/}}
|
||||||
|
{{- define "graphql.serviceAccountName" -}}
|
||||||
|
{{- if .Values.serviceAccount.create }}
|
||||||
|
{{- default (include "graphql.fullname" .) .Values.serviceAccount.name }}
|
||||||
|
{{- else }}
|
||||||
|
{{- default "default" .Values.serviceAccount.name }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{- define "jwt.key" -}}
|
||||||
|
{{- $secret := lookup "v1" "Secret" .Release.Namespace .Values.app.jwt.secretName -}}
|
||||||
|
{{- if and $secret $secret.data.private -}}
|
||||||
|
{{/*
|
||||||
|
Reusing existing secret data
|
||||||
|
*/}}
|
||||||
|
key: {{ $secret.data.private }}
|
||||||
|
{{- else -}}
|
||||||
|
{{/*
|
||||||
|
Generate new data
|
||||||
|
*/}}
|
||||||
|
key: {{ genPrivateKey "ecdsa" | b64enc }}
|
||||||
|
{{- end -}}
|
||||||
|
{{- end -}}
|
||||||
|
|
||||||
|
{{- define "objectStorage.r2" -}}
|
||||||
|
{{- $secret := lookup "v1" "Secret" .Release.Namespace .Values.app.objectStorage.r2.secretName -}}
|
||||||
|
{{- if $secret -}}
|
||||||
|
{{/*
|
||||||
|
Reusing existing secret data
|
||||||
|
*/}}
|
||||||
|
accountId: {{ $secret.data.accountId }}
|
||||||
|
accessKeyId: {{ $secret.data.accessKeyId }}
|
||||||
|
secretAccessKey: {{ $secret.data.secretAccessKey }}
|
||||||
|
bucket: {{ $secret.data.bucket }}
|
||||||
|
{{- else -}}
|
||||||
|
{{/*
|
||||||
|
Generate new data
|
||||||
|
*/}}
|
||||||
|
accountId: {{ .Values.app.objectStorage.r2.accountId | b64enc }}
|
||||||
|
accessKeyId: {{ .Values.app.objectStorage.r2.accessKeyId | b64enc }}
|
||||||
|
secretAccessKey: {{ .Values.app.objectStorage.r2.secretAccessKey | b64enc }}
|
||||||
|
bucket: {{ .Values.app.objectStorage.r2.bucket | b64enc }}
|
||||||
|
{{- end -}}
|
||||||
|
{{- end -}}
|
||||||
|
|
||||||
|
{{- define "objectStorage.oauth.google" -}}
|
||||||
|
{{- $secret := lookup "v1" "Secret" .Release.Namespace .Values.app.oauth.google.secretName -}}
|
||||||
|
{{- if $secret -}}
|
||||||
|
{{/*
|
||||||
|
Reusing existing secret data
|
||||||
|
*/}}
|
||||||
|
clientId: {{ $secret.data.clientId }}
|
||||||
|
clientSecret: {{ $secret.data.clientSecret }}
|
||||||
|
{{- else -}}
|
||||||
|
{{/*
|
||||||
|
Generate new data
|
||||||
|
*/}}
|
||||||
|
clientId: "{{ .Values.app.oauth.google.clientId | b64enc }}"
|
||||||
|
clientSecret: "{{ .Values.app.oauth.google.clientSecret | b64enc }}"
|
||||||
|
{{- end -}}
|
||||||
|
{{- end -}}
|
||||||
|
|
||||||
|
{{- define "objectStorage.oauth.github" -}}
|
||||||
|
{{- $secret := lookup "v1" "Secret" .Release.Namespace .Values.app.oauth.github.secretName -}}
|
||||||
|
{{- if $secret -}}
|
||||||
|
{{/*
|
||||||
|
Reusing existing secret data
|
||||||
|
*/}}
|
||||||
|
clientId: {{ $secret.data.clientId }}
|
||||||
|
clientSecret: {{ $secret.data.clientSecret }}
|
||||||
|
{{- else -}}
|
||||||
|
{{/*
|
||||||
|
Generate new data
|
||||||
|
*/}}
|
||||||
|
clientId: "{{ .Values.app.oauth.github.clientId | b64enc }}"
|
||||||
|
clientSecret: "{{ .Values.app.oauth.github.clientSecret | b64enc }}"
|
||||||
|
{{- end -}}
|
||||||
|
{{- end -}}
|
||||||
126
.github/helm/affine/charts/graphql/templates/deployment.yaml
vendored
Normal file
126
.github/helm/affine/charts/graphql/templates/deployment.yaml
vendored
Normal file
@@ -0,0 +1,126 @@
|
|||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: {{ include "graphql.fullname" . }}
|
||||||
|
labels:
|
||||||
|
{{- include "graphql.labels" . | nindent 4 }}
|
||||||
|
spec:
|
||||||
|
replicas: {{ .Values.replicaCount }}
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
{{- include "graphql.selectorLabels" . | nindent 6 }}
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
{{- with .Values.podAnnotations }}
|
||||||
|
annotations:
|
||||||
|
{{- toYaml . | nindent 8 }}
|
||||||
|
{{- end }}
|
||||||
|
labels:
|
||||||
|
{{- include "graphql.selectorLabels" . | nindent 8 }}
|
||||||
|
spec:
|
||||||
|
{{- with .Values.imagePullSecrets }}
|
||||||
|
imagePullSecrets:
|
||||||
|
{{- toYaml . | nindent 8 }}
|
||||||
|
{{- end }}
|
||||||
|
serviceAccountName: {{ include "graphql.serviceAccountName" . }}
|
||||||
|
containers:
|
||||||
|
- name: {{ .Chart.Name }}
|
||||||
|
image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}"
|
||||||
|
imagePullPolicy: {{ .Values.image.pullPolicy }}
|
||||||
|
env:
|
||||||
|
- name: AUTH_PRIVATE_KEY
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: "{{ .Values.app.jwt.secretName }}"
|
||||||
|
key: key
|
||||||
|
- name: NODE_ENV
|
||||||
|
value: "{{ .Values.env }}"
|
||||||
|
- name: DATABSE_PASSWORD
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: pg-postgresql
|
||||||
|
key: postgres-password
|
||||||
|
- name: DATABASE_URL
|
||||||
|
value: postgres://{{ .Values.database.user }}:$(DATABSE_PASSWORD)@{{ .Values.database.url }}:{{ .Values.database.port }}/{{ .Values.database.name }}
|
||||||
|
- name: AFFINE_SERVER_PORT
|
||||||
|
value: "{{ .Values.service.port }}"
|
||||||
|
- name: AFFINE_SERVER_SUB_PATH
|
||||||
|
value: "{{ .Values.app.path }}"
|
||||||
|
- name: AFFINE_SERVER_HOST
|
||||||
|
value: "{{ .Values.app.host }}"
|
||||||
|
- name: ENABLE_R2_OBJECT_STORAGE
|
||||||
|
value: "{{ .Values.app.objectStorage.r2.enabled }}"
|
||||||
|
{{ if .Values.app.objectStorage.r2.enabled }}
|
||||||
|
- name: R2_OBJECT_STORAGE_ACCOUNT_ID
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: "{{ .Values.app.objectStorage.r2.secretName }}"
|
||||||
|
key: accountId
|
||||||
|
- name: R2_OBJECT_STORAGE_ACCESS_KEY_ID
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: "{{ .Values.app.objectStorage.r2.secretName }}"
|
||||||
|
key: accessKeyId
|
||||||
|
- name: R2_OBJECT_STORAGE_SECRET_ACCESS_KEY
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: "{{ .Values.app.objectStorage.r2.secretName }}"
|
||||||
|
key: secretAccessKey
|
||||||
|
- name: R2_OBJECT_STORAGE_BUCKET
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: "{{ .Values.app.objectStorage.r2.secretName }}"
|
||||||
|
key: bucket
|
||||||
|
{{ end }}
|
||||||
|
{{ if .Values.app.oauth.google.enabled }}
|
||||||
|
- name: OAUTH_GOOGLE_CLIENT_ID
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: "{{ .Values.app.oauth.google.secretName }}"
|
||||||
|
key: clientId
|
||||||
|
- name: OAUTH_GOOGLE_CLIENT_SECRET
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: "{{ .Values.app.oauth.google.secretName }}"
|
||||||
|
key: clientSecret
|
||||||
|
{{ end }}
|
||||||
|
{{ if .Values.app.oauth.github.enabled }}
|
||||||
|
- name: OAUTH_GITHUB_CLIENT_ID
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: "{{ .Values.app.oauth.github.secretName }}"
|
||||||
|
key: clientId
|
||||||
|
- name: OAUTH_GITHUB_CLIENT_SECRET
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: "{{ .Values.app.oauth.github.secretName }}"
|
||||||
|
key: clientSecret
|
||||||
|
{{ end }}
|
||||||
|
ports:
|
||||||
|
- name: http
|
||||||
|
containerPort: {{ .Values.service.port }}
|
||||||
|
protocol: TCP
|
||||||
|
livenessProbe:
|
||||||
|
httpGet:
|
||||||
|
path: /
|
||||||
|
port: http
|
||||||
|
initialDelaySeconds: {{ .Values.probe.initialDelaySeconds }}
|
||||||
|
readinessProbe:
|
||||||
|
httpGet:
|
||||||
|
path: /
|
||||||
|
port: http
|
||||||
|
initialDelaySeconds: {{ .Values.probe.initialDelaySeconds }}
|
||||||
|
resources:
|
||||||
|
{{- toYaml .Values.resources | nindent 12 }}
|
||||||
|
{{- with .Values.nodeSelector }}
|
||||||
|
nodeSelector:
|
||||||
|
{{- toYaml . | nindent 8 }}
|
||||||
|
{{- end }}
|
||||||
|
{{- with .Values.affinity }}
|
||||||
|
affinity:
|
||||||
|
{{- toYaml . | nindent 8 }}
|
||||||
|
{{- end }}
|
||||||
|
{{- with .Values.tolerations }}
|
||||||
|
tolerations:
|
||||||
|
{{- toYaml . | nindent 8 }}
|
||||||
|
{{- end }}
|
||||||
7
.github/helm/affine/charts/graphql/templates/jwt-secret.yaml
vendored
Normal file
7
.github/helm/affine/charts/graphql/templates/jwt-secret.yaml
vendored
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: Secret
|
||||||
|
metadata:
|
||||||
|
name: "{{ .Values.app.jwt.secretName }}"
|
||||||
|
type: Opaque
|
||||||
|
data:
|
||||||
|
{{- ( include "jwt.key" . ) | indent 2 -}}
|
||||||
34
.github/helm/affine/charts/graphql/templates/migration.yaml
vendored
Normal file
34
.github/helm/affine/charts/graphql/templates/migration.yaml
vendored
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
apiVersion: batch/v1
|
||||||
|
kind: Job
|
||||||
|
metadata:
|
||||||
|
name: {{ include "graphql.fullname" . }}-database-migration
|
||||||
|
labels:
|
||||||
|
{{- include "graphql.labels" . | nindent 4 }}
|
||||||
|
annotations:
|
||||||
|
"helm.sh/hook": pre-install,pre-upgrade
|
||||||
|
"helm.sh/hook-weight": "-1"
|
||||||
|
"helm.sh/hook-delete-policy": before-hook-creation
|
||||||
|
|
||||||
|
spec:
|
||||||
|
template:
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: {{ .Chart.Name }}
|
||||||
|
image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}"
|
||||||
|
command: ["yarn", "prisma", "migrate", "deploy"]
|
||||||
|
env:
|
||||||
|
- name: NODE_ENV
|
||||||
|
value: "{{ .Values.env }}"
|
||||||
|
- name: DATABSE_PASSWORD
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: pg-postgresql
|
||||||
|
key: postgres-password
|
||||||
|
- name: DATABASE_URL
|
||||||
|
value: postgres://{{ .Values.database.user }}:$(DATABSE_PASSWORD)@{{ .Values.database.url }}:{{ .Values.database.port }}/{{ .Values.database.name }}
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
cpu: '100m'
|
||||||
|
memory: '200Mi'
|
||||||
|
restartPolicy: Never
|
||||||
|
backoffLimit: 1
|
||||||
10
.github/helm/affine/charts/graphql/templates/oauth-github-secret.yaml
vendored
Normal file
10
.github/helm/affine/charts/graphql/templates/oauth-github-secret.yaml
vendored
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
{{- if .Values.app.oauth.github.enabled -}}
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Secret
|
||||||
|
metadata:
|
||||||
|
name: "{{ .Values.app.oauth.github.secretName }}"
|
||||||
|
type: Opaque
|
||||||
|
data:
|
||||||
|
{{- ( include "objectStorage.oauth.github" . ) | indent 2 -}}
|
||||||
|
|
||||||
|
{{- end }}
|
||||||
10
.github/helm/affine/charts/graphql/templates/oauth-google-secret.yaml
vendored
Normal file
10
.github/helm/affine/charts/graphql/templates/oauth-google-secret.yaml
vendored
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
{{- if .Values.app.oauth.google.enabled -}}
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Secret
|
||||||
|
metadata:
|
||||||
|
name: "{{ .Values.app.oauth.google.secretName }}"
|
||||||
|
type: Opaque
|
||||||
|
data:
|
||||||
|
{{- ( include "objectStorage.oauth.google" . ) | indent 2 -}}
|
||||||
|
|
||||||
|
{{- end }}
|
||||||
9
.github/helm/affine/charts/graphql/templates/r2-secret.yaml
vendored
Normal file
9
.github/helm/affine/charts/graphql/templates/r2-secret.yaml
vendored
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
{{- if .Values.app.objectStorage.r2.enabled -}}
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Secret
|
||||||
|
metadata:
|
||||||
|
name: "{{ .Values.app.objectStorage.r2.secretName }}"
|
||||||
|
type: Opaque
|
||||||
|
data:
|
||||||
|
{{- ( include "objectStorage.r2" . ) | indent 2 -}}
|
||||||
|
{{- end }}
|
||||||
15
.github/helm/affine/charts/graphql/templates/service.yaml
vendored
Normal file
15
.github/helm/affine/charts/graphql/templates/service.yaml
vendored
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: {{ include "graphql.fullname" . }}
|
||||||
|
labels:
|
||||||
|
{{- include "graphql.labels" . | nindent 4 }}
|
||||||
|
spec:
|
||||||
|
type: {{ .Values.service.type }}
|
||||||
|
ports:
|
||||||
|
- port: {{ .Values.service.port }}
|
||||||
|
targetPort: http
|
||||||
|
protocol: TCP
|
||||||
|
name: http
|
||||||
|
selector:
|
||||||
|
{{- include "graphql.selectorLabels" . | nindent 4 }}
|
||||||
12
.github/helm/affine/charts/graphql/templates/serviceaccount.yaml
vendored
Normal file
12
.github/helm/affine/charts/graphql/templates/serviceaccount.yaml
vendored
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
{{- if .Values.serviceAccount.create -}}
|
||||||
|
apiVersion: v1
|
||||||
|
kind: ServiceAccount
|
||||||
|
metadata:
|
||||||
|
name: {{ include "graphql.serviceAccountName" . }}
|
||||||
|
labels:
|
||||||
|
{{- include "graphql.labels" . | nindent 4 }}
|
||||||
|
{{- with .Values.serviceAccount.annotations }}
|
||||||
|
annotations:
|
||||||
|
{{- toYaml . | nindent 4 }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
15
.github/helm/affine/charts/graphql/templates/tests/test-connection.yaml
vendored
Normal file
15
.github/helm/affine/charts/graphql/templates/tests/test-connection.yaml
vendored
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: Pod
|
||||||
|
metadata:
|
||||||
|
name: "{{ include "graphql.fullname" . }}-test-connection"
|
||||||
|
labels:
|
||||||
|
{{- include "graphql.labels" . | nindent 4 }}
|
||||||
|
annotations:
|
||||||
|
"helm.sh/hook": test
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: wget
|
||||||
|
image: busybox
|
||||||
|
command: ['wget']
|
||||||
|
args: ['{{ include "graphql.fullname" . }}:{{ .Values.service.port }}']
|
||||||
|
restartPolicy: Never
|
||||||
69
.github/helm/affine/charts/graphql/values.yaml
vendored
Normal file
69
.github/helm/affine/charts/graphql/values.yaml
vendored
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
replicaCount: 1
|
||||||
|
image:
|
||||||
|
repository: ghcr.io/toeverything/affine-graphql
|
||||||
|
pullPolicy: IfNotPresent
|
||||||
|
tag: ''
|
||||||
|
|
||||||
|
imagePullSecrets: []
|
||||||
|
nameOverride: ''
|
||||||
|
fullnameOverride: ''
|
||||||
|
# map to NODE_ENV environment variable
|
||||||
|
env: 'production'
|
||||||
|
database:
|
||||||
|
user: 'postgres'
|
||||||
|
url: 'pg-postgresql'
|
||||||
|
port: '5432'
|
||||||
|
name: 'affine'
|
||||||
|
app:
|
||||||
|
# AFFINE_SERVER_SUB_PATH
|
||||||
|
path: ''
|
||||||
|
# AFFINE_SERVER_HOST
|
||||||
|
host: '0.0.0.0'
|
||||||
|
jwt:
|
||||||
|
secretName: jwt-private-key
|
||||||
|
# base64 encoded ecdsa private key
|
||||||
|
privateKey: ''
|
||||||
|
objectStorage:
|
||||||
|
r2:
|
||||||
|
enabled: false
|
||||||
|
secretName: r2
|
||||||
|
accountId: ''
|
||||||
|
accessKeyId: ''
|
||||||
|
secretAccessKey: ''
|
||||||
|
bucket: ''
|
||||||
|
oauth:
|
||||||
|
google:
|
||||||
|
enabled: false
|
||||||
|
secretName: oauth-google
|
||||||
|
clientId: ''
|
||||||
|
clientSecret: ''
|
||||||
|
github:
|
||||||
|
enabled: false
|
||||||
|
secretName: oauth-github
|
||||||
|
clientId: ''
|
||||||
|
clientSecret: ''
|
||||||
|
|
||||||
|
serviceAccount:
|
||||||
|
create: true
|
||||||
|
annotations: {}
|
||||||
|
name: 'affine-graphql'
|
||||||
|
|
||||||
|
podAnnotations: {}
|
||||||
|
|
||||||
|
podSecurityContext:
|
||||||
|
fsGroup: 2000
|
||||||
|
|
||||||
|
resources:
|
||||||
|
limits:
|
||||||
|
cpu: '2000m'
|
||||||
|
memory: 4Gi
|
||||||
|
requests:
|
||||||
|
cpu: '1000m'
|
||||||
|
memory: 2Gi
|
||||||
|
|
||||||
|
probe:
|
||||||
|
initialDelaySeconds: 20
|
||||||
|
|
||||||
|
nodeSelector: {}
|
||||||
|
tolerations: []
|
||||||
|
affinity: {}
|
||||||
23
.github/helm/affine/charts/web/.helmignore
vendored
Normal file
23
.github/helm/affine/charts/web/.helmignore
vendored
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
# Patterns to ignore when building packages.
|
||||||
|
# This supports shell glob matching, relative path matching, and
|
||||||
|
# negation (prefixed with !). Only one pattern per line.
|
||||||
|
.DS_Store
|
||||||
|
# Common VCS dirs
|
||||||
|
.git/
|
||||||
|
.gitignore
|
||||||
|
.bzr/
|
||||||
|
.bzrignore
|
||||||
|
.hg/
|
||||||
|
.hgignore
|
||||||
|
.svn/
|
||||||
|
# Common backup files
|
||||||
|
*.swp
|
||||||
|
*.bak
|
||||||
|
*.tmp
|
||||||
|
*.orig
|
||||||
|
*~
|
||||||
|
# Various IDEs
|
||||||
|
.project
|
||||||
|
.idea/
|
||||||
|
*.tmproj
|
||||||
|
.vscode/
|
||||||
6
.github/helm/affine/charts/web/Chart.yaml
vendored
Normal file
6
.github/helm/affine/charts/web/Chart.yaml
vendored
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
apiVersion: v2
|
||||||
|
name: web
|
||||||
|
description: A Helm chart for Kubernetes
|
||||||
|
type: application
|
||||||
|
version: 0.0.0
|
||||||
|
appVersion: "0.7.0-canary.18"
|
||||||
16
.github/helm/affine/charts/web/templates/NOTES.txt
vendored
Normal file
16
.github/helm/affine/charts/web/templates/NOTES.txt
vendored
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
1. Get the application URL by running these commands:
|
||||||
|
{{- if contains "NodePort" .Values.service.type }}
|
||||||
|
export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include "web.fullname" . }})
|
||||||
|
export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}")
|
||||||
|
echo http://$NODE_IP:$NODE_PORT
|
||||||
|
{{- else if contains "LoadBalancer" .Values.service.type }}
|
||||||
|
NOTE: It may take a few minutes for the LoadBalancer IP to be available.
|
||||||
|
You can watch the status of by running 'kubectl get --namespace {{ .Release.Namespace }} svc -w {{ include "web.fullname" . }}'
|
||||||
|
export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include "web.fullname" . }} --template "{{"{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}"}}")
|
||||||
|
echo http://$SERVICE_IP:{{ .Values.service.port }}
|
||||||
|
{{- else if contains "ClusterIP" .Values.service.type }}
|
||||||
|
export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ include "web.name" . }},app.kubernetes.io/instance={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}")
|
||||||
|
export CONTAINER_PORT=$(kubectl get pod --namespace {{ .Release.Namespace }} $POD_NAME -o jsonpath="{.spec.containers[0].ports[0].containerPort}")
|
||||||
|
echo "Visit http://127.0.0.1:8080 to use your application"
|
||||||
|
kubectl --namespace {{ .Release.Namespace }} port-forward $POD_NAME 8080:$CONTAINER_PORT
|
||||||
|
{{- end }}
|
||||||
62
.github/helm/affine/charts/web/templates/_helpers.tpl
vendored
Normal file
62
.github/helm/affine/charts/web/templates/_helpers.tpl
vendored
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
{{/*
|
||||||
|
Expand the name of the chart.
|
||||||
|
*/}}
|
||||||
|
{{- define "web.name" -}}
|
||||||
|
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{/*
|
||||||
|
Create a default fully qualified app name.
|
||||||
|
We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
|
||||||
|
If release name contains chart name it will be used as a full name.
|
||||||
|
*/}}
|
||||||
|
{{- define "web.fullname" -}}
|
||||||
|
{{- if .Values.fullnameOverride }}
|
||||||
|
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }}
|
||||||
|
{{- else }}
|
||||||
|
{{- $name := default .Chart.Name .Values.nameOverride }}
|
||||||
|
{{- if contains $name .Release.Name }}
|
||||||
|
{{- .Release.Name | trunc 63 | trimSuffix "-" }}
|
||||||
|
{{- else }}
|
||||||
|
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{/*
|
||||||
|
Create chart name and version as used by the chart label.
|
||||||
|
*/}}
|
||||||
|
{{- define "web.chart" -}}
|
||||||
|
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{/*
|
||||||
|
Common labels
|
||||||
|
*/}}
|
||||||
|
{{- define "web.labels" -}}
|
||||||
|
helm.sh/chart: {{ include "web.chart" . }}
|
||||||
|
{{ include "web.selectorLabels" . }}
|
||||||
|
{{- if .Chart.AppVersion }}
|
||||||
|
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
|
||||||
|
{{- end }}
|
||||||
|
app.kubernetes.io/managed-by: {{ .Release.Service }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{/*
|
||||||
|
Selector labels
|
||||||
|
*/}}
|
||||||
|
{{- define "web.selectorLabels" -}}
|
||||||
|
app.kubernetes.io/name: {{ include "web.name" . }}
|
||||||
|
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{/*
|
||||||
|
Create the name of the service account to use
|
||||||
|
*/}}
|
||||||
|
{{- define "web.serviceAccountName" -}}
|
||||||
|
{{- if .Values.serviceAccount.create }}
|
||||||
|
{{- default (include "web.fullname" .) .Values.serviceAccount.name }}
|
||||||
|
{{- else }}
|
||||||
|
{{- default "default" .Values.serviceAccount.name }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
57
.github/helm/affine/charts/web/templates/deployment.yaml
vendored
Normal file
57
.github/helm/affine/charts/web/templates/deployment.yaml
vendored
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: {{ include "web.fullname" . }}
|
||||||
|
labels:
|
||||||
|
{{- include "web.labels" . | nindent 4 }}
|
||||||
|
spec:
|
||||||
|
replicas: {{ .Values.replicaCount }}
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
{{- include "web.selectorLabels" . | nindent 6 }}
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
{{- with .Values.podAnnotations }}
|
||||||
|
annotations:
|
||||||
|
{{- toYaml . | nindent 8 }}
|
||||||
|
{{- end }}
|
||||||
|
labels:
|
||||||
|
{{- include "web.selectorLabels" . | nindent 8 }}
|
||||||
|
spec:
|
||||||
|
{{- with .Values.imagePullSecrets }}
|
||||||
|
imagePullSecrets:
|
||||||
|
{{- toYaml . | nindent 8 }}
|
||||||
|
{{- end }}
|
||||||
|
serviceAccountName: {{ include "web.serviceAccountName" . }}
|
||||||
|
containers:
|
||||||
|
- name: {{ .Chart.Name }}
|
||||||
|
image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}"
|
||||||
|
imagePullPolicy: {{ .Values.image.pullPolicy }}
|
||||||
|
ports:
|
||||||
|
- name: http
|
||||||
|
containerPort: {{ .Values.service.port }}
|
||||||
|
protocol: TCP
|
||||||
|
livenessProbe:
|
||||||
|
httpGet:
|
||||||
|
path: /
|
||||||
|
port: http
|
||||||
|
initialDelaySeconds: {{ .Values.probe.initialDelaySeconds }}
|
||||||
|
readinessProbe:
|
||||||
|
httpGet:
|
||||||
|
path: /
|
||||||
|
port: http
|
||||||
|
initialDelaySeconds: {{ .Values.probe.initialDelaySeconds }}
|
||||||
|
resources:
|
||||||
|
{{- toYaml .Values.resources | nindent 12 }}
|
||||||
|
{{- with .Values.nodeSelector }}
|
||||||
|
nodeSelector:
|
||||||
|
{{- toYaml . | nindent 8 }}
|
||||||
|
{{- end }}
|
||||||
|
{{- with .Values.affinity }}
|
||||||
|
affinity:
|
||||||
|
{{- toYaml . | nindent 8 }}
|
||||||
|
{{- end }}
|
||||||
|
{{- with .Values.tolerations }}
|
||||||
|
tolerations:
|
||||||
|
{{- toYaml . | nindent 8 }}
|
||||||
|
{{- end }}
|
||||||
15
.github/helm/affine/charts/web/templates/service.yaml
vendored
Normal file
15
.github/helm/affine/charts/web/templates/service.yaml
vendored
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: {{ include "web.fullname" . }}
|
||||||
|
labels:
|
||||||
|
{{- include "web.labels" . | nindent 4 }}
|
||||||
|
spec:
|
||||||
|
type: {{ .Values.service.type }}
|
||||||
|
ports:
|
||||||
|
- port: {{ .Values.service.port }}
|
||||||
|
targetPort: http
|
||||||
|
protocol: TCP
|
||||||
|
name: http
|
||||||
|
selector:
|
||||||
|
{{- include "web.selectorLabels" . | nindent 4 }}
|
||||||
12
.github/helm/affine/charts/web/templates/serviceaccount.yaml
vendored
Normal file
12
.github/helm/affine/charts/web/templates/serviceaccount.yaml
vendored
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
{{- if .Values.serviceAccount.create -}}
|
||||||
|
apiVersion: v1
|
||||||
|
kind: ServiceAccount
|
||||||
|
metadata:
|
||||||
|
name: {{ include "web.serviceAccountName" . }}
|
||||||
|
labels:
|
||||||
|
{{- include "web.labels" . | nindent 4 }}
|
||||||
|
{{- with .Values.serviceAccount.annotations }}
|
||||||
|
annotations:
|
||||||
|
{{- toYaml . | nindent 4 }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
15
.github/helm/affine/charts/web/templates/tests/test-connection.yaml
vendored
Normal file
15
.github/helm/affine/charts/web/templates/tests/test-connection.yaml
vendored
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: Pod
|
||||||
|
metadata:
|
||||||
|
name: "{{ include "web.fullname" . }}-test-connection"
|
||||||
|
labels:
|
||||||
|
{{- include "web.labels" . | nindent 4 }}
|
||||||
|
annotations:
|
||||||
|
"helm.sh/hook": test
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: wget
|
||||||
|
image: busybox
|
||||||
|
command: ['wget']
|
||||||
|
args: ['{{ include "web.fullname" . }}:{{ .Values.service.port }}']
|
||||||
|
restartPolicy: Never
|
||||||
37
.github/helm/affine/charts/web/values.yaml
vendored
Normal file
37
.github/helm/affine/charts/web/values.yaml
vendored
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
replicaCount: 1
|
||||||
|
|
||||||
|
image:
|
||||||
|
repository: ghcr.io/toeverything/affine-front
|
||||||
|
pullPolicy: IfNotPresent
|
||||||
|
tag: ""
|
||||||
|
|
||||||
|
imagePullSecrets: []
|
||||||
|
nameOverride: ""
|
||||||
|
fullnameOverride: ""
|
||||||
|
|
||||||
|
serviceAccount:
|
||||||
|
create: true
|
||||||
|
annotations: {}
|
||||||
|
name: "affine-web"
|
||||||
|
|
||||||
|
podAnnotations: {}
|
||||||
|
|
||||||
|
podSecurityContext:
|
||||||
|
fsGroup: 2000
|
||||||
|
|
||||||
|
resources:
|
||||||
|
limits:
|
||||||
|
cpu: '500m'
|
||||||
|
memory: 2Gi
|
||||||
|
requests:
|
||||||
|
cpu: '500m'
|
||||||
|
memory: 2Gi
|
||||||
|
|
||||||
|
nodeSelector: {}
|
||||||
|
|
||||||
|
tolerations: []
|
||||||
|
|
||||||
|
affinity: {}
|
||||||
|
|
||||||
|
probe:
|
||||||
|
initialDelaySeconds: 1
|
||||||
62
.github/helm/affine/templates/_helpers.tpl
vendored
Normal file
62
.github/helm/affine/templates/_helpers.tpl
vendored
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
{{/*
|
||||||
|
Expand the name of the chart.
|
||||||
|
*/}}
|
||||||
|
{{- define "affine.name" -}}
|
||||||
|
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{/*
|
||||||
|
Create a default fully qualified app name.
|
||||||
|
We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
|
||||||
|
If release name contains chart name it will be used as a full name.
|
||||||
|
*/}}
|
||||||
|
{{- define "affine.fullname" -}}
|
||||||
|
{{- if .Values.fullnameOverride }}
|
||||||
|
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }}
|
||||||
|
{{- else }}
|
||||||
|
{{- $name := default .Chart.Name .Values.nameOverride }}
|
||||||
|
{{- if contains $name .Release.Name }}
|
||||||
|
{{- .Release.Name | trunc 63 | trimSuffix "-" }}
|
||||||
|
{{- else }}
|
||||||
|
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{/*
|
||||||
|
Create chart name and version as used by the chart label.
|
||||||
|
*/}}
|
||||||
|
{{- define "affine.chart" -}}
|
||||||
|
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{/*
|
||||||
|
Common labels
|
||||||
|
*/}}
|
||||||
|
{{- define "affine.labels" -}}
|
||||||
|
helm.sh/chart: {{ include "affine.chart" . }}
|
||||||
|
{{ include "affine.selectorLabels" . }}
|
||||||
|
{{- if .Chart.AppVersion }}
|
||||||
|
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
|
||||||
|
{{- end }}
|
||||||
|
app.kubernetes.io/managed-by: {{ .Release.Service }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{/*
|
||||||
|
Selector labels
|
||||||
|
*/}}
|
||||||
|
{{- define "affine.selectorLabels" -}}
|
||||||
|
app.kubernetes.io/name: {{ include "affine.name" . }}
|
||||||
|
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{/*
|
||||||
|
Create the name of the service account to use
|
||||||
|
*/}}
|
||||||
|
{{- define "affine.serviceAccountName" -}}
|
||||||
|
{{- if .Values.serviceAccount.create }}
|
||||||
|
{{- default (include "affine.fullname" .) .Values.serviceAccount.name }}
|
||||||
|
{{- else }}
|
||||||
|
{{- default "default" .Values.serviceAccount.name }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
64
.github/helm/affine/templates/ingress.yaml
vendored
Normal file
64
.github/helm/affine/templates/ingress.yaml
vendored
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
{{- if .Values.ingress.enabled -}}
|
||||||
|
{{- $fullName := include "affine.fullname" . -}}
|
||||||
|
{{- if and .Values.ingress.className (not (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion)) }}
|
||||||
|
{{- if not (hasKey .Values.ingress.annotations "kubernetes.io/ingress.class") }}
|
||||||
|
{{- $_ := set .Values.ingress.annotations "kubernetes.io/ingress.class" .Values.ingress.className}}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
{{- if semverCompare ">=1.19-0" .Capabilities.KubeVersion.GitVersion -}}
|
||||||
|
apiVersion: networking.k8s.io/v1
|
||||||
|
{{- else if semverCompare ">=1.14-0" .Capabilities.KubeVersion.GitVersion -}}
|
||||||
|
apiVersion: networking.k8s.io/v1beta1
|
||||||
|
{{- else -}}
|
||||||
|
apiVersion: extensions/v1beta1
|
||||||
|
{{- end }}
|
||||||
|
kind: Ingress
|
||||||
|
metadata:
|
||||||
|
name: {{ $fullName }}
|
||||||
|
labels:
|
||||||
|
{{- include "affine.labels" . | nindent 4 }}
|
||||||
|
{{- with .Values.ingress.annotations }}
|
||||||
|
annotations:
|
||||||
|
{{- toYaml . | nindent 4 }}
|
||||||
|
{{- end }}
|
||||||
|
spec:
|
||||||
|
{{- if and .Values.ingress.className (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion) }}
|
||||||
|
ingressClassName: {{ .Values.ingress.className }}
|
||||||
|
{{- end }}
|
||||||
|
{{- if .Values.ingress.tls }}
|
||||||
|
tls:
|
||||||
|
{{- range .Values.ingress.tls }}
|
||||||
|
- hosts:
|
||||||
|
{{- range .hosts }}
|
||||||
|
- {{ . | quote }}
|
||||||
|
{{- end }}
|
||||||
|
secretName: {{ .secretName }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
rules:
|
||||||
|
- host: "{{ .Values.ingress.host }}"
|
||||||
|
http:
|
||||||
|
paths:
|
||||||
|
- path: /graphql
|
||||||
|
pathType: Prefix
|
||||||
|
backend:
|
||||||
|
service:
|
||||||
|
name: affine-graphql
|
||||||
|
port:
|
||||||
|
number: {{ .Values.graphql.service.port }}
|
||||||
|
- path: /api
|
||||||
|
pathType: Prefix
|
||||||
|
backend:
|
||||||
|
service:
|
||||||
|
name: affine-graphql
|
||||||
|
port:
|
||||||
|
number: {{ .Values.graphql.service.port }}
|
||||||
|
- path: /
|
||||||
|
pathType: Prefix
|
||||||
|
backend:
|
||||||
|
service:
|
||||||
|
name: affine-web
|
||||||
|
port:
|
||||||
|
number: {{ .Values.web.service.port }}
|
||||||
|
|
||||||
|
{{- end }}
|
||||||
17
.github/helm/affine/values.yaml
vendored
Normal file
17
.github/helm/affine/values.yaml
vendored
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
ingress:
|
||||||
|
enabled: false
|
||||||
|
className: ''
|
||||||
|
annotations:
|
||||||
|
kubernetes.io/ingress.class: nginx
|
||||||
|
host: affine.pro
|
||||||
|
tls: []
|
||||||
|
|
||||||
|
graphql:
|
||||||
|
service:
|
||||||
|
type: ClusterIP
|
||||||
|
port: 3000
|
||||||
|
|
||||||
|
web:
|
||||||
|
service:
|
||||||
|
type: ClusterIP
|
||||||
|
port: 8080
|
||||||
37
.github/workflows/build.yml
vendored
37
.github/workflows/build.yml
vendored
@@ -53,6 +53,12 @@ jobs:
|
|||||||
run: yarn prettier . --ignore-unknown --cache --check
|
run: yarn prettier . --ignore-unknown --cache --check
|
||||||
- name: Run circular
|
- name: Run circular
|
||||||
run: yarn circular
|
run: yarn circular
|
||||||
|
- name: Upload server dist
|
||||||
|
uses: actions/upload-artifact@v3
|
||||||
|
with:
|
||||||
|
name: server-dist
|
||||||
|
path: ./apps/server/dist
|
||||||
|
if-no-files-found: error
|
||||||
|
|
||||||
build-docs:
|
build-docs:
|
||||||
name: Build Docs
|
name: Build Docs
|
||||||
@@ -172,6 +178,12 @@ jobs:
|
|||||||
env:
|
env:
|
||||||
CARGO_TARGET_DIR: '${{ github.workspace }}/target'
|
CARGO_TARGET_DIR: '${{ github.workspace }}/target'
|
||||||
DATABASE_URL: postgresql://affine:affine@localhost:5432/affine
|
DATABASE_URL: postgresql://affine:affine@localhost:5432/affine
|
||||||
|
- name: Upload storage.node
|
||||||
|
uses: actions/upload-artifact@v3
|
||||||
|
with:
|
||||||
|
name: storage.node
|
||||||
|
path: ./packages/storage/storage.node
|
||||||
|
if-no-files-found: error
|
||||||
- name: Upload server test coverage results
|
- name: Upload server test coverage results
|
||||||
uses: codecov/codecov-action@v3
|
uses: codecov/codecov-action@v3
|
||||||
with:
|
with:
|
||||||
@@ -439,7 +451,9 @@ jobs:
|
|||||||
if: github.ref == 'refs/heads/master'
|
if: github.ref == 'refs/heads/master'
|
||||||
name: Build Docker
|
name: Build Docker
|
||||||
needs:
|
needs:
|
||||||
- build-web-desktop
|
- lint
|
||||||
|
- desktop-test
|
||||||
|
- server-test
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
@@ -448,6 +462,16 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
name: next-js-static
|
name: next-js-static
|
||||||
path: ./apps/web/out
|
path: ./apps/web/out
|
||||||
|
- name: Download server dist
|
||||||
|
uses: actions/download-artifact@v3
|
||||||
|
with:
|
||||||
|
name: server-dist
|
||||||
|
path: ./apps/server/dist
|
||||||
|
- name: Download storage.node
|
||||||
|
uses: actions/download-artifact@v3
|
||||||
|
with:
|
||||||
|
name: storage.node
|
||||||
|
path: ./apps/server
|
||||||
- name: Setup Git short hash
|
- name: Setup Git short hash
|
||||||
run: |
|
run: |
|
||||||
echo "GIT_SHORT_HASH=$(git rev-parse --short HEAD)" >> "$GITHUB_ENV"
|
echo "GIT_SHORT_HASH=$(git rev-parse --short HEAD)" >> "$GITHUB_ENV"
|
||||||
@@ -473,14 +497,21 @@ jobs:
|
|||||||
file: .github/deployment/front/Dockerfile
|
file: .github/deployment/front/Dockerfile
|
||||||
tags: ghcr.io/toeverything/affine-front:${{ env.GIT_SHORT_HASH }},ghcr.io/toeverything/affine-front:latest
|
tags: ghcr.io/toeverything/affine-front:${{ env.GIT_SHORT_HASH }},ghcr.io/toeverything/affine-front:latest
|
||||||
|
|
||||||
|
# setup node without cache configuration
|
||||||
|
# Prisma cache is not compatible with docker build cache
|
||||||
- name: Setup Node.js
|
- name: Setup Node.js
|
||||||
uses: ./.github/actions/setup-node
|
uses: actions/setup-node@v3
|
||||||
with:
|
with:
|
||||||
package-install: false
|
node-version-file: '.nvmrc'
|
||||||
|
registry-url: https://npm.pkg.github.com
|
||||||
|
scope: '@toeverything'
|
||||||
|
|
||||||
- name: Install Node.js dependencies
|
- name: Install Node.js dependencies
|
||||||
run: yarn workspaces focus @affine/server --production
|
run: yarn workspaces focus @affine/server --production
|
||||||
|
|
||||||
|
- name: Generate Prisma client
|
||||||
|
run: yarn workspace @affine/server prisma generate
|
||||||
|
|
||||||
- name: Build graphql Dockerfile
|
- name: Build graphql Dockerfile
|
||||||
uses: docker/build-push-action@v4
|
uses: docker/build-push-action@v4
|
||||||
with:
|
with:
|
||||||
|
|||||||
@@ -15,7 +15,6 @@
|
|||||||
"postinstall": "prisma generate"
|
"postinstall": "prisma generate"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@affine/storage": "workspace:*",
|
|
||||||
"@apollo/server": "^4.7.4",
|
"@apollo/server": "^4.7.4",
|
||||||
"@auth/prisma-adapter": "^1.0.0",
|
"@auth/prisma-adapter": "^1.0.0",
|
||||||
"@aws-sdk/client-s3": "^3.359.0",
|
"@aws-sdk/client-s3": "^3.359.0",
|
||||||
@@ -41,6 +40,7 @@
|
|||||||
"rxjs": "^7.8.1"
|
"rxjs": "^7.8.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@affine/storage": "workspace:*",
|
||||||
"@napi-rs/image": "^1.6.1",
|
"@napi-rs/image": "^1.6.1",
|
||||||
"@nestjs/testing": "^10.0.3",
|
"@nestjs/testing": "^10.0.3",
|
||||||
"@types/express": "^4.17.17",
|
"@types/express": "^4.17.17",
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
generator client {
|
generator client {
|
||||||
provider = "prisma-client-js"
|
provider = "prisma-client-js"
|
||||||
|
binaryTargets = ["native", "debian-openssl-3.0.x"]
|
||||||
}
|
}
|
||||||
|
|
||||||
datasource db {
|
datasource db {
|
||||||
|
|||||||
13
apps/server/src/app.controller.ts
Normal file
13
apps/server/src/app.controller.ts
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
import { Controller, Get } from '@nestjs/common';
|
||||||
|
|
||||||
|
import pkg from '../package.json' assert { type: 'json' };
|
||||||
|
|
||||||
|
@Controller('/')
|
||||||
|
export class AppController {
|
||||||
|
@Get()
|
||||||
|
hello() {
|
||||||
|
return {
|
||||||
|
message: `AFFiNE GraphQL server: ${pkg.version}`,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
import { Module } from '@nestjs/common';
|
import { Module } from '@nestjs/common';
|
||||||
|
|
||||||
|
import { AppController } from './app.controller';
|
||||||
import { ConfigModule } from './config';
|
import { ConfigModule } from './config';
|
||||||
import { GqlModule } from './graphql.module';
|
import { GqlModule } from './graphql.module';
|
||||||
import { BusinessModules } from './modules';
|
import { BusinessModules } from './modules';
|
||||||
@@ -14,5 +15,6 @@ import { StorageModule } from './storage';
|
|||||||
StorageModule.forRoot(),
|
StorageModule.forRoot(),
|
||||||
...BusinessModules,
|
...BusinessModules,
|
||||||
],
|
],
|
||||||
|
controllers: [AppController],
|
||||||
})
|
})
|
||||||
export class AppModule {}
|
export class AppModule {}
|
||||||
|
|||||||
@@ -106,7 +106,7 @@ export interface AFFiNEConfig {
|
|||||||
/**
|
/**
|
||||||
* which port the server will listen on
|
* which port the server will listen on
|
||||||
*
|
*
|
||||||
* @default 3000
|
* @default 3010
|
||||||
* @env AFFINE_SERVER_PORT
|
* @env AFFINE_SERVER_PORT
|
||||||
*/
|
*/
|
||||||
port: number;
|
port: number;
|
||||||
@@ -153,23 +153,13 @@ export interface AFFiNEConfig {
|
|||||||
/**
|
/**
|
||||||
* whether use remote object storage
|
* whether use remote object storage
|
||||||
*/
|
*/
|
||||||
enable: boolean;
|
r2: {
|
||||||
/**
|
enabled: boolean;
|
||||||
* used to store all uploaded builds and analysis reports
|
accountId: string;
|
||||||
*
|
bucket: string;
|
||||||
* the concrete type definition is not given here because different storage providers introduce
|
accessKeyId: string;
|
||||||
* significant differences in configuration
|
secretAccessKey: string;
|
||||||
*
|
};
|
||||||
* @example
|
|
||||||
* {
|
|
||||||
* provider: 'aws',
|
|
||||||
* region: 'eu-west-1',
|
|
||||||
* aws_access_key_id: '',
|
|
||||||
* aws_secret_access_key: '',
|
|
||||||
* // other aws storage config...
|
|
||||||
* }
|
|
||||||
*/
|
|
||||||
config: Record<string, string>;
|
|
||||||
/**
|
/**
|
||||||
* Only used when `enable` is `false`
|
* Only used when `enable` is `false`
|
||||||
*/
|
*/
|
||||||
@@ -224,6 +214,7 @@ export interface AFFiNEConfig {
|
|||||||
Record<
|
Record<
|
||||||
ExternalAccount,
|
ExternalAccount,
|
||||||
{
|
{
|
||||||
|
enabled: boolean;
|
||||||
clientId: string;
|
clientId: string;
|
||||||
clientSecret: string;
|
clientSecret: string;
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
/// <reference types="../global.d.ts" />
|
/// <reference types="../global.d.ts" />
|
||||||
|
|
||||||
|
import { createPrivateKey, createPublicKey } from 'node:crypto';
|
||||||
import { homedir } from 'node:os';
|
import { homedir } from 'node:os';
|
||||||
import { join } from 'node:path';
|
import { join } from 'node:path';
|
||||||
|
|
||||||
@@ -7,82 +8,130 @@ import parse from 'parse-duration';
|
|||||||
|
|
||||||
import pkg from '../../package.json' assert { type: 'json' };
|
import pkg from '../../package.json' assert { type: 'json' };
|
||||||
import type { AFFiNEConfig } from './def';
|
import type { AFFiNEConfig } from './def';
|
||||||
|
import { applyEnvToConfig } from './env';
|
||||||
|
|
||||||
// Don't use this in production
|
// Don't use this in production
|
||||||
export const examplePublicKey = `-----BEGIN PUBLIC KEY-----
|
export const examplePrivateKey = `-----BEGIN EC PRIVATE KEY-----
|
||||||
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEnxM+GhB6eNKPmTP6uH5Gpr+bmQ87
|
MHcCAQEEIEtyAJLIULkphVhqXqxk4Nr8Ggty3XLwUJWBxzAWCWTMoAoGCCqGSM49
|
||||||
hHGeOiCsay0w/aPwMqzAOKkZGqX+HZ9BNGy/yiXmnscey5b2vOTzxtRvxA==
|
AwEHoUQDQgAEF3U/0wIeJ3jRKXeFKqQyBKlr9F7xaAUScRrAuSP33rajm3cdfihI
|
||||||
-----END PUBLIC KEY-----`;
|
3JvMxVNsS2lE8PSGQrvDrJZaDo0L+Lq9Gg==
|
||||||
|
-----END EC PRIVATE KEY-----`;
|
||||||
|
|
||||||
// Don't use this in production
|
const jwtKeyPair = (function () {
|
||||||
export const examplePrivateKey = `-----BEGIN PRIVATE KEY-----
|
const AUTH_PRIVATE_KEY = process.env.AUTH_PRIVATE_KEY ?? examplePrivateKey;
|
||||||
MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgWOog5SFXs1Vjh/WP
|
const privateKey = createPrivateKey({
|
||||||
QCYPQKgf/jsNmWsvD+jYSn6mi3yhRANCAASfEz4aEHp40o+ZM/q4fkamv5uZDzuE
|
key: Buffer.from(AUTH_PRIVATE_KEY),
|
||||||
cZ46IKxrLTD9o/AyrMA4qRkapf4dn0E0bL/KJeaexx7Llva85PPG1G/E
|
format: 'pem',
|
||||||
-----END PRIVATE KEY-----`;
|
type: 'sec1',
|
||||||
|
})
|
||||||
|
.export({
|
||||||
|
format: 'pem',
|
||||||
|
type: 'pkcs8',
|
||||||
|
})
|
||||||
|
.toString('utf8');
|
||||||
|
const publicKey = createPublicKey({
|
||||||
|
key: Buffer.from(AUTH_PRIVATE_KEY),
|
||||||
|
format: 'pem',
|
||||||
|
type: 'spki',
|
||||||
|
})
|
||||||
|
.export({
|
||||||
|
format: 'pem',
|
||||||
|
type: 'spki',
|
||||||
|
})
|
||||||
|
.toString('utf8');
|
||||||
|
|
||||||
export const getDefaultAFFiNEConfig: () => AFFiNEConfig = () => ({
|
return {
|
||||||
serverId: 'affine-nestjs-server',
|
publicKey,
|
||||||
version: pkg.version,
|
privateKey,
|
||||||
ENV_MAP: {},
|
};
|
||||||
env: process.env.NODE_ENV ?? 'development',
|
})();
|
||||||
get prod() {
|
|
||||||
return this.env === 'production';
|
export const getDefaultAFFiNEConfig: () => AFFiNEConfig = () => {
|
||||||
},
|
const defaultConfig = {
|
||||||
get dev() {
|
serverId: 'affine-nestjs-server',
|
||||||
return this.env === 'development';
|
version: pkg.version,
|
||||||
},
|
ENV_MAP: {
|
||||||
get test() {
|
AFFINE_SERVER_PORT: 'port',
|
||||||
return this.env === 'test';
|
AFFINE_SERVER_HOST: 'host',
|
||||||
},
|
AFFINE_SERVER_SUB_PATH: 'path',
|
||||||
get deploy() {
|
DATABASE_URL: 'db.url',
|
||||||
return !this.dev && !this.test;
|
AUTH_PRIVATE_KEY: 'auth.privateKey',
|
||||||
},
|
ENABLE_R2_OBJECT_STORAGE: 'objectStorage.r2.enabled',
|
||||||
https: false,
|
R2_OBJECT_STORAGE_ACCOUNT_ID: 'objectStorage.r2.accountId',
|
||||||
host: 'localhost',
|
R2_OBJECT_STORAGE_ACCESS_KEY_ID: 'objectStorage.r2.accessKeyId',
|
||||||
port: 3010,
|
R2_OBJECT_STORAGE_SECRET_ACCESS_KEY: 'objectStorage.r2.secretAccessKey',
|
||||||
path: '',
|
R2_OBJECT_STORAGE_BUCKET: 'objectStorage.r2.bucket',
|
||||||
get origin() {
|
OAUTH_GOOGLE_CLIENT_ID: 'auth.oauthProviders.google.clientId',
|
||||||
return this.dev
|
OAUTH_GOOGLE_CLIENT_SECRET: 'auth.oauthProviders.google.clientSecret',
|
||||||
? 'http://localhost:8080'
|
OAUTH_GITHUB_CLIENT_ID: 'auth.oauthProviders.github.clientId',
|
||||||
: `${this.https ? 'https' : 'http'}://${this.host}${
|
OAUTH_GITHUB_CLIENT_SECRET: 'auth.oauthProviders.github.clientSecret',
|
||||||
this.host === 'localhost' ? `:${this.port}` : ''
|
} satisfies AFFiNEConfig['ENV_MAP'],
|
||||||
}`;
|
env: process.env.NODE_ENV ?? 'development',
|
||||||
},
|
get prod() {
|
||||||
get baseUrl() {
|
return this.env === 'production';
|
||||||
return `${this.origin}${this.path}`;
|
|
||||||
},
|
|
||||||
db: {
|
|
||||||
url: '',
|
|
||||||
},
|
|
||||||
graphql: {
|
|
||||||
buildSchemaOptions: {
|
|
||||||
numberScalarMode: 'integer',
|
|
||||||
},
|
},
|
||||||
introspection: true,
|
get dev() {
|
||||||
playground: true,
|
return this.env === 'development';
|
||||||
debug: true,
|
|
||||||
},
|
|
||||||
auth: {
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
||||||
accessTokenExpiresIn: parse('1h')! / 1000,
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
||||||
refreshTokenExpiresIn: parse('7d')! / 1000,
|
|
||||||
leeway: 60,
|
|
||||||
publicKey: examplePublicKey,
|
|
||||||
privateKey: examplePrivateKey,
|
|
||||||
enableSignup: true,
|
|
||||||
enableOauth: false,
|
|
||||||
nextAuthSecret: '',
|
|
||||||
oauthProviders: {},
|
|
||||||
},
|
|
||||||
objectStorage: {
|
|
||||||
enable: false,
|
|
||||||
config: {},
|
|
||||||
fs: {
|
|
||||||
path: join(homedir(), '.affine-storage'),
|
|
||||||
},
|
},
|
||||||
},
|
get test() {
|
||||||
});
|
return this.env === 'test';
|
||||||
|
},
|
||||||
|
get deploy() {
|
||||||
|
return !this.dev && !this.test;
|
||||||
|
},
|
||||||
|
https: false,
|
||||||
|
host: 'localhost',
|
||||||
|
port: 3010,
|
||||||
|
path: '',
|
||||||
|
db: {
|
||||||
|
url: '',
|
||||||
|
},
|
||||||
|
get origin() {
|
||||||
|
return this.dev
|
||||||
|
? 'http://localhost:8080'
|
||||||
|
: `${this.https ? 'https' : 'http'}://${this.host}${
|
||||||
|
this.host === 'localhost' ? `:${this.port}` : ''
|
||||||
|
}`;
|
||||||
|
},
|
||||||
|
get baseUrl() {
|
||||||
|
return `${this.origin}${this.path}`;
|
||||||
|
},
|
||||||
|
graphql: {
|
||||||
|
buildSchemaOptions: {
|
||||||
|
numberScalarMode: 'integer',
|
||||||
|
},
|
||||||
|
introspection: true,
|
||||||
|
playground: true,
|
||||||
|
debug: true,
|
||||||
|
},
|
||||||
|
auth: {
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||||
|
accessTokenExpiresIn: parse('1h')! / 1000,
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||||
|
refreshTokenExpiresIn: parse('7d')! / 1000,
|
||||||
|
leeway: 60,
|
||||||
|
privateKey: jwtKeyPair.privateKey,
|
||||||
|
publicKey: jwtKeyPair.publicKey,
|
||||||
|
enableSignup: true,
|
||||||
|
enableOauth: false,
|
||||||
|
nextAuthSecret: '',
|
||||||
|
oauthProviders: {},
|
||||||
|
},
|
||||||
|
objectStorage: {
|
||||||
|
r2: {
|
||||||
|
enabled: false,
|
||||||
|
bucket: '',
|
||||||
|
accountId: '',
|
||||||
|
accessKeyId: '',
|
||||||
|
secretAccessKey: '',
|
||||||
|
},
|
||||||
|
fs: {
|
||||||
|
path: join(homedir(), '.affine-storage'),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
} as const;
|
||||||
|
|
||||||
export { registerEnvs } from './env';
|
applyEnvToConfig(defaultConfig);
|
||||||
|
|
||||||
|
return defaultConfig;
|
||||||
|
};
|
||||||
|
|||||||
@@ -1,17 +1,17 @@
|
|||||||
import { set } from 'lodash-es';
|
import { set } from 'lodash-es';
|
||||||
|
|
||||||
import { parseEnvValue } from './def';
|
import { type AFFiNEConfig, parseEnvValue } from './def';
|
||||||
|
|
||||||
export function registerEnvs() {
|
export function applyEnvToConfig(rawConfig: AFFiNEConfig) {
|
||||||
for (const env in globalThis.AFFiNE.ENV_MAP) {
|
for (const env in rawConfig.ENV_MAP) {
|
||||||
const config = globalThis.AFFiNE.ENV_MAP[env];
|
const config = rawConfig.ENV_MAP[env];
|
||||||
const [path, value] =
|
const [path, value] =
|
||||||
typeof config === 'string'
|
typeof config === 'string'
|
||||||
? [config, process.env[env]]
|
? [config, process.env[env]]
|
||||||
: [config[0], parseEnvValue(process.env[env], config[1])];
|
: [config[0], parseEnvValue(process.env[env], config[1])];
|
||||||
|
|
||||||
if (typeof value !== 'undefined') {
|
if (typeof value !== 'undefined') {
|
||||||
set(globalThis.AFFiNE, path, process.env[env]);
|
set(rawConfig, path, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,12 +27,12 @@ app.use(
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
const host = process.env.HOST ?? 'localhost';
|
|
||||||
const port = process.env.PORT ?? 3010;
|
|
||||||
|
|
||||||
const config = app.get(Config);
|
const config = app.get(Config);
|
||||||
|
|
||||||
if (!config.objectStorage.enable) {
|
const host = config.host ?? 'localhost';
|
||||||
|
const port = config.port ?? 3010;
|
||||||
|
|
||||||
|
if (!config.objectStorage.r2.enabled) {
|
||||||
app.use('/assets', staticMiddleware(config.objectStorage.fs.path));
|
app.use('/assets', staticMiddleware(config.objectStorage.fs.path));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,14 @@ export const S3_SERVICE = Symbol('S3_SERVICE');
|
|||||||
export const S3: FactoryProvider<S3Client> = {
|
export const S3: FactoryProvider<S3Client> = {
|
||||||
provide: S3_SERVICE,
|
provide: S3_SERVICE,
|
||||||
useFactory: (config: Config) => {
|
useFactory: (config: Config) => {
|
||||||
const s3 = new S3Client(config.objectStorage.config);
|
const s3 = new S3Client({
|
||||||
|
region: 'auto',
|
||||||
|
endpoint: `https://${config.objectStorage.r2.accountId}.r2.cloudflarestorage.com`,
|
||||||
|
credentials: {
|
||||||
|
accessKeyId: config.objectStorage.r2.accessKeyId,
|
||||||
|
secretAccessKey: config.objectStorage.r2.secretAccessKey,
|
||||||
|
},
|
||||||
|
});
|
||||||
return s3;
|
return s3;
|
||||||
},
|
},
|
||||||
inject: [Config],
|
inject: [Config],
|
||||||
|
|||||||
@@ -15,11 +15,11 @@ export class StorageService {
|
|||||||
) {}
|
) {}
|
||||||
|
|
||||||
async uploadFile(key: string, file: FileUpload) {
|
async uploadFile(key: string, file: FileUpload) {
|
||||||
if (this.config.objectStorage.enable) {
|
if (this.config.objectStorage.r2.enabled) {
|
||||||
await this.s3.send(
|
await this.s3.send(
|
||||||
new PutObjectCommand({
|
new PutObjectCommand({
|
||||||
Body: file.createReadStream(),
|
Body: file.createReadStream(),
|
||||||
Bucket: this.config.objectStorage.config.bucket,
|
Bucket: this.config.objectStorage.r2.bucket,
|
||||||
Key: key,
|
Key: key,
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,10 +1,19 @@
|
|||||||
import { Storage } from '@affine/storage';
|
import type { Storage } from '@affine/storage';
|
||||||
import { Controller, Get, NotFoundException, Param, Res } from '@nestjs/common';
|
import {
|
||||||
|
Controller,
|
||||||
|
Get,
|
||||||
|
Inject,
|
||||||
|
NotFoundException,
|
||||||
|
Param,
|
||||||
|
Res,
|
||||||
|
} from '@nestjs/common';
|
||||||
import type { Response } from 'express';
|
import type { Response } from 'express';
|
||||||
|
|
||||||
|
import { StorageProvide } from '../../storage';
|
||||||
|
|
||||||
@Controller('/api/workspaces')
|
@Controller('/api/workspaces')
|
||||||
export class WorkspacesController {
|
export class WorkspacesController {
|
||||||
constructor(private readonly storage: Storage) {}
|
constructor(@Inject(StorageProvide) private readonly storage: Storage) {}
|
||||||
|
|
||||||
@Get('/:id/blobs/:name')
|
@Get('/:id/blobs/:name')
|
||||||
async blob(
|
async blob(
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { Storage } from '@affine/storage';
|
import type { Storage } from '@affine/storage';
|
||||||
import { ForbiddenException, NotFoundException } from '@nestjs/common';
|
import { ForbiddenException, Inject, NotFoundException } from '@nestjs/common';
|
||||||
import {
|
import {
|
||||||
Args,
|
Args,
|
||||||
Field,
|
Field,
|
||||||
@@ -21,6 +21,7 @@ import type { User, Workspace } from '@prisma/client';
|
|||||||
import GraphQLUpload from 'graphql-upload/GraphQLUpload.mjs';
|
import GraphQLUpload from 'graphql-upload/GraphQLUpload.mjs';
|
||||||
|
|
||||||
import { PrismaService } from '../../prisma';
|
import { PrismaService } from '../../prisma';
|
||||||
|
import { StorageProvide } from '../../storage';
|
||||||
import type { FileUpload } from '../../types';
|
import type { FileUpload } from '../../types';
|
||||||
import { Auth, CurrentUser } from '../auth';
|
import { Auth, CurrentUser } from '../auth';
|
||||||
import { UserType } from '../users/resolver';
|
import { UserType } from '../users/resolver';
|
||||||
@@ -60,7 +61,7 @@ export class WorkspaceResolver {
|
|||||||
constructor(
|
constructor(
|
||||||
private readonly prisma: PrismaService,
|
private readonly prisma: PrismaService,
|
||||||
private readonly permissionProvider: PermissionService,
|
private readonly permissionProvider: PermissionService,
|
||||||
private readonly storage: Storage
|
@Inject(StorageProvide) private readonly storage: Storage
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
@ResolveField(() => Permission, {
|
@ResolveField(() => Permission, {
|
||||||
|
|||||||
@@ -1,12 +1,6 @@
|
|||||||
import 'reflect-metadata';
|
import 'reflect-metadata';
|
||||||
import 'dotenv/config';
|
import 'dotenv/config';
|
||||||
|
|
||||||
import { getDefaultAFFiNEConfig, registerEnvs } from './config/default';
|
import { getDefaultAFFiNEConfig } from './config/default';
|
||||||
|
|
||||||
globalThis.AFFiNE = getDefaultAFFiNEConfig();
|
globalThis.AFFiNE = getDefaultAFFiNEConfig();
|
||||||
|
|
||||||
globalThis.AFFiNE.ENV_MAP = {
|
|
||||||
DATABASE_URL: 'db.url',
|
|
||||||
};
|
|
||||||
|
|
||||||
registerEnvs();
|
|
||||||
|
|||||||
@@ -1,14 +1,28 @@
|
|||||||
import { Storage } from '@affine/storage';
|
import { createRequire } from 'node:module';
|
||||||
|
|
||||||
|
import type { Storage } from '@affine/storage';
|
||||||
import { type DynamicModule, type FactoryProvider } from '@nestjs/common';
|
import { type DynamicModule, type FactoryProvider } from '@nestjs/common';
|
||||||
|
|
||||||
import { Config } from '../config';
|
import { Config } from '../config';
|
||||||
|
|
||||||
|
export const StorageProvide = Symbol('Storage');
|
||||||
|
|
||||||
|
const require = createRequire(import.meta.url);
|
||||||
|
|
||||||
export class StorageModule {
|
export class StorageModule {
|
||||||
static forRoot(): DynamicModule {
|
static forRoot(): DynamicModule {
|
||||||
const storageProvider: FactoryProvider = {
|
const storageProvider: FactoryProvider = {
|
||||||
provide: Storage,
|
provide: StorageProvide,
|
||||||
useFactory: async (config: Config) => {
|
useFactory: async (config: Config) => {
|
||||||
return Storage.connect(config.db.url);
|
let StorageFactory: typeof Storage;
|
||||||
|
try {
|
||||||
|
// dev mode
|
||||||
|
StorageFactory = (await import('@affine/storage')).Storage;
|
||||||
|
} catch {
|
||||||
|
// In docker
|
||||||
|
StorageFactory = require('../../storage.node').Storage;
|
||||||
|
}
|
||||||
|
return StorageFactory.connect(config.db.url);
|
||||||
},
|
},
|
||||||
inject: [Config],
|
inject: [Config],
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user