gaojintao01 commited on
Commit
f8b5d42
·
1 Parent(s): 18b32f0

Add files using Git LFS

Browse files
This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. .devcontainer/README.md +73 -0
  2. .devcontainer/devcontainer.json +211 -0
  3. .editorconfig +17 -0
  4. .gitattributes +3 -0
  5. .github/FUNDING.yml +1 -0
  6. .github/ISSUE_TEMPLATE/01_bug.yml +42 -0
  7. .github/ISSUE_TEMPLATE/02_feature.yml +19 -0
  8. .github/ISSUE_TEMPLATE/03_documentation.yml +13 -0
  9. .github/ISSUE_TEMPLATE/config.yml +5 -0
  10. .github/workflows/build-and-push-image-semver.yaml +117 -0
  11. .github/workflows/build-and-push-image.yaml +138 -0
  12. .github/workflows/check-package-versions.yaml +37 -0
  13. .github/workflows/check-translations.yaml +37 -0
  14. .github/workflows/dev-build.yaml +124 -0
  15. .github/workflows/run-tests.yaml +77 -0
  16. .github/workflows/sponsors.yaml +44 -0
  17. .gitignore +12 -0
  18. .gitmodules +7 -0
  19. .hadolint.yaml +8 -0
  20. .nvmrc +1 -0
  21. .prettierignore +17 -0
  22. .prettierrc +38 -0
  23. .vscode/launch.json +74 -0
  24. .vscode/settings.json +63 -0
  25. .vscode/tasks.json +94 -0
  26. BARE_METAL.md +147 -0
  27. CONTRIBUTING.md +105 -0
  28. LICENSE +21 -0
  29. SECURITY.md +15 -0
  30. cloud-deployments/aws/cloudformation/DEPLOY.md +49 -0
  31. cloud-deployments/aws/cloudformation/aws_https_instructions.md +118 -0
  32. cloud-deployments/aws/cloudformation/cloudformation_create_anythingllm.json +234 -0
  33. cloud-deployments/digitalocean/terraform/DEPLOY.md +44 -0
  34. cloud-deployments/digitalocean/terraform/main.tf +52 -0
  35. cloud-deployments/digitalocean/terraform/outputs.tf +4 -0
  36. cloud-deployments/digitalocean/terraform/user_data.tp1 +22 -0
  37. cloud-deployments/gcp/deployment/DEPLOY.md +54 -0
  38. cloud-deployments/gcp/deployment/gcp_deploy_anything_llm.yaml +45 -0
  39. cloud-deployments/huggingface-spaces/Dockerfile +31 -0
  40. cloud-deployments/k8/manifest.yaml +214 -0
  41. collector/.env.example +1 -0
  42. collector/.gitignore +6 -0
  43. collector/.nvmrc +1 -0
  44. collector/__tests__/utils/extensions/YoutubeTranscript/YoutubeLoader/youtube-transcript.test.js +16 -0
  45. collector/extensions/index.js +207 -0
  46. collector/extensions/resync/index.js +153 -0
  47. collector/hotdir/__HOTDIR__.md +3 -0
  48. collector/index.js +188 -0
  49. collector/middleware/setDataSigner.js +41 -0
  50. collector/middleware/verifyIntegrity.js +26 -0
.devcontainer/README.md ADDED
@@ -0,0 +1,73 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # AnythingLLM Development Container Setup
2
+
3
+ Welcome to the AnythingLLM development container configuration, designed to create a seamless and feature-rich development environment for this project.
4
+
5
+ <center><h1><b>PLEASE READ THIS</b></h1></center>
6
+
7
+ ## Prerequisites
8
+
9
+ - [Docker](https://www.docker.com/get-started)
10
+ - [Visual Studio Code](https://code.visualstudio.com/)
11
+ - [Remote - Containers](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers) VS Code extension
12
+
13
+ ## Features
14
+
15
+ - **Base Image**: Built on `mcr.microsoft.com/devcontainers/javascript-node:1-18-bookworm`, thus Node.JS LTS v18.
16
+ - **Additional Tools**: Includes `hadolint`, and essential apt-packages such as `curl`, `gnupg`, and more.
17
+ - **Ports**: Configured to auto-forward ports `3000` (Frontend) and `3001` (Backend).
18
+ - **Environment Variables**: Sets `NODE_ENV` to `development` and `ESLINT_USE_FLAT_CONFIG` to `true`.
19
+ - **VS Code Extensions**: A suite of extensions such as `Prettier`, `Docker`, `ESLint`, and more are automatically installed. Please revise if you do not agree with any of these extensions. AI-powered extensions and time trackers are (for now) not included to avoid any privacy concerns, but you can install them later in your own environment.
20
+
21
+ ## Getting Started
22
+
23
+ 1. Using GitHub Codespaces. Just select to create a new workspace, and the devcontainer will be created for you.
24
+
25
+ 2. Using your Local VSCode (Release or Insiders). We suggest you first make a fork of the repo and then clone it to your local machine using VSCode tools. Then open the project folder in VSCode, which will prompt you to open the project in a devcontainer. Select yes, and the devcontainer will be created for you. If this does not happen, you can open the command palette and select "Remote-Containers: Reopen in Container".
26
+
27
+ ## On Creation:
28
+
29
+ When the container is built for the first time, it will automatically run `yarn setup` to ensure everything is in place for the Collector, Server and Frontend. This command is expected to be automatically re-run if there is a content change on next reboot.
30
+
31
+ ## Work in the Container:
32
+
33
+ Once the container is up, be patient. Some extensions may complain because dependencies are still being installed, and in the Extensions tab, some may ask you to "Reload" the project. Don't do that yet. First, wait until all settle down for the first time. We suggest you create a new VSCode profile for this devcontainer, so any configuration and extensions you change, won't affect your default profile.
34
+
35
+ Checklist:
36
+
37
+ - [ ] The usual message asking you to start the Server and Frontend in different windows are now "hidden" in the building process of the devcontainer. Don't forget to do as suggested.
38
+ - [ ] Open a JavaScript file, for example "server/index.js" and check if `eslint` is working. It will complain that `'err' is defined but never used.`. This means it is working.
39
+ - [ ] Open a React File, for example, "frontend/src/main.jsx," and check if `eslint` complains about `Fast refresh only works when a file has exports. Move your component(s) to a separate file.`. Again, it means `eslint` is working. Now check at the status bar if the `Prettier` has a double checkmark :heavy_check_mark: (double). It means Prettier is working. You will see a nice extension `Formatting:`:heavy_check_mark: that can be used to disable the `Format on Save` feature temporarily.
40
+ - [ ] Check if, on the left pane, you have the NPM Scripts (this may be disabled; look at the "Explorer" tree-dots up-right). There will be scripts inside the `package.json` files. You will basically need to run the `dev:collector`, `dev:server` and the `dev:frontend` in this order. When the frontend finishes starting, a window browser will open **inside** the VSCode. Still, you can open it outside.
41
+
42
+ :warning: **Important for all developers** :warning:
43
+
44
+ - [ ] When you are using the `NODE_ENV=development` the server will not store the configurations you set for security reasons. Please set the proper config on file `.env.development`. The side-effect if you don't, everytime you restart the server, you will be sent to the "Onboarding" page again.
45
+
46
+ **Note when using GitHub Codespaces**
47
+
48
+ - [ ] When running the "Server" for the first time, it will automatically configure its port to be publicly accessible by default, as this is required for the front end to reach the server backend. To know more, read the content of the `.env` file on the frontend folder about this, and if any issues occur, make sure to manually set the port "Visibility" of the "Server" is set to "Public" if needed. Again, this is only needed for developing on GitHub Codespaces.
49
+
50
+
51
+ **For the Collector:**
52
+
53
+ - [x] In the past, the Collector dwelled within the Python domain, but now it has journeyed to the splendid realm of Node.JS. Consequently, the configuration complexities of bygone versions are no longer a concern.
54
+
55
+ ### Now it is ready to start
56
+
57
+ In the status bar you will see three shortcuts names `Collector`, `Server` and `Frontend`. Just click-and-wait on that order (don't forget to set the Server port 3001 to Public if you are using GH Codespaces **_before_** starting the Frontend).
58
+
59
+ Now you can enjoy your time developing instead of reconfiguring everything.
60
+
61
+ ## Debugging with the devcontainers
62
+
63
+ ### For debugging the collector, server and frontend
64
+
65
+ First, make sure the built-in extension (ms-vscode.js-debug) is active (I don't know why it would not be, but just in case). If you want, you can install the nightly version (ms-vscode.js-debug-nightly)
66
+
67
+ Then, in the "Run and Debug" tab (Ctrl+shift+D), you can select on the menu:
68
+
69
+ - Collector debug. This will start the collector in debug mode and attach the debugger. Works very well.
70
+ - Server debug. This will start the server in debug mode and attach the debugger. Works very well.
71
+ - Frontend debug. This will start the frontend in debug mode and attach the debugger. I am still struggling with this one. I don't know if VSCode can handle the .jsx files seamlessly as the pure .js on the server. Maybe there is a need for a particular configuration for Vite or React. Anyway, it starts. Another two configurations launch Chrome and Edge, and I think we could add breakpoints on .jsx files somehow. The best scenario would be always to use the embedded browser. WIP.
72
+
73
+ Please leave comments on the Issues tab or the [![](https://img.shields.io/discord/1114740394715004990?logo=Discord&logoColor=white&label=Discord&labelColor=%235568ee&color=%2355A2DD&link=https%3A%2F%2Fdiscord.gg%2F6UyHPeGZAC)]("https://discord.gg/6UyHPeGZAC")
.devcontainer/devcontainer.json ADDED
@@ -0,0 +1,211 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // For format details, see https://aka.ms/devcontainer.json. For config options, see the
2
+ // README at: https://github.com/devcontainers/templates/tree/main/src/javascript-node
3
+ {
4
+ "name": "Node.js",
5
+ // Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile
6
+ // "build": {
7
+ // "args": {
8
+ // "ARG_UID": "1000",
9
+ // "ARG_GID": "1000"
10
+ // },
11
+ // "dockerfile": "Dockerfile"
12
+ // },
13
+ // "containerUser": "anythingllm",
14
+ // Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile
15
+ "image": "mcr.microsoft.com/devcontainers/javascript-node:1-18-bookworm",
16
+ // Features to add to the dev container. More info: https://containers.dev/features.
17
+ "features": {
18
+ // Docker very useful linter
19
+ "ghcr.io/dhoeric/features/hadolint:1": {
20
+ "version": "latest"
21
+ },
22
+ // Terraform support
23
+ "ghcr.io/devcontainers/features/terraform:1": {},
24
+ // Just a wrap to install needed packages
25
+ "ghcr.io/devcontainers-contrib/features/apt-packages:1": {
26
+ // Dependencies copied from ../docker/Dockerfile plus some dev stuff
27
+ "packages": [
28
+ "build-essential",
29
+ "ca-certificates",
30
+ "curl",
31
+ "ffmpeg",
32
+ "fonts-liberation",
33
+ "git",
34
+ "gnupg",
35
+ "htop",
36
+ "less",
37
+ "libappindicator1",
38
+ "libasound2",
39
+ "libatk-bridge2.0-0",
40
+ "libatk1.0-0",
41
+ "libc6",
42
+ "libcairo2",
43
+ "libcups2",
44
+ "libdbus-1-3",
45
+ "libexpat1",
46
+ "libfontconfig1",
47
+ "libgbm1",
48
+ "libgcc1",
49
+ "libgfortran5",
50
+ "libglib2.0-0",
51
+ "libgtk-3-0",
52
+ "libnspr4",
53
+ "libnss3",
54
+ "libpango-1.0-0",
55
+ "libpangocairo-1.0-0",
56
+ "libstdc++6",
57
+ "libx11-6",
58
+ "libx11-xcb1",
59
+ "libxcb1",
60
+ "libxcomposite1",
61
+ "libxcursor1",
62
+ "libxdamage1",
63
+ "libxext6",
64
+ "libxfixes3",
65
+ "libxi6",
66
+ "libxrandr2",
67
+ "libxrender1",
68
+ "libxss1",
69
+ "libxtst6",
70
+ "locales",
71
+ "lsb-release",
72
+ "procps",
73
+ "tzdata",
74
+ "wget",
75
+ "xdg-utils"
76
+ ]
77
+ }
78
+ },
79
+ "updateContentCommand": "cd server && yarn && cd ../collector && PUPPETEER_DOWNLOAD_BASE_URL=https://storage.googleapis.com/chrome-for-testing-public yarn && cd ../frontend && yarn && cd .. && yarn setup:envs && yarn prisma:setup && echo \"Please run yarn dev:server, yarn dev:collector, and yarn dev:frontend in separate terminal tabs.\"",
80
+ // Use 'postCreateCommand' to run commands after the container is created.
81
+ // This configures VITE for github codespaces and installs gh cli
82
+ "postCreateCommand": "if [ \"${CODESPACES}\" = \"true\" ]; then echo 'VITE_API_BASE=\"https://$CODESPACE_NAME-3001.$GITHUB_CODESPACES_PORT_FORWARDING_DOMAIN/api\"' > ./frontend/.env && (type -p wget >/dev/null || (sudo apt update && sudo apt-get install wget -y)) && sudo mkdir -p -m 755 /etc/apt/keyrings && wget -qO- https://cli.github.com/packages/githubcli-archive-keyring.gpg | sudo tee /etc/apt/keyrings/githubcli-archive-keyring.gpg > /dev/null && sudo chmod go+r /etc/apt/keyrings/githubcli-archive-keyring.gpg && echo \"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main\" | sudo tee /etc/apt/sources.list.d/github-cli.list > /dev/null && sudo apt update && sudo apt install gh -y; fi",
83
+ "portsAttributes": {
84
+ "3001": {
85
+ "label": "Backend",
86
+ "onAutoForward": "notify"
87
+ },
88
+ "3000": {
89
+ "label": "Frontend",
90
+ "onAutoForward": "openPreview"
91
+ }
92
+ },
93
+ "capAdd": [
94
+ "SYS_ADMIN" // needed for puppeteer using headless chrome in sandbox
95
+ ],
96
+ "remoteEnv": {
97
+ "NODE_ENV": "development",
98
+ "ESLINT_USE_FLAT_CONFIG": "true",
99
+ "ANYTHING_LLM_RUNTIME": "docker"
100
+ },
101
+ // "initializeCommand": "echo Initialize....",
102
+ "shutdownAction": "stopContainer",
103
+ // Configure tool-specific properties.
104
+ "customizations": {
105
+ "codespaces": {
106
+ "openFiles": [
107
+ "README.md",
108
+ ".devcontainer/README.md"
109
+ ]
110
+ },
111
+ "vscode": {
112
+ "openFiles": [
113
+ "README.md",
114
+ ".devcontainer/README.md"
115
+ ],
116
+ "extensions": [
117
+ "bierner.github-markdown-preview",
118
+ "bradlc.vscode-tailwindcss",
119
+ "dbaeumer.vscode-eslint",
120
+ "editorconfig.editorconfig",
121
+ "esbenp.prettier-vscode",
122
+ "exiasr.hadolint",
123
+ "flowtype.flow-for-vscode",
124
+ "gamunu.vscode-yarn",
125
+ "hashicorp.terraform",
126
+ "mariusschulz.yarn-lock-syntax",
127
+ "ms-azuretools.vscode-docker",
128
+ "streetsidesoftware.code-spell-checker",
129
+ "actboy168.tasks",
130
+ "tombonnike.vscode-status-bar-format-toggle",
131
+ "ms-vscode.js-debug"
132
+ ],
133
+ "settings": {
134
+ "[css]": {
135
+ "editor.defaultFormatter": "esbenp.prettier-vscode"
136
+ },
137
+ "[dockercompose]": {
138
+ "editor.defaultFormatter": "esbenp.prettier-vscode"
139
+ },
140
+ "[dockerfile]": {
141
+ "editor.defaultFormatter": "ms-azuretools.vscode-docker"
142
+ },
143
+ "[html]": {
144
+ "editor.defaultFormatter": "esbenp.prettier-vscode"
145
+ },
146
+ "[javascript]": {
147
+ "editor.defaultFormatter": "esbenp.prettier-vscode"
148
+ },
149
+ "[javascriptreact]": {
150
+ "editor.defaultFormatter": "esbenp.prettier-vscode"
151
+ },
152
+ "[json]": {
153
+ "editor.defaultFormatter": "esbenp.prettier-vscode"
154
+ },
155
+ "[jsonc]": {
156
+ "editor.defaultFormatter": "esbenp.prettier-vscode"
157
+ },
158
+ "[markdown]": {
159
+ "editor.defaultFormatter": "esbenp.prettier-vscode"
160
+ },
161
+ "[postcss]": {
162
+ "editor.defaultFormatter": "esbenp.prettier-vscode"
163
+ },
164
+ "[toml]": {
165
+ "editor.defaultFormatter": "tamasfe.even-better-toml"
166
+ },
167
+ "eslint.debug": true,
168
+ "eslint.enable": true,
169
+ "eslint.experimental.useFlatConfig": true,
170
+ "eslint.run": "onSave",
171
+ "files.associations": {
172
+ ".*ignore": "ignore",
173
+ ".editorconfig": "editorconfig",
174
+ ".env*": "properties",
175
+ ".flowconfig": "ini",
176
+ ".prettierrc": "json",
177
+ "*.css": "tailwindcss",
178
+ "*.md": "markdown",
179
+ "*.sh": "shellscript",
180
+ "docker-compose.*": "dockercompose",
181
+ "Dockerfile*": "dockerfile",
182
+ "yarn.lock": "yarnlock"
183
+ },
184
+ "javascript.format.enable": false,
185
+ "javascript.inlayHints.enumMemberValues.enabled": true,
186
+ "javascript.inlayHints.functionLikeReturnTypes.enabled": true,
187
+ "javascript.inlayHints.parameterTypes.enabled": true,
188
+ "javascript.inlayHints.variableTypes.enabled": true,
189
+ "js/ts.implicitProjectConfig.module": "CommonJS",
190
+ "json.format.enable": false,
191
+ "json.schemaDownload.enable": true,
192
+ "npm.autoDetect": "on",
193
+ "npm.packageManager": "yarn",
194
+ "prettier.useEditorConfig": false,
195
+ "tailwindCSS.files.exclude": [
196
+ "**/.git/**",
197
+ "**/node_modules/**",
198
+ "**/.hg/**",
199
+ "**/.svn/**",
200
+ "**/dist/**"
201
+ ],
202
+ "typescript.validate.enable": false,
203
+ "workbench.editorAssociations": {
204
+ "*.md": "vscode.markdown.preview.editor"
205
+ }
206
+ }
207
+ }
208
+ }
209
+ // Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root.
210
+ // "remoteUser": "root"
211
+ }
.editorconfig ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # EditorConfig is awesome: https://EditorConfig.org
2
+
3
+ # top-most EditorConfig file
4
+ root = true
5
+
6
+ [*]
7
+ # Non-configurable Prettier behaviors
8
+ charset = utf-8
9
+ insert_final_newline = true
10
+ trim_trailing_whitespace = true
11
+
12
+ # Configurable Prettier behaviors
13
+ # (change these if your Prettier config differs)
14
+ end_of_line = lf
15
+ indent_style = space
16
+ indent_size = 2
17
+ max_line_length = 80
.gitattributes CHANGED
@@ -33,3 +33,6 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
 
 
 
 
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
36
+ *.ttf filter=lfs diff=lfs merge=lfs -text
37
+ *.png filter=lfs diff=lfs merge=lfs -text
38
+ *.webm filter=lfs diff=lfs merge=lfs -text
.github/FUNDING.yml ADDED
@@ -0,0 +1 @@
 
 
1
+ github: Mintplex-Labs
.github/ISSUE_TEMPLATE/01_bug.yml ADDED
@@ -0,0 +1,42 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ name: 🐛 Bug Report
2
+ description: File a bug report for AnythingLLM
3
+ title: "[BUG]: "
4
+ labels: [possible bug]
5
+ body:
6
+ - type: markdown
7
+ attributes:
8
+ value: |
9
+ Use this template to file a bug report for AnythingLLM. Please be as descriptive as possible to allow everyone to replicate and solve your issue.
10
+ - type: dropdown
11
+ id: runtime
12
+ attributes:
13
+ label: How are you running AnythingLLM?
14
+ description: AnythingLLM can be run in many environments, pick the one that best represents where you encounter the bug.
15
+ options:
16
+ - Docker (local)
17
+ - Docker (remote machine)
18
+ - Local development
19
+ - AnythingLLM desktop app
20
+ - All versions
21
+ - Not listed
22
+ default: 0
23
+ validations:
24
+ required: true
25
+
26
+ - type: textarea
27
+ id: what-happened
28
+ attributes:
29
+ label: What happened?
30
+ description: Also tell us, what did you expect to happen?
31
+ validations:
32
+ required: true
33
+
34
+ - type: textarea
35
+ id: reproduction
36
+ attributes:
37
+ label: Are there known steps to reproduce?
38
+ description: |
39
+ Let us know how to reproduce the bug and we may be able to fix it more
40
+ quickly. This is not required, but it is helpful.
41
+ validations:
42
+ required: false
.github/ISSUE_TEMPLATE/02_feature.yml ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ name: ✨ New Feature suggestion
2
+ description: Suggest a new feature for AnythingLLM!
3
+ title: "[FEAT]: "
4
+ labels: [enhancement, feature request]
5
+ body:
6
+ - type: markdown
7
+ attributes:
8
+ value: |
9
+ Share a new idea for a feature or improvement. Be sure to search existing
10
+ issues first to avoid duplicates.
11
+
12
+ - type: textarea
13
+ id: description
14
+ attributes:
15
+ label: What would you like to see?
16
+ description: |
17
+ Describe the feature and why it would be useful to your use-case as well as others.
18
+ validations:
19
+ required: true
.github/ISSUE_TEMPLATE/03_documentation.yml ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ name: 📚 Documentation improvement
2
+ title: "[DOCS]: "
3
+ description: Report an issue or problem with the documentation.
4
+ labels: [documentation]
5
+
6
+ body:
7
+ - type: textarea
8
+ id: description
9
+ attributes:
10
+ label: Description
11
+ description: Describe the issue with the documentation that is giving you trouble or causing confusion.
12
+ validations:
13
+ required: true
.github/ISSUE_TEMPLATE/config.yml ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ blank_issues_enabled: true
2
+ contact_links:
3
+ - name: 🧑‍🤝‍🧑 Community Discord
4
+ url: https://discord.gg/6UyHPeGZAC
5
+ about: Interact with the Mintplex Labs community here by asking for help, discussing and more!
.github/workflows/build-and-push-image-semver.yaml ADDED
@@ -0,0 +1,117 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ name: Publish AnythingLLM Docker image on Release (amd64 & arm64)
2
+
3
+ concurrency:
4
+ group: build-${{ github.ref }}
5
+ cancel-in-progress: true
6
+
7
+ on:
8
+ release:
9
+ types: [published]
10
+
11
+ jobs:
12
+ push_multi_platform_to_registries:
13
+ name: Push Docker multi-platform image to multiple registries
14
+ runs-on: ubuntu-latest
15
+ permissions:
16
+ packages: write
17
+ contents: read
18
+ steps:
19
+ - name: Check out the repo
20
+ uses: actions/checkout@v4
21
+
22
+ - name: Check if DockerHub build needed
23
+ shell: bash
24
+ run: |
25
+ # Check if the secret for USERNAME is set (don't even check for the password)
26
+ if [[ -z "${{ secrets.DOCKER_USERNAME }}" ]]; then
27
+ echo "DockerHub build not needed"
28
+ echo "enabled=false" >> $GITHUB_OUTPUT
29
+ else
30
+ echo "DockerHub build needed"
31
+ echo "enabled=true" >> $GITHUB_OUTPUT
32
+ fi
33
+ id: dockerhub
34
+
35
+ - name: Set up QEMU
36
+ uses: docker/setup-qemu-action@v3
37
+
38
+ - name: Set up Docker Buildx
39
+ uses: docker/setup-buildx-action@v3
40
+ with:
41
+ version: v0.22.0
42
+
43
+ - name: Log in to Docker Hub
44
+ uses: docker/login-action@f4ef78c080cd8ba55a85445d5b36e214a81df20a
45
+ # Only login to the Docker Hub if the repo is mintplex/anythingllm, to allow for forks to build on GHCR
46
+ if: steps.dockerhub.outputs.enabled == 'true'
47
+ with:
48
+ username: ${{ secrets.DOCKER_USERNAME }}
49
+ password: ${{ secrets.DOCKER_PASSWORD }}
50
+
51
+ - name: Log in to the Container registry
52
+ uses: docker/login-action@65b78e6e13532edd9afa3aa52ac7964289d1a9c1
53
+ with:
54
+ registry: ghcr.io
55
+ username: ${{ github.actor }}
56
+ password: ${{ secrets.GITHUB_TOKEN }}
57
+
58
+ - name: Extract metadata (tags, labels) for Docker
59
+ id: meta
60
+ uses: docker/metadata-action@9ec57ed1fcdbf14dcef7dfbe97b2010124a938b7
61
+ with:
62
+ images: |
63
+ ${{ steps.dockerhub.outputs.enabled == 'true' && 'mintplexlabs/anythingllm' || '' }}
64
+ ghcr.io/${{ github.repository }}
65
+ tags: |
66
+ type=semver,pattern={{version}}
67
+ type=semver,pattern={{major}}.{{minor}}
68
+
69
+ - name: Build and push multi-platform Docker image
70
+ uses: docker/build-push-action@v6
71
+ with:
72
+ context: .
73
+ file: ./docker/Dockerfile
74
+ push: true
75
+ sbom: true
76
+ provenance: mode=max
77
+ platforms: linux/amd64,linux/arm64
78
+ tags: ${{ steps.meta.outputs.tags }}
79
+ labels: ${{ steps.meta.outputs.labels }}
80
+ cache-from: type=gha
81
+ cache-to: type=gha,mode=max
82
+
83
+ # For Docker scout there are some intermediary reported CVEs which exists outside
84
+ # of execution content or are unreachable by an attacker but exist in image.
85
+ # We create VEX files for these so they don't show in scout summary.
86
+ - name: Collect known and verified CVE exceptions
87
+ id: cve-list
88
+ run: |
89
+ # Collect CVEs from filenames in vex folder
90
+ CVE_NAMES=""
91
+ for file in ./docker/vex/*.vex.json; do
92
+ [ -e "$file" ] || continue
93
+ filename=$(basename "$file")
94
+ stripped_filename=${filename%.vex.json}
95
+ CVE_NAMES+=" $stripped_filename"
96
+ done
97
+ echo "CVE_EXCEPTIONS=$CVE_NAMES" >> $GITHUB_OUTPUT
98
+ shell: bash
99
+
100
+ # About VEX attestations https://docs.docker.com/scout/explore/exceptions/
101
+ # Justifications https://github.com/openvex/spec/blob/main/OPENVEX-SPEC.md#status-justifications
102
+ - name: Add VEX attestations
103
+ env:
104
+ CVE_EXCEPTIONS: ${{ steps.cve-list.outputs.CVE_EXCEPTIONS }}
105
+ run: |
106
+ echo $CVE_EXCEPTIONS
107
+ curl -sSfL https://raw.githubusercontent.com/docker/scout-cli/main/install.sh | sh -s --
108
+ for cve in $CVE_EXCEPTIONS; do
109
+ for tag in "${{ join(fromJSON(steps.meta.outputs.json).tags, ' ') }}"; do
110
+ echo "Attaching VEX exception $cve to $tag"
111
+ docker scout attestation add \
112
+ --file "./docker/vex/$cve.vex.json" \
113
+ --predicate-type https://openvex.dev/ns/v0.2.0 \
114
+ $tag
115
+ done
116
+ done
117
+ shell: bash
.github/workflows/build-and-push-image.yaml ADDED
@@ -0,0 +1,138 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # This GitHub action is for publishing of the primary image for AnythingLLM
2
+ # It will publish a linux/amd64 and linux/arm64 image at the same time
3
+ # This file should ONLY BY USED FOR `master` BRANCH.
4
+ # TODO: GitHub now has an ubuntu-24.04-arm64 runner, but we still need
5
+ # to use QEMU to build the arm64 image because Chromium is not available for Linux arm64
6
+ # so builds will still fail, or fail much more often. Its inconsistent and frustrating.
7
+ name: Publish AnythingLLM Primary Docker image (amd64/arm64)
8
+
9
+ concurrency:
10
+ group: build-${{ github.ref }}
11
+ cancel-in-progress: true
12
+
13
+ on:
14
+ push:
15
+ branches: ['master'] # master branch only. Do not modify.
16
+ paths-ignore:
17
+ - '**.md'
18
+ - '.gitmodules'
19
+ - 'cloud-deployments/**/*'
20
+ - 'images/**/*'
21
+ - '.vscode/**/*'
22
+ - '**/.env.example'
23
+ - '.github/ISSUE_TEMPLATE/**/*'
24
+ - '.devcontainer/**/*'
25
+ - 'embed/**/*' # Embed is submodule
26
+ - 'browser-extension/**/*' # Chrome extension is submodule
27
+ - 'server/utils/agents/aibitat/example/**/*' # Do not push new image for local dev testing of new aibitat images.
28
+ - 'extras/**/*' # Extra is just for news and other local content.
29
+
30
+ jobs:
31
+ push_multi_platform_to_registries:
32
+ name: Push Docker multi-platform image to multiple registries
33
+ runs-on: ubuntu-latest
34
+ permissions:
35
+ packages: write
36
+ contents: read
37
+ steps:
38
+ - name: Check out the repo
39
+ uses: actions/checkout@v4
40
+
41
+ - name: Check if DockerHub build needed
42
+ shell: bash
43
+ run: |
44
+ # Check if the secret for USERNAME is set (don't even check for the password)
45
+ if [[ -z "${{ secrets.DOCKER_USERNAME }}" ]]; then
46
+ echo "DockerHub build not needed"
47
+ echo "enabled=false" >> $GITHUB_OUTPUT
48
+ else
49
+ echo "DockerHub build needed"
50
+ echo "enabled=true" >> $GITHUB_OUTPUT
51
+ fi
52
+ id: dockerhub
53
+
54
+ - name: Set up QEMU
55
+ uses: docker/setup-qemu-action@v3
56
+
57
+ - name: Set up Docker Buildx
58
+ uses: docker/setup-buildx-action@v3
59
+ with:
60
+ version: v0.22.0
61
+
62
+ - name: Log in to Docker Hub
63
+ uses: docker/login-action@f4ef78c080cd8ba55a85445d5b36e214a81df20a
64
+ # Only login to the Docker Hub if the repo is mintplex/anythingllm, to allow for forks to build on GHCR
65
+ if: steps.dockerhub.outputs.enabled == 'true'
66
+ with:
67
+ username: ${{ secrets.DOCKER_USERNAME }}
68
+ password: ${{ secrets.DOCKER_PASSWORD }}
69
+
70
+ - name: Log in to the Container registry
71
+ uses: docker/login-action@65b78e6e13532edd9afa3aa52ac7964289d1a9c1
72
+ with:
73
+ registry: ghcr.io
74
+ username: ${{ github.actor }}
75
+ password: ${{ secrets.GITHUB_TOKEN }}
76
+
77
+ - name: Extract metadata (tags, labels) for Docker
78
+ id: meta
79
+ uses: docker/metadata-action@9ec57ed1fcdbf14dcef7dfbe97b2010124a938b7
80
+ with:
81
+ images: |
82
+ ${{ steps.dockerhub.outputs.enabled == 'true' && 'mintplexlabs/anythingllm' || '' }}
83
+ ghcr.io/${{ github.repository }}
84
+ tags: |
85
+ type=raw,value=latest,enable={{is_default_branch}}
86
+ type=ref,event=branch
87
+ type=ref,event=tag
88
+ type=ref,event=pr
89
+
90
+ - name: Build and push multi-platform Docker image
91
+ uses: docker/build-push-action@v6
92
+ with:
93
+ context: .
94
+ file: ./docker/Dockerfile
95
+ push: true
96
+ sbom: true
97
+ provenance: mode=max
98
+ platforms: linux/amd64,linux/arm64
99
+ tags: ${{ steps.meta.outputs.tags }}
100
+ labels: ${{ steps.meta.outputs.labels }}
101
+ cache-from: type=gha
102
+ cache-to: type=gha,mode=max
103
+
104
+ # For Docker scout there are some intermediary reported CVEs which exists outside
105
+ # of execution content or are unreachable by an attacker but exist in image.
106
+ # We create VEX files for these so they don't show in scout summary.
107
+ - name: Collect known and verified CVE exceptions
108
+ id: cve-list
109
+ run: |
110
+ # Collect CVEs from filenames in vex folder
111
+ CVE_NAMES=""
112
+ for file in ./docker/vex/*.vex.json; do
113
+ [ -e "$file" ] || continue
114
+ filename=$(basename "$file")
115
+ stripped_filename=${filename%.vex.json}
116
+ CVE_NAMES+=" $stripped_filename"
117
+ done
118
+ echo "CVE_EXCEPTIONS=$CVE_NAMES" >> $GITHUB_OUTPUT
119
+ shell: bash
120
+
121
+ # About VEX attestations https://docs.docker.com/scout/explore/exceptions/
122
+ # Justifications https://github.com/openvex/spec/blob/main/OPENVEX-SPEC.md#status-justifications
123
+ - name: Add VEX attestations
124
+ env:
125
+ CVE_EXCEPTIONS: ${{ steps.cve-list.outputs.CVE_EXCEPTIONS }}
126
+ run: |
127
+ echo $CVE_EXCEPTIONS
128
+ curl -sSfL https://raw.githubusercontent.com/docker/scout-cli/main/install.sh | sh -s --
129
+ for cve in $CVE_EXCEPTIONS; do
130
+ for tag in "${{ join(fromJSON(steps.meta.outputs.json).tags, ' ') }}"; do
131
+ echo "Attaching VEX exception $cve to $tag"
132
+ docker scout attestation add \
133
+ --file "./docker/vex/$cve.vex.json" \
134
+ --predicate-type https://openvex.dev/ns/v0.2.0 \
135
+ $tag
136
+ done
137
+ done
138
+ shell: bash
.github/workflows/check-package-versions.yaml ADDED
@@ -0,0 +1,37 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # This GitHub action is for checking the versions of the packages in the project.
2
+ # Any package that is present in both the `server` and `collector` package.json file
3
+ # is checked to ensure that they are the same version.
4
+ name: Check package versions
5
+
6
+ concurrency:
7
+ group: build-${{ github.ref }}
8
+ cancel-in-progress: true
9
+
10
+ on:
11
+ pull_request:
12
+ types: [opened, synchronize, reopened]
13
+ paths:
14
+ - "server/package.json"
15
+ - "collector/package.json"
16
+
17
+ jobs:
18
+ run-script:
19
+ runs-on: ubuntu-latest
20
+
21
+ steps:
22
+ - name: Checkout repository
23
+ uses: actions/checkout@v2
24
+
25
+ - name: Set up Node.js
26
+ uses: actions/setup-node@v3
27
+ with:
28
+ node-version: '18'
29
+
30
+ - name: Run verifyPackageVersions.mjs script
31
+ run: |
32
+ cd extras/scripts
33
+ node verifyPackageVersions.mjs
34
+
35
+ - name: Fail job on error
36
+ if: failure()
37
+ run: exit 1
.github/workflows/check-translations.yaml ADDED
@@ -0,0 +1,37 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # This GitHub action is for validation of all languages which translations are offered for
2
+ # in the locales folder in `frontend/src`. All languages are compared to the EN translation
3
+ # schema since that is the fallback language setting. This workflow will run on all PRs that
4
+ # modify any files in the translation directory
5
+ name: Verify translations files
6
+
7
+ concurrency:
8
+ group: build-${{ github.ref }}
9
+ cancel-in-progress: true
10
+
11
+ on:
12
+ pull_request:
13
+ types: [opened, synchronize, reopened]
14
+ paths:
15
+ - "frontend/src/locales/**.js"
16
+
17
+ jobs:
18
+ run-script:
19
+ runs-on: ubuntu-latest
20
+
21
+ steps:
22
+ - name: Checkout repository
23
+ uses: actions/checkout@v2
24
+
25
+ - name: Set up Node.js
26
+ uses: actions/setup-node@v3
27
+ with:
28
+ node-version: '18'
29
+
30
+ - name: Run verifyTranslations.mjs script
31
+ run: |
32
+ cd frontend/src/locales
33
+ node verifyTranslations.mjs
34
+
35
+ - name: Fail job on error
36
+ if: failure()
37
+ run: exit 1
.github/workflows/dev-build.yaml ADDED
@@ -0,0 +1,124 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ name: AnythingLLM Development Docker image (amd64)
2
+
3
+ concurrency:
4
+ group: build-${{ github.ref }}
5
+ cancel-in-progress: true
6
+
7
+ on:
8
+ push:
9
+ branches: ['3999-chromium-flags'] # put your current branch to create a build. Core team only.
10
+ paths-ignore:
11
+ - '**.md'
12
+ - 'cloud-deployments/*'
13
+ - 'images/**/*'
14
+ - '.vscode/**/*'
15
+ - '**/.env.example'
16
+ - '.github/ISSUE_TEMPLATE/**/*'
17
+ - '.devcontainer/**/*'
18
+ - 'embed/**/*' # Embed should be published to frontend (yarn build:publish) if any changes are introduced
19
+ - 'browser-extension/**/*' # Chrome extension is submodule
20
+ - 'server/utils/agents/aibitat/example/**/*' # Do not push new image for local dev testing of new aibitat images.
21
+ - 'extras/**/*' # Extra is just for news and other local content.
22
+
23
+ jobs:
24
+ push_multi_platform_to_registries:
25
+ name: Push Docker multi-platform image to multiple registries
26
+ runs-on: ubuntu-latest
27
+ permissions:
28
+ packages: write
29
+ contents: read
30
+ steps:
31
+ - name: Check out the repo
32
+ uses: actions/checkout@v4
33
+
34
+ - name: Check if DockerHub build needed
35
+ shell: bash
36
+ run: |
37
+ # Check if the secret for USERNAME is set (don't even check for the password)
38
+ if [[ -z "${{ secrets.DOCKER_USERNAME }}" ]]; then
39
+ echo "DockerHub build not needed"
40
+ echo "enabled=false" >> $GITHUB_OUTPUT
41
+ else
42
+ echo "DockerHub build needed"
43
+ echo "enabled=true" >> $GITHUB_OUTPUT
44
+ fi
45
+ id: dockerhub
46
+
47
+ # Uncomment this + add linux/arm64 to platforms if you want to build for arm64 as well
48
+ # - name: Set up QEMU
49
+ # uses: docker/setup-qemu-action@v3
50
+
51
+ - name: Set up Docker Buildx
52
+ uses: docker/setup-buildx-action@v3
53
+ with:
54
+ version: v0.22.0
55
+
56
+ - name: Log in to Docker Hub
57
+ uses: docker/login-action@f4ef78c080cd8ba55a85445d5b36e214a81df20a
58
+ # Only login to the Docker Hub if the repo is mintplex/anythingllm, to allow for forks to build on GHCR
59
+ if: steps.dockerhub.outputs.enabled == 'true'
60
+ with:
61
+ username: ${{ secrets.DOCKER_USERNAME }}
62
+ password: ${{ secrets.DOCKER_PASSWORD }}
63
+
64
+ - name: Extract metadata (tags, labels) for Docker
65
+ id: meta
66
+ uses: docker/metadata-action@9ec57ed1fcdbf14dcef7dfbe97b2010124a938b7
67
+ with:
68
+ images: |
69
+ ${{ steps.dockerhub.outputs.enabled == 'true' && 'mintplexlabs/anythingllm' || '' }}
70
+ tags: |
71
+ type=raw,value=dev
72
+
73
+ - name: Build and push multi-platform Docker image
74
+ uses: docker/build-push-action@v6
75
+ with:
76
+ context: .
77
+ file: ./docker/Dockerfile
78
+ push: true
79
+ sbom: true
80
+ provenance: mode=max
81
+ platforms: linux/amd64
82
+ # platforms: linux/amd64,linux/arm64
83
+ tags: ${{ steps.meta.outputs.tags }}
84
+ labels: ${{ steps.meta.outputs.labels }}
85
+ cache-from: type=gha
86
+ cache-to: type=gha,mode=max
87
+
88
+ # For Docker scout there are some intermediary reported CVEs which exists outside
89
+ # of execution content or are unreachable by an attacker but exist in image.
90
+ # We create VEX files for these so they don't show in scout summary.
91
+ - name: Collect known and verified CVE exceptions
92
+ id: cve-list
93
+ run: |
94
+ # Collect CVEs from filenames in vex folder
95
+ CVE_NAMES=""
96
+ for file in ./docker/vex/*.vex.json; do
97
+ [ -e "$file" ] || continue
98
+ filename=$(basename "$file")
99
+ stripped_filename=${filename%.vex.json}
100
+ CVE_NAMES+=" $stripped_filename"
101
+ done
102
+ echo "CVE_EXCEPTIONS=$CVE_NAMES" >> $GITHUB_OUTPUT
103
+ shell: bash
104
+
105
+ # About VEX attestations https://docs.docker.com/scout/explore/exceptions/
106
+ # Justifications https://github.com/openvex/spec/blob/main/OPENVEX-SPEC.md#status-justifications
107
+ # Fixed to use v1.15.1 of scout-cli as v1.16.0 install script is broken
108
+ # https://github.com/docker/scout-cli
109
+ - name: Add VEX attestations
110
+ env:
111
+ CVE_EXCEPTIONS: ${{ steps.cve-list.outputs.CVE_EXCEPTIONS }}
112
+ run: |
113
+ echo $CVE_EXCEPTIONS
114
+ curl -sSfL https://raw.githubusercontent.com/docker/scout-cli/main/install.sh | sh -s --
115
+ for cve in $CVE_EXCEPTIONS; do
116
+ for tag in "${{ join(fromJSON(steps.meta.outputs.json).tags, ' ') }}"; do
117
+ echo "Attaching VEX exception $cve to $tag"
118
+ docker scout attestation add \
119
+ --file "./docker/vex/$cve.vex.json" \
120
+ --predicate-type https://openvex.dev/ns/v0.2.0 \
121
+ $tag
122
+ done
123
+ done
124
+ shell: bash
.github/workflows/run-tests.yaml ADDED
@@ -0,0 +1,77 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ name: Run backend tests
2
+
3
+ concurrency:
4
+ group: build-${{ github.ref }}
5
+ cancel-in-progress: true
6
+
7
+ on:
8
+ pull_request:
9
+ types: [opened, synchronize, reopened]
10
+ paths:
11
+ - "server/**.js"
12
+ - "collector/**.js"
13
+
14
+ jobs:
15
+ run-script:
16
+ runs-on: ubuntu-latest
17
+
18
+ steps:
19
+ - name: Checkout repository
20
+ uses: actions/checkout@v2
21
+
22
+ - name: Set up Node.js
23
+ uses: actions/setup-node@v3
24
+ with:
25
+ node-version: '18'
26
+
27
+ - name: Cache root dependencies
28
+ uses: actions/cache@v3
29
+ with:
30
+ path: |
31
+ node_modules
32
+ ~/.cache/yarn
33
+ key: ${{ runner.os }}-yarn-root-${{ hashFiles('**/yarn.lock') }}
34
+ restore-keys: |
35
+ ${{ runner.os }}-yarn-root-
36
+
37
+ - name: Cache server dependencies
38
+ uses: actions/cache@v3
39
+ with:
40
+ path: |
41
+ server/node_modules
42
+ ~/.cache/yarn
43
+ key: ${{ runner.os }}-yarn-server-${{ hashFiles('server/yarn.lock') }}
44
+ restore-keys: |
45
+ ${{ runner.os }}-yarn-server-
46
+
47
+ - name: Cache collector dependencies
48
+ uses: actions/cache@v3
49
+ with:
50
+ path: |
51
+ collector/node_modules
52
+ ~/.cache/yarn
53
+ key: ${{ runner.os }}-yarn-collector-${{ hashFiles('collector/yarn.lock') }}
54
+ restore-keys: |
55
+ ${{ runner.os }}-yarn-collector-
56
+
57
+ - name: Install root dependencies
58
+ if: steps.cache-root.outputs.cache-hit != 'true'
59
+ run: yarn install --frozen-lockfile
60
+
61
+ - name: Install server dependencies
62
+ if: steps.cache-server.outputs.cache-hit != 'true'
63
+ run: cd server && yarn install --frozen-lockfile
64
+
65
+ - name: Install collector dependencies
66
+ if: steps.cache-collector.outputs.cache-hit != 'true'
67
+ run: cd collector && yarn install --frozen-lockfile
68
+
69
+ - name: Setup environment and Prisma
70
+ run: yarn setup:envs && yarn prisma:setup
71
+
72
+ - name: Run test suites
73
+ run: yarn test
74
+
75
+ - name: Fail job on error
76
+ if: failure()
77
+ run: exit 1
.github/workflows/sponsors.yaml ADDED
@@ -0,0 +1,44 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ name: Generate Sponsors README
2
+
3
+ on:
4
+ schedule:
5
+ - cron: "0 12 * * 3" # Run every Wednesday at 12:00 PM UTC
6
+
7
+ permissions:
8
+ contents: write
9
+ jobs:
10
+ deploy:
11
+ runs-on: ubuntu-latest
12
+ steps:
13
+ - name: Checkout 🛎️
14
+ uses: actions/checkout@v2
15
+
16
+ - name: Generate All Sponsors README
17
+ id: generate-all-sponsors
18
+ uses: JamesIves/github-sponsors-readme-action@v1
19
+ with:
20
+ token: ${{ secrets.SPONSOR_PAT }}
21
+ file: 'README.md'
22
+ organization: true
23
+ active-only: false
24
+ marker: 'all-sponsors'
25
+
26
+ - name: Commit and Push 🚀
27
+ uses: stefanzweifel/git-auto-commit-action@v5
28
+ id: auto-commit-action
29
+ with:
30
+ commit_message: 'Update Sponsors README'
31
+ file_pattern: 'README.md'
32
+
33
+ - name: Generate PR if changes detected
34
+ uses: peter-evans/create-pull-request@v7
35
+ if: steps.auto-commit-action.outputs.files_changed == 'true'
36
+ with:
37
+ token: ${{ secrets.GITHUB_TOKEN }}
38
+ title: 'Update Sponsors README'
39
+ branch: 'chore/update-sponsors'
40
+ base: 'master'
41
+ draft: false
42
+ reviewers: 'timothycarambat'
43
+ assignees: 'timothycarambat'
44
+ maintainer-can-modify: true
.gitignore ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ v-env
2
+ .env
3
+ !.env.example
4
+
5
+ node_modules
6
+ __pycache__
7
+ v-env
8
+ .DS_Store
9
+ aws_cf_deploy_anything_llm.json
10
+ yarn.lock
11
+ *.bak
12
+ .idea
.gitmodules ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ [submodule "browser-extension"]
2
+ path = browser-extension
3
+ url = https://github.com/Mintplex-Labs/anythingllm-extension.git
4
+ [submodule "embed"]
5
+ path = embed
6
+ url = https://github.com/Mintplex-Labs/anythingllm-embed.git
7
+ branch = main
.hadolint.yaml ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
 
1
+ failure-threshold: warning
2
+ ignored:
3
+ - DL3008
4
+ - DL3013
5
+ format: tty
6
+ trustedRegistries:
7
+ - docker.io
8
+ - gcr.io
.nvmrc ADDED
@@ -0,0 +1 @@
 
 
1
+ v18.18.0
.prettierignore ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # defaults
2
+ **/.git
3
+ **/.svn
4
+ **/.hg
5
+ **/node_modules
6
+
7
+ #frontend
8
+ frontend/bundleinspector.html
9
+ **/dist
10
+
11
+ #server
12
+ server/swagger/openapi.json
13
+ server/**/*.mjs
14
+
15
+ #embed
16
+ **/static/**
17
+ embed/src/utils/chat/hljs.js
.prettierrc ADDED
@@ -0,0 +1,38 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "tabWidth": 2,
3
+ "useTabs": false,
4
+ "endOfLine": "lf",
5
+ "semi": true,
6
+ "singleQuote": false,
7
+ "printWidth": 80,
8
+ "trailingComma": "es5",
9
+ "bracketSpacing": true,
10
+ "bracketSameLine": false,
11
+ "overrides": [
12
+ {
13
+ "files": ["*.js", "*.mjs", "*.jsx"],
14
+ "options": {
15
+ "parser": "flow",
16
+ "arrowParens": "always"
17
+ }
18
+ },
19
+ {
20
+ "files": ["*.config.js"],
21
+ "options": {
22
+ "semi": false,
23
+ "parser": "flow",
24
+ "trailingComma": "none"
25
+ }
26
+ },
27
+ {
28
+ "files": "*.html",
29
+ "options": {
30
+ "bracketSameLine": true
31
+ }
32
+ },
33
+ {
34
+ "files": ".prettierrc",
35
+ "options": { "parser": "json" }
36
+ }
37
+ ]
38
+ }
.vscode/launch.json ADDED
@@ -0,0 +1,74 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ // Use IntelliSense to learn about possible attributes.
3
+ // Hover to view descriptions of existing attributes.
4
+ // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
5
+ "version": "0.2.0",
6
+ "configurations": [
7
+ {
8
+ "name": "Collector debug",
9
+ "request": "launch",
10
+ "cwd": "${workspaceFolder}/collector",
11
+ "env": {
12
+ "NODE_ENV": "development"
13
+ },
14
+ "runtimeArgs": [
15
+ "index.js"
16
+ ],
17
+ // not using yarn/nodemon because it doesn't work with breakpoints
18
+ // "runtimeExecutable": "yarn",
19
+ "skipFiles": [
20
+ "<node_internals>/**"
21
+ ],
22
+ "type": "node"
23
+ },
24
+ {
25
+ "name": "Server debug",
26
+ "request": "launch",
27
+ "cwd": "${workspaceFolder}/server",
28
+ "env": {
29
+ "NODE_ENV": "development"
30
+ },
31
+ "runtimeArgs": [
32
+ "index.js"
33
+ ],
34
+ // not using yarn/nodemon because it doesn't work with breakpoints
35
+ // "runtimeExecutable": "yarn",
36
+ "skipFiles": [
37
+ "<node_internals>/**"
38
+ ],
39
+ "type": "node"
40
+ },
41
+ {
42
+ "name": "Frontend debug",
43
+ "request": "launch",
44
+ "cwd": "${workspaceFolder}/frontend",
45
+ "env": {
46
+ "NODE_ENV": "development",
47
+ },
48
+ "runtimeExecutable": "${workspaceFolder}/frontend/node_modules/.bin/vite",
49
+ "runtimeArgs": [
50
+ "--debug",
51
+ "--host=0.0.0.0"
52
+ ],
53
+ // "runtimeExecutable": "yarn",
54
+ "skipFiles": [
55
+ "<node_internals>/**"
56
+ ],
57
+ "type": "node"
58
+ },
59
+ {
60
+ "name": "Launch Edge",
61
+ "request": "launch",
62
+ "type": "msedge",
63
+ "url": "http://localhost:3000",
64
+ "webRoot": "${workspaceFolder}"
65
+ },
66
+ {
67
+ "type": "chrome",
68
+ "request": "launch",
69
+ "name": "Launch Chrome against localhost",
70
+ "url": "http://localhost:3000",
71
+ "webRoot": "${workspaceFolder}"
72
+ }
73
+ ]
74
+ }
.vscode/settings.json ADDED
@@ -0,0 +1,63 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "cSpell.words": [
3
+ "adoc",
4
+ "aibitat",
5
+ "AIbitat",
6
+ "allm",
7
+ "anythingllm",
8
+ "Apipie",
9
+ "Astra",
10
+ "Chartable",
11
+ "cleancss",
12
+ "comkey",
13
+ "cooldown",
14
+ "cooldowns",
15
+ "datafile",
16
+ "Deduplicator",
17
+ "Dockerized",
18
+ "docpath",
19
+ "elevenlabs",
20
+ "Embeddable",
21
+ "epub",
22
+ "fireworksai",
23
+ "GROQ",
24
+ "hljs",
25
+ "huggingface",
26
+ "inferencing",
27
+ "koboldcpp",
28
+ "Langchain",
29
+ "lmstudio",
30
+ "localai",
31
+ "mbox",
32
+ "Milvus",
33
+ "Mintplex",
34
+ "mixtral",
35
+ "moderations",
36
+ "novita",
37
+ "numpages",
38
+ "Ollama",
39
+ "Oobabooga",
40
+ "openai",
41
+ "opendocument",
42
+ "openrouter",
43
+ "pagerender",
44
+ "ppio",
45
+ "Qdrant",
46
+ "royalblue",
47
+ "SearchApi",
48
+ "searxng",
49
+ "Serper",
50
+ "Serply",
51
+ "streamable",
52
+ "textgenwebui",
53
+ "togetherai",
54
+ "Unembed",
55
+ "uuidv",
56
+ "vectordbs",
57
+ "Weaviate",
58
+ "XAILLM",
59
+ "Zilliz"
60
+ ],
61
+ "eslint.experimental.useFlatConfig": true,
62
+ "docker.languageserver.formatter.ignoreMultilineInstructions": true
63
+ }
.vscode/tasks.json ADDED
@@ -0,0 +1,94 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ // See https://go.microsoft.com/fwlink/?LinkId=733558
3
+ // for the documentation about the tasks.json format
4
+ "version": "2.0.0",
5
+ "tasks": [
6
+ {
7
+ "type": "shell",
8
+ "options": {
9
+ "cwd": "${workspaceFolder}/collector",
10
+ "statusbar": {
11
+ "color": "#ffea00",
12
+ "detail": "Runs the collector",
13
+ "label": "Collector: $(play) run",
14
+ "running": {
15
+ "color": "#ffea00",
16
+ "label": "Collector: $(gear~spin) running"
17
+ }
18
+ }
19
+ },
20
+ "command": "cd ${workspaceFolder}/collector/ && yarn dev",
21
+ "runOptions": {
22
+ "instanceLimit": 1,
23
+ "reevaluateOnRerun": true
24
+ },
25
+ "presentation": {
26
+ "echo": true,
27
+ "reveal": "always",
28
+ "focus": false,
29
+ "panel": "shared",
30
+ "showReuseMessage": true,
31
+ "clear": false
32
+ },
33
+ "label": "Collector: run"
34
+ },
35
+ {
36
+ "type": "shell",
37
+ "options": {
38
+ "cwd": "${workspaceFolder}/server",
39
+ "statusbar": {
40
+ "color": "#ffea00",
41
+ "detail": "Runs the server",
42
+ "label": "Server: $(play) run",
43
+ "running": {
44
+ "color": "#ffea00",
45
+ "label": "Server: $(gear~spin) running"
46
+ }
47
+ }
48
+ },
49
+ "command": "if [ \"${CODESPACES}\" = \"true\" ]; then while ! gh codespace ports -c $CODESPACE_NAME | grep 3001; do sleep 1; done; gh codespace ports visibility 3001:public -c $CODESPACE_NAME; fi & cd ${workspaceFolder}/server/ && yarn dev",
50
+ "runOptions": {
51
+ "instanceLimit": 1,
52
+ "reevaluateOnRerun": true
53
+ },
54
+ "presentation": {
55
+ "echo": true,
56
+ "reveal": "always",
57
+ "focus": false,
58
+ "panel": "shared",
59
+ "showReuseMessage": true,
60
+ "clear": false
61
+ },
62
+ "label": "Server: run"
63
+ },
64
+ {
65
+ "type": "shell",
66
+ "options": {
67
+ "cwd": "${workspaceFolder}/frontend",
68
+ "statusbar": {
69
+ "color": "#ffea00",
70
+ "detail": "Runs the frontend",
71
+ "label": "Frontend: $(play) run",
72
+ "running": {
73
+ "color": "#ffea00",
74
+ "label": "Frontend: $(gear~spin) running"
75
+ }
76
+ }
77
+ },
78
+ "command": "cd ${workspaceFolder}/frontend/ && yarn dev",
79
+ "runOptions": {
80
+ "instanceLimit": 1,
81
+ "reevaluateOnRerun": true
82
+ },
83
+ "presentation": {
84
+ "echo": true,
85
+ "reveal": "always",
86
+ "focus": false,
87
+ "panel": "shared",
88
+ "showReuseMessage": true,
89
+ "clear": false
90
+ },
91
+ "label": "Frontend: run"
92
+ }
93
+ ]
94
+ }
BARE_METAL.md ADDED
@@ -0,0 +1,147 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Run AnythingLLM in production without Docker
2
+
3
+ > [!WARNING]
4
+ > This method of deployment is **not supported** by the core-team and is to be used as a reference for your deployment.
5
+ > You are fully responsible for securing your deployment and data in this mode.
6
+ > **Any issues** experienced from bare-metal or non-containerized deployments will be **not** answered or supported.
7
+
8
+ Here you can find the scripts and known working process to run AnythingLLM outside of a Docker container.
9
+
10
+ ### Minimum Requirements
11
+ > [!TIP]
12
+ > You should aim for at least 2GB of RAM. Disk storage is proportional to however much data
13
+ > you will be storing (documents, vectors, models, etc). Minimum 10GB recommended.
14
+
15
+ - NodeJS v18
16
+ - Yarn
17
+
18
+
19
+ ## Getting started
20
+
21
+ 1. Clone the repo into your server as the user who the application will run as.
22
+ `git clone git@github.com:Mintplex-Labs/anything-llm.git`
23
+
24
+ 2. `cd anything-llm` and run `yarn setup`. This will install all dependencies to run in production as well as debug the application.
25
+
26
+ 3. `cp server/.env.example server/.env` to create the basic ENV file for where instance settings will be read from on service start.
27
+
28
+ 4. Ensure that the `server/.env` file has _at least_ these keys to start. These values will persist and this file will be automatically written and managed after your first successful boot.
29
+ ```
30
+ STORAGE_DIR="/your/absolute/path/to/server/storage"
31
+ ```
32
+
33
+ 5. Edit the `frontend/.env` file for the `VITE_BASE_API` to now be set to `/api`. This is documented in the .env for which one you should use.
34
+ ```
35
+ # VITE_API_BASE='http://localhost:3001/api' # Use this URL when developing locally
36
+ # VITE_API_BASE="https://$CODESPACE_NAME-3001.$GITHUB_CODESPACES_PORT_FORWARDING_DOMAIN/api" # for GitHub Codespaces
37
+ VITE_API_BASE='/api' # Use this URL deploying on non-localhost address OR in docker.
38
+ ```
39
+
40
+ ## To start the application
41
+
42
+ AnythingLLM is comprised of three main sections. The `frontend`, `server`, and `collector`. When running in production you will be running `server` and `collector` on two different processes, with a build step for compilation of the frontend.
43
+
44
+ 1. Build the frontend application.
45
+ `cd frontend && yarn build` - this will produce a `frontend/dist` folder that will be used later.
46
+
47
+ 2. Copy `frontend/dist` to `server/public` - `cp -R frontend/dist server/public`.
48
+ This should create a folder in `server` named `public` which contains a top level `index.html` file and various other files/folders.
49
+
50
+ 3. Migrate and prepare your database file.
51
+ ```
52
+ cd server && npx prisma generate --schema=./prisma/schema.prisma
53
+ cd server && npx prisma migrate deploy --schema=./prisma/schema.prisma
54
+ ```
55
+
56
+ 4. Boot the server in production
57
+ `cd server && NODE_ENV=production node index.js &`
58
+
59
+ 5. Boot the collection in another process
60
+ `cd collector && NODE_ENV=production node index.js &`
61
+
62
+ AnythingLLM should now be running on `http://localhost:3001`!
63
+
64
+ ## Updating AnythingLLM
65
+
66
+ To update AnythingLLM with future updates you can `git pull origin master` to pull in the latest code and then repeat steps 2 - 5 to deploy with all changes fully.
67
+
68
+ _note_ You should ensure that each folder runs `yarn` again to ensure packages are up to date in case any dependencies were added, changed, or removed.
69
+
70
+ _note_ You should `pkill node` before running an update so that you are not running multiple AnythingLLM processes on the same instance as this can cause conflicts.
71
+
72
+
73
+ ### Example update script
74
+
75
+ ```shell
76
+ #!/bin/bash
77
+
78
+ cd $HOME/anything-llm &&\
79
+ git checkout . &&\
80
+ git pull origin master &&\
81
+ echo "HEAD pulled to commit $(git log -1 --pretty=format:"%h" | tail -n 1)"
82
+
83
+ echo "Freezing current ENVs"
84
+ curl -I "http://localhost:3001/api/env-dump" | head -n 1|cut -d$' ' -f2
85
+
86
+ echo "Rebuilding Frontend"
87
+ cd $HOME/anything-llm/frontend && yarn && yarn build && cd $HOME/anything-llm
88
+
89
+ echo "Copying to Server Public"
90
+ rm -rf server/public
91
+ cp -r frontend/dist server/public
92
+
93
+ echo "Killing node processes"
94
+ pkill node
95
+
96
+ echo "Installing collector dependencies"
97
+ cd $HOME/anything-llm/collector && yarn
98
+
99
+ echo "Installing server dependencies & running migrations"
100
+ cd $HOME/anything-llm/server && yarn
101
+ cd $HOME/anything-llm/server && npx prisma migrate deploy --schema=./prisma/schema.prisma
102
+ cd $HOME/anything-llm/server && npx prisma generate
103
+
104
+ echo "Booting up services."
105
+ truncate -s 0 /logs/server.log # Or any other log file location.
106
+ truncate -s 0 /logs/collector.log
107
+
108
+ cd $HOME/anything-llm/server
109
+ (NODE_ENV=production node index.js) &> /logs/server.log &
110
+
111
+ cd $HOME/anything-llm/collector
112
+ (NODE_ENV=production node index.js) &> /logs/collector.log &
113
+ ```
114
+
115
+ ## Using Nginx?
116
+
117
+ If you are using Nginx, you can use the following example configuration to proxy the requests to the server. Chats for streaming require **websocket** connections, so you need to ensure that the Nginx configuration is set up to support websockets. You can do this with a simple reverse proxy configuration.
118
+
119
+ ```nginx
120
+ server {
121
+ # Enable websocket connections for agent protocol.
122
+ location ~* ^/api/agent-invocation/(.*) {
123
+ proxy_pass http://0.0.0.0:3001;
124
+ proxy_http_version 1.1;
125
+ proxy_set_header Upgrade $http_upgrade;
126
+ proxy_set_header Connection "Upgrade";
127
+ }
128
+
129
+ listen 80;
130
+ server_name [insert FQDN here];
131
+ location / {
132
+ # Prevent timeouts on long-running requests.
133
+ proxy_connect_timeout 605;
134
+ proxy_send_timeout 605;
135
+ proxy_read_timeout 605;
136
+ send_timeout 605;
137
+ keepalive_timeout 605;
138
+
139
+ # Enable readable HTTP Streaming for LLM streamed responses
140
+ proxy_buffering off;
141
+ proxy_cache off;
142
+
143
+ # Proxy your locally running service
144
+ proxy_pass http://0.0.0.0:3001;
145
+ }
146
+ }
147
+ ```
CONTRIBUTING.md ADDED
@@ -0,0 +1,105 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Contributing to AnythingLLM
2
+
3
+ AnythingLLM is an open-source project and we welcome contributions from the community.
4
+
5
+ ## Reporting Issues
6
+
7
+ If you encounter a bug or have a feature request, please open an issue on the
8
+ [GitHub issue tracker](https://github.com/mintplex-labs/anything-llm).
9
+
10
+ ## Picking an issue
11
+
12
+ We track issues on the GitHub issue tracker. If you are looking for something to
13
+ work on, check the [good first issue](https://github.com/mintplex-labs/anything-llm/contribute) label. These issues are typically the best described and have the smallest scope. There may be issues that are not labeled as good first issue, but are still a good starting point.
14
+
15
+ If there's an issue you are interested in working on, please leave a comment on the issue. This will help us avoid duplicate work. Additionally, if you have questions about the issue, please ask them in the issue comments. We are happy to provide guidance on how to approach the issue.
16
+
17
+ ## Before you start
18
+
19
+ Keep in mind that we are a small team and have limited resources. We will do our best to review and merge your PRs, but please be patient. Ultimately, **we become the maintainer** of your changes. It is our responsibility to make sure that the changes are working as expected and are of high quality as well as being compatible with the rest of the project both for existing users and for future users & features.
20
+
21
+ Before you start working on an issue, please read the following so that you don't waste time on something that is not a good fit for the project or is more suitable for a personal fork. We would rather answer a comment on an issue than close a PR after you've spent time on it. Your time is valuable and we appreciate your time and effort to make AnythingLLM better.
22
+
23
+ 0. (most important) If you are making a PR that does not have a corresponding issue, **it will not be merged.** _The only exception to this is language translations._
24
+
25
+ 1. If you are modifying the permission system for a new role or something custom, you are likely better off forking the project and building your own version since this is a core part of the project and is only to be maintained by the AnythingLLM team.
26
+
27
+ 2. Integrations (LLM, Vector DB, etc.) are reviewed at our discretion. We will eventually get to them. Do not expect us to merge your integration PR instantly since there are often many moving parts and we want to make sure we get it right. We will get to it!
28
+
29
+ 3. It is our discretion to merge or not merge a PR. We value every contribution, but we also value the quality of the code and the user experience we envision for the project. It is a fine line to walk when running a project like this and please understand that merging or not merging a PR is not a reflection of the quality of the contribution and is not personal. We will do our best to provide feedback on the PR and help you make the changes necessary to get it merged.
30
+
31
+ 4. **Security** is always important. If you have a security concern, please do not open an issue. Instead, please open a CVE on our designated reporting platform [Huntr](https://huntr.com) or contact us at [team@mintplexlabs.com](mailto:team@mintplexlabs.com).
32
+
33
+ ## Configuring Git
34
+
35
+ First, fork the repository on GitHub, then clone your fork:
36
+
37
+ ```bash
38
+ git clone https://github.com/<username>/anything-llm.git
39
+ cd anything-llm
40
+ ```
41
+
42
+ Then add the main repository as a remote:
43
+
44
+ ```bash
45
+ git remote add upstream https://github.com/mintplex-labs/anything-llm.git
46
+ git fetch upstream
47
+ ```
48
+
49
+ ## Setting up your development environment
50
+
51
+ In the root of the repository, run:
52
+
53
+ ```bash
54
+ yarn setup
55
+ ```
56
+
57
+ This will install the dependencies, set up the proper and expected ENV files for the project, and run the prisma setup script.
58
+ Next, run:
59
+
60
+ ```bash
61
+ yarn dev:all
62
+ ```
63
+ This will start the server, frontend, and collector in development mode. Changes to the code will be hot reloaded.
64
+
65
+ ## Best practices for pull requests
66
+
67
+ For the best chance of having your pull request accepted, please follow these guidelines:
68
+
69
+ 1. Unit test all bug fixes and new features. Your code will not be merged if it
70
+ doesn't have tests.
71
+ 1. If you change the public API, update the documentation in the `anythingllm-docs` repository.
72
+ 1. Aim to minimize the number of changes in each pull request. Keep to solving
73
+ one problem at a time, when possible.
74
+ 1. Before marking a pull request ready-for-review, do a self review of your code.
75
+ Is it clear why you are making the changes? Are the changes easy to understand?
76
+ 1. Use [conventional commit messages](https://www.conventionalcommits.org/en/) as pull request titles. Examples:
77
+ * New feature: `feat: adding foo API`
78
+ * Bug fix: `fix: issue with foo API`
79
+ * Documentation change: `docs: adding foo API documentation`
80
+ 1. If your pull request is a work in progress, leave the pull request as a draft.
81
+ We will assume the pull request is ready for review when it is opened.
82
+ 1. When writing tests, test the error cases. Make sure they have understandable
83
+ error messages.
84
+
85
+ ## Project structure
86
+
87
+ The core library is written in Node.js. There are additional sub-repositories for the embed widget and browser extension. These are not part of the core AnythingLLM project, but are maintained by the AnythingLLM team.
88
+
89
+ * `server`: Node.js server source code
90
+ * `frontend`: React frontend source code
91
+ * `collector`: Python collector source code
92
+
93
+ ## Release process
94
+
95
+ Changes to the core AnythingLLM project are released through the `master` branch. When a PR is merged into `master`, a new version of the package is published to Docker and GitHub Container Registry under the `latest` tag.
96
+
97
+ When a new version is released, the following steps are taken a new image is built and pushed to Docker Hub and GitHub Container Registry under the assoicated version tag. Version tags are of the format `v<major>.<minor>.<patch>` and are pinned code, while `latest` is the latest version of the code at any point in time.
98
+
99
+ ### Desktop propogation
100
+
101
+ Changes to the desktop app are downstream of the core AnythingLLM project. Releases of the desktop app are published at the same time as the core AnythingLLM project. Code from the core AnythingLLM project is copied into the desktop app into an Electron wrapper. The Electron wrapper that wraps around the core AnythingLLM project is **not** part of the core AnythingLLM project, but is maintained by the AnythingLLM team.
102
+
103
+ ## License
104
+
105
+ By contributing to AnythingLLM (this repository), you agree to license your contributions under the MIT license.
LICENSE ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ The MIT License
2
+
3
+ Copyright (c) Mintplex Labs Inc.
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
SECURITY.md ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Security Policy
2
+
3
+ ## Supported Versions
4
+
5
+ Use this section to tell people about which versions of your project are
6
+ currently being supported with security updates.
7
+
8
+ | Version | Supported |
9
+ | ------- | ------------------ |
10
+ | 0.1.x | :white_check_mark: |
11
+
12
+
13
+ ## Reporting a Vulnerability
14
+
15
+ If a security concern is found that you would like to disclose you can create a PR for it or if you would like to clear this issue before posting you can email [Core Mintplex Labs Team](mailto:team@mintplexlabs.com).
cloud-deployments/aws/cloudformation/DEPLOY.md ADDED
@@ -0,0 +1,49 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # How to deploy a private AnythingLLM instance on AWS
2
+
3
+ With an AWS account you can easily deploy a private AnythingLLM instance on AWS. This will create a url that you can access from any browser over HTTP (HTTPS not supported). This single instance will run on your own keys and they will not be exposed - however if you want your instance to be protected it is highly recommend that you set a password once setup is complete.
4
+
5
+ **Quick Launch (EASY)**
6
+ 1. Log in to your AWS account
7
+ 2. Open [CloudFormation](https://us-west-1.console.aws.amazon.com/cloudformation/home)
8
+ 3. Ensure you are deploying in a geographic zone that is nearest to your physical location to reduce latency.
9
+ 4. Click `Create Stack`
10
+
11
+ ![Create Stack](../../../images/screenshots/create_stack.png)
12
+
13
+ 5. Use the file `cloudformation_create_anythingllm.json` as your JSON template.
14
+
15
+ ![Upload Stack](../../../images/screenshots/upload.png)
16
+
17
+ 6. Click Deploy.
18
+ 7. Wait for stack events to finish and be marked as `Completed`
19
+ 8. View `Outputs` tab.
20
+
21
+ ![Stack Output](../../../images/screenshots/cf_outputs.png)
22
+
23
+ 9. Wait for all resources to be built. Now wait until instance is available on `[InstanceIP]:3001`.
24
+ This process may take up to 10 minutes. See **Note** below on how to visualize this process.
25
+
26
+ The output of this cloudformation stack will be:
27
+ - 1 EC2 Instance
28
+ - 1 Security Group with 0.0.0.0/0 access on port 3001
29
+ - 1 EC2 Instance Volume `gb2` of 10Gib minimum - customizable pre-deploy.
30
+
31
+ **Requirements**
32
+ - An AWS account with billing information.
33
+
34
+ ## Please read this notice before submitting issues about your deployment
35
+
36
+ **Note:**
37
+ Your instance will not be available instantly. Depending on the instance size you launched with it can take 5-10 minutes to fully boot up.
38
+
39
+ If you want to check the instance's progress, navigate to [your deployed EC2 instances](https://us-west-1.console.aws.amazon.com/ec2/home) and connect to your instance via SSH in browser.
40
+
41
+ Once connected run `sudo tail -f /var/log/cloud-init-output.log` and wait for the file to conclude deployment of the docker image.
42
+ You should see an output like this
43
+ ```
44
+ [+] Running 2/2
45
+ ⠿ Network docker_anything-llm Created
46
+ ⠿ Container anything-llm Started
47
+ ```
48
+
49
+ Additionally, your use of this deployment process means you are responsible for any costs of these AWS resources fully.
cloud-deployments/aws/cloudformation/aws_https_instructions.md ADDED
@@ -0,0 +1,118 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # How to Configure HTTPS for Anything LLM AWS private deployment
2
+ Instructions for manual https configuration after generating and running the aws cloudformation template (aws_build_from_source_no_credentials.json). Tested on following browsers: Firefox version 119, Chrome version 118, Edge 118.
3
+
4
+ **Requirements**
5
+ - Successful deployment of Amazon Linux 2023 EC2 instance with Docker container running Anything LLM
6
+ - Admin priv to configure Elastic IP for EC2 instance via AWS Management Console UI
7
+ - Admin priv to configure DNS services (i.e. AWS Route 53) via AWS Management Console UI
8
+ - Admin priv to configure EC2 Security Group rules via AWS Management Console UI
9
+
10
+ ## Step 1: Allocate and assign Elastic IP Address to your deployed EC2 instance
11
+ 1. Follow AWS instructions on allocating EIP here: https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/elastic-ip-addresses-eip.html#using-instance-addressing-eips-allocating
12
+ 2. Follow AWS instructions on assigning EIP to EC2 instance here: https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/elastic-ip-addresses-eip.html#using-instance-addressing-eips-associating
13
+
14
+ ## Step 2: Configure DNS A record to resolve to the previously assigned EC2 instance via EIP
15
+ These instructions assume that you already have a top-level domain configured and are using a subdomain
16
+ to access AnythingLLM.
17
+ 1. Follow AWS instructions on routing traffic to EC2 instance here: https://docs.aws.amazon.com/Route53/latest/DeveloperGuide/routing-to-ec2-instance.html
18
+
19
+ ## Step 3: Install and enable nginx
20
+ These instructions are for CLI configuration and assume you are logged in to EC2 instance as the ec2-user.
21
+ 1. $sudo yum install nginx -y
22
+ 2. $sudo systemctl enable nginx && sudo systemctl start nginx
23
+
24
+ ## Step 4: Install certbot
25
+ These instructions are for CLI configuration and assume you are logged in to EC2 instance as the ec2-user.
26
+ 1. $sudo yum install -y augeas-libs
27
+ 2. $sudo python3 -m venv /opt/certbot/
28
+ 3. $sudo /opt/certbot/bin/pip install --upgrade pip
29
+ 4. $sudo /opt/certbot/bin/pip install certbot certbot-nginx
30
+ 5. $sudo ln -s /opt/certbot/bin/certbot /usr/bin/certbot
31
+
32
+ ## Step 5: Configure temporary Inbound Traffic Rule for Security Group to certbot DNS verification
33
+ 1. Follow AWS instructions on creating inbound rule (http port 80 0.0.0.0/0) for EC2 security group here: https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/working-with-security-groups.html#adding-security-group-rule
34
+
35
+ ## Step 6: Comment out default http NGINX proxy configuration
36
+ These instructions are for CLI configuration and assume you are logged in to EC2 instance as the ec2-user.
37
+ 1. $sudo vi /etc/nginx/nginx.conf
38
+ 2. In the nginx.conf file, comment out the default server block configuration for http/port 80. It should look something like the following:
39
+ ```
40
+ # server {
41
+ # listen 80;
42
+ # listen [::]:80;
43
+ # server_name _;
44
+ # root /usr/share/nginx/html;
45
+ #
46
+ # # Load configuration files for the default server block.
47
+ # include /etc/nginx/default.d/*.conf;
48
+ #
49
+ # error_page 404 /404.html;
50
+ # location = /404.html {
51
+ # }
52
+ #
53
+ # error_page 500 502 503 504 /50x.html;
54
+ # location = /50x.html {
55
+ # }
56
+ # }
57
+ ```
58
+ 3. Enter ':wq' to save the changes to the nginx default config
59
+
60
+ ## Step 7: Create simple http proxy configuration for AnythingLLM
61
+ These instructions are for CLI configuration and assume you are logged in to EC2 instance as the ec2-user.
62
+ 1. $sudo vi /etc/nginx/conf.d/anything.conf
63
+ 2. Add the following configuration ensuring that you add your FQDN:.
64
+
65
+ ```
66
+ server {
67
+ # Enable websocket connections for agent protocol.
68
+ location ~* ^/api/agent-invocation/(.*) {
69
+ proxy_pass http://0.0.0.0:3001;
70
+ proxy_http_version 1.1;
71
+ proxy_set_header Upgrade $http_upgrade;
72
+ proxy_set_header Connection "Upgrade";
73
+ }
74
+
75
+ listen 80;
76
+ server_name [insert FQDN here];
77
+ location / {
78
+ # Prevent timeouts on long-running requests.
79
+ proxy_connect_timeout 605;
80
+ proxy_send_timeout 605;
81
+ proxy_read_timeout 605;
82
+ send_timeout 605;
83
+ keepalive_timeout 605;
84
+
85
+ # Enable readable HTTP Streaming for LLM streamed responses
86
+ proxy_buffering off;
87
+ proxy_cache off;
88
+
89
+ # Proxy your locally running service
90
+ proxy_pass http://0.0.0.0:3001;
91
+ }
92
+ }
93
+ ```
94
+ 3. Enter ':wq' to save the changes to the anything config file
95
+
96
+ ## Step 8: Test nginx http proxy config and restart nginx service
97
+ These instructions are for CLI configuration and assume you are logged in to EC2 instance as the ec2-user.
98
+ 1. $sudo nginx -t
99
+ 2. $sudo systemctl restart nginx
100
+ 3. Navigate to http://FQDN in a browser and you should be proxied to the AnythingLLM web UI.
101
+
102
+ ## Step 9: Generate/install cert
103
+ These instructions are for CLI configuration and assume you are logged in to EC2 instance as the ec2-user.
104
+ 1. $sudo certbot --nginx -d [Insert FQDN here]
105
+ Example command: $sudo certbot --nginx -d anythingllm.exampleorganization.org
106
+ This command will generate the appropriate certificate files, write the files to /etc/letsencrypt/live/yourFQDN, and make updates to the nginx
107
+ configuration file for anythingllm located at /etc/nginx/conf.d/anything.llm
108
+ 3. Enter the email address you would like to use for updates.
109
+ 4. Accept the terms of service.
110
+ 5. Accept or decline to receive communication from LetsEncrypt.
111
+
112
+ ## Step 10: Test Cert installation
113
+ 1. $sudo cat /etc/nginx/conf.d/anything.conf
114
+ Your should see a completely updated configuration that includes https/443 and a redirect configuration for http/80.
115
+ 2. Navigate to https://FQDN in a browser and you should be proxied to the AnythingLLM web UI.
116
+
117
+ ## Step 11: (Optional) Remove temporary Inbound Traffic Rule for Security Group to certbot DNS verification
118
+ 1. Follow AWS instructions on deleting inbound rule (http port 80 0.0.0.0/0) for EC2 security group here: https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/working-with-security-groups.html#deleting-security-group-rule
cloud-deployments/aws/cloudformation/cloudformation_create_anythingllm.json ADDED
@@ -0,0 +1,234 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "AWSTemplateFormatVersion": "2010-09-09",
3
+ "Description": "Create a stack that runs AnythingLLM on a single instance",
4
+ "Parameters": {
5
+ "InstanceType": {
6
+ "Description": "EC2 instance type",
7
+ "Type": "String",
8
+ "Default": "t3.small"
9
+ },
10
+ "InstanceVolume": {
11
+ "Description": "Storage size of disk on Instance in GB",
12
+ "Type": "Number",
13
+ "Default": 10,
14
+ "MinValue": 4
15
+ }
16
+ },
17
+ "Resources": {
18
+ "AnythingLLMInstance": {
19
+ "Type": "AWS::EC2::Instance",
20
+ "Properties": {
21
+ "ImageId": {
22
+ "Fn::FindInMap": [
23
+ "Region2AMI",
24
+ {
25
+ "Ref": "AWS::Region"
26
+ },
27
+ "AMI"
28
+ ]
29
+ },
30
+ "InstanceType": {
31
+ "Ref": "InstanceType"
32
+ },
33
+ "SecurityGroupIds": [
34
+ {
35
+ "Ref": "AnythingLLMInstanceSecurityGroup"
36
+ }
37
+ ],
38
+ "BlockDeviceMappings": [
39
+ {
40
+ "DeviceName": {
41
+ "Fn::FindInMap": [
42
+ "Region2AMI",
43
+ {
44
+ "Ref": "AWS::Region"
45
+ },
46
+ "RootDeviceName"
47
+ ]
48
+ },
49
+ "Ebs": {
50
+ "VolumeSize": {
51
+ "Ref": "InstanceVolume"
52
+ }
53
+ }
54
+ }
55
+ ],
56
+ "UserData": {
57
+ "Fn::Base64": {
58
+ "Fn::Join": [
59
+ "",
60
+ [
61
+ "Content-Type: multipart/mixed; boundary=\"//\"\n",
62
+ "MIME-Version: 1.0\n",
63
+ "\n",
64
+ "--//\n",
65
+ "Content-Type: text/cloud-config; charset=\"us-ascii\"\n",
66
+ "MIME-Version: 1.0\n",
67
+ "Content-Transfer-Encoding: 7bit\n",
68
+ "Content-Disposition: attachment; filename=\"cloud-config.txt\"\n",
69
+ "\n",
70
+ "\n",
71
+ "#cloud-config\n",
72
+ "cloud_final_modules:\n",
73
+ "- [scripts-user, once-per-instance]\n",
74
+ "\n",
75
+ "\n",
76
+ "--//\n",
77
+ "Content-Type: text/x-shellscript; charset=\"us-ascii\"\n",
78
+ "MIME-Version: 1.0\n",
79
+ "Content-Transfer-Encoding: 7bit\n",
80
+ "Content-Disposition: attachment; filename=\"userdata.txt\"\n",
81
+ "\n",
82
+ "\n",
83
+ "#!/bin/bash\n",
84
+ "# check output of userdata script with sudo tail -f /var/log/cloud-init-output.log\n",
85
+ "sudo yum install docker iptables -y\n",
86
+ "sudo iptables -A OUTPUT -m owner ! --uid-owner root -d 169.254.169.254 -j DROP\n",
87
+ "sudo systemctl enable docker\n",
88
+ "sudo systemctl start docker\n",
89
+ "mkdir -p /home/ec2-user/anythingllm\n",
90
+ "touch /home/ec2-user/anythingllm/.env\n",
91
+ "sudo chown ec2-user:ec2-user -R /home/ec2-user/anythingllm\n",
92
+ "docker pull mintplexlabs/anythingllm\n",
93
+ "docker run -d -p 3001:3001 --cap-add SYS_ADMIN -v /home/ec2-user/anythingllm:/app/server/storage -v /home/ec2-user/anythingllm/.env:/app/server/.env -e STORAGE_DIR=\"/app/server/storage\" mintplexlabs/anythingllm\n",
94
+ "echo \"Container ID: $(sudo docker ps --latest --quiet)\"\n",
95
+ "export ONLINE=$(curl -Is http://localhost:3001/api/ping | head -n 1|cut -d$' ' -f2)\n",
96
+ "echo \"Health check: $ONLINE\"\n",
97
+ "echo \"Setup complete! AnythingLLM instance is now online!\"\n",
98
+ "\n",
99
+ "--//--\n"
100
+ ]
101
+ ]
102
+ }
103
+ }
104
+ }
105
+ },
106
+ "AnythingLLMInstanceSecurityGroup": {
107
+ "Type": "AWS::EC2::SecurityGroup",
108
+ "Properties": {
109
+ "GroupDescription": "AnythingLLM Instance Security Group",
110
+ "SecurityGroupIngress": [
111
+ {
112
+ "IpProtocol": "tcp",
113
+ "FromPort": "22",
114
+ "ToPort": "22",
115
+ "CidrIp": "0.0.0.0/0"
116
+ },
117
+ {
118
+ "IpProtocol": "tcp",
119
+ "FromPort": "3001",
120
+ "ToPort": "3001",
121
+ "CidrIp": "0.0.0.0/0"
122
+ },
123
+ {
124
+ "IpProtocol": "tcp",
125
+ "FromPort": "3001",
126
+ "ToPort": "3001",
127
+ "CidrIpv6": "::/0"
128
+ }
129
+ ]
130
+ }
131
+ }
132
+ },
133
+ "Outputs": {
134
+ "ServerIp": {
135
+ "Description": "IP address of the AnythingLLM instance",
136
+ "Value": {
137
+ "Fn::GetAtt": [
138
+ "AnythingLLMInstance",
139
+ "PublicIp"
140
+ ]
141
+ }
142
+ },
143
+ "ServerURL": {
144
+ "Description": "URL of the AnythingLLM server",
145
+ "Value": {
146
+ "Fn::Join": [
147
+ "",
148
+ [
149
+ "http://",
150
+ {
151
+ "Fn::GetAtt": [
152
+ "AnythingLLMInstance",
153
+ "PublicIp"
154
+ ]
155
+ },
156
+ ":3001"
157
+ ]
158
+ ]
159
+ }
160
+ }
161
+ },
162
+ "Mappings": {
163
+ "Region2AMI": {
164
+ "ap-south-1": {
165
+ "AMI": "ami-0e6329e222e662a52",
166
+ "RootDeviceName": "/dev/xvda"
167
+ },
168
+ "eu-north-1": {
169
+ "AMI": "ami-08c308b1bb265e927",
170
+ "RootDeviceName": "/dev/xvda"
171
+ },
172
+ "eu-west-3": {
173
+ "AMI": "ami-069d1ea6bc64443f0",
174
+ "RootDeviceName": "/dev/xvda"
175
+ },
176
+ "eu-west-2": {
177
+ "AMI": "ami-06a566ca43e14780d",
178
+ "RootDeviceName": "/dev/xvda"
179
+ },
180
+ "eu-west-1": {
181
+ "AMI": "ami-0a8dc52684ee2fee2",
182
+ "RootDeviceName": "/dev/xvda"
183
+ },
184
+ "ap-northeast-3": {
185
+ "AMI": "ami-0c8a89b455fae8513",
186
+ "RootDeviceName": "/dev/xvda"
187
+ },
188
+ "ap-northeast-2": {
189
+ "AMI": "ami-0ff56409a6e8ea2a0",
190
+ "RootDeviceName": "/dev/xvda"
191
+ },
192
+ "ap-northeast-1": {
193
+ "AMI": "ami-0ab0bbbd329f565e6",
194
+ "RootDeviceName": "/dev/xvda"
195
+ },
196
+ "ca-central-1": {
197
+ "AMI": "ami-033c256a10931f206",
198
+ "RootDeviceName": "/dev/xvda"
199
+ },
200
+ "sa-east-1": {
201
+ "AMI": "ami-0dabf4dab6b183eef",
202
+ "RootDeviceName": "/dev/xvda"
203
+ },
204
+ "ap-southeast-1": {
205
+ "AMI": "ami-0dc5785603ad4ff54",
206
+ "RootDeviceName": "/dev/xvda"
207
+ },
208
+ "ap-southeast-2": {
209
+ "AMI": "ami-0c5d61202c3b9c33e",
210
+ "RootDeviceName": "/dev/xvda"
211
+ },
212
+ "eu-central-1": {
213
+ "AMI": "ami-004359656ecac6a95",
214
+ "RootDeviceName": "/dev/xvda"
215
+ },
216
+ "us-east-1": {
217
+ "AMI": "ami-0cff7528ff583bf9a",
218
+ "RootDeviceName": "/dev/xvda"
219
+ },
220
+ "us-east-2": {
221
+ "AMI": "ami-02238ac43d6385ab3",
222
+ "RootDeviceName": "/dev/xvda"
223
+ },
224
+ "us-west-1": {
225
+ "AMI": "ami-01163e76c844a2129",
226
+ "RootDeviceName": "/dev/xvda"
227
+ },
228
+ "us-west-2": {
229
+ "AMI": "ami-0ceecbb0f30a902a6",
230
+ "RootDeviceName": "/dev/xvda"
231
+ }
232
+ }
233
+ }
234
+ }
cloud-deployments/digitalocean/terraform/DEPLOY.md ADDED
@@ -0,0 +1,44 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # How to deploy a private AnythingLLM instance on DigitalOcean using Terraform
2
+
3
+ With a DigitalOcean account, you can easily deploy a private AnythingLLM instance using Terraform. This will create a URL that you can access from any browser over HTTP (HTTPS not supported). This single instance will run on your own keys, and they will not be exposed. However, if you want your instance to be protected, it is highly recommended that you set a password once setup is complete.
4
+
5
+ The output of this Terraform configuration will be:
6
+ - 1 DigitalOcean Droplet
7
+ - An IP address to access your application
8
+
9
+ **Requirements**
10
+ - An DigitalOcean account with billing information
11
+ - Terraform installed on your local machine
12
+ - Follow the instructions in the [official Terraform documentation](https://developer.hashicorp.com/terraform/tutorials/aws-get-started/install-cli) for your operating system.
13
+
14
+ ## How to deploy on DigitalOcean
15
+ Open your terminal and navigate to the `docker` folder
16
+ 1. Create a `.env` file by cloning the `.env.example`.
17
+ 2. Navigate to `digitalocean/terraform` folder.
18
+ 3. Replace the token value in the provider "digitalocean" block in main.tf with your DigitalOcean API token.
19
+ 4. Run the following commands to initialize Terraform, review the infrastructure changes, and apply them:
20
+ ```
21
+ terraform init
22
+ terraform plan
23
+ terraform apply
24
+ ```
25
+ Confirm the changes by typing yes when prompted.
26
+ 5. Once the deployment is complete, Terraform will output the public IP address of your droplet. You can access your application using this IP address.
27
+
28
+ ## How to deploy on DigitalOcean
29
+ To delete the resources created by Terraform, run the following command in the terminal:
30
+ `
31
+ terraform destroy
32
+ `
33
+
34
+ ## Please read this notice before submitting issues about your deployment
35
+
36
+ **Note:**
37
+ Your instance will not be available instantly. Depending on the instance size you launched with it can take anywhere from 5-10 minutes to fully boot up.
38
+
39
+ If you want to check the instances progress, navigate to [your deployed instances](https://cloud.digitalocean.com/droplets) and connect to your instance via SSH in browser.
40
+
41
+ Once connected run `sudo tail -f /var/log/cloud-init-output.log` and wait for the file to conclude deployment of the docker image.
42
+
43
+
44
+ Additionally, your use of this deployment process means you are responsible for any costs of these Digital Ocean resources fully.
cloud-deployments/digitalocean/terraform/main.tf ADDED
@@ -0,0 +1,52 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ terraform {
2
+ required_version = ">= 1.0.0"
3
+
4
+ required_providers {
5
+ digitalocean = {
6
+ source = "digitalocean/digitalocean"
7
+ version = "~> 2.0"
8
+ }
9
+ }
10
+ }
11
+
12
+ provider "digitalocean" {
13
+ # Add your DigitalOcean API token here
14
+ token = "DigitalOcean API token"
15
+ }
16
+
17
+
18
+ resource "digitalocean_droplet" "anything_llm_instance" {
19
+ image = "ubuntu-24-04-x64"
20
+ name = "anything-llm-instance"
21
+ region = "nyc3"
22
+ size = "s-2vcpu-2gb"
23
+
24
+ user_data = templatefile("user_data.tp1", {
25
+ env_content = local.formatted_env_content
26
+ })
27
+ }
28
+
29
+ locals {
30
+ env_content = file("../../../docker/.env")
31
+ formatted_env_content = join("\n", [
32
+ for line in split("\n", local.env_content) :
33
+ line
34
+ if !(
35
+ (
36
+ substr(line, 0, 1) == "#"
37
+ ) ||
38
+ (
39
+ substr(line, 0, 3) == "UID"
40
+ ) ||
41
+ (
42
+ substr(line, 0, 3) == "GID"
43
+ ) ||
44
+ (
45
+ substr(line, 0, 11) == "CLOUD_BUILD"
46
+ ) ||
47
+ (
48
+ line == ""
49
+ )
50
+ )
51
+ ])
52
+ }
cloud-deployments/digitalocean/terraform/outputs.tf ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ output "ip_address" {
2
+ value = digitalocean_droplet.anything_llm_instance.ipv4_address
3
+ description = "The public IP address of your droplet application."
4
+ }
cloud-deployments/digitalocean/terraform/user_data.tp1 ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/bin/bash
2
+ # check output of userdata script with sudo tail -f /var/log/cloud-init-output.log
3
+
4
+ sudo apt-get update
5
+ sudo apt-get install -y docker.io
6
+ sudo usermod -a -G docker ubuntu
7
+
8
+ sudo systemctl enable docker
9
+ sudo systemctl start docker
10
+
11
+ mkdir -p /home/anythingllm
12
+ cat <<EOF >/home/anythingllm/.env
13
+ ${env_content}
14
+ EOF
15
+
16
+ sudo docker pull mintplexlabs/anythingllm
17
+ sudo docker run -d -p 3001:3001 --cap-add SYS_ADMIN -v /home/anythingllm:/app/server/storage -v /home/anythingllm/.env:/app/server/.env -e STORAGE_DIR="/app/server/storage" mintplexlabs/anythingllm
18
+ echo "Container ID: $(sudo docker ps --latest --quiet)"
19
+
20
+ export ONLINE=$(curl -Is http://localhost:3001/api/ping | head -n 1|cut -d$' ' -f2)
21
+ echo "Health check: $ONLINE"
22
+ echo "Setup complete! AnythingLLM instance is now online!"
cloud-deployments/gcp/deployment/DEPLOY.md ADDED
@@ -0,0 +1,54 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # How to deploy a private AnythingLLM instance on GCP
2
+
3
+ With a GCP account you can easily deploy a private AnythingLLM instance on GCP. This will create a url that you can access from any browser over HTTP (HTTPS not supported). This single instance will run on your own keys and they will not be exposed - however if you want your instance to be protected it is highly recommend that you set a password once setup is complete.
4
+
5
+ The output of this cloudformation stack will be:
6
+ - 1 GCP VM
7
+ - 1 Security Group with 0.0.0.0/0 access on Ports 22 & 3001
8
+ - 1 GCP VM Volume `gb2` of 10Gib minimum
9
+
10
+ **Requirements**
11
+ - An GCP account with billing information.
12
+
13
+ ## How to deploy on GCP
14
+ Open your terminal
15
+ 1. Log in to your GCP account using the following command:
16
+ ```
17
+ gcloud auth login
18
+ ```
19
+
20
+ 2. After successful login, Run the following command to create a deployment using the Deployment Manager CLI:
21
+
22
+ ```
23
+
24
+ gcloud deployment-manager deployments create anything-llm-deployment --config gcp/deployment/gcp_deploy_anything_llm.yaml
25
+
26
+ ```
27
+
28
+ Once you execute these steps, the CLI will initiate the deployment process on GCP based on your configuration file. You can monitor the deployment status and view the outputs using the Google Cloud Console or the Deployment Manager CLI commands.
29
+
30
+ ```
31
+ gcloud compute instances get-serial-port-output anything-llm-instance
32
+ ```
33
+
34
+ ssh into the instance
35
+
36
+ ```
37
+ gcloud compute ssh anything-llm-instance
38
+ ```
39
+
40
+ Delete the deployment
41
+ ```
42
+ gcloud deployment-manager deployments delete anything-llm-deployment
43
+ ```
44
+
45
+ ## Please read this notice before submitting issues about your deployment
46
+
47
+ **Note:**
48
+ Your instance will not be available instantly. Depending on the instance size you launched with it can take anywhere from 5-10 minutes to fully boot up.
49
+
50
+ If you want to check the instances progress, navigate to [your deployed instances](https://console.cloud.google.com/compute/instances) and connect to your instance via SSH in browser.
51
+
52
+ Once connected run `sudo tail -f /var/log/cloud-init-output.log` and wait for the file to conclude deployment of the docker image.
53
+
54
+ Additionally, your use of this deployment process means you are responsible for any costs of these GCP resources fully.
cloud-deployments/gcp/deployment/gcp_deploy_anything_llm.yaml ADDED
@@ -0,0 +1,45 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ resources:
2
+ - name: anything-llm-instance
3
+ type: compute.v1.instance
4
+ properties:
5
+ zone: us-central1-a
6
+ machineType: zones/us-central1-a/machineTypes/n1-standard-1
7
+ disks:
8
+ - deviceName: boot
9
+ type: PERSISTENT
10
+ boot: true
11
+ autoDelete: true
12
+ initializeParams:
13
+ sourceImage: projects/ubuntu-os-cloud/global/images/family/ubuntu-2004-lts
14
+ diskSizeGb: 10
15
+ networkInterfaces:
16
+ - network: global/networks/default
17
+ accessConfigs:
18
+ - name: External NAT
19
+ type: ONE_TO_ONE_NAT
20
+ metadata:
21
+ items:
22
+ - key: startup-script
23
+ value: |
24
+ #!/bin/bash
25
+ # check output of userdata script with sudo tail -f /var/log/cloud-init-output.log
26
+
27
+ sudo apt-get update
28
+ sudo apt-get install -y docker.io
29
+ sudo usermod -a -G docker ubuntu
30
+ sudo systemctl enable docker
31
+ sudo systemctl start docker
32
+
33
+ mkdir -p /home/anythingllm
34
+ touch /home/anythingllm/.env
35
+ sudo chown -R ubuntu:ubuntu /home/anythingllm
36
+
37
+ sudo docker pull mintplexlabs/anythingllm
38
+ sudo docker run -d -p 3001:3001 --cap-add SYS_ADMIN -v /home/anythingllm:/app/server/storage -v /home/anythingllm/.env:/app/server/.env -e STORAGE_DIR="/app/server/storage" mintplexlabs/anythingllm
39
+ echo "Container ID: $(sudo docker ps --latest --quiet)"
40
+
41
+ export ONLINE=$(curl -Is http://localhost:3001/api/ping | head -n 1|cut -d$' ' -f2)
42
+ echo "Health check: $ONLINE"
43
+
44
+ echo "Setup complete! AnythingLLM instance is now online!"
45
+
cloud-deployments/huggingface-spaces/Dockerfile ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # With this dockerfile in a Huggingface space you will get an entire AnythingLLM instance running
2
+ # in your space with all features you would normally get from the docker based version of AnythingLLM.
3
+ #
4
+ # How to use
5
+ # - Login to https://huggingface.co/spaces
6
+ # - Click on "Create new Space"
7
+ # - Name the space and select "Docker" as the SDK w/ a blank template
8
+ # - The default 2vCPU/16GB machine is OK. The more the merrier.
9
+ # - Decide if you want your AnythingLLM Space public or private.
10
+ # **You might want to stay private until you at least set a password or enable multi-user mode**
11
+ # - Click "Create Space"
12
+ # - Click on "Settings" on top of page (https://huggingface.co/spaces/<username>/<space-name>/settings)
13
+ # - Scroll to "Persistent Storage" and select the lowest tier of now - you can upgrade if you run out.
14
+ # - Confirm and continue storage upgrade
15
+ # - Go to "Files" Tab (https://huggingface.co/spaces/<username>/<space-name>/tree/main)
16
+ # - Click "Add Files"
17
+ # - Upload this file or create a file named `Dockerfile` and copy-paste this content into it. "Commit to main" and save.
18
+ # - Your container will build and boot. You now have AnythingLLM on HuggingFace. Your data is stored in the persistent storage attached.
19
+ # Have Fun 🤗
20
+ # Have issues? Check the logs on HuggingFace for clues.
21
+ FROM mintplexlabs/anythingllm:render
22
+
23
+ USER root
24
+ RUN mkdir -p /data/storage
25
+ RUN ln -s /data/storage /storage
26
+ USER anythingllm
27
+
28
+ ENV STORAGE_DIR="/data/storage"
29
+ ENV SERVER_PORT=7860
30
+
31
+ ENTRYPOINT ["/bin/bash", "/usr/local/bin/render-entrypoint.sh"]
cloud-deployments/k8/manifest.yaml ADDED
@@ -0,0 +1,214 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ apiVersion: v1
3
+ kind: PersistentVolume
4
+ metadata:
5
+ name: anything-llm-volume
6
+ annotations:
7
+ pv.beta.kubernetes.io/uid: "1000"
8
+ pv.beta.kubernetes.io/gid: "1000"
9
+ spec:
10
+ storageClassName: gp2
11
+ capacity:
12
+ storage: 5Gi
13
+ accessModes:
14
+ - ReadWriteOnce
15
+ awsElasticBlockStore:
16
+ # This is the volume UUID from AWS EC2 EBS Volumes list.
17
+ volumeID: "{{ anythingllm_awsElasticBlockStore_volumeID }}"
18
+ fsType: ext4
19
+ nodeAffinity:
20
+ required:
21
+ nodeSelectorTerms:
22
+ - matchExpressions:
23
+ - key: topology.kubernetes.io/zone
24
+ operator: In
25
+ values:
26
+ - us-east-1c
27
+ ---
28
+ apiVersion: v1
29
+ kind: PersistentVolumeClaim
30
+ metadata:
31
+ name: anything-llm-volume-claim
32
+ namespace: "{{ namespace }}"
33
+ spec:
34
+ accessModes:
35
+ - ReadWriteOnce
36
+ resources:
37
+ requests:
38
+ storage: 5Gi
39
+ ---
40
+ apiVersion: apps/v1
41
+ kind: Deployment
42
+ metadata:
43
+ name: anything-llm
44
+ namespace: "{{ namespace }}"
45
+ labels:
46
+ anything-llm: "true"
47
+ spec:
48
+ selector:
49
+ matchLabels:
50
+ k8s-app: anything-llm
51
+ replicas: 1
52
+ strategy:
53
+ type: RollingUpdate
54
+ rollingUpdate:
55
+ maxSurge: 0%
56
+ maxUnavailable: 100%
57
+ template:
58
+ metadata:
59
+ labels:
60
+ anything-llm: "true"
61
+ k8s-app: anything-llm
62
+ app.kubernetes.io/name: anything-llm
63
+ app.kubernetes.io/part-of: anything-llm
64
+ annotations:
65
+ prometheus.io/scrape: "true"
66
+ prometheus.io/path: /metrics
67
+ prometheus.io/port: "9090"
68
+ spec:
69
+ serviceAccountName: "default"
70
+ terminationGracePeriodSeconds: 10
71
+ securityContext:
72
+ fsGroup: 1000
73
+ runAsNonRoot: true
74
+ runAsGroup: 1000
75
+ runAsUser: 1000
76
+ affinity:
77
+ nodeAffinity:
78
+ requiredDuringSchedulingIgnoredDuringExecution:
79
+ nodeSelectorTerms:
80
+ - matchExpressions:
81
+ - key: topology.kubernetes.io/zone
82
+ operator: In
83
+ values:
84
+ - us-east-1c
85
+ containers:
86
+ - name: anything-llm
87
+ resources:
88
+ limits:
89
+ memory: "1Gi"
90
+ cpu: "500m"
91
+ requests:
92
+ memory: "512Mi"
93
+ cpu: "250m"
94
+ imagePullPolicy: IfNotPresent
95
+ image: "mintplexlabs/anythingllm:render"
96
+ securityContext:
97
+ allowPrivilegeEscalation: true
98
+ capabilities:
99
+ add:
100
+ - SYS_ADMIN
101
+ runAsNonRoot: true
102
+ runAsGroup: 1000
103
+ runAsUser: 1000
104
+ command:
105
+ # Specify a command to override the Dockerfile's ENTRYPOINT.
106
+ - /bin/bash
107
+ - -c
108
+ - |
109
+ set -x -e
110
+ sleep 3
111
+ echo "AWS_REGION: $AWS_REGION"
112
+ echo "SERVER_PORT: $SERVER_PORT"
113
+ echo "NODE_ENV: $NODE_ENV"
114
+ echo "STORAGE_DIR: $STORAGE_DIR"
115
+ {
116
+ cd /app/server/ &&
117
+ npx prisma generate --schema=./prisma/schema.prisma &&
118
+ npx prisma migrate deploy --schema=./prisma/schema.prisma &&
119
+ node /app/server/index.js
120
+ echo "Server process exited with status $?"
121
+ } &
122
+ {
123
+ node /app/collector/index.js
124
+ echo "Collector process exited with status $?"
125
+ } &
126
+ wait -n
127
+ exit $?
128
+ readinessProbe:
129
+ httpGet:
130
+ path: /v1/api/health
131
+ port: 8888
132
+ initialDelaySeconds: 15
133
+ periodSeconds: 5
134
+ successThreshold: 2
135
+ livenessProbe:
136
+ httpGet:
137
+ path: /v1/api/health
138
+ port: 8888
139
+ initialDelaySeconds: 15
140
+ periodSeconds: 5
141
+ failureThreshold: 3
142
+ env:
143
+ - name: AWS_REGION
144
+ value: "{{ aws_region }}"
145
+ - name: AWS_ACCESS_KEY_ID
146
+ value: "{{ aws_access_id }}"
147
+ - name: AWS_SECRET_ACCESS_KEY
148
+ value: "{{ aws_access_secret }}"
149
+ - name: SERVER_PORT
150
+ value: "3001"
151
+ - name: JWT_SECRET
152
+ value: "my-random-string-for-seeding" # Please generate random string at least 12 chars long.
153
+ - name: STORAGE_DIR
154
+ value: "/storage"
155
+ - name: NODE_ENV
156
+ value: "production"
157
+ - name: UID
158
+ value: "1000"
159
+ - name: GID
160
+ value: "1000"
161
+ volumeMounts:
162
+ - name: anything-llm-server-storage-volume-mount
163
+ mountPath: /storage
164
+ volumes:
165
+ - name: anything-llm-server-storage-volume-mount
166
+ persistentVolumeClaim:
167
+ claimName: anything-llm-volume-claim
168
+ ---
169
+ # This serves the UI and the backend.
170
+ apiVersion: networking.k8s.io/v1
171
+ kind: Ingress
172
+ metadata:
173
+ name: anything-llm-ingress
174
+ namespace: "{{ namespace }}"
175
+ annotations:
176
+ external-dns.alpha.kubernetes.io/hostname: "{{ namespace }}-chat.{{ base_domain }}"
177
+ kubernetes.io/ingress.class: "internal-ingress"
178
+ nginx.ingress.kubernetes.io/rewrite-target: /
179
+ ingress.kubernetes.io/ssl-redirect: "false"
180
+ spec:
181
+ rules:
182
+ - host: "{{ namespace }}-chat.{{ base_domain }}"
183
+ http:
184
+ paths:
185
+ - path: /
186
+ pathType: Prefix
187
+ backend:
188
+ service:
189
+ name: anything-llm-svc
190
+ port:
191
+ number: 3001
192
+ tls: # < placing a host in the TLS config will indicate a cert should be created
193
+ - hosts:
194
+ - "{{ namespace }}-chat.{{ base_domain }}"
195
+ secretName: letsencrypt-prod
196
+ ---
197
+ apiVersion: v1
198
+ kind: Service
199
+ metadata:
200
+ labels:
201
+ kubernetes.io/name: anything-llm
202
+ name: anything-llm-svc
203
+ namespace: "{{ namespace }}"
204
+ spec:
205
+ ports:
206
+ # "port" is external port, and "targetPort" is internal.
207
+ - port: 3301
208
+ targetPort: 3001
209
+ name: traffic
210
+ - port: 9090
211
+ targetPort: 9090
212
+ name: metrics
213
+ selector:
214
+ k8s-app: anything-llm
collector/.env.example ADDED
@@ -0,0 +1 @@
 
 
1
+ # Placeholder .env file for collector runtime
collector/.gitignore ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ hotdir/*
2
+ !hotdir/__HOTDIR__.md
3
+ yarn-error.log
4
+ !yarn.lock
5
+ outputs
6
+ scripts
collector/.nvmrc ADDED
@@ -0,0 +1 @@
 
 
1
+ v18.13.0
collector/__tests__/utils/extensions/YoutubeTranscript/YoutubeLoader/youtube-transcript.test.js ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ const { YoutubeTranscript } = require("../../../../../utils/extensions/YoutubeTranscript/YoutubeLoader/youtube-transcript.js");
2
+
3
+ describe("YoutubeTranscript", () => {
4
+ it("should fetch transcript from YouTube video", async () => {
5
+ const videoId = "BJjsfNO5JTo";
6
+ const transcript = await YoutubeTranscript.fetchTranscript(videoId, {
7
+ lang: "en",
8
+ });
9
+
10
+ expect(transcript).toBeDefined();
11
+ expect(typeof transcript).toBe("string");
12
+ expect(transcript.length).toBeGreaterThan(0);
13
+ // console.log("Success! Transcript length:", transcript.length);
14
+ // console.log("First 200 characters:", transcript.substring(0, 200) + "...");
15
+ }, 30000);
16
+ });
collector/extensions/index.js ADDED
@@ -0,0 +1,207 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ const { setDataSigner } = require("../middleware/setDataSigner");
2
+ const { verifyPayloadIntegrity } = require("../middleware/verifyIntegrity");
3
+ const { resolveRepoLoader, resolveRepoLoaderFunction } = require("../utils/extensions/RepoLoader");
4
+ const { reqBody } = require("../utils/http");
5
+ const { validURL } = require("../utils/url");
6
+ const RESYNC_METHODS = require("./resync");
7
+ const { loadObsidianVault } = require("../utils/extensions/ObsidianVault");
8
+
9
+ function extensions(app) {
10
+ if (!app) return;
11
+
12
+ app.post(
13
+ "/ext/resync-source-document",
14
+ [verifyPayloadIntegrity, setDataSigner],
15
+ async function (request, response) {
16
+ try {
17
+ const { type, options } = reqBody(request);
18
+ if (!RESYNC_METHODS.hasOwnProperty(type)) throw new Error(`Type "${type}" is not a valid type to sync.`);
19
+ return await RESYNC_METHODS[type](options, response);
20
+ } catch (e) {
21
+ console.error(e);
22
+ response.status(200).json({
23
+ success: false,
24
+ content: null,
25
+ reason: e.message || "A processing error occurred.",
26
+ });
27
+ }
28
+ return;
29
+ }
30
+ )
31
+
32
+ app.post(
33
+ "/ext/:repo_platform-repo",
34
+ [verifyPayloadIntegrity, setDataSigner],
35
+ async function (request, response) {
36
+ try {
37
+ const loadRepo = resolveRepoLoaderFunction(request.params.repo_platform);
38
+ const { success, reason, data } = await loadRepo(
39
+ reqBody(request),
40
+ response,
41
+ );
42
+ response.status(200).json({
43
+ success,
44
+ reason,
45
+ data,
46
+ });
47
+ } catch (e) {
48
+ console.error(e);
49
+ response.status(200).json({
50
+ success: false,
51
+ reason: e.message || "A processing error occurred.",
52
+ data: {},
53
+ });
54
+ }
55
+ return;
56
+ }
57
+ );
58
+
59
+ // gets all branches for a specific repo
60
+ app.post(
61
+ "/ext/:repo_platform-repo/branches",
62
+ [verifyPayloadIntegrity],
63
+ async function (request, response) {
64
+ try {
65
+ const RepoLoader = resolveRepoLoader(request.params.repo_platform);
66
+ const allBranches = await new RepoLoader(
67
+ reqBody(request)
68
+ ).getRepoBranches();
69
+ response.status(200).json({
70
+ success: true,
71
+ reason: null,
72
+ data: {
73
+ branches: allBranches,
74
+ },
75
+ });
76
+ } catch (e) {
77
+ console.error(e);
78
+ response.status(400).json({
79
+ success: false,
80
+ reason: e.message,
81
+ data: {
82
+ branches: [],
83
+ },
84
+ });
85
+ }
86
+ return;
87
+ }
88
+ );
89
+
90
+ app.post(
91
+ "/ext/youtube-transcript",
92
+ [verifyPayloadIntegrity],
93
+ async function (request, response) {
94
+ try {
95
+ const { loadYouTubeTranscript } = require("../utils/extensions/YoutubeTranscript");
96
+ const { success, reason, data } = await loadYouTubeTranscript(
97
+ reqBody(request)
98
+ );
99
+ response.status(200).json({ success, reason, data });
100
+ } catch (e) {
101
+ console.error(e);
102
+ response.status(400).json({
103
+ success: false,
104
+ reason: e.message,
105
+ data: {
106
+ title: null,
107
+ author: null,
108
+ },
109
+ });
110
+ }
111
+ return;
112
+ }
113
+ );
114
+
115
+ app.post(
116
+ "/ext/website-depth",
117
+ [verifyPayloadIntegrity],
118
+ async function (request, response) {
119
+ try {
120
+ const websiteDepth = require("../utils/extensions/WebsiteDepth");
121
+ const { url, depth = 1, maxLinks = 20 } = reqBody(request);
122
+ if (!validURL(url)) throw new Error("Not a valid URL.");
123
+ const scrapedData = await websiteDepth(url, depth, maxLinks);
124
+ response.status(200).json({ success: true, data: scrapedData });
125
+ } catch (e) {
126
+ console.error(e);
127
+ response.status(400).json({ success: false, reason: e.message });
128
+ }
129
+ return;
130
+ }
131
+ );
132
+
133
+ app.post(
134
+ "/ext/confluence",
135
+ [verifyPayloadIntegrity, setDataSigner],
136
+ async function (request, response) {
137
+ try {
138
+ const { loadConfluence } = require("../utils/extensions/Confluence");
139
+ const { success, reason, data } = await loadConfluence(
140
+ reqBody(request),
141
+ response
142
+ );
143
+ response.status(200).json({ success, reason, data });
144
+ } catch (e) {
145
+ console.error(e);
146
+ response.status(400).json({
147
+ success: false,
148
+ reason: e.message,
149
+ data: {
150
+ title: null,
151
+ author: null,
152
+ },
153
+ });
154
+ }
155
+ return;
156
+ }
157
+ );
158
+
159
+ app.post(
160
+ "/ext/drupalwiki",
161
+ [verifyPayloadIntegrity, setDataSigner],
162
+ async function (request, response) {
163
+ try {
164
+ const { loadAndStoreSpaces } = require("../utils/extensions/DrupalWiki");
165
+ const { success, reason, data } = await loadAndStoreSpaces(
166
+ reqBody(request),
167
+ response
168
+ );
169
+ response.status(200).json({ success, reason, data });
170
+ } catch (e) {
171
+ console.error(e);
172
+ response.status(400).json({
173
+ success: false,
174
+ reason: e.message,
175
+ data: {
176
+ title: null,
177
+ author: null,
178
+ },
179
+ });
180
+ }
181
+ return;
182
+ }
183
+ );
184
+
185
+ app.post(
186
+ "/ext/obsidian/vault",
187
+ [verifyPayloadIntegrity, setDataSigner],
188
+ async function (request, response) {
189
+ try {
190
+ const { files } = reqBody(request);
191
+ const result = await loadObsidianVault({ files });
192
+ response.status(200).json(result);
193
+ } catch (e) {
194
+ console.error(e);
195
+ response.status(400).json({
196
+ success: false,
197
+ reason: e.message,
198
+ data: null,
199
+ });
200
+ }
201
+ return;
202
+ }
203
+ );
204
+ }
205
+
206
+
207
+ module.exports = extensions;
collector/extensions/resync/index.js ADDED
@@ -0,0 +1,153 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ const { getLinkText } = require("../../processLink");
2
+
3
+ /**
4
+ * Fetches the content of a raw link. Returns the content as a text string of the link in question.
5
+ * @param {object} data - metadata from document (eg: link)
6
+ * @param {import("../../middleware/setDataSigner").ResponseWithSigner} response
7
+ */
8
+ async function resyncLink({ link }, response) {
9
+ if (!link) throw new Error('Invalid link provided');
10
+ try {
11
+ const { success, content = null } = await getLinkText(link);
12
+ if (!success) throw new Error(`Failed to sync link content. ${reason}`);
13
+ response.status(200).json({ success, content });
14
+ } catch (e) {
15
+ console.error(e);
16
+ response.status(200).json({
17
+ success: false,
18
+ content: null,
19
+ });
20
+ }
21
+ }
22
+
23
+ /**
24
+ * Fetches the content of a YouTube link. Returns the content as a text string of the video in question.
25
+ * We offer this as there may be some videos where a transcription could be manually edited after initial scraping
26
+ * but in general - transcriptions often never change.
27
+ * @param {object} data - metadata from document (eg: link)
28
+ * @param {import("../../middleware/setDataSigner").ResponseWithSigner} response
29
+ */
30
+ async function resyncYouTube({ link }, response) {
31
+ if (!link) throw new Error('Invalid link provided');
32
+ try {
33
+ const { fetchVideoTranscriptContent } = require("../../utils/extensions/YoutubeTranscript");
34
+ const { success, reason, content } = await fetchVideoTranscriptContent({ url: link });
35
+ if (!success) throw new Error(`Failed to sync YouTube video transcript. ${reason}`);
36
+ response.status(200).json({ success, content });
37
+ } catch (e) {
38
+ console.error(e);
39
+ response.status(200).json({
40
+ success: false,
41
+ content: null,
42
+ });
43
+ }
44
+ }
45
+
46
+ /**
47
+ * Fetches the content of a specific confluence page via its chunkSource.
48
+ * Returns the content as a text string of the page in question and only that page.
49
+ * @param {object} data - metadata from document (eg: chunkSource)
50
+ * @param {import("../../middleware/setDataSigner").ResponseWithSigner} response
51
+ */
52
+ async function resyncConfluence({ chunkSource }, response) {
53
+ if (!chunkSource) throw new Error('Invalid source property provided');
54
+ try {
55
+ // Confluence data is `payload` encrypted. So we need to expand its
56
+ // encrypted payload back into query params so we can reFetch the page with same access token/params.
57
+ const source = response.locals.encryptionWorker.expandPayload(chunkSource);
58
+ const { fetchConfluencePage } = require("../../utils/extensions/Confluence");
59
+ const { success, reason, content } = await fetchConfluencePage({
60
+ pageUrl: `https:${source.pathname}`, // need to add back the real protocol
61
+ baseUrl: source.searchParams.get('baseUrl'),
62
+ spaceKey: source.searchParams.get('spaceKey'),
63
+ accessToken: source.searchParams.get('token'),
64
+ username: source.searchParams.get('username'),
65
+ });
66
+
67
+ if (!success) throw new Error(`Failed to sync Confluence page content. ${reason}`);
68
+ response.status(200).json({ success, content });
69
+ } catch (e) {
70
+ console.error(e);
71
+ response.status(200).json({
72
+ success: false,
73
+ content: null,
74
+ });
75
+ }
76
+ }
77
+
78
+ /**
79
+ * Fetches the content of a specific confluence page via its chunkSource.
80
+ * Returns the content as a text string of the page in question and only that page.
81
+ * @param {object} data - metadata from document (eg: chunkSource)
82
+ * @param {import("../../middleware/setDataSigner").ResponseWithSigner} response
83
+ */
84
+ async function resyncGithub({ chunkSource }, response) {
85
+ if (!chunkSource) throw new Error('Invalid source property provided');
86
+ try {
87
+ // Github file data is `payload` encrypted (might contain PAT). So we need to expand its
88
+ // encrypted payload back into query params so we can reFetch the page with same access token/params.
89
+ const source = response.locals.encryptionWorker.expandPayload(chunkSource);
90
+ const { fetchGithubFile } = require("../../utils/extensions/RepoLoader/GithubRepo");
91
+ const { success, reason, content } = await fetchGithubFile({
92
+ repoUrl: `https:${source.pathname}`, // need to add back the real protocol
93
+ branch: source.searchParams.get('branch'),
94
+ accessToken: source.searchParams.get('pat'),
95
+ sourceFilePath: source.searchParams.get('path'),
96
+ });
97
+
98
+ if (!success) throw new Error(`Failed to sync GitHub file content. ${reason}`);
99
+ response.status(200).json({ success, content });
100
+ } catch (e) {
101
+ console.error(e);
102
+ response.status(200).json({
103
+ success: false,
104
+ content: null,
105
+ });
106
+ }
107
+ }
108
+
109
+
110
+ /**
111
+ * Fetches the content of a specific DrupalWiki page via its chunkSource.
112
+ * Returns the content as a text string of the page in question and only that page.
113
+ * @param {object} data - metadata from document (eg: chunkSource)
114
+ * @param {import("../../middleware/setDataSigner").ResponseWithSigner} response
115
+ */
116
+ async function resyncDrupalWiki({ chunkSource }, response) {
117
+ if (!chunkSource) throw new Error('Invalid source property provided');
118
+ try {
119
+ // DrupalWiki data is `payload` encrypted. So we need to expand its
120
+ // encrypted payload back into query params so we can reFetch the page with same access token/params.
121
+ const source = response.locals.encryptionWorker.expandPayload(chunkSource);
122
+ const { loadPage } = require("../../utils/extensions/DrupalWiki");
123
+ const { success, reason, content } = await loadPage({
124
+ baseUrl: source.searchParams.get('baseUrl'),
125
+ pageId: source.searchParams.get('pageId'),
126
+ accessToken: source.searchParams.get('accessToken'),
127
+ });
128
+
129
+ if (!success) {
130
+ console.error(`Failed to sync DrupalWiki page content. ${reason}`);
131
+ response.status(200).json({
132
+ success: false,
133
+ content: null,
134
+ });
135
+ } else {
136
+ response.status(200).json({ success, content });
137
+ }
138
+ } catch (e) {
139
+ console.error(e);
140
+ response.status(200).json({
141
+ success: false,
142
+ content: null,
143
+ });
144
+ }
145
+ }
146
+
147
+ module.exports = {
148
+ link: resyncLink,
149
+ youtube: resyncYouTube,
150
+ confluence: resyncConfluence,
151
+ github: resyncGithub,
152
+ drupalwiki: resyncDrupalWiki,
153
+ }
collector/hotdir/__HOTDIR__.md ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ ### What is the "Hot directory"
2
+
3
+ This is a pre-set file location that documents will be written to when uploaded by AnythingLLM. There is really no need to touch it.
collector/index.js ADDED
@@ -0,0 +1,188 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ process.env.NODE_ENV === "development"
2
+ ? require("dotenv").config({ path: `.env.${process.env.NODE_ENV}` })
3
+ : require("dotenv").config();
4
+
5
+ require("./utils/logger")();
6
+ const express = require("express");
7
+ const bodyParser = require("body-parser");
8
+ const cors = require("cors");
9
+ const path = require("path");
10
+ const { ACCEPTED_MIMES } = require("./utils/constants");
11
+ const { reqBody } = require("./utils/http");
12
+ const { processSingleFile } = require("./processSingleFile");
13
+ const { processLink, getLinkText } = require("./processLink");
14
+ const { wipeCollectorStorage } = require("./utils/files");
15
+ const extensions = require("./extensions");
16
+ const { processRawText } = require("./processRawText");
17
+ const { verifyPayloadIntegrity } = require("./middleware/verifyIntegrity");
18
+ const app = express();
19
+ const FILE_LIMIT = "3GB";
20
+
21
+ app.use(cors({ origin: true }));
22
+ app.use(
23
+ bodyParser.text({ limit: FILE_LIMIT }),
24
+ bodyParser.json({ limit: FILE_LIMIT }),
25
+ bodyParser.urlencoded({
26
+ limit: FILE_LIMIT,
27
+ extended: true,
28
+ })
29
+ );
30
+
31
+ app.post(
32
+ "/process",
33
+ [verifyPayloadIntegrity],
34
+ async function (request, response) {
35
+ const { filename, options = {}, metadata = {} } = reqBody(request);
36
+ try {
37
+ const targetFilename = path
38
+ .normalize(filename)
39
+ .replace(/^(\.\.(\/|\\|$))+/, "");
40
+ const {
41
+ success,
42
+ reason,
43
+ documents = [],
44
+ } = await processSingleFile(targetFilename, options, metadata);
45
+ response
46
+ .status(200)
47
+ .json({ filename: targetFilename, success, reason, documents });
48
+ } catch (e) {
49
+ console.error(e);
50
+ response.status(200).json({
51
+ filename: filename,
52
+ success: false,
53
+ reason: "A processing error occurred.",
54
+ documents: [],
55
+ });
56
+ }
57
+ return;
58
+ }
59
+ );
60
+
61
+ app.post(
62
+ "/parse",
63
+ [verifyPayloadIntegrity],
64
+ async function (request, response) {
65
+ const { filename, options = {} } = reqBody(request);
66
+ try {
67
+ const targetFilename = path
68
+ .normalize(filename)
69
+ .replace(/^(\.\.(\/|\\|$))+/, "");
70
+ const {
71
+ success,
72
+ reason,
73
+ documents = [],
74
+ } = await processSingleFile(targetFilename, {
75
+ ...options,
76
+ parseOnly: true,
77
+ });
78
+ response
79
+ .status(200)
80
+ .json({ filename: targetFilename, success, reason, documents });
81
+ } catch (e) {
82
+ console.error(e);
83
+ response.status(200).json({
84
+ filename: filename,
85
+ success: false,
86
+ reason: "A processing error occurred.",
87
+ documents: [],
88
+ });
89
+ }
90
+ return;
91
+ }
92
+ );
93
+
94
+ app.post(
95
+ "/process-link",
96
+ [verifyPayloadIntegrity],
97
+ async function (request, response) {
98
+ const { link, scraperHeaders = {}, metadata = {} } = reqBody(request);
99
+ try {
100
+ const {
101
+ success,
102
+ reason,
103
+ documents = [],
104
+ } = await processLink(link, scraperHeaders, metadata);
105
+ response.status(200).json({ url: link, success, reason, documents });
106
+ } catch (e) {
107
+ console.error(e);
108
+ response.status(200).json({
109
+ url: link,
110
+ success: false,
111
+ reason: "A processing error occurred.",
112
+ documents: [],
113
+ });
114
+ }
115
+ return;
116
+ }
117
+ );
118
+
119
+ app.post(
120
+ "/util/get-link",
121
+ [verifyPayloadIntegrity],
122
+ async function (request, response) {
123
+ const { link, captureAs = "text" } = reqBody(request);
124
+ try {
125
+ const { success, content = null } = await getLinkText(link, captureAs);
126
+ response.status(200).json({ url: link, success, content });
127
+ } catch (e) {
128
+ console.error(e);
129
+ response.status(200).json({
130
+ url: link,
131
+ success: false,
132
+ content: null,
133
+ });
134
+ }
135
+ return;
136
+ }
137
+ );
138
+
139
+ app.post(
140
+ "/process-raw-text",
141
+ [verifyPayloadIntegrity],
142
+ async function (request, response) {
143
+ const { textContent, metadata } = reqBody(request);
144
+ try {
145
+ const {
146
+ success,
147
+ reason,
148
+ documents = [],
149
+ } = await processRawText(textContent, metadata);
150
+ response
151
+ .status(200)
152
+ .json({ filename: metadata.title, success, reason, documents });
153
+ } catch (e) {
154
+ console.error(e);
155
+ response.status(200).json({
156
+ filename: metadata?.title || "Unknown-doc.txt",
157
+ success: false,
158
+ reason: "A processing error occurred.",
159
+ documents: [],
160
+ });
161
+ }
162
+ return;
163
+ }
164
+ );
165
+
166
+ extensions(app);
167
+
168
+ app.get("/accepts", function (_, response) {
169
+ response.status(200).json(ACCEPTED_MIMES);
170
+ });
171
+
172
+ app.all("*", function (_, response) {
173
+ response.sendStatus(200);
174
+ });
175
+
176
+ app
177
+ .listen(8888, async () => {
178
+ await wipeCollectorStorage();
179
+ console.log(`Document processor app listening on port 8888`);
180
+ })
181
+ .on("error", function (_) {
182
+ process.once("SIGUSR2", function () {
183
+ process.kill(process.pid, "SIGUSR2");
184
+ });
185
+ process.on("SIGINT", function () {
186
+ process.kill(process.pid, "SIGINT");
187
+ });
188
+ });
collector/middleware/setDataSigner.js ADDED
@@ -0,0 +1,41 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ const { EncryptionWorker } = require("../utils/EncryptionWorker");
2
+ const { CommunicationKey } = require("../utils/comKey");
3
+
4
+ /**
5
+ * Express Response Object interface with defined encryptionWorker attached to locals property.
6
+ * @typedef {import("express").Response & import("express").Response['locals'] & {encryptionWorker: EncryptionWorker} } ResponseWithSigner
7
+ */
8
+
9
+ // You can use this middleware to assign the EncryptionWorker to the response locals
10
+ // property so that if can be used to encrypt/decrypt arbitrary data via response object.
11
+ // eg: Encrypting API keys in chunk sources.
12
+
13
+ // The way this functions is that the rolling RSA Communication Key is used server-side to private-key encrypt the raw
14
+ // key of the persistent EncryptionManager credentials. Since EncryptionManager credentials do _not_ roll, we should not send them
15
+ // even between server<>collector in plaintext because if the user configured the server/collector to be public they could technically
16
+ // be exposing the key in transit via the X-Payload-Signer header. Even if this risk is minimal we should not do this.
17
+
18
+ // This middleware uses the CommunicationKey public key to first decrypt the base64 representation of the EncryptionManager credentials
19
+ // and then loads that in to the EncryptionWorker as a buffer so we can use the same credentials across the system. Should we ever break the
20
+ // collector out into its own service this would still work without SSL/TLS.
21
+
22
+ /**
23
+ *
24
+ * @param {import("express").Request} request
25
+ * @param {import("express").Response} response
26
+ * @param {import("express").NextFunction} next
27
+ */
28
+ function setDataSigner(request, response, next) {
29
+ const comKey = new CommunicationKey();
30
+ const encryptedPayloadSigner = request.header("X-Payload-Signer");
31
+ if (!encryptedPayloadSigner) console.log('Failed to find signed-payload to set encryption worker! Encryption calls will fail.');
32
+
33
+ const decryptedPayloadSignerKey = comKey.decrypt(encryptedPayloadSigner);
34
+ const encryptionWorker = new EncryptionWorker(decryptedPayloadSignerKey);
35
+ response.locals.encryptionWorker = encryptionWorker;
36
+ next();
37
+ }
38
+
39
+ module.exports = {
40
+ setDataSigner
41
+ }
collector/middleware/verifyIntegrity.js ADDED
@@ -0,0 +1,26 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ const { CommunicationKey } = require("../utils/comKey");
2
+ const RuntimeSettings = require("../utils/runtimeSettings");
3
+ const runtimeSettings = new RuntimeSettings();
4
+
5
+ function verifyPayloadIntegrity(request, response, next) {
6
+ const comKey = new CommunicationKey();
7
+ if (process.env.NODE_ENV === "development") {
8
+ comKey.log('verifyPayloadIntegrity is skipped in development.');
9
+ runtimeSettings.parseOptionsFromRequest(request);
10
+ next();
11
+ return;
12
+ }
13
+
14
+ const signature = request.header("X-Integrity");
15
+ if (!signature) return response.status(400).json({ msg: 'Failed integrity signature check.' })
16
+
17
+ const validSignedPayload = comKey.verify(signature, request.body);
18
+ if (!validSignedPayload) return response.status(400).json({ msg: 'Failed integrity signature check.' });
19
+
20
+ runtimeSettings.parseOptionsFromRequest(request);
21
+ next();
22
+ }
23
+
24
+ module.exports = {
25
+ verifyPayloadIntegrity
26
+ }