diff --git a/.devcontainer/codespaces.sh b/.devcontainer/codespaces.sh index 7e6f4a7836..a3dd9e4f22 100644 --- a/.devcontainer/codespaces.sh +++ b/.devcontainer/codespaces.sh @@ -11,4 +11,4 @@ gh codespace ports visibility 3000:public -c $CODESPACE_NAME gh codespace ports visibility 4200:public -c $CODESPACE_NAME export BACKEND_URL=$(gh codespace ports -c $CODESPACE_NAME --json sourcePort,browseUrl | jq -r '.[] | select(.sourcePort == 3000) | .browseUrl') sed -i "s|apiUrl: 'http://localhost:3000/v1'|apiUrl: '${BACKEND_URL}/v1'|g" /workspace/packages/ui/common/src/lib/environments/environment.ts -sed -i "s|AP_WEBHOOK_URL=\"http://localhost:3000\"|AP_WEBHOOK_URL=\"${BACKEND_URL}\"|g" /workspace/packages/backend/.env \ No newline at end of file +sed -i "s|AP_WEBHOOK_URL=\"http://localhost:3000\"|AP_WEBHOOK_URL=\"${BACKEND_URL}\"|g" /workspace/packages/server/api/.env \ No newline at end of file diff --git a/.github/workflows/build-cloud-nx.yml b/.github/workflows/build-cloud-nx.yml index 771f77f87f..81e42fa6f9 100644 --- a/.github/workflows/build-cloud-nx.yml +++ b/.github/workflows/build-cloud-nx.yml @@ -19,7 +19,7 @@ jobs: parallel-commands-on-agents: | npx nx affected --target=lint --parallel=3 npx nx affected --target=build -c production --parallel=3 - npx nx run-many --target=test --projects=engine,shared,backend --parallel=3 + npx nx run-many --target=test --projects=engine,shared,server-api --parallel=3 agents: name: Nx Cloud - Agents diff --git a/.gitignore b/.gitignore index f6956f1590..0d794a28ea 100644 --- a/.gitignore +++ b/.gitignore @@ -6,7 +6,6 @@ tmp .nx/ /out-tsc firebase-admin-sdk.json -cache dev # SDK Build @@ -49,7 +48,6 @@ Thumbs.db .angular activepieces-engine.js .history/ -packages/backend/.env # produced by unsandboxed engine execution .pnpm-store @@ -61,4 +59,3 @@ packages/backend/.env scratch.md # environment variables -.env diff --git a/.husky/commit-msg b/.husky/commit-msg index 5074338aac..5098393f9d 100755 --- a/.husky/commit-msg +++ b/.husky/commit-msg @@ -2,7 +2,7 @@ . "$(dirname -- "$0")/_/husky.sh" # Check if the commit includes changes to the backend's .env file -if git diff --cached --name-only -- packages/backend/.env | grep -q '^packages/backend/.env$'; then +if git diff --cached --name-only -- packages/server/api/.env | grep -q '^packages/server/api/.env$'; then echo "Error: You're attempting to commit the backend's .env file. Please avoid committing this file." exit 1 fi diff --git a/Dockerfile b/Dockerfile index 5f3ac35297..8e09252e80 100644 --- a/Dockerfile +++ b/Dockerfile @@ -49,10 +49,10 @@ COPY . . COPY .npmrc package.json package-lock.json ./ RUN npm ci -RUN npx nx run-many --target=build --projects=backend,ui-core --configuration production --skip-nx-cache +RUN npx nx run-many --target=build --projects=server-api,ui-core --configuration production --skip-nx-cache # Install backend production dependencies -RUN cd dist/packages/backend && npm install --production --force +RUN cd dist/packages/server/api && npm install --production --force ### STAGE 2: Run ### FROM base AS run @@ -60,7 +60,7 @@ FROM base AS run # Set up backend WORKDIR /usr/src/app -COPY packages/backend/src/assets/default.cf /usr/local/etc/isolate +COPY packages/server/api/src/assets/default.cf /usr/local/etc/isolate # Install Nginx and gettext for envsubst RUN apt-get update && apt-get install -y nginx gettext diff --git a/LICENSE b/LICENSE index 188558cd3d..73e0a2f7ac 100755 --- a/LICENSE +++ b/LICENSE @@ -2,7 +2,7 @@ Copyright (c) 2020-2024 Activepieces Inc. Portions of this software are licensed as follows: -* All content that resides under the "packages/ee/" and "packages/backend/src/app/ee/" directory of this repository, if that directory exists, is licensed under the license defined in packages/ee/LICENSE +* All content that resides under the "packages/ee/" and "packages/server/api/src/app/ee" directory of this repository, if that directory exists, is licensed under the license defined in packages/ee/LICENSE * All third party components incorporated into the Activepieces Inc Software are licensed under the original license provided by the owner of the applicable component. * Content outside of the above mentioned directories or restrictions above is available under the "MIT Expat" license as defined below. diff --git a/docker-entrypoint.sh b/docker-entrypoint.sh index c5b165540a..e09ada01a3 100644 --- a/docker-entrypoint.sh +++ b/docker-entrypoint.sh @@ -4,4 +4,4 @@ nginx -g "daemon off;" & # Start backend server -node --enable-source-maps dist/packages/backend/main.js +node --enable-source-maps dist/packages/server/api/main.js diff --git a/docs/about/license.mdx b/docs/about/license.mdx index 67c09b51e7..26c3224e41 100755 --- a/docs/about/license.mdx +++ b/docs/about/license.mdx @@ -8,7 +8,7 @@ Activepieces' **core** is released as open source under the [MIT license](https: The MIT license is a permissive license that grants users the freedom to use, modify, or distribute the software without any significant restrictions. The only requirement is that you include the license notice along with the software when distributing it. -Using the enterprise features (under the packages/ee and packages/backend/src/app/ee folder) with a self-hosted instance requires an Activepieces license. If you are looking for these features, contact us at [sales@activepieces.com](mailto:sales@activepieces.com). +Using the enterprise features (under the packages/ee and packages/server/api/src/app/ee folder) with a self-hosted instance requires an Activepieces license. If you are looking for these features, contact us at [sales@activepieces.com](mailto:sales@activepieces.com). **Benefits of Dual Licensing Repo** diff --git a/docs/developers/architecture/repo-structure.mdx b/docs/developers/architecture/repo-structure.mdx index 38be2477db..ee70dd6c33 100755 --- a/docs/developers/architecture/repo-structure.mdx +++ b/docs/developers/architecture/repo-structure.mdx @@ -9,7 +9,7 @@ The repository is structured as a monorepo using the NX build system, with TypeS . ├── packages │ ├── ui -│ ├── backend +│ ├── server | ├── ee │ ├── engine │ ├── pieces @@ -18,7 +18,7 @@ The repository is structured as a monorepo using the NX build system, with TypeS ``` - `ui`: This package contains the user interface, implemented using the Angular framework. -- `backend`: This package contains the API implementation, using the Fastify framework. +- `server`: This package contains the API implementation, using the Fastify framework. - `ee`: This package contains features that are only available in the paid edition. - `engine`: This package contains the logic for flow execution within the sandbox. - `pieces`: This package contains the implementation of triggers and actions for third-party apps. diff --git a/docs/developers/building-pieces/create-action.mdx b/docs/developers/building-pieces/create-action.mdx index 44f730596b..d2f83dfc9e 100755 --- a/docs/developers/building-pieces/create-action.mdx +++ b/docs/developers/building-pieces/create-action.mdx @@ -169,7 +169,7 @@ export const gelato = createPiece({ # Testing -By default, the development setup only builds specific components. Open the file `packages/backend/.env` and include "gelato" in the `AP_DEV_PIECES`. +By default, the development setup only builds specific components. Open the file `packages/server/api/.env` and include "gelato" in the `AP_DEV_PIECES`. For more details, check out the [Piece Development](../development-setup/getting-started) section. diff --git a/docs/developers/building-pieces/create-trigger.mdx b/docs/developers/building-pieces/create-trigger.mdx index a56312c711..cbff24bd4f 100644 --- a/docs/developers/building-pieces/create-trigger.mdx +++ b/docs/developers/building-pieces/create-trigger.mdx @@ -128,7 +128,7 @@ export const gelato = createPiece({ # Testing -By default, the development setup only builds specific components. Open the file `packages/backend/.env` and include "gelato" in the `AP_DEV_PIECES`. +By default, the development setup only builds specific components. Open the file `packages/server/api/.env` and include "gelato" in the `AP_DEV_PIECES`. For more details, check out the [Piece Development](../development-setup/getting-started) section. diff --git a/docs/developers/development-setup/getting-started.mdx b/docs/developers/development-setup/getting-started.mdx index 07c5e03126..a4b078165a 100644 --- a/docs/developers/development-setup/getting-started.mdx +++ b/docs/developers/development-setup/getting-started.mdx @@ -16,7 +16,7 @@ To set up the development environment, you can choose one of the following metho To avoid making the dev environment slow, not all pieces are functional during development at first. By default, only these pieces are functional at first, as specified in `AP_DEV_PIECES`. -(https://github.com/activepieces/activepieces/blob/main/packages/backend/.env#L4 +https://github.com/activepieces/activepieces/blob/main/packages/server/api/.env#L4 To override the default list available at first, define an `AP_DEV_PIECES` environment variable with a comma-separated list of pieces to make available. For example, to make `google-sheets` and `cal-com` available, you can use: diff --git a/docs/developers/piece-reference/triggers/webhook-trigger.mdx b/docs/developers/piece-reference/triggers/webhook-trigger.mdx index 2223552c86..086e14eb0b 100644 --- a/docs/developers/piece-reference/triggers/webhook-trigger.mdx +++ b/docs/developers/piece-reference/triggers/webhook-trigger.mdx @@ -30,7 +30,7 @@ To make your webhook accessible from the internet, you need to configure the bac 1. Install ngrok. 2. Run the command `ngrok http 3000`. -3. Replace the `AP_WEBHOOK_URL` environment variable in `packages/backend/.env` with the ngrok URL. +3. Replace the `AP_WEBHOOK_URL` environment variable in `packages/server/api/.env` with the ngrok URL. Once you have completed these configurations, you are good to go! diff --git a/package-lock.json b/package-lock.json index 27cba1052a..eb45cdf5ca 100644 --- a/package-lock.json +++ b/package-lock.json @@ -269,6 +269,8 @@ "typescript": "5.1.6", "verdaccio": "5.29.0", "wait-on": "7.2.0", + "webpack": "5.90.1", + "webpack-cli": "5.1.4", "webpack-ignore-dynamic-require": "1.0.0" } }, @@ -866,6 +868,15 @@ "node": ">=12" } }, + "node_modules/@angular-devkit/build-angular/node_modules/ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "dev": true, + "peerDependencies": { + "ajv": "^6.9.1" + } + }, "node_modules/@angular-devkit/build-angular/node_modules/autoprefixer": { "version": "10.4.14", "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.14.tgz", @@ -937,6 +948,28 @@ "@esbuild/win32-x64": "0.18.17" } }, + "node_modules/@angular-devkit/build-angular/node_modules/eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, "node_modules/@angular-devkit/build-angular/node_modules/inquirer": { "version": "8.2.4", "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-8.2.4.tgz", @@ -963,6 +996,12 @@ "node": ">=12.0.0" } }, + "node_modules/@angular-devkit/build-angular/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, "node_modules/@angular-devkit/build-angular/node_modules/lru-cache": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", @@ -981,6 +1020,40 @@ "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==", "dev": true }, + "node_modules/@angular-devkit/build-angular/node_modules/schema-utils": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", + "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/schema-utils/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, "node_modules/@angular-devkit/build-angular/node_modules/semver": { "version": "7.5.4", "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", @@ -1002,6 +1075,53 @@ "integrity": "sha512-t0hLfiEKfMUoqhG+U1oid7Pva4bbDPHYfJNiB7BiIjRkj1pyC++4N3huJfqY6aRH6VTB0rvtzQwjM4K6qpfOig==", "dev": true }, + "node_modules/@angular-devkit/build-angular/node_modules/webpack": { + "version": "5.88.2", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.88.2.tgz", + "integrity": "sha512-JmcgNZ1iKj+aiR0OvTYtWQqJwq37Pf683dY9bVORwVbUrDhLhdn/PlO2sHsFHPkj7sHNQF3JwaAkp49V+Sq1tQ==", + "dev": true, + "dependencies": { + "@types/eslint-scope": "^3.7.3", + "@types/estree": "^1.0.0", + "@webassemblyjs/ast": "^1.11.5", + "@webassemblyjs/wasm-edit": "^1.11.5", + "@webassemblyjs/wasm-parser": "^1.11.5", + "acorn": "^8.7.1", + "acorn-import-assertions": "^1.9.0", + "browserslist": "^4.14.5", + "chrome-trace-event": "^1.0.2", + "enhanced-resolve": "^5.15.0", + "es-module-lexer": "^1.2.1", + "eslint-scope": "5.1.1", + "events": "^3.2.0", + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.2.9", + "json-parse-even-better-errors": "^2.3.1", + "loader-runner": "^4.2.0", + "mime-types": "^2.1.27", + "neo-async": "^2.6.2", + "schema-utils": "^3.2.0", + "tapable": "^2.1.1", + "terser-webpack-plugin": "^5.3.7", + "watchpack": "^2.4.0", + "webpack-sources": "^3.2.3" + }, + "bin": { + "webpack": "bin/webpack.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependenciesMeta": { + "webpack-cli": { + "optional": true + } + } + }, "node_modules/@angular-devkit/build-angular/node_modules/wrap-ansi": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", @@ -13732,6 +13852,50 @@ "@xtuc/long": "4.2.2" } }, + "node_modules/@webpack-cli/configtest": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-2.1.1.tgz", + "integrity": "sha512-wy0mglZpDSiSS0XHrVR+BAdId2+yxPSoJW8fsna3ZpYSlufjvxnP4YbKTCBZnNIcGN4r6ZPXV55X4mYExOfLmw==", + "dev": true, + "engines": { + "node": ">=14.15.0" + }, + "peerDependencies": { + "webpack": "5.x.x", + "webpack-cli": "5.x.x" + } + }, + "node_modules/@webpack-cli/info": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-2.0.2.tgz", + "integrity": "sha512-zLHQdI/Qs1UyT5UBdWNqsARasIA+AaF8t+4u2aS2nEpBQh2mWIVb8qAklq0eUENnC5mOItrIB4LiS9xMtph18A==", + "dev": true, + "engines": { + "node": ">=14.15.0" + }, + "peerDependencies": { + "webpack": "5.x.x", + "webpack-cli": "5.x.x" + } + }, + "node_modules/@webpack-cli/serve": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-2.0.5.tgz", + "integrity": "sha512-lqaoKnRYBdo1UgDX8uF24AfGMifWK19TxPmM5FHc2vAGxrJ/qtyUyFBWoY1tISZdelsQ5fBcOusifo5o5wSJxQ==", + "dev": true, + "engines": { + "node": ">=14.15.0" + }, + "peerDependencies": { + "webpack": "5.x.x", + "webpack-cli": "5.x.x" + }, + "peerDependenciesMeta": { + "webpack-dev-server": { + "optional": true + } + } + }, "node_modules/@wessberg/ts-evaluator": { "version": "0.0.27", "resolved": "https://registry.npmjs.org/@wessberg/ts-evaluator/-/ts-evaluator-0.0.27.tgz", @@ -22513,6 +22677,15 @@ "node": ">=12" } }, + "node_modules/interpret": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-3.1.1.tgz", + "integrity": "sha512-6xwYfHbajpoF0xLW+iwLkhwgvLoZDfjYfoFNu8ftMoXINzwuymNLd9u/KmwtdT2GbR+/Cz66otEGEVVUHX9QLQ==", + "dev": true, + "engines": { + "node": ">=10.13.0" + } + }, "node_modules/ioredis": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/ioredis/-/ioredis-5.3.2.tgz", @@ -32433,6 +32606,18 @@ "node": ">= 12.13.0" } }, + "node_modules/rechoir": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.8.0.tgz", + "integrity": "sha512-/vxpCXddiX8NGfGO/mTafwjq4aFa/71pvamip0++IQk3zG8cbCj0fifNPrjjF1XMXUne91jL9OoxmdykoEtifQ==", + "dev": true, + "dependencies": { + "resolve": "^1.20.0" + }, + "engines": { + "node": ">= 10.13.0" + } + }, "node_modules/redent": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz", @@ -38372,19 +38557,19 @@ } }, "node_modules/webpack": { - "version": "5.88.2", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.88.2.tgz", - "integrity": "sha512-JmcgNZ1iKj+aiR0OvTYtWQqJwq37Pf683dY9bVORwVbUrDhLhdn/PlO2sHsFHPkj7sHNQF3JwaAkp49V+Sq1tQ==", + "version": "5.90.1", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.90.1.tgz", + "integrity": "sha512-SstPdlAC5IvgFnhiRok8hqJo/+ArAbNv7rhU4fnWGHNVfN59HSQFaxZDSAL3IFG2YmqxuRs+IU33milSxbPlog==", "dev": true, "dependencies": { "@types/eslint-scope": "^3.7.3", - "@types/estree": "^1.0.0", + "@types/estree": "^1.0.5", "@webassemblyjs/ast": "^1.11.5", "@webassemblyjs/wasm-edit": "^1.11.5", "@webassemblyjs/wasm-parser": "^1.11.5", "acorn": "^8.7.1", "acorn-import-assertions": "^1.9.0", - "browserslist": "^4.14.5", + "browserslist": "^4.21.10", "chrome-trace-event": "^1.0.2", "enhanced-resolve": "^5.15.0", "es-module-lexer": "^1.2.1", @@ -38398,7 +38583,7 @@ "neo-async": "^2.6.2", "schema-utils": "^3.2.0", "tapable": "^2.1.1", - "terser-webpack-plugin": "^5.3.7", + "terser-webpack-plugin": "^5.3.10", "watchpack": "^2.4.0", "webpack-sources": "^3.2.3" }, @@ -38418,6 +38603,60 @@ } } }, + "node_modules/webpack-cli": { + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-5.1.4.tgz", + "integrity": "sha512-pIDJHIEI9LR0yxHXQ+Qh95k2EvXpWzZ5l+d+jIo+RdSm9MiHfzazIxwwni/p7+x4eJZuvG1AJwgC4TNQ7NRgsg==", + "dev": true, + "dependencies": { + "@discoveryjs/json-ext": "^0.5.0", + "@webpack-cli/configtest": "^2.1.1", + "@webpack-cli/info": "^2.0.2", + "@webpack-cli/serve": "^2.0.5", + "colorette": "^2.0.14", + "commander": "^10.0.1", + "cross-spawn": "^7.0.3", + "envinfo": "^7.7.3", + "fastest-levenshtein": "^1.0.12", + "import-local": "^3.0.2", + "interpret": "^3.1.1", + "rechoir": "^0.8.0", + "webpack-merge": "^5.7.3" + }, + "bin": { + "webpack-cli": "bin/cli.js" + }, + "engines": { + "node": ">=14.15.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "5.x.x" + }, + "peerDependenciesMeta": { + "@webpack-cli/generators": { + "optional": true + }, + "webpack-bundle-analyzer": { + "optional": true + }, + "webpack-dev-server": { + "optional": true + } + } + }, + "node_modules/webpack-cli/node_modules/commander": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz", + "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==", + "dev": true, + "engines": { + "node": ">=14" + } + }, "node_modules/webpack-dev-middleware": { "version": "6.1.1", "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-6.1.1.tgz", diff --git a/package.json b/package.json index e6567b9249..e29e5bf761 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "scripts": { "prepare": "husky install", "serve:frontend": "nx serve ui-core", - "serve:backend": "nx serve backend", + "serve:backend": "nx serve server-api", "serve:engine": "nx serve engine", "serve:pieces": "turbowatch tools/scripts/pieces/turbowatch.ts", "dev": "cross-env-shell FORCE_COLOR=true concurrently -n \"GUI,API,ENG,PCS\" -c \"bgBlue.bold,bgGreen.bold,bgRed.bold,bgYellow.bold\" \"npm:serve:frontend\" \"npm:serve:backend\" \"npm:serve:engine\" \"npm:serve:pieces\"", @@ -281,6 +281,8 @@ "typescript": "5.1.6", "verdaccio": "5.29.0", "wait-on": "7.2.0", + "webpack": "5.90.1", + "webpack-cli": "5.1.4", "webpack-ignore-dynamic-require": "1.0.0" }, "nx": { diff --git a/packages/backend/.eslintrc.json b/packages/backend/.eslintrc.json deleted file mode 100644 index 3072cca532..0000000000 --- a/packages/backend/.eslintrc.json +++ /dev/null @@ -1,102 +0,0 @@ -{ - "extends": [ - "../../.eslintrc.json", - "plugin:@typescript-eslint/eslint-recommended", - "plugin:@typescript-eslint/recommended", - "plugin:@typescript-eslint/strict" - ], - "ignorePatterns": [ - "!**/*" - ], - "overrides": [ - { - "files": [ - "*.ts", - "*.js" - ], - "parserOptions": { - "project": [ - "packages/backend/tsconfig.*?.json" - ] - }, - "rules": { - "no-console": "error", - "object-shorthand": "error", - "@typescript-eslint/switch-exhaustiveness-check": "error", - "@typescript-eslint/brace-style": [ - "error", - "stroustrup" - ], - "@typescript-eslint/comma-dangle": [ - "error", - "always-multiline" - ], - "@typescript-eslint/indent": [ - "error", - 4 - ], - "@typescript-eslint/quotes": [ - "error", - "single" - ], - "@typescript-eslint/semi": [ - "error", - "never" - ], - "@typescript-eslint/consistent-type-definitions": [ - "error", - "type" - ], - "@typescript-eslint/no-explicit-any": "error", - "@typescript-eslint/no-redundant-type-constituents": "error", - "@typescript-eslint/await-thenable": "error", - "@typescript-eslint/adjacent-overload-signatures": "error", - "@typescript-eslint/comma-spacing": "error", - "@typescript-eslint/type-annotation-spacing": "error", - "@typescript-eslint/block-spacing": "error", - "@typescript-eslint/func-call-spacing": "error", - "@typescript-eslint/key-spacing": "error", - "@typescript-eslint/object-curly-spacing": [ - "error", - "always" - ], - "@typescript-eslint/space-before-blocks": "error", - "@typescript-eslint/member-delimiter-style": [ - "error", - { - "multiline": { - "delimiter": "none" - }, - "singleline": { - "delimiter": "comma", - "requireLast": false - } - } - ], - "@typescript-eslint/no-unused-vars": [ - "error", - { - "varsIgnorePattern": "^_", - "argsIgnorePattern": "^_" - } - ], - "@typescript-eslint/space-before-function-paren": [ - "error", - { - "anonymous": "always", - "named": "never", - "asyncArrow": "always" - } - ], - "@typescript-eslint/space-infix-ops": "error", - "@typescript-eslint/keyword-spacing": "error", - "@typescript-eslint/explicit-function-return-type": "warn", - "@typescript-eslint/no-floating-promises": "error", - "@typescript-eslint/no-misused-promises": "warn", - "no-return-await": "off", - "@typescript-eslint/return-await": ["error", "in-try-catch"], - "default-case-last": "error" - } - } - ] -} diff --git a/packages/backend/src/app/app-connection/app-connection-worker-controller.ts b/packages/backend/src/app/app-connection/app-connection-worker-controller.ts deleted file mode 100644 index 1fdfb28848..0000000000 --- a/packages/backend/src/app/app-connection/app-connection-worker-controller.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { ActivepiecesError, AppConnection, ErrorCode, isNil } from '@activepieces/shared' -import { FastifyPluginCallbackTypebox, Type } from '@fastify/type-provider-typebox' -import { allowWorkersOnly } from '../authentication/authorization' -import { appConnectionService } from './app-connection-service/app-connection-service' - -export const appConnectionWorkerController: FastifyPluginCallbackTypebox = (app, _opts, done) => { - app.addHook('preHandler', allowWorkersOnly) - - app.get('/:connectionName', GetAppConnectionRequest, async (request): Promise => { - const appConnection = await appConnectionService.getOne({ - projectId: request.principal.projectId, - name: request.params.connectionName, - }) - - if (isNil(appConnection)) { - throw new ActivepiecesError({ - code: ErrorCode.APP_CONNECTION_NOT_FOUND, - params: { - id: request.params.connectionName, - }, - }) - } - - return appConnection - }) - - done() -} - -const GetAppConnectionRequest = { - schema: { - params: Type.Object({ - connectionName: Type.String(), - }), - }, -} diff --git a/packages/backend/src/app/app-event-routing/app-event-routing.service.ts b/packages/backend/src/app/app-event-routing/app-event-routing.service.ts deleted file mode 100644 index 8774543549..0000000000 --- a/packages/backend/src/app/app-event-routing/app-event-routing.service.ts +++ /dev/null @@ -1,52 +0,0 @@ -import { apId, FlowId, ProjectId } from '@activepieces/shared' -import { databaseConnection } from '../database/database-connection' -import { AppEventRouting, AppEventRoutingEntity } from './app-event-routing.entity' -import { logger } from '../helper/logger' -import { SystemProp } from '../helper/system/system-prop' -import { system } from '../helper/system/system' - - -const appEventRoutingRepo = databaseConnection.getRepository(AppEventRoutingEntity) - -export const appEventRoutingService = { - async listListeners({ appName, event, identifierValue }: { appName: string, event: string, identifierValue: string }): Promise { - return appEventRoutingRepo.findBy({ appName, event, identifierValue }) - }, - async createListeners({ appName, events, identifierValue, flowId, projectId }: { - appName: string - events: string[] - identifierValue: string - flowId: FlowId - projectId: ProjectId - }): Promise { - logger.info(`Creating listeners for ${appName}, events=${events}, identifierValue=${identifierValue}`) - const upsertCommands: Promise[] = [] - events.forEach(event => { - const upsert = appEventRoutingRepo.upsert({ - id: apId(), - appName, - event, - identifierValue, - flowId, - projectId, - }, ['appName', 'event', 'identifierValue', 'projectId']) - upsertCommands.push(upsert) - }) - await Promise.all(upsertCommands) - }, - async deleteListeners({ projectId, flowId }: { projectId: ProjectId, flowId: FlowId }): Promise { - await appEventRoutingRepo.delete({ - projectId, - flowId, - }) - }, - async getAppWebhookUrl({ appName }: { appName: string }): Promise { - const webhookUrl = system.get(SystemProp.WEBHOOK_URL) - if (webhookUrl) { - return `${webhookUrl}/v1/app-events/${appName}` - } - const frontendUrl = system.get(SystemProp.FRONTEND_URL) - return `${frontendUrl}/api/v1/app-events/${appName}` - }, -} - diff --git a/packages/backend/src/app/database/migration/common/1697969398200-store-code-inside-flow.ts b/packages/backend/src/app/database/migration/common/1697969398200-store-code-inside-flow.ts deleted file mode 100644 index 7676564939..0000000000 --- a/packages/backend/src/app/database/migration/common/1697969398200-store-code-inside-flow.ts +++ /dev/null @@ -1,169 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm' -import { logger } from '../../../helper/logger' -import { isNil } from '@activepieces/shared' -import decompress from 'decompress' - -type FunctionTransformer = (s: CodeStep, fileRepo: QueryRunner, flowId: string, flowVersionId: string) => Promise - -export class StoreCodeInsideFlow1697969398200 implements MigrationInterface { - - public async up(queryRunner: QueryRunner): Promise { - await this.processFlowVersions(queryRunner, flattenCodeStep) - await this.processFlowTemplates(queryRunner, flattenCodeStep) - - logger.info('StoreCodeInsideFlow1697969398200: up finished') - } - - public async down(queryRunner: QueryRunner): Promise { - await this.processFlowVersions(queryRunner, removeNewCodeField) - await this.processFlowTemplates(queryRunner, removeNewCodeField) - - logger.info('StoreCodeInsideFlow1697969398200: down finished') - } - - private async processFlowVersions(queryRunner: QueryRunner, stepFunction: FunctionTransformer) { - const flowVersionIds = await queryRunner.query('SELECT id FROM flow_version') - - for (const { id } of flowVersionIds) { - const flowVersion = await this.findFlowVersionById(queryRunner, id) - - if (flowVersion) { - const updated = await traverseAndUpdateSubFlow(stepFunction, flowVersion.trigger, queryRunner, flowVersion.flowId, flowVersion.id) - - if (updated) { - await this.updateFlowVersion(queryRunner, flowVersion.id, flowVersion) - } - } - } - } - - private async processFlowTemplates(queryRunner: QueryRunner, stepFunction: FunctionTransformer) { - // Check if the "flow_template" table exists - const doesTableExist = await queryRunner.hasTable('flow_template') - - if (doesTableExist) { - logger.info('StoreCodeInsideFlow1697969398200: flow template table exists') - - const templates = await queryRunner.query('SELECT * FROM flow_template') - for (const template of templates) { - const updated = await traverseAndUpdateSubFlow(stepFunction, template.template.trigger, queryRunner, template.projectId, template.id) - - if (updated) { - await queryRunner.query('UPDATE flow_template SET template = $1 WHERE id = $2', [template.template, template.id]) - } - } - } - } - - private async findFlowVersionById(queryRunner: QueryRunner, id: string): Promise { - const flowVersion = await queryRunner.query('SELECT * FROM flow_version WHERE id = $1', [id]) - return flowVersion[0] - } - - private async updateFlowVersion(queryRunner: QueryRunner, id: string, flowVersion: FlowVersion): Promise { - await queryRunner.query('UPDATE flow_version SET "flowId" = $1, trigger = $2 WHERE id = $3', [flowVersion.flowId, flowVersion.trigger, id]) - } -} - -const traverseAndUpdateSubFlow = async (updater: FunctionTransformer, root: Step | undefined, queryRunner: QueryRunner, flowId: string, flowVersionId: string): Promise => { - if (!root) { - return false - } - - let updated = false - - switch (root.type) { - case 'BRANCH': - updated = await traverseAndUpdateSubFlow(updater, root.onSuccessAction, queryRunner, flowId, flowVersionId) || updated - updated = await traverseAndUpdateSubFlow(updater, root.onFailureAction, queryRunner, flowId, flowVersionId) || updated - break - case 'LOOP_ON_ITEMS': - updated = await traverseAndUpdateSubFlow(updater, root.firstLoopAction, queryRunner, flowId, flowVersionId) || updated - break - case 'CODE': - await updater(root, queryRunner, flowId, flowVersionId) - updated = true - break - default: - break - } - - updated = await traverseAndUpdateSubFlow(updater, root.nextAction, queryRunner, flowId, flowVersionId) || updated - return updated -} - -const flattenCodeStep = async (codeStep: CodeStep, queryRunner: QueryRunner, flowVersionId: string, flowId: string): Promise => { - const sourceCodeId = codeStep.settings.artifactSourceId - const sourceCode = codeStep.settings.sourceCode - if (!isNil(sourceCodeId) && isNil(sourceCode)) { - const [file] = await queryRunner.query('SELECT * FROM file WHERE id = $1', [sourceCodeId]) - if (isNil(file)) { - logger.warn(`StoreCodeInsideFlow1697969398100: file not found for file id ${sourceCodeId} in flow ${flowId} of flow version ${flowVersionId}`) - return - } - const buffer = await decompress(file.data) - const code = buffer.find((f: { path: string | string[] }) => f.path.includes('index.ts') || f.path.includes('index.js')) - const packageJson = buffer.find((f: { path: string | string[] }) => f.path.includes('package.json')) - if (isNil(code) || isNil(packageJson)) { - logger.warn(`StoreCodeInsideFlow1697969398100: code or package.json not found for file ${file.id} in flow ${flowId} of flow version ${flowVersionId}`) - return - } - codeStep.settings.sourceCode = { - code: code.data.toString('utf-8'), - packageJson: packageJson.data.toString('utf-8'), - } - } -} - -const removeNewCodeField = async (codeStep: CodeStep, _queryRunner: QueryRunner): Promise => { - delete codeStep.settings.sourceCode -} - - -type StepType = - | 'BRANCH' - | 'CODE' - | 'EMPTY' - | 'LOOP_ON_ITEMS' - | 'MISSING' - | 'PIECE' - | 'PIECE_TRIGGER' - | 'WEBHOOK' - -type BaseStep = { - type: T - nextAction?: Step -} - -type BranchStep = BaseStep<'BRANCH'> & { - onFailureAction?: Step - onSuccessAction?: Step -} - -type LoopOnItemsStep = BaseStep<'LOOP_ON_ITEMS'> & { - firstLoopAction?: Step -} - -type CodeStep = BaseStep<'CODE'> & { - settings: { - artifactSourceId: string - sourceCode?: { - code: string - packageJson: string - } - } -} - -type GenericStep = BaseStep<'PIECE' | 'PIECE_TRIGGER' | 'EMPTY' | 'MISSING' | 'WEBHOOK'> - -type Step = - | BranchStep - | LoopOnItemsStep - | GenericStep - | CodeStep - -type FlowVersion = { - id: string - flowId: string - trigger?: Step -} diff --git a/packages/backend/src/app/database/migration/postgres/1674788714498-FlowAndFileProjectId.ts b/packages/backend/src/app/database/migration/postgres/1674788714498-FlowAndFileProjectId.ts deleted file mode 100644 index 1a948c9df3..0000000000 --- a/packages/backend/src/app/database/migration/postgres/1674788714498-FlowAndFileProjectId.ts +++ /dev/null @@ -1,83 +0,0 @@ -import { logger } from '../../../helper/logger' -import { MigrationInterface, QueryRunner } from 'typeorm' - -export class FlowAndFileProjectId1674788714498 implements MigrationInterface { - - public async up(queryRunner: QueryRunner): Promise { - logger.info('FlowAndFileProjectId1674788714498: started') - - const flowTableExistsQueryResponse: { exists: boolean }[] = await queryRunner.query( - `SELECT exists ( - SELECT FROM information_schema.tables - WHERE table_schema = 'public' - AND table_name = 'flow' - )`, - ) - - const flowTableNotExist = - flowTableExistsQueryResponse && - flowTableExistsQueryResponse.length > 0 && - !flowTableExistsQueryResponse[0].exists - - if (flowTableNotExist) { - logger.info('FlowAndFileProjectId1674788714498: skipped') - return - } - - const flows = await queryRunner.query('SELECT * FROM flow') - for (let i = 0; i < flows.length; ++i) { - const currentFlow = flows[i] - const collection = await queryRunner.query('SELECT * FROM collection WHERE id = $1', [currentFlow.collectionId]) - currentFlow.projectId = collection[0].projectId - await queryRunner.query('UPDATE flow SET "projectId" = $1 WHERE id = $2', [currentFlow.projectId, currentFlow.id]) - } - - const flowVersions = await queryRunner.query('SELECT * FROM flow_version') - for (let i = 0; i < flowVersions.length; ++i) { - const currentFlowVersion = flowVersions[i] - const currentFlow = await queryRunner.query('SELECT * FROM flow WHERE id = $1', [currentFlowVersion.flowId]) - let action = currentFlowVersion.trigger?.nextAction - while (action !== undefined && action !== null) { - if (action.type === 'CODE') { - const packagedFileId = action.settings.artifactPackagedId - if (packagedFileId !== undefined && packagedFileId !== null) { - const packagedFileToUpdate = await queryRunner.query('SELECT * FROM file WHERE id = $1', [packagedFileId]) - if (packagedFileToUpdate.length === 0) { - logger.error('Found an old packaged artifact file id without file ' + packagedFileId + ' and for flow ' + currentFlow[0].id) - } - else { - packagedFileToUpdate[0].projectId = currentFlow[0].projectId - await queryRunner.query('UPDATE file SET "projectId" = $1 WHERE id = $2', [packagedFileToUpdate[0].projectId, packagedFileId]) - } - } - const sourceFileId = action.settings.artifactSourceId - if (sourceFileId !== undefined && sourceFileId !== null) { - const sourceFileToUpdate = await queryRunner.query('SELECT * FROM file WHERE id = $1', [sourceFileId]) - if (sourceFileToUpdate.length === 0) { - logger.error('Found an old source artifact file id without file ' + sourceFileId + ' and for flow ' + currentFlow[0].id) - } - else { - sourceFileToUpdate[0].projectId = currentFlow[0].projectId - await queryRunner.query('UPDATE file SET "projectId" = $1 WHERE id = $2', [sourceFileToUpdate[0].projectId, sourceFileId]) - } - } - } - action = action.nextAction - } - } - - const flowRuns = await queryRunner.query('SELECT * FROM flow_run') - for (let i = 0; i < flowRuns.length; ++i) { - const currentFlowRun = flowRuns[i] - if (currentFlowRun.logsFileId !== undefined && currentFlowRun.logsFileId !== null) { - const logFlowRunFile = await queryRunner.query('SELECT * FROM file WHERE id = $1', [currentFlowRun.logsFileId]) - logFlowRunFile[0].projectId = currentFlowRun.projectId - await queryRunner.query('UPDATE file SET "projectId" = $1 WHERE id = $2', [logFlowRunFile[0].projectId, logFlowRunFile[0].id]) - } - } - } - - // eslint-disable-next-line @typescript-eslint/no-empty-function - public async down(): Promise { } - -} diff --git a/packages/backend/src/app/database/migration/postgres/1676238396411-initialize-schema.ts b/packages/backend/src/app/database/migration/postgres/1676238396411-initialize-schema.ts deleted file mode 100644 index 8c446b5bc8..0000000000 --- a/packages/backend/src/app/database/migration/postgres/1676238396411-initialize-schema.ts +++ /dev/null @@ -1,107 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm' -import { logger } from '../../../helper/logger' - -export class initializeSchema1676238396411 implements MigrationInterface { - name = 'initializeSchema1676238396411' - - public async up(queryRunner: QueryRunner): Promise { - logger.info('initializeSchema1676238396411: started') - - const userTableExistsQueryResponse: { exists: boolean }[] = await queryRunner.query( - `SELECT exists ( - SELECT FROM information_schema.tables - WHERE table_schema = 'public' - AND table_name = 'user' - )`, - ) - - const userTableExists = - userTableExistsQueryResponse && - userTableExistsQueryResponse.length > 0 && - userTableExistsQueryResponse[0].exists - - if (userTableExists) { - logger.info('initializeSchema1676238396411: skipped') - return - } - - await queryRunner.query('CREATE TABLE "collection" ("id" character varying(21) NOT NULL, "created" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "updated" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "projectId" character varying(21) NOT NULL, CONSTRAINT "PK_ad3f485bbc99d875491f44d7c85" PRIMARY KEY ("id"))') - await queryRunner.query('CREATE INDEX "idx_collection_project_id" ON "collection" ("projectId") ') - await queryRunner.query('CREATE TABLE "collection_version" ("id" character varying(21) NOT NULL, "created" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "updated" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "displayName" character varying NOT NULL, "collectionId" character varying(21) NOT NULL, "configs" jsonb NOT NULL, "state" character varying NOT NULL, CONSTRAINT "PK_76c769e96c091b478e3c338a0ac" PRIMARY KEY ("id"))') - await queryRunner.query('CREATE INDEX "idx_collection_version_collection_id" ON "collection_version" ("collectionId") ') - await queryRunner.query('CREATE TABLE "file" ("id" character varying(21) NOT NULL, "created" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "updated" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "projectId" character varying(21), "data" bytea NOT NULL, CONSTRAINT "PK_36b46d232307066b3a2c9ea3a1d" PRIMARY KEY ("id"))') - await queryRunner.query('CREATE TABLE "flag" ("id" character varying(21) NOT NULL, "created" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "updated" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "value" jsonb NOT NULL, CONSTRAINT "PK_17b74257294fdfd221178a132d4" PRIMARY KEY ("id"))') - await queryRunner.query('CREATE TABLE "flow" ("id" character varying(21) NOT NULL, "created" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "updated" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "projectId" character varying(21), "collectionId" character varying(21) NOT NULL, CONSTRAINT "PK_6c2ad4a3e86394cd9bb7a80a228" PRIMARY KEY ("id"))') - await queryRunner.query('CREATE INDEX "idx_flow_collection_id" ON "flow" ("collectionId") ') - await queryRunner.query('CREATE TABLE "flow_version" ("id" character varying(21) NOT NULL, "created" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "updated" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "flowId" character varying(21) NOT NULL, "displayName" character varying NOT NULL, "trigger" jsonb, "valid" boolean NOT NULL, "state" character varying NOT NULL, CONSTRAINT "PK_2f20a52dcddf98d3fafe621a9f5" PRIMARY KEY ("id"))') - await queryRunner.query('CREATE INDEX "idx_flow_version_flow_id" ON "flow_version" ("flowId") ') - await queryRunner.query('CREATE TABLE "instance" ("id" character varying(21) NOT NULL, "created" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "updated" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "projectId" character varying(21) NOT NULL, "collectionId" character varying(21) NOT NULL, "collectionVersionId" character varying(21) NOT NULL, "flowIdToVersionId" jsonb NOT NULL, "status" character varying NOT NULL, CONSTRAINT "REL_183c020130aa172f58c6a0c647" UNIQUE ("collectionVersionId"), CONSTRAINT "REL_6b75536fbdf7d8dc967fc350ff" UNIQUE ("collectionId"), CONSTRAINT "PK_eaf60e4a0c399c9935413e06474" PRIMARY KEY ("id"))') - await queryRunner.query('CREATE INDEX "idx_instance_project_id" ON "instance" ("projectId") ') - await queryRunner.query('CREATE UNIQUE INDEX "idx_instance_collection_id" ON "instance" ("collectionId") ') - await queryRunner.query('CREATE TABLE "flow_run" ("id" character varying(21) NOT NULL, "created" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "updated" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "projectId" character varying(21) NOT NULL, "flowId" character varying(21) NOT NULL, "collectionId" character varying(21) NOT NULL, "flowVersionId" character varying(21) NOT NULL, "collectionVersionId" character varying(21) NOT NULL, "environment" character varying, "flowDisplayName" character varying NOT NULL, "collectionDisplayName" character varying NOT NULL, "logsFileId" character varying(21), "status" character varying NOT NULL, "startTime" TIMESTAMP WITH TIME ZONE NOT NULL, "finishTime" TIMESTAMP WITH TIME ZONE, CONSTRAINT "PK_858b1dd0d1055c44261ae00d45b" PRIMARY KEY ("id"))') - await queryRunner.query('CREATE INDEX "idx_run_project_id" ON "flow_run" ("projectId") ') - await queryRunner.query('CREATE TABLE "project" ("id" character varying(21) NOT NULL, "created" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "updated" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "ownerId" character varying(21) NOT NULL, "displayName" character varying NOT NULL, CONSTRAINT "PK_4d68b1358bb5b766d3e78f32f57" PRIMARY KEY ("id"))') - await queryRunner.query('CREATE INDEX "idx_project_owner_id" ON "project" ("ownerId") ') - await queryRunner.query('CREATE TABLE "store-entry" ("id" character varying(21) NOT NULL, "created" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "updated" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "key" character varying NOT NULL, "collectionId" character varying(21) NOT NULL, "value" jsonb NOT NULL, CONSTRAINT "PK_afb44ca7c0b4606b19deb1680d6" PRIMARY KEY ("id"))') - await queryRunner.query('CREATE TABLE "user" ("id" character varying(21) NOT NULL, "created" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "updated" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "email" character varying NOT NULL, "firstName" character varying NOT NULL, "lastName" character varying NOT NULL, "password" character varying NOT NULL, "status" character varying NOT NULL, "trackEvents" boolean, "newsLetter" boolean, CONSTRAINT "UQ_e12875dfb3b1d92d7d7c5377e22" UNIQUE ("email"), CONSTRAINT "PK_cace4a159ff9f2512dd42373760" PRIMARY KEY ("id"))') - await queryRunner.query('CREATE TABLE "app_connection" ("id" character varying(21) NOT NULL, "created" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "updated" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "name" character varying NOT NULL, "appName" character varying NOT NULL, "projectId" character varying(21) NOT NULL, "value" jsonb NOT NULL, CONSTRAINT "PK_9efa2d6633ecc57cc5adeafa039" PRIMARY KEY ("id"))') - await queryRunner.query('CREATE UNIQUE INDEX "idx_app_connection_project_id_and_app_name_and_name" ON "app_connection" ("projectId", "appName", "name") ') - await queryRunner.query('CREATE UNIQUE INDEX "idx_app_connection_project_id_and_name" ON "app_connection" ("projectId", "name") ') - await queryRunner.query('ALTER TABLE "collection" ADD CONSTRAINT "fk_collection_project_id" FOREIGN KEY ("projectId") REFERENCES "project"("id") ON DELETE CASCADE ON UPDATE NO ACTION') - await queryRunner.query('ALTER TABLE "collection_version" ADD CONSTRAINT "fk_collection_version_collection_id" FOREIGN KEY ("collectionId") REFERENCES "collection"("id") ON DELETE CASCADE ON UPDATE NO ACTION') - await queryRunner.query('ALTER TABLE "file" ADD CONSTRAINT "fk_file_project_id" FOREIGN KEY ("projectId") REFERENCES "project"("id") ON DELETE CASCADE ON UPDATE NO ACTION') - await queryRunner.query('ALTER TABLE "flow" ADD CONSTRAINT "fk_flow_project_id" FOREIGN KEY ("projectId") REFERENCES "project"("id") ON DELETE CASCADE ON UPDATE NO ACTION') - await queryRunner.query('ALTER TABLE "flow" ADD CONSTRAINT "fk_flow_collection_id" FOREIGN KEY ("collectionId") REFERENCES "collection"("id") ON DELETE CASCADE ON UPDATE NO ACTION') - await queryRunner.query('ALTER TABLE "flow_version" ADD CONSTRAINT "fk_flow_version_flow" FOREIGN KEY ("flowId") REFERENCES "flow"("id") ON DELETE CASCADE ON UPDATE NO ACTION') - await queryRunner.query('ALTER TABLE "instance" ADD CONSTRAINT "fk_instance_collection_version" FOREIGN KEY ("collectionVersionId") REFERENCES "collection_version"("id") ON DELETE CASCADE ON UPDATE NO ACTION') - await queryRunner.query('ALTER TABLE "instance" ADD CONSTRAINT "fk_instance_collection" FOREIGN KEY ("collectionId") REFERENCES "collection"("id") ON DELETE CASCADE ON UPDATE NO ACTION') - await queryRunner.query('ALTER TABLE "flow_run" ADD CONSTRAINT "fk_flow_run_project_id" FOREIGN KEY ("projectId") REFERENCES "project"("id") ON DELETE CASCADE ON UPDATE NO ACTION') - await queryRunner.query('ALTER TABLE "flow_run" ADD CONSTRAINT "fk_flow_run_flow_id" FOREIGN KEY ("flowId") REFERENCES "flow"("id") ON DELETE CASCADE ON UPDATE NO ACTION') - await queryRunner.query('ALTER TABLE "flow_run" ADD CONSTRAINT "fk_flow_run_collection_id" FOREIGN KEY ("collectionId") REFERENCES "collection"("id") ON DELETE CASCADE ON UPDATE NO ACTION') - await queryRunner.query('ALTER TABLE "flow_run" ADD CONSTRAINT "fk_flow_run_collection_version_id" FOREIGN KEY ("collectionVersionId") REFERENCES "collection_version"("id") ON DELETE CASCADE ON UPDATE NO ACTION') - await queryRunner.query('ALTER TABLE "project" ADD CONSTRAINT "fk_project_owner_id" FOREIGN KEY ("ownerId") REFERENCES "user"("id") ON DELETE NO ACTION ON UPDATE NO ACTION') - await queryRunner.query('ALTER TABLE "app_connection" ADD CONSTRAINT "fk_app_connection_app_project_id" FOREIGN KEY ("projectId") REFERENCES "project"("id") ON DELETE CASCADE ON UPDATE NO ACTION') - - logger.info('initializeSchema1676238396411: completed') - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query('ALTER TABLE "app_connection" DROP CONSTRAINT "fk_app_connection_app_project_id"') - await queryRunner.query('ALTER TABLE "project" DROP CONSTRAINT "fk_project_owner_id"') - await queryRunner.query('ALTER TABLE "flow_run" DROP CONSTRAINT "fk_flow_run_collection_version_id"') - await queryRunner.query('ALTER TABLE "flow_run" DROP CONSTRAINT "fk_flow_run_collection_id"') - await queryRunner.query('ALTER TABLE "flow_run" DROP CONSTRAINT "fk_flow_run_flow_id"') - await queryRunner.query('ALTER TABLE "flow_run" DROP CONSTRAINT "fk_flow_run_project_id"') - await queryRunner.query('ALTER TABLE "instance" DROP CONSTRAINT "fk_instance_collection"') - await queryRunner.query('ALTER TABLE "instance" DROP CONSTRAINT "fk_instance_collection_version"') - await queryRunner.query('ALTER TABLE "flow_version" DROP CONSTRAINT "fk_flow_version_flow"') - await queryRunner.query('ALTER TABLE "flow" DROP CONSTRAINT "fk_flow_collection_id"') - await queryRunner.query('ALTER TABLE "flow" DROP CONSTRAINT "fk_flow_project_id"') - await queryRunner.query('ALTER TABLE "file" DROP CONSTRAINT "fk_file_project_id"') - await queryRunner.query('ALTER TABLE "collection_version" DROP CONSTRAINT "fk_collection_version_collection_id"') - await queryRunner.query('ALTER TABLE "collection" DROP CONSTRAINT "fk_collection_project_id"') - await queryRunner.query('DROP INDEX "public"."idx_app_connection_project_id_and_name"') - await queryRunner.query('DROP INDEX "public"."idx_app_connection_project_id_and_app_name_and_name"') - await queryRunner.query('DROP TABLE "app_connection"') - await queryRunner.query('DROP TABLE "user"') - await queryRunner.query('DROP TABLE "store-entry"') - await queryRunner.query('DROP INDEX "public"."idx_project_owner_id"') - await queryRunner.query('DROP TABLE "project"') - await queryRunner.query('DROP INDEX "public"."idx_run_project_id"') - await queryRunner.query('DROP TABLE "flow_run"') - await queryRunner.query('DROP INDEX "public"."idx_instance_collection_id"') - await queryRunner.query('DROP INDEX "public"."idx_instance_project_id"') - await queryRunner.query('DROP TABLE "instance"') - await queryRunner.query('DROP INDEX "public"."idx_flow_version_flow_id"') - await queryRunner.query('DROP TABLE "flow_version"') - await queryRunner.query('DROP INDEX "public"."idx_flow_collection_id"') - await queryRunner.query('DROP TABLE "flow"') - await queryRunner.query('DROP TABLE "flag"') - await queryRunner.query('DROP TABLE "file"') - await queryRunner.query('DROP INDEX "public"."idx_collection_version_collection_id"') - await queryRunner.query('DROP TABLE "collection_version"') - await queryRunner.query('DROP INDEX "public"."idx_collection_project_id"') - await queryRunner.query('DROP TABLE "collection"') - } - -} diff --git a/packages/backend/src/app/database/migration/postgres/1677286751592-billing.ts b/packages/backend/src/app/database/migration/postgres/1677286751592-billing.ts deleted file mode 100644 index 1c269a8f35..0000000000 --- a/packages/backend/src/app/database/migration/postgres/1677286751592-billing.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm' -import { logger } from '../../../helper/logger' - -export class billing1677286751592 implements MigrationInterface { - name = 'billing1677286751592' - - public async up(queryRunner: QueryRunner): Promise { - logger.info('Running migration billing1677286751592') - await queryRunner.query('DROP INDEX "public"."idx_app_connection_project_id_and_app_name_and_name"') - await queryRunner.query('CREATE TABLE "project_plan" ("id" character varying(21) NOT NULL, "created" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "updated" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "projectId" character varying(21) NOT NULL, "name" character varying NOT NULL, "stripeCustomerId" character varying NOT NULL, "stripeSubscriptionId" character varying NOT NULL, "tasks" integer NOT NULL, "subscriptionStartDatetime" TIMESTAMP WITH TIME ZONE NOT NULL, CONSTRAINT "REL_4f52e89612966d95843e4158bb" UNIQUE ("projectId"), CONSTRAINT "PK_759d33fce71c95de832df935841" PRIMARY KEY ("id"))') - await queryRunner.query('CREATE UNIQUE INDEX "idx_plan_project_id" ON "project_plan" ("projectId") ') - await queryRunner.query('CREATE UNIQUE INDEX "idx_plan_stripe_customer_id" ON "project_plan" ("stripeCustomerId") ') - await queryRunner.query('CREATE TABLE "project_usage" ("id" character varying(21) NOT NULL, "created" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "updated" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "projectId" character varying(21) NOT NULL, "consumedTasks" integer NOT NULL, "nextResetDatetime" TIMESTAMP WITH TIME ZONE NOT NULL, CONSTRAINT "REL_c407fc9b2bfb44515af69d575a" UNIQUE ("projectId"), CONSTRAINT "PK_100c1959e9dc487c4cadbf9cb56" PRIMARY KEY ("id"))') - await queryRunner.query('CREATE UNIQUE INDEX "idx_project_usage_project_id" ON "project_usage" ("projectId") ') - await queryRunner.query('ALTER TABLE "project_plan" ADD CONSTRAINT "fk_project_plan_project_id" FOREIGN KEY ("projectId") REFERENCES "project"("id") ON DELETE CASCADE ON UPDATE NO ACTION') - await queryRunner.query('ALTER TABLE "project_usage" ADD CONSTRAINT "fk_project_usage_project_id" FOREIGN KEY ("projectId") REFERENCES "project"("id") ON DELETE CASCADE ON UPDATE NO ACTION') - logger.info('Finished migration billing1677286751592') - } - - public async down(queryRunner: QueryRunner): Promise { - logger.info('rolling back migration billing1677286751592') - await queryRunner.query('ALTER TABLE "project_usage" DROP CONSTRAINT "fk_project_usage_project_id"') - await queryRunner.query('ALTER TABLE "project_plan" DROP CONSTRAINT "fk_project_plan_project_id"') - await queryRunner.query('DROP INDEX "public"."idx_project_usage_project_id"') - await queryRunner.query('DROP TABLE "project_usage"') - await queryRunner.query('DROP INDEX "public"."idx_plan_stripe_customer_id"') - await queryRunner.query('DROP INDEX "public"."idx_plan_project_id"') - await queryRunner.query('DROP TABLE "project_plan"') - await queryRunner.query('CREATE UNIQUE INDEX "idx_app_connection_project_id_and_app_name_and_name" ON "app_connection" ("name", "appName", "projectId") ') - logger.info('Finished rolling back billing1677286751592') - } - -} diff --git a/packages/backend/src/app/database/migration/postgres/1677894800372-product-embed.ts b/packages/backend/src/app/database/migration/postgres/1677894800372-product-embed.ts deleted file mode 100644 index 977013f67e..0000000000 --- a/packages/backend/src/app/database/migration/postgres/1677894800372-product-embed.ts +++ /dev/null @@ -1,43 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm' -import { logger } from '../../../helper/logger' - -export class productEmbed1677894800372 implements MigrationInterface { - name = 'productEmbed1677894800372' - - public async up(queryRunner: QueryRunner): Promise { - const appCredentialExistsQuery: { exists: boolean }[] = await queryRunner.query( - `SELECT exists ( - SELECT FROM information_schema.tables - WHERE table_schema = 'public' - AND table_name = 'app_credential' - )`, - ) - - const appCredentialExists = - appCredentialExistsQuery && - appCredentialExistsQuery.length > 0 && - appCredentialExistsQuery[0].exists - - if (appCredentialExists) { - logger.info('initializeSchema1676238396411: skipped') - return - } - await queryRunner.query('CREATE TABLE "app_credential" ("id" character varying(21) NOT NULL, "created" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "updated" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "appName" character varying NOT NULL, "projectId" character varying(21) NOT NULL, "settings" jsonb NOT NULL, CONSTRAINT "PK_62eb102bb75a05d2951796a3b46" PRIMARY KEY ("id"))') - await queryRunner.query('CREATE UNIQUE INDEX "idx_app_credentials_projectId_appName" ON "app_credential" ("appName", "projectId") ') - await queryRunner.query('CREATE TABLE "connection_key" ("id" character varying(21) NOT NULL, "created" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "updated" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "projectId" character varying(21) NOT NULL, "settings" jsonb NOT NULL, CONSTRAINT "PK_4dcf1d9ae4ba5eb261a6c775ad2" PRIMARY KEY ("id"))') - await queryRunner.query('CREATE INDEX "idx_connection_key_project_id" ON "connection_key" ("projectId") ') - await queryRunner.query('ALTER TABLE "app_credential" ADD CONSTRAINT "FK_d82bfb4c7432a69dc2419083a0e" FOREIGN KEY ("projectId") REFERENCES "project"("id") ON DELETE NO ACTION ON UPDATE NO ACTION') - await queryRunner.query('ALTER TABLE "connection_key" ADD CONSTRAINT "FK_03177dc6779e6e147866d43c050" FOREIGN KEY ("projectId") REFERENCES "project"("id") ON DELETE NO ACTION ON UPDATE NO ACTION') - - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query('DROP INDEX "public"."idx_connection_key_project_id"') - await queryRunner.query('DROP TABLE "connection_key"') - await queryRunner.query('DROP INDEX "public"."idx_app_credentials_projectId_appName"') - await queryRunner.query('DROP TABLE "app_credential"') - await queryRunner.query('ALTER TABLE "connection_key" DROP CONSTRAINT "FK_03177dc6779e6e147866d43c050"') - await queryRunner.query('ALTER TABLE "app_credential" DROP CONSTRAINT "FK_d82bfb4c7432a69dc2419083a0e"') - } - -} diff --git a/packages/backend/src/app/database/migration/postgres/1678382946390-add-event-routing.ts b/packages/backend/src/app/database/migration/postgres/1678382946390-add-event-routing.ts deleted file mode 100644 index f549ff48f4..0000000000 --- a/packages/backend/src/app/database/migration/postgres/1678382946390-add-event-routing.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm' -import { logger } from '../../../helper/logger' - -export class addEventRouting1678382946390 implements MigrationInterface { - name = 'addEventRouting1678382946390' - - public async up(queryRunner: QueryRunner): Promise { - logger.info('Running migration addEventRouting1678382946390') - await queryRunner.query('CREATE TABLE "app_event_routing" ("id" character varying(21) NOT NULL, "created" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "updated" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "appName" character varying NOT NULL, "projectId" character varying(21) NOT NULL, "flowId" character varying(21) NOT NULL, "identifierValue" character varying NOT NULL, "event" character varying NOT NULL, CONSTRAINT "PK_2107df2b2faf9d50435f9d5acd7" PRIMARY KEY ("id"))') - await queryRunner.query('CREATE INDEX "idx_app_event_routing_flow_id" ON "app_event_routing" ("flowId") ') - await queryRunner.query('CREATE UNIQUE INDEX "idx_app_event_project_id_appName_identifier_value_event" ON "app_event_routing" ("appName", "projectId", "identifierValue", "event") ') - logger.info('Finished migration addEventRouting1678382946390') - } - - public async down(queryRunner: QueryRunner): Promise { - logger.info('Rolling Back migration addEventRouting1678382946390') - await queryRunner.query('DROP INDEX "public"."idx_app_event_project_id_appName_identifier_value_event"') - await queryRunner.query('DROP INDEX "public"."idx_app_event_routing_flow_id"') - await queryRunner.query('DROP TABLE "app_event_routing"') - logger.info('Finished Rolling Back migration addEventRouting1678382946390') - } - -} diff --git a/packages/backend/src/app/database/migration/postgres/1678492809093-removeCollectionVersion.ts b/packages/backend/src/app/database/migration/postgres/1678492809093-removeCollectionVersion.ts deleted file mode 100644 index d45002aa07..0000000000 --- a/packages/backend/src/app/database/migration/postgres/1678492809093-removeCollectionVersion.ts +++ /dev/null @@ -1,56 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm' -import { logger } from '../../../helper/logger' - -export class removeCollectionVersion1678492809093 implements MigrationInterface { - name = 'removeCollectionVersion1678492809093' - - public async up(queryRunner: QueryRunner): Promise { - logger.info('Running migration removeCollectionVersion1678492809093') - await queryRunner.query('ALTER TABLE "instance" DROP CONSTRAINT "fk_instance_collection_version"') - await queryRunner.query('ALTER TABLE "flow_run" DROP CONSTRAINT "fk_flow_run_collection_version_id"') - await queryRunner.query('ALTER TABLE "instance" DROP CONSTRAINT "REL_183c020130aa172f58c6a0c647"') - await queryRunner.query('ALTER TABLE "instance" DROP COLUMN "collectionVersionId"') - await queryRunner.query('ALTER TABLE "flow_run" DROP COLUMN "collectionVersionId"') - await queryRunner.query('ALTER TABLE "collection" ADD "displayName" character varying') - const collections = await queryRunner.query('SELECT * FROM public.collection') - - for (let i = 0; i < collections.length; ++i) { - let currentCollection = collections[i] - const latestCollectionVersionQuery = ` - SELECT * FROM public.collection_version - WHERE "collectionId" = '${currentCollection.id}' - ORDER BY created DESC - LIMIT 1 - ` - const [latestCollectionVersion] = await queryRunner.query(latestCollectionVersionQuery) - - let displayName = 'Untitled' - if (latestCollectionVersion) { - displayName = latestCollectionVersion.displayName - } - - currentCollection = { - ...currentCollection, - displayName, - } - - const updateCollectionQuery = ` - UPDATE public.collection - SET displayName = '${displayName}' - WHERE id = '${currentCollection.id}' - ` - await queryRunner.query(updateCollectionQuery) - } - logger.info('Finished migration removeCollectionVersion1678492809093') - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query('ALTER TABLE "collection" DROP COLUMN "displayName"') - await queryRunner.query('ALTER TABLE "flow_run" ADD "collectionVersionId" character varying(21) NOT NULL') - await queryRunner.query('ALTER TABLE "instance" ADD "collectionVersionId" character varying(21) NOT NULL') - await queryRunner.query('ALTER TABLE "instance" ADD CONSTRAINT "REL_183c020130aa172f58c6a0c647" UNIQUE ("collectionVersionId")') - await queryRunner.query('ALTER TABLE "flow_run" ADD CONSTRAINT "fk_flow_run_collection_version_id" FOREIGN KEY ("collectionVersionId") REFERENCES "collection_version"("id") ON DELETE CASCADE ON UPDATE NO ACTION') - await queryRunner.query('ALTER TABLE "instance" ADD CONSTRAINT "fk_instance_collection_version" FOREIGN KEY ("collectionVersionId") REFERENCES "collection_version"("id") ON DELETE CASCADE ON UPDATE NO ACTION') - } - -} diff --git a/packages/backend/src/app/database/migration/postgres/1678621361185-addtriggerevents.ts b/packages/backend/src/app/database/migration/postgres/1678621361185-addtriggerevents.ts deleted file mode 100644 index c3a1fc1d8c..0000000000 --- a/packages/backend/src/app/database/migration/postgres/1678621361185-addtriggerevents.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm' -import { logger } from '../../../helper/logger' - -export class addtriggerevents1678621361185 implements MigrationInterface { - name = 'addtriggerevents1678621361185' - - public async up(queryRunner: QueryRunner): Promise { - logger.info('addtriggerevents1678621361185 up: started') - await queryRunner.query('CREATE TABLE "trigger_event" ("id" character varying(21) NOT NULL, "created" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "updated" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "flowId" character varying(21) NOT NULL, "projectId" character varying(21) NOT NULL, "sourceName" character varying NOT NULL, "payload" jsonb NOT NULL, CONSTRAINT "PK_79bbc8c2af95776e801c7eaab11" PRIMARY KEY ("id"))') - await queryRunner.query('CREATE INDEX "idx_trigger_event_flow_id" ON "trigger_event" ("flowId") ') - await queryRunner.query('ALTER TABLE "trigger_event" ADD CONSTRAINT "fk_trigger_event_project_id" FOREIGN KEY ("projectId") REFERENCES "project"("id") ON DELETE CASCADE ON UPDATE NO ACTION') - await queryRunner.query('ALTER TABLE "trigger_event" ADD CONSTRAINT "fk_trigger_event_flow_id" FOREIGN KEY ("flowId") REFERENCES "flow"("id") ON DELETE CASCADE ON UPDATE NO ACTION') - logger.info('addtriggerevents1678621361185 up: finished') - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query('ALTER TABLE "trigger_event" DROP CONSTRAINT "fk_trigger_event_flow_id"') - await queryRunner.query('ALTER TABLE "trigger_event" DROP CONSTRAINT "fk_trigger_event_project_id"') - await queryRunner.query('DROP INDEX "public"."idx_trigger_event_flow_id"') - await queryRunner.query('DROP TABLE "trigger_event"') - } - -} diff --git a/packages/backend/src/app/database/migration/postgres/1680698259291-create-webhook-simulation-schema.ts b/packages/backend/src/app/database/migration/postgres/1680698259291-create-webhook-simulation-schema.ts deleted file mode 100644 index ad5aa2d962..0000000000 --- a/packages/backend/src/app/database/migration/postgres/1680698259291-create-webhook-simulation-schema.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm' - -export class CreateWebhookSimulationSchema1680698259291 implements MigrationInterface { - name = 'CreateWebhookSimulationSchema1680698259291' - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query('CREATE TABLE "webhook_simulation" ("id" character varying(21) NOT NULL, "created" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "updated" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "flowId" character varying(21) NOT NULL, "projectId" character varying(21) NOT NULL, CONSTRAINT "PK_6854a1ac9a5b24810b29aaf0f43" PRIMARY KEY ("id"))') - await queryRunner.query('CREATE UNIQUE INDEX "idx_webhook_simulation_flow_id" ON "webhook_simulation" ("flowId") ') - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query('DROP INDEX "public"."idx_webhook_simulation_flow_id"') - await queryRunner.query('DROP TABLE "webhook_simulation"') - } - -} diff --git a/packages/backend/src/app/database/migration/postgres/1680986182074-RemoveCollections.ts b/packages/backend/src/app/database/migration/postgres/1680986182074-RemoveCollections.ts deleted file mode 100644 index a61cf22e68..0000000000 --- a/packages/backend/src/app/database/migration/postgres/1680986182074-RemoveCollections.ts +++ /dev/null @@ -1,109 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm' -import { logger } from '../../../helper/logger' -import { apId } from '@activepieces/shared' - -export class RemoveCollections1680986182074 implements MigrationInterface { - name = 'RemoveCollections1680986182074' - - public async up(queryRunner: QueryRunner): Promise { - logger.info('Running RemoveCollections1680986182074 migration') - // Data Queries - await queryRunner.query(` - UPDATE "store-entry" - SET "collectionId" = "collection"."projectId" - FROM "collection" - WHERE "store-entry"."collectionId" = "collection"."id"; - `) - await queryRunner.query('CREATE TABLE "folder" ("id" character varying(21) NOT NULL, "created" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "updated" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "displayName" character varying NOT NULL, "projectId" character varying(21) NOT NULL, CONSTRAINT "PK_6278a41a706740c94c02e288df8" PRIMARY KEY ("id"))') - await queryRunner.query('CREATE INDEX "idx_folder_project_id" ON "folder" ("projectId") ') - await queryRunner.query('ALTER TABLE "flow" ADD "folderId" character varying(21)') - - let countFolders = 0 - const collections = await queryRunner.query('SELECT * FROM "collection"') - for (const collection of collections) { - const randomId = apId() - await queryRunner.query( - 'INSERT INTO "folder" ("id", "created", "updated", "displayName", "projectId") VALUES ($1, NOW(), NOW(), $2, $3)', - [randomId, collection.displayName, collection.projectId], - ); await queryRunner.query(`UPDATE "flow" SET "folderId" = '${randomId}' WHERE "collectionId" = '${collection.id}'`) - countFolders++ - } - logger.info(`RemoveCollections1680986182074 Migrated ${countFolders} folders`) - // Schema Queries - await queryRunner.query('ALTER TABLE "flow" DROP CONSTRAINT "fk_flow_collection_id"') - await queryRunner.query('ALTER TABLE "flow_run" DROP CONSTRAINT "fk_flow_run_collection_id"') - await queryRunner.query('DROP INDEX "public"."idx_flow_collection_id"') - await queryRunner.query('ALTER TABLE "store-entry" RENAME COLUMN "collectionId" TO "projectId"') - await queryRunner.query('CREATE TABLE "flow_instance" ("id" character varying(21) NOT NULL, "created" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "updated" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "projectId" character varying(21) NOT NULL, "flowId" character varying(21) NOT NULL, "flowVersionId" character varying(21) NOT NULL, "status" character varying NOT NULL, CONSTRAINT "REL_cb897f5e48cc3cba1418966326" UNIQUE ("flowId"), CONSTRAINT "REL_ec72f514c21734fb7a08797d75" UNIQUE ("flowVersionId"), CONSTRAINT "PK_5b0308060b7de5abec61ac5d2db" PRIMARY KEY ("id"))') - await queryRunner.query('CREATE UNIQUE INDEX "idx_flow_instance_project_id_flow_id" ON "flow_instance" ("projectId", "flowId") ') - await queryRunner.query('ALTER TABLE "flow" DROP COLUMN "collectionId"') - await queryRunner.query('ALTER TABLE "flow_run" DROP COLUMN "collectionId"') - await queryRunner.query('ALTER TABLE "flow_run" DROP COLUMN "collectionDisplayName"') - await queryRunner.query('ALTER TABLE "flow" DROP CONSTRAINT "fk_flow_project_id"') - await queryRunner.query('ALTER TABLE "flow" ALTER COLUMN "projectId" SET NOT NULL') - await queryRunner.query('CREATE INDEX "idx_flow_project_id" ON "flow" ("projectId") ') - await queryRunner.query('CREATE INDEX "idx_flow_folder_id" ON "flow" ("folderId") ') - await queryRunner.query('ALTER TABLE "flow_instance" ADD CONSTRAINT "fk_flow_instance_flow" FOREIGN KEY ("flowId") REFERENCES "flow"("id") ON DELETE CASCADE ON UPDATE NO ACTION') - await queryRunner.query('ALTER TABLE "flow_instance" ADD CONSTRAINT "fk_flow_instance_flow_version" FOREIGN KEY ("flowVersionId") REFERENCES "flow_version"("id") ON DELETE CASCADE ON UPDATE NO ACTION') - await queryRunner.query('ALTER TABLE "flow" ADD CONSTRAINT "fk_flow_folder_id" FOREIGN KEY ("folderId") REFERENCES "folder"("id") ON DELETE SET NULL ON UPDATE NO ACTION') - await queryRunner.query('ALTER TABLE "flow" ADD CONSTRAINT "fk_flow_project_id" FOREIGN KEY ("projectId") REFERENCES "project"("id") ON DELETE CASCADE ON UPDATE NO ACTION') - await queryRunner.query('ALTER TABLE "folder" ADD CONSTRAINT "fk_folder_project" FOREIGN KEY ("projectId") REFERENCES "project"("id") ON DELETE CASCADE ON UPDATE NO ACTION') - - // Migrate Flow Instances - const instances = await queryRunner.query('SELECT * FROM "instance"') - let count = 0 - let failed = 0 - for (const instance of instances) { - const flowIdToVersionId = instance.flowIdToVersionId - for (const flowId of Object.keys(flowIdToVersionId)) { - const flowVersionId = flowIdToVersionId[flowId] - const randomId = apId() - - const flowExists = await queryRunner.query(`SELECT EXISTS(SELECT 1 FROM "flow" WHERE "id" = '${flowId}')`) - const flowVersionExists = await queryRunner.query(`SELECT EXISTS(SELECT 1 FROM "flow_version" WHERE "id" = '${flowVersionId}')`) - if (!flowExists[0].exists || !flowVersionExists[0].exists) { - failed++ - logger.info(`Skipping flow instance ${instance.id} because flow ${flowId} or flow version ${flowVersionId} does not exist`) - } - else { - await queryRunner.query(`INSERT INTO "flow_instance" ("id", "created", "updated", "projectId", "flowId", "flowVersionId", "status") VALUES ('${randomId}', 'NOW()', 'NOW()', '${instance.projectId}', '${flowId}', '${flowVersionId}', '${instance.status}')`) - count++ - } - } - } - - logger.info(`Finished Running RemoveCollections1680986182074 migration with ${count} flow instances migrated and ${failed} failed`) - } - - public async down(queryRunner: QueryRunner): Promise { - // Schema Queries - await queryRunner.query('ALTER TABLE "folder" DROP CONSTRAINT "fk_folder_project"') - await queryRunner.query('ALTER TABLE "flow" DROP CONSTRAINT "fk_flow_project_id"') - await queryRunner.query('ALTER TABLE "flow" DROP CONSTRAINT "fk_flow_folder_id"') - await queryRunner.query('ALTER TABLE "flow_instance" DROP CONSTRAINT "fk_flow_instance_flow_version"') - await queryRunner.query('ALTER TABLE "flow_instance" DROP CONSTRAINT "fk_flow_instance_flow"') - await queryRunner.query('DROP INDEX "public"."idx_flow_folder_id"') - await queryRunner.query('DROP INDEX "public"."idx_flow_project_id"') - await queryRunner.query('ALTER TABLE "flow" ALTER COLUMN "projectId" DROP NOT NULL') - await queryRunner.query('ALTER TABLE "flow" ADD CONSTRAINT "fk_flow_project_id" FOREIGN KEY ("projectId") REFERENCES "project"("id") ON DELETE CASCADE ON UPDATE NO ACTION') - await queryRunner.query('ALTER TABLE "flow" DROP COLUMN "folderId"') - await queryRunner.query('ALTER TABLE "flow_run" ADD "collectionDisplayName" character varying NOT NULL') - await queryRunner.query('ALTER TABLE "flow_run" ADD "collectionId" character varying(21) NOT NULL') - await queryRunner.query('ALTER TABLE "flow" ADD "collectionId" character varying(21) NOT NULL') - await queryRunner.query('DROP INDEX "public"."idx_folder_project_id"') - await queryRunner.query('DROP TABLE "folder"') - await queryRunner.query('DROP INDEX "public"."idx_flow_instance_project_id_flow_id"') - await queryRunner.query('DROP TABLE "flow_instance"') - await queryRunner.query('ALTER TABLE "store-entry" RENAME COLUMN "projectId" TO "collectionId"') - await queryRunner.query('CREATE INDEX "idx_flow_collection_id" ON "flow" ("collectionId") ') - await queryRunner.query('ALTER TABLE "flow_run" ADD CONSTRAINT "fk_flow_run_collection_id" FOREIGN KEY ("collectionId") REFERENCES "collection"("id") ON DELETE CASCADE ON UPDATE NO ACTION') - await queryRunner.query('ALTER TABLE "flow" ADD CONSTRAINT "fk_flow_collection_id" FOREIGN KEY ("collectionId") REFERENCES "collection"("id") ON DELETE CASCADE ON UPDATE NO ACTION') - // Data queries - await queryRunner.query(` - UPDATE "store-entry" - SET "collectionId" = "collection"."id" - FROM "collection" - WHERE "store-entry"."collectionId" = "collection"."projectId";`) - } - -} diff --git a/packages/backend/src/app/database/migration/postgres/1681019096716-StoreAllPeriods.ts b/packages/backend/src/app/database/migration/postgres/1681019096716-StoreAllPeriods.ts deleted file mode 100644 index 643e7981cd..0000000000 --- a/packages/backend/src/app/database/migration/postgres/1681019096716-StoreAllPeriods.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm' -import { logger } from '../../../helper/logger' - -export class StoreAllPeriods1681019096716 implements MigrationInterface { - name = 'StoreAllPeriods1681019096716' - - public async up(queryRunner: QueryRunner): Promise { - logger.info('Running StoreAllPeriods1681019096716') - await queryRunner.query('ALTER TABLE "project_usage" DROP CONSTRAINT "REL_c407fc9b2bfb44515af69d575a"') - await queryRunner.query('DROP INDEX "public"."idx_project_usage_project_id"') - await queryRunner.query('CREATE INDEX "idx_project_usage_project_id" ON "project_usage" ("projectId") ') - logger.info('Finished Running StoreAllPeriods1681019096716') - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query('ALTER TABLE "project_usage" ADD CONSTRAINT "REL_c407fc9b2bfb44515af69d575a" UNIQUE ("projectId")') - await queryRunner.query('DROP INDEX "public"."idx_project_usage_project_id"') - await queryRunner.query('CREATE UNIQUE INDEX "idx_project_usage_project_id" ON "project_usage" ("projectId") ') - } - -} diff --git a/packages/backend/src/app/database/migration/postgres/1683040965874-allow-nullable-store-entry.ts b/packages/backend/src/app/database/migration/postgres/1683040965874-allow-nullable-store-entry.ts deleted file mode 100644 index d734ece994..0000000000 --- a/packages/backend/src/app/database/migration/postgres/1683040965874-allow-nullable-store-entry.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm' -import { logger } from '../../../helper/logger' -export class AllowNullableStoreEntryAndTrigger1683040965874 implements MigrationInterface { - name = 'AllowNullableStoreEntryAndTrigger1683040965874' - - public async up(queryRunner: QueryRunner): Promise { - logger.info('AllowNullableStoreEntryAndTrigger1683040965874, started') - await queryRunner.query('ALTER TABLE "store-entry" ALTER COLUMN "value" DROP NOT NULL') - await queryRunner.query('ALTER TABLE "trigger_event" ALTER COLUMN "payload" DROP NOT NULL') - logger.info('AllowNullableStoreEntryAndTrigger1683040965874, ended') - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query('ALTER TABLE "trigger_event" ALTER COLUMN "payload" SET NOT NULL') - await queryRunner.query('ALTER TABLE "store-entry" ALTER COLUMN "value" SET NOT NULL') - } - -} diff --git a/packages/backend/src/app/database/migration/postgres/1683199709317-list-flow-runs-indices.ts b/packages/backend/src/app/database/migration/postgres/1683199709317-list-flow-runs-indices.ts deleted file mode 100644 index 9d4504634c..0000000000 --- a/packages/backend/src/app/database/migration/postgres/1683199709317-list-flow-runs-indices.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm' - -export class ListFlowRunsIndices1683199709317 implements MigrationInterface { - name = 'ListFlowRunsIndices1683199709317' - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query('DROP INDEX "public"."idx_run_project_id"') - await queryRunner.query('CREATE INDEX "idx_run_project_id_environment_created_desc" ON "flow_run" ("projectId", "environment", "created" DESC) ') - await queryRunner.query('CREATE INDEX "idx_run_project_id_environment_status_created_desc" ON "flow_run" ("projectId", "environment", "status", "created" DESC) ') - await queryRunner.query('CREATE INDEX "idx_run_project_id_flow_id_environment_created_desc" ON "flow_run" ("projectId", "flowId", "environment", "created" DESC) ') - await queryRunner.query('CREATE INDEX "idx_run_project_id_flow_id_environment_status_created_desc" ON "flow_run" ("projectId", "flowId", "environment", "status", "created" DESC) ') - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query('DROP INDEX "public"."idx_run_project_id_flow_id_environment_status_created_desc"') - await queryRunner.query('DROP INDEX "public"."idx_run_project_id_flow_id_environment_created_desc"') - await queryRunner.query('DROP INDEX "public"."idx_run_project_id_environment_status_created_desc"') - await queryRunner.query('DROP INDEX "public"."idx_run_project_id_environment_created_desc"') - await queryRunner.query('CREATE INDEX "idx_run_project_id" ON "flow_run" ("projectId") ') - } - -} diff --git a/packages/backend/src/app/database/migration/postgres/1683458275525-project-notify-status-not-null.ts b/packages/backend/src/app/database/migration/postgres/1683458275525-project-notify-status-not-null.ts deleted file mode 100644 index 1fad8225c4..0000000000 --- a/packages/backend/src/app/database/migration/postgres/1683458275525-project-notify-status-not-null.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm' -import { logger } from '../../../helper/logger' - -export class ProjectNotifyStatusNotNull1683458275525 implements MigrationInterface { - name = 'ProjectNotifyStatusNotNull1683458275525' - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query('UPDATE "project" SET "notifyStatus" = \'ALWAYS\' WHERE "notifyStatus" IS NULL') - await queryRunner.query('ALTER TABLE "project" ALTER COLUMN "notifyStatus" SET NOT NULL') - - logger.info('[ProjectNotifyStatusNotNull1683458275525] up') - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query('ALTER TABLE "project" ALTER COLUMN "notifyStatus" DROP NOT NULL') - await queryRunner.query('UPDATE "project" SET "notifyStatus" = NULL WHERE "notifyStatus" = \'ALWAYS\'') - - logger.info('[ProjectNotifyStatusNotNull1683458275525] down') - } - -} diff --git a/packages/backend/src/app/database/migration/postgres/1685537054805-piece-metadata.ts b/packages/backend/src/app/database/migration/postgres/1685537054805-piece-metadata.ts deleted file mode 100644 index e3d76122a4..0000000000 --- a/packages/backend/src/app/database/migration/postgres/1685537054805-piece-metadata.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm' -import { logger } from '../../../helper/logger' - -export class PieceMetadata1685537054805 implements MigrationInterface { - name = 'PieceMetadata1685537054805' - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query('CREATE COLLATION en_natural (LOCALE = \'en-US-u-kn-true\', PROVIDER = \'icu\')') - await queryRunner.query('CREATE TABLE "piece_metadata" ("id" character varying(21) NOT NULL, "created" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "updated" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "name" character varying NOT NULL, "displayName" character varying NOT NULL, "logoUrl" character varying NOT NULL, "description" character varying, "version" character varying COLLATE "en_natural" NOT NULL, "minimumSupportedRelease" character varying COLLATE "en_natural" NOT NULL, "maximumSupportedRelease" character varying COLLATE "en_natural" NOT NULL, "actions" jsonb NOT NULL, "triggers" jsonb NOT NULL, CONSTRAINT "PK_b045821e9caf2be9aba520d96da" PRIMARY KEY ("id"))') - await queryRunner.query('CREATE UNIQUE INDEX "idx_piece_metadata_name_version" ON "piece_metadata" ("name", "version") ') - - logger.info('[PieceMetadata1685537054805] up') - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query('DROP COLLATION en_natural') - await queryRunner.query('DROP INDEX "public"."idx_piece_metadata_name_version"') - await queryRunner.query('DROP TABLE "piece_metadata"') - - logger.info('[PieceMetadata1685537054805] down') - } - -} diff --git a/packages/backend/src/app/database/migration/postgres/1686090319016-AddProjectIdToPieceMetadata.ts b/packages/backend/src/app/database/migration/postgres/1686090319016-AddProjectIdToPieceMetadata.ts deleted file mode 100644 index 0cb76651e5..0000000000 --- a/packages/backend/src/app/database/migration/postgres/1686090319016-AddProjectIdToPieceMetadata.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm' -import { logger } from '../../../helper/logger' - -export class AddProjectIdToPieceMetadata1686090319016 implements MigrationInterface { - name = 'AddProjectIdToPieceMetadata1686090319016' - - public async up(queryRunner: QueryRunner): Promise { - logger.info('[AddProjectIdToPieceMetadata1686090319016] up') - await queryRunner.query('DROP INDEX "public"."idx_piece_metadata_name_version"') - await queryRunner.query('ALTER TABLE "piece_metadata" ADD "projectId" character varying') - await queryRunner.query('CREATE UNIQUE INDEX "idx_piece_metadata_name_project_id_version" ON "piece_metadata" ("name", "version", "projectId") ') - await queryRunner.query('ALTER TABLE "piece_metadata" ADD CONSTRAINT "fk_piece_metadata_project_id" FOREIGN KEY ("projectId") REFERENCES "project"("id") ON DELETE CASCADE ON UPDATE NO ACTION') - logger.info('[AddProjectIdToPieceMetadata1686090319016] finished') - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query('ALTER TABLE "piece_metadata" DROP CONSTRAINT "fk_piece_metadata_project_id"') - await queryRunner.query('DROP INDEX "public"."idx_piece_metadata_name_project_id_version"') - await queryRunner.query('ALTER TABLE "piece_metadata" DROP COLUMN "projectId"') - await queryRunner.query('CREATE UNIQUE INDEX "idx_piece_metadata_name_version" ON "piece_metadata" ("name", "version") ') - } - -} diff --git a/packages/backend/src/app/database/migration/postgres/1689292797727-AddUpdatedByInFlowVersion.ts b/packages/backend/src/app/database/migration/postgres/1689292797727-AddUpdatedByInFlowVersion.ts deleted file mode 100644 index 1592996a67..0000000000 --- a/packages/backend/src/app/database/migration/postgres/1689292797727-AddUpdatedByInFlowVersion.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm' -import { logger } from '../../../helper/logger' - -export class AddUpdatedByInFlowVersion1689292797727 implements MigrationInterface { - name = 'AddUpdatedByInFlowVersion1689292797727' - - public async up(queryRunner: QueryRunner): Promise { - logger.info('AddUpdatedByInFlowVersion1689292797727 up') - await queryRunner.query('ALTER TABLE "flow_version" ADD "updatedBy" character varying') - await queryRunner.query('ALTER TABLE "flow_version" ADD CONSTRAINT "fk_updated_by_user_flow" FOREIGN KEY ("updatedBy") REFERENCES "user"("id") ON DELETE CASCADE ON UPDATE NO ACTION') - logger.info('AddUpdatedByInFlowVersion1689292797727 finished') - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query('ALTER TABLE "flow_version" DROP CONSTRAINT "fk_updated_by_user_flow"') - await queryRunner.query('ALTER TABLE "flow_version" DROP COLUMN "updatedBy"') - } - -} diff --git a/packages/backend/src/app/database/migration/postgres/1693004806926-AddFileToPostgres.ts b/packages/backend/src/app/database/migration/postgres/1693004806926-AddFileToPostgres.ts deleted file mode 100644 index 44edbc2d2d..0000000000 --- a/packages/backend/src/app/database/migration/postgres/1693004806926-AddFileToPostgres.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm' - -export class AddFileToPostgres1693004806926 implements MigrationInterface { - name = 'AddFileToPostgres1693004806926' - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query('CREATE TABLE "step_file" ("id" character varying(21) NOT NULL, "created" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "updated" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "flowId" character varying(21) NOT NULL, "projectId" character varying(21) NOT NULL, "name" character varying NOT NULL, "size" integer NOT NULL, "stepName" character varying NOT NULL, "data" bytea NOT NULL, CONSTRAINT "PK_04bb9022ff8c2190fea2036174e" PRIMARY KEY ("id"))') - await queryRunner.query('CREATE UNIQUE INDEX "step_file_project_id_flow_id_step_name_name" ON "step_file" ("projectId", "flowId", "stepName", "name") ') - await queryRunner.query('ALTER TABLE "step_file" ADD CONSTRAINT "fk_step_file_project_id" FOREIGN KEY ("projectId") REFERENCES "project"("id") ON DELETE CASCADE ON UPDATE NO ACTION') - await queryRunner.query('ALTER TABLE "step_file" ADD CONSTRAINT "fk_step_file_flow_id" FOREIGN KEY ("flowId") REFERENCES "flow"("id") ON DELETE CASCADE ON UPDATE NO ACTION') - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query('ALTER TABLE "step_file" DROP CONSTRAINT "fk_step_file_flow_id"') - await queryRunner.query('ALTER TABLE "step_file" DROP CONSTRAINT "fk_step_file_project_id"') - await queryRunner.query('DROP INDEX "public"."step_file_project_id_flow_id_step_name_name"') - await queryRunner.query('DROP TABLE "step_file"') - } - -} diff --git a/packages/backend/src/app/database/migration/postgres/1693402930301-AddStatusToConnections.ts b/packages/backend/src/app/database/migration/postgres/1693402930301-AddStatusToConnections.ts deleted file mode 100644 index ecda505ac4..0000000000 --- a/packages/backend/src/app/database/migration/postgres/1693402930301-AddStatusToConnections.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm' - -export class AddStatusToConnections1693402930301 implements MigrationInterface { - name = 'AddStatusToConnections1693402930301' - - public async up(queryRunner: QueryRunner): Promise { - // Add the new column without NOT NULL constraint first - await queryRunner.query('ALTER TABLE "app_connection" ADD "status" character varying DEFAULT \'ACTIVE\'') - - // Update existing rows to set the default value - await queryRunner.query('UPDATE "app_connection" SET "status" = \'ACTIVE\'') - - // Finally, alter the column to set NOT NULL constraint - await queryRunner.query('ALTER TABLE "app_connection" ALTER COLUMN "status" SET NOT NULL') - } - - public async down(queryRunner: QueryRunner): Promise { - // Remove NOT NULL constraint first - await queryRunner.query('ALTER TABLE "app_connection" ALTER COLUMN "status" DROP NOT NULL') - - // Drop the "status" column - await queryRunner.query('ALTER TABLE "app_connection" DROP COLUMN "status"') - } -} diff --git a/packages/backend/src/app/database/migration/postgres/1694367186954-fix-piece-metadata-order-bug.ts b/packages/backend/src/app/database/migration/postgres/1694367186954-fix-piece-metadata-order-bug.ts deleted file mode 100644 index 0bc1a5e6e4..0000000000 --- a/packages/backend/src/app/database/migration/postgres/1694367186954-fix-piece-metadata-order-bug.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm' -import { logger } from '../../../helper/logger' - -export class FixPieceMetadataOrderBug1694367186954 implements MigrationInterface { - name = 'FixPieceMetadataOrderBug1694367186954' - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query('ALTER TABLE "piece_metadata" ALTER COLUMN "auth" TYPE json') - await queryRunner.query('ALTER TABLE "piece_metadata" ALTER COLUMN "actions" TYPE json') - await queryRunner.query('ALTER TABLE "piece_metadata" ALTER COLUMN "triggers" TYPE json') - - logger.info('[FixPieceMetadataOrderBug1694367186954] up') - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query('ALTER TABLE "piece_metadata" ALTER COLUMN "auth" SET DATA TYPE jsonb USING my_json::jsonb') - await queryRunner.query('ALTER TABLE "piece_metadata" ALTER COLUMN "actions" SET DATA TYPE jsonb USING my_json::jsonb') - await queryRunner.query('ALTER TABLE "piece_metadata" ALTER COLUMN "triggers" SET DATA TYPE jsonb USING my_json::jsonb') - - logger.info('[FixPieceMetadataOrderBug1694367186954] down') - } - -} diff --git a/packages/backend/src/app/database/migration/postgres/1694902537040-Chatbot.ts b/packages/backend/src/app/database/migration/postgres/1694902537040-Chatbot.ts deleted file mode 100644 index bc6a78e21c..0000000000 --- a/packages/backend/src/app/database/migration/postgres/1694902537040-Chatbot.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm' - -export class Chatbot1694902537040 implements MigrationInterface { - name = 'Chatbot1694902537040' - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query('CREATE TABLE "chatbot" ("id" character varying(21) NOT NULL, "created" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "updated" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "type" character varying NOT NULL, "displayName" character varying NOT NULL, "projectId" character varying NOT NULL, "connectionId" character varying, "dataSources" jsonb NOT NULL, "prompt" character varying, CONSTRAINT "PK_1ee1961e62c5cec278314f1d68e" PRIMARY KEY ("id"))') - await queryRunner.query('ALTER TABLE "chatbot" ADD CONSTRAINT "FK_d2f5f245c27541cd70f13f169eb" FOREIGN KEY ("projectId") REFERENCES "project"("id") ON DELETE NO ACTION ON UPDATE NO ACTION') - await queryRunner.query('ALTER TABLE "chatbot" ADD CONSTRAINT "FK_13f7ad52cefa43433864732c384" FOREIGN KEY ("connectionId") REFERENCES "app_connection"("id") ON DELETE NO ACTION ON UPDATE NO ACTION') - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query('ALTER TABLE "chatbot" DROP CONSTRAINT "FK_13f7ad52cefa43433864732c384"') - await queryRunner.query('ALTER TABLE "chatbot" DROP CONSTRAINT "FK_d2f5f245c27541cd70f13f169eb"') - await queryRunner.query('DROP TABLE "chatbot"') - } - -} diff --git a/packages/backend/src/app/database/migration/postgres/1695719749099-AddVisibilityStatusToChatbot.ts b/packages/backend/src/app/database/migration/postgres/1695719749099-AddVisibilityStatusToChatbot.ts deleted file mode 100644 index 377fab66f2..0000000000 --- a/packages/backend/src/app/database/migration/postgres/1695719749099-AddVisibilityStatusToChatbot.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm' - -export class AddVisibilityStatusToChatbot1695719749099 implements MigrationInterface { - name = 'AddVisibilityStatusToChatbot1695719749099' - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query('ALTER TABLE "chatbot" ADD "visibilityStatus" character varying NOT NULL DEFAULT \'PRIVATE\'') - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query('ALTER TABLE "chatbot" DROP COLUMN "visibilityStatus"') - } -} diff --git a/packages/backend/src/app/database/migration/postgres/1695992551156-add-piece-type-and-package-type-to-piece-metadata.ts b/packages/backend/src/app/database/migration/postgres/1695992551156-add-piece-type-and-package-type-to-piece-metadata.ts deleted file mode 100644 index 2c6da44b88..0000000000 --- a/packages/backend/src/app/database/migration/postgres/1695992551156-add-piece-type-and-package-type-to-piece-metadata.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm' -import { logger } from '../../../helper/logger' - -export class AddPieceTypeAndPackageTypeToPieceMetadata1695992551156 implements MigrationInterface { - name = 'AddPieceTypeAndPackageTypeToPieceMetadata1695992551156' - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query('ALTER TABLE "piece_metadata" ADD "pieceType" character varying') - await queryRunner.query('UPDATE "piece_metadata" SET "pieceType" = \'OFFICIAL\' WHERE "projectId" IS NULL') - await queryRunner.query('UPDATE "piece_metadata" SET "pieceType" = \'CUSTOM\' WHERE "projectId" IS NOT NULL') - await queryRunner.query('ALTER TABLE "piece_metadata" ALTER COLUMN "pieceType" SET NOT NULL') - - await queryRunner.query('ALTER TABLE "piece_metadata" ADD "packageType" character varying') - await queryRunner.query('UPDATE "piece_metadata" SET "packageType" = \'REGISTRY\'') - await queryRunner.query('ALTER TABLE "piece_metadata" ALTER COLUMN "packageType" SET NOT NULL') - - logger.info('AddPieceTypeAndPackageTypeToPieceMetadata1695992551156 up') - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query('ALTER TABLE "piece_metadata" DROP COLUMN "packageType"') - await queryRunner.query('ALTER TABLE "piece_metadata" DROP COLUMN "pieceType"') - - logger.info('AddPieceTypeAndPackageTypeToPieceMetadata1695992551156 down') - } - -} diff --git a/packages/backend/src/app/database/migration/sqlite/1690195839899-InitialSql3Migration.ts b/packages/backend/src/app/database/migration/sqlite/1690195839899-InitialSql3Migration.ts deleted file mode 100644 index 8d2b717744..0000000000 --- a/packages/backend/src/app/database/migration/sqlite/1690195839899-InitialSql3Migration.ts +++ /dev/null @@ -1,208 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm' -import { logger } from '../../../helper/logger' - -export class InitialSql3Migration1690195839899 implements MigrationInterface { - name = 'InitialSql3Migration1690195839899' - - public async up(queryRunner: QueryRunner): Promise { - logger.info(`Running migration ${this.name}`) - await queryRunner.query('CREATE TABLE "trigger_event" ("id" varchar(21) PRIMARY KEY NOT NULL, "created" datetime NOT NULL DEFAULT (datetime(\'now\')), "updated" datetime NOT NULL DEFAULT (datetime(\'now\')), "flowId" varchar(21) NOT NULL, "projectId" varchar(21) NOT NULL, "sourceName" varchar NOT NULL, "payload" text)') - await queryRunner.query('CREATE INDEX "idx_trigger_event_flow_id" ON "trigger_event" ("flowId") ') - await queryRunner.query('CREATE TABLE "flow_instance" ("id" varchar(21) PRIMARY KEY NOT NULL, "created" datetime NOT NULL DEFAULT (datetime(\'now\')), "updated" datetime NOT NULL DEFAULT (datetime(\'now\')), "projectId" varchar(21) NOT NULL, "flowId" varchar(21) NOT NULL, "flowVersionId" varchar(21) NOT NULL, "status" varchar NOT NULL, "schedule" text, CONSTRAINT "REL_cb897f5e48cc3cba1418966326" UNIQUE ("flowId"), CONSTRAINT "REL_ec72f514c21734fb7a08797d75" UNIQUE ("flowVersionId"))') - await queryRunner.query('CREATE UNIQUE INDEX "idx_flow_instance_project_id_flow_id" ON "flow_instance" ("projectId", "flowId") ') - await queryRunner.query('CREATE TABLE "app_event_routing" ("id" varchar(21) PRIMARY KEY NOT NULL, "created" datetime NOT NULL DEFAULT (datetime(\'now\')), "updated" datetime NOT NULL DEFAULT (datetime(\'now\')), "appName" varchar NOT NULL, "projectId" varchar(21) NOT NULL, "flowId" varchar(21) NOT NULL, "identifierValue" varchar NOT NULL, "event" varchar NOT NULL)') - await queryRunner.query('CREATE INDEX "idx_app_event_routing_flow_id" ON "app_event_routing" ("flowId") ') - await queryRunner.query('CREATE UNIQUE INDEX "idx_app_event_project_id_appName_identifier_value_event" ON "app_event_routing" ("appName", "projectId", "identifierValue", "event") ') - await queryRunner.query('CREATE TABLE "file" ("id" varchar(21) PRIMARY KEY NOT NULL, "created" datetime NOT NULL DEFAULT (datetime(\'now\')), "updated" datetime NOT NULL DEFAULT (datetime(\'now\')), "projectId" varchar(21), "data" blob NOT NULL)') - await queryRunner.query('CREATE TABLE "flag" ("id" varchar(21) PRIMARY KEY NOT NULL, "created" datetime NOT NULL DEFAULT (datetime(\'now\')), "updated" datetime NOT NULL DEFAULT (datetime(\'now\')), "value" text NOT NULL)') - await queryRunner.query('CREATE TABLE "flow" ("id" varchar(21) PRIMARY KEY NOT NULL, "created" datetime NOT NULL DEFAULT (datetime(\'now\')), "updated" datetime NOT NULL DEFAULT (datetime(\'now\')), "projectId" varchar(21) NOT NULL, "folderId" varchar(21))') - await queryRunner.query('CREATE INDEX "idx_flow_project_id" ON "flow" ("projectId") ') - await queryRunner.query('CREATE INDEX "idx_flow_folder_id" ON "flow" ("folderId") ') - await queryRunner.query('CREATE TABLE "flow_version" ("id" varchar(21) PRIMARY KEY NOT NULL, "created" datetime NOT NULL DEFAULT (datetime(\'now\')), "updated" datetime NOT NULL DEFAULT (datetime(\'now\')), "flowId" varchar(21) NOT NULL, "displayName" varchar NOT NULL, "trigger" text, "updatedBy" varchar, "valid" boolean NOT NULL, "state" varchar NOT NULL)') - await queryRunner.query('CREATE INDEX "idx_flow_version_flow_id" ON "flow_version" ("flowId") ') - await queryRunner.query('CREATE TABLE "flow_run" ("id" varchar(21) PRIMARY KEY NOT NULL, "created" datetime NOT NULL DEFAULT (datetime(\'now\')), "updated" datetime NOT NULL DEFAULT (datetime(\'now\')), "projectId" varchar(21) NOT NULL, "flowId" varchar(21) NOT NULL, "flowVersionId" varchar(21) NOT NULL, "environment" varchar, "flowDisplayName" varchar NOT NULL, "logsFileId" varchar(21), "status" varchar NOT NULL, "tasks" integer, "startTime" datetime NOT NULL, "finishTime" datetime, "pauseMetadata" text)') - await queryRunner.query('CREATE INDEX "idx_run_project_id_environment_created_desc" ON "flow_run" ("projectId", "environment", "created") ') - await queryRunner.query('CREATE INDEX "idx_run_project_id_environment_status_created_desc" ON "flow_run" ("projectId", "environment", "status", "created") ') - await queryRunner.query('CREATE INDEX "idx_run_project_id_flow_id_environment_created_desc" ON "flow_run" ("projectId", "flowId", "environment", "created") ') - await queryRunner.query('CREATE INDEX "idx_run_project_id_flow_id_environment_status_created_desc" ON "flow_run" ("projectId", "flowId", "environment", "status", "created") ') - await queryRunner.query('CREATE TABLE "project" ("id" varchar(21) PRIMARY KEY NOT NULL, "created" datetime NOT NULL DEFAULT (datetime(\'now\')), "updated" datetime NOT NULL DEFAULT (datetime(\'now\')), "ownerId" varchar(21) NOT NULL, "displayName" varchar NOT NULL, "notifyStatus" varchar NOT NULL)') - await queryRunner.query('CREATE INDEX "idx_project_owner_id" ON "project" ("ownerId") ') - await queryRunner.query('CREATE TABLE "store-entry" ("id" varchar(21) PRIMARY KEY NOT NULL, "created" datetime NOT NULL DEFAULT (datetime(\'now\')), "updated" datetime NOT NULL DEFAULT (datetime(\'now\')), "key" varchar NOT NULL, "projectId" varchar(21) NOT NULL, "value" text)') - await queryRunner.query('CREATE TABLE "user" ("id" varchar(21) PRIMARY KEY NOT NULL, "created" datetime NOT NULL DEFAULT (datetime(\'now\')), "updated" datetime NOT NULL DEFAULT (datetime(\'now\')), "email" varchar NOT NULL, "firstName" varchar NOT NULL, "lastName" varchar NOT NULL, "password" varchar NOT NULL, "status" varchar NOT NULL, "trackEvents" boolean, "newsLetter" boolean, CONSTRAINT "UQ_e12875dfb3b1d92d7d7c5377e22" UNIQUE ("email"))') - await queryRunner.query('CREATE TABLE "app_connection" ("id" varchar(21) PRIMARY KEY NOT NULL, "created" datetime NOT NULL DEFAULT (datetime(\'now\')), "updated" datetime NOT NULL DEFAULT (datetime(\'now\')), "name" varchar NOT NULL, "appName" varchar NOT NULL, "projectId" varchar(21) NOT NULL, "value" text NOT NULL)') - await queryRunner.query('CREATE UNIQUE INDEX "idx_app_connection_project_id_and_name" ON "app_connection" ("projectId", "name") ') - await queryRunner.query('CREATE TABLE "webhook_simulation" ("id" varchar(21) PRIMARY KEY NOT NULL, "created" datetime NOT NULL DEFAULT (datetime(\'now\')), "updated" datetime NOT NULL DEFAULT (datetime(\'now\')), "flowId" varchar(21) NOT NULL, "projectId" varchar(21) NOT NULL)') - await queryRunner.query('CREATE UNIQUE INDEX "idx_webhook_simulation_flow_id" ON "webhook_simulation" ("flowId") ') - await queryRunner.query('CREATE TABLE "folder" ("id" varchar(21) PRIMARY KEY NOT NULL, "created" datetime NOT NULL DEFAULT (datetime(\'now\')), "updated" datetime NOT NULL DEFAULT (datetime(\'now\')), "displayName" varchar NOT NULL, "projectId" varchar(21) NOT NULL)') - await queryRunner.query('CREATE INDEX "idx_folder_project_id" ON "folder" ("projectId") ') - await queryRunner.query('CREATE TABLE "piece_metadata" ("id" varchar(21) PRIMARY KEY NOT NULL, "created" datetime NOT NULL DEFAULT (datetime(\'now\')), "updated" datetime NOT NULL DEFAULT (datetime(\'now\')), "name" varchar NOT NULL, "displayName" varchar NOT NULL, "logoUrl" varchar NOT NULL, "description" varchar, "projectId" varchar, "version" varchar NOT NULL, "minimumSupportedRelease" varchar NOT NULL, "maximumSupportedRelease" varchar NOT NULL, "auth" text, "actions" text NOT NULL, "triggers" text NOT NULL)') - await queryRunner.query('CREATE UNIQUE INDEX "idx_piece_metadata_name_project_id_version" ON "piece_metadata" ("name", "version", "projectId") ') - await queryRunner.query('DROP INDEX "idx_trigger_event_flow_id"') - await queryRunner.query('CREATE TABLE "temporary_trigger_event" ("id" varchar(21) PRIMARY KEY NOT NULL, "created" datetime NOT NULL DEFAULT (datetime(\'now\')), "updated" datetime NOT NULL DEFAULT (datetime(\'now\')), "flowId" varchar(21) NOT NULL, "projectId" varchar(21) NOT NULL, "sourceName" varchar NOT NULL, "payload" text, CONSTRAINT "fk_trigger_event_project_id" FOREIGN KEY ("projectId") REFERENCES "project" ("id") ON DELETE CASCADE ON UPDATE NO ACTION, CONSTRAINT "fk_trigger_event_flow_id" FOREIGN KEY ("flowId") REFERENCES "flow" ("id") ON DELETE CASCADE ON UPDATE NO ACTION)') - await queryRunner.query('INSERT INTO "temporary_trigger_event"("id", "created", "updated", "flowId", "projectId", "sourceName", "payload") SELECT "id", "created", "updated", "flowId", "projectId", "sourceName", "payload" FROM "trigger_event"') - await queryRunner.query('DROP TABLE "trigger_event"') - await queryRunner.query('ALTER TABLE "temporary_trigger_event" RENAME TO "trigger_event"') - await queryRunner.query('CREATE INDEX "idx_trigger_event_flow_id" ON "trigger_event" ("flowId") ') - await queryRunner.query('DROP INDEX "idx_flow_instance_project_id_flow_id"') - await queryRunner.query('CREATE TABLE "temporary_flow_instance" ("id" varchar(21) PRIMARY KEY NOT NULL, "created" datetime NOT NULL DEFAULT (datetime(\'now\')), "updated" datetime NOT NULL DEFAULT (datetime(\'now\')), "projectId" varchar(21) NOT NULL, "flowId" varchar(21) NOT NULL, "flowVersionId" varchar(21) NOT NULL, "status" varchar NOT NULL, "schedule" text, CONSTRAINT "REL_cb897f5e48cc3cba1418966326" UNIQUE ("flowId"), CONSTRAINT "REL_ec72f514c21734fb7a08797d75" UNIQUE ("flowVersionId"), CONSTRAINT "fk_flow_instance_flow" FOREIGN KEY ("flowId") REFERENCES "flow" ("id") ON DELETE CASCADE ON UPDATE NO ACTION, CONSTRAINT "fk_flow_instance_flow_version" FOREIGN KEY ("flowVersionId") REFERENCES "flow_version" ("id") ON DELETE CASCADE ON UPDATE NO ACTION)') - await queryRunner.query('INSERT INTO "temporary_flow_instance"("id", "created", "updated", "projectId", "flowId", "flowVersionId", "status", "schedule") SELECT "id", "created", "updated", "projectId", "flowId", "flowVersionId", "status", "schedule" FROM "flow_instance"') - await queryRunner.query('DROP TABLE "flow_instance"') - await queryRunner.query('ALTER TABLE "temporary_flow_instance" RENAME TO "flow_instance"') - await queryRunner.query('CREATE UNIQUE INDEX "idx_flow_instance_project_id_flow_id" ON "flow_instance" ("projectId", "flowId") ') - await queryRunner.query('CREATE TABLE "temporary_file" ("id" varchar(21) PRIMARY KEY NOT NULL, "created" datetime NOT NULL DEFAULT (datetime(\'now\')), "updated" datetime NOT NULL DEFAULT (datetime(\'now\')), "projectId" varchar(21), "data" blob NOT NULL, CONSTRAINT "fk_file_project_id" FOREIGN KEY ("projectId") REFERENCES "project" ("id") ON DELETE CASCADE ON UPDATE NO ACTION)') - await queryRunner.query('INSERT INTO "temporary_file"("id", "created", "updated", "projectId", "data") SELECT "id", "created", "updated", "projectId", "data" FROM "file"') - await queryRunner.query('DROP TABLE "file"') - await queryRunner.query('ALTER TABLE "temporary_file" RENAME TO "file"') - await queryRunner.query('DROP INDEX "idx_flow_project_id"') - await queryRunner.query('DROP INDEX "idx_flow_folder_id"') - await queryRunner.query('CREATE TABLE "temporary_flow" ("id" varchar(21) PRIMARY KEY NOT NULL, "created" datetime NOT NULL DEFAULT (datetime(\'now\')), "updated" datetime NOT NULL DEFAULT (datetime(\'now\')), "projectId" varchar(21) NOT NULL, "folderId" varchar(21), CONSTRAINT "fk_flow_folder_id" FOREIGN KEY ("folderId") REFERENCES "folder" ("id") ON DELETE SET NULL ON UPDATE NO ACTION, CONSTRAINT "fk_flow_project_id" FOREIGN KEY ("projectId") REFERENCES "project" ("id") ON DELETE CASCADE ON UPDATE NO ACTION)') - await queryRunner.query('INSERT INTO "temporary_flow"("id", "created", "updated", "projectId", "folderId") SELECT "id", "created", "updated", "projectId", "folderId" FROM "flow"') - await queryRunner.query('DROP TABLE "flow"') - await queryRunner.query('ALTER TABLE "temporary_flow" RENAME TO "flow"') - await queryRunner.query('CREATE INDEX "idx_flow_project_id" ON "flow" ("projectId") ') - await queryRunner.query('CREATE INDEX "idx_flow_folder_id" ON "flow" ("folderId") ') - await queryRunner.query('DROP INDEX "idx_flow_version_flow_id"') - await queryRunner.query('CREATE TABLE "temporary_flow_version" ("id" varchar(21) PRIMARY KEY NOT NULL, "created" datetime NOT NULL DEFAULT (datetime(\'now\')), "updated" datetime NOT NULL DEFAULT (datetime(\'now\')), "flowId" varchar(21) NOT NULL, "displayName" varchar NOT NULL, "trigger" text, "updatedBy" varchar, "valid" boolean NOT NULL, "state" varchar NOT NULL, CONSTRAINT "fk_updated_by_user_flow" FOREIGN KEY ("updatedBy") REFERENCES "user" ("id") ON DELETE CASCADE ON UPDATE NO ACTION, CONSTRAINT "fk_flow_version_flow" FOREIGN KEY ("flowId") REFERENCES "flow" ("id") ON DELETE CASCADE ON UPDATE NO ACTION)') - await queryRunner.query('INSERT INTO "temporary_flow_version"("id", "created", "updated", "flowId", "displayName", "trigger", "updatedBy", "valid", "state") SELECT "id", "created", "updated", "flowId", "displayName", "trigger", "updatedBy", "valid", "state" FROM "flow_version"') - await queryRunner.query('DROP TABLE "flow_version"') - await queryRunner.query('ALTER TABLE "temporary_flow_version" RENAME TO "flow_version"') - await queryRunner.query('CREATE INDEX "idx_flow_version_flow_id" ON "flow_version" ("flowId") ') - await queryRunner.query('DROP INDEX "idx_run_project_id_environment_created_desc"') - await queryRunner.query('DROP INDEX "idx_run_project_id_environment_status_created_desc"') - await queryRunner.query('DROP INDEX "idx_run_project_id_flow_id_environment_created_desc"') - await queryRunner.query('DROP INDEX "idx_run_project_id_flow_id_environment_status_created_desc"') - await queryRunner.query('CREATE TABLE "temporary_flow_run" ("id" varchar(21) PRIMARY KEY NOT NULL, "created" datetime NOT NULL DEFAULT (datetime(\'now\')), "updated" datetime NOT NULL DEFAULT (datetime(\'now\')), "projectId" varchar(21) NOT NULL, "flowId" varchar(21) NOT NULL, "flowVersionId" varchar(21) NOT NULL, "environment" varchar, "flowDisplayName" varchar NOT NULL, "logsFileId" varchar(21), "status" varchar NOT NULL, "tasks" integer, "startTime" datetime NOT NULL, "finishTime" datetime, "pauseMetadata" text, CONSTRAINT "fk_flow_run_project_id" FOREIGN KEY ("projectId") REFERENCES "project" ("id") ON DELETE CASCADE ON UPDATE NO ACTION, CONSTRAINT "fk_flow_run_flow_id" FOREIGN KEY ("flowId") REFERENCES "flow" ("id") ON DELETE CASCADE ON UPDATE NO ACTION)') - await queryRunner.query('INSERT INTO "temporary_flow_run"("id", "created", "updated", "projectId", "flowId", "flowVersionId", "environment", "flowDisplayName", "logsFileId", "status", "tasks", "startTime", "finishTime", "pauseMetadata") SELECT "id", "created", "updated", "projectId", "flowId", "flowVersionId", "environment", "flowDisplayName", "logsFileId", "status", "tasks", "startTime", "finishTime", "pauseMetadata" FROM "flow_run"') - await queryRunner.query('DROP TABLE "flow_run"') - await queryRunner.query('ALTER TABLE "temporary_flow_run" RENAME TO "flow_run"') - await queryRunner.query('CREATE INDEX "idx_run_project_id_environment_created_desc" ON "flow_run" ("projectId", "environment", "created") ') - await queryRunner.query('CREATE INDEX "idx_run_project_id_environment_status_created_desc" ON "flow_run" ("projectId", "environment", "status", "created") ') - await queryRunner.query('CREATE INDEX "idx_run_project_id_flow_id_environment_created_desc" ON "flow_run" ("projectId", "flowId", "environment", "created") ') - await queryRunner.query('CREATE INDEX "idx_run_project_id_flow_id_environment_status_created_desc" ON "flow_run" ("projectId", "flowId", "environment", "status", "created") ') - await queryRunner.query('DROP INDEX "idx_project_owner_id"') - await queryRunner.query('CREATE TABLE "temporary_project" ("id" varchar(21) PRIMARY KEY NOT NULL, "created" datetime NOT NULL DEFAULT (datetime(\'now\')), "updated" datetime NOT NULL DEFAULT (datetime(\'now\')), "ownerId" varchar(21) NOT NULL, "displayName" varchar NOT NULL, "notifyStatus" varchar NOT NULL, CONSTRAINT "fk_project_owner_id" FOREIGN KEY ("ownerId") REFERENCES "user" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION)') - await queryRunner.query('INSERT INTO "temporary_project"("id", "created", "updated", "ownerId", "displayName", "notifyStatus") SELECT "id", "created", "updated", "ownerId", "displayName", "notifyStatus" FROM "project"') - await queryRunner.query('DROP TABLE "project"') - await queryRunner.query('ALTER TABLE "temporary_project" RENAME TO "project"') - await queryRunner.query('CREATE INDEX "idx_project_owner_id" ON "project" ("ownerId") ') - await queryRunner.query('DROP INDEX "idx_app_connection_project_id_and_name"') - await queryRunner.query('CREATE TABLE "temporary_app_connection" ("id" varchar(21) PRIMARY KEY NOT NULL, "created" datetime NOT NULL DEFAULT (datetime(\'now\')), "updated" datetime NOT NULL DEFAULT (datetime(\'now\')), "name" varchar NOT NULL, "appName" varchar NOT NULL, "projectId" varchar(21) NOT NULL, "value" text NOT NULL, CONSTRAINT "fk_app_connection_app_project_id" FOREIGN KEY ("projectId") REFERENCES "project" ("id") ON DELETE CASCADE ON UPDATE NO ACTION)') - await queryRunner.query('INSERT INTO "temporary_app_connection"("id", "created", "updated", "name", "appName", "projectId", "value") SELECT "id", "created", "updated", "name", "appName", "projectId", "value" FROM "app_connection"') - await queryRunner.query('DROP TABLE "app_connection"') - await queryRunner.query('ALTER TABLE "temporary_app_connection" RENAME TO "app_connection"') - await queryRunner.query('CREATE UNIQUE INDEX "idx_app_connection_project_id_and_name" ON "app_connection" ("projectId", "name") ') - await queryRunner.query('DROP INDEX "idx_folder_project_id"') - await queryRunner.query('CREATE TABLE "temporary_folder" ("id" varchar(21) PRIMARY KEY NOT NULL, "created" datetime NOT NULL DEFAULT (datetime(\'now\')), "updated" datetime NOT NULL DEFAULT (datetime(\'now\')), "displayName" varchar NOT NULL, "projectId" varchar(21) NOT NULL, CONSTRAINT "fk_folder_project" FOREIGN KEY ("projectId") REFERENCES "project" ("id") ON DELETE CASCADE ON UPDATE NO ACTION)') - await queryRunner.query('INSERT INTO "temporary_folder"("id", "created", "updated", "displayName", "projectId") SELECT "id", "created", "updated", "displayName", "projectId" FROM "folder"') - await queryRunner.query('DROP TABLE "folder"') - await queryRunner.query('ALTER TABLE "temporary_folder" RENAME TO "folder"') - await queryRunner.query('CREATE INDEX "idx_folder_project_id" ON "folder" ("projectId") ') - await queryRunner.query('DROP INDEX "idx_piece_metadata_name_project_id_version"') - await queryRunner.query('CREATE TABLE "temporary_piece_metadata" ("id" varchar(21) PRIMARY KEY NOT NULL, "created" datetime NOT NULL DEFAULT (datetime(\'now\')), "updated" datetime NOT NULL DEFAULT (datetime(\'now\')), "name" varchar NOT NULL, "displayName" varchar NOT NULL, "logoUrl" varchar NOT NULL, "description" varchar, "projectId" varchar, "version" varchar NOT NULL, "minimumSupportedRelease" varchar NOT NULL, "maximumSupportedRelease" varchar NOT NULL, "auth" text, "actions" text NOT NULL, "triggers" text NOT NULL, CONSTRAINT "fk_piece_metadata_project_id" FOREIGN KEY ("projectId") REFERENCES "project" ("id") ON DELETE CASCADE ON UPDATE NO ACTION)') - await queryRunner.query('INSERT INTO "temporary_piece_metadata"("id", "created", "updated", "name", "displayName", "logoUrl", "description", "projectId", "version", "minimumSupportedRelease", "maximumSupportedRelease", "auth", "actions", "triggers") SELECT "id", "created", "updated", "name", "displayName", "logoUrl", "description", "projectId", "version", "minimumSupportedRelease", "maximumSupportedRelease", "auth", "actions", "triggers" FROM "piece_metadata"') - await queryRunner.query('DROP TABLE "piece_metadata"') - await queryRunner.query('ALTER TABLE "temporary_piece_metadata" RENAME TO "piece_metadata"') - await queryRunner.query('CREATE UNIQUE INDEX "idx_piece_metadata_name_project_id_version" ON "piece_metadata" ("name", "version", "projectId") ') - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query('DROP INDEX "idx_piece_metadata_name_project_id_version"') - await queryRunner.query('ALTER TABLE "piece_metadata" RENAME TO "temporary_piece_metadata"') - await queryRunner.query('CREATE TABLE "piece_metadata" ("id" varchar(21) PRIMARY KEY NOT NULL, "created" datetime NOT NULL DEFAULT (datetime(\'now\')), "updated" datetime NOT NULL DEFAULT (datetime(\'now\')), "name" varchar NOT NULL, "displayName" varchar NOT NULL, "logoUrl" varchar NOT NULL, "description" varchar, "projectId" varchar, "version" varchar NOT NULL, "minimumSupportedRelease" varchar NOT NULL, "maximumSupportedRelease" varchar NOT NULL, "auth" text, "actions" text NOT NULL, "triggers" text NOT NULL)') - await queryRunner.query('INSERT INTO "piece_metadata"("id", "created", "updated", "name", "displayName", "logoUrl", "description", "projectId", "version", "minimumSupportedRelease", "maximumSupportedRelease", "auth", "actions", "triggers") SELECT "id", "created", "updated", "name", "displayName", "logoUrl", "description", "projectId", "version", "minimumSupportedRelease", "maximumSupportedRelease", "auth", "actions", "triggers" FROM "temporary_piece_metadata"') - await queryRunner.query('DROP TABLE "temporary_piece_metadata"') - await queryRunner.query('CREATE UNIQUE INDEX "idx_piece_metadata_name_project_id_version" ON "piece_metadata" ("name", "version", "projectId") ') - await queryRunner.query('DROP INDEX "idx_folder_project_id"') - await queryRunner.query('ALTER TABLE "folder" RENAME TO "temporary_folder"') - await queryRunner.query('CREATE TABLE "folder" ("id" varchar(21) PRIMARY KEY NOT NULL, "created" datetime NOT NULL DEFAULT (datetime(\'now\')), "updated" datetime NOT NULL DEFAULT (datetime(\'now\')), "displayName" varchar NOT NULL, "projectId" varchar(21) NOT NULL)') - await queryRunner.query('INSERT INTO "folder"("id", "created", "updated", "displayName", "projectId") SELECT "id", "created", "updated", "displayName", "projectId" FROM "temporary_folder"') - await queryRunner.query('DROP TABLE "temporary_folder"') - await queryRunner.query('CREATE INDEX "idx_folder_project_id" ON "folder" ("projectId") ') - await queryRunner.query('DROP INDEX "idx_app_connection_project_id_and_name"') - await queryRunner.query('ALTER TABLE "app_connection" RENAME TO "temporary_app_connection"') - await queryRunner.query('CREATE TABLE "app_connection" ("id" varchar(21) PRIMARY KEY NOT NULL, "created" datetime NOT NULL DEFAULT (datetime(\'now\')), "updated" datetime NOT NULL DEFAULT (datetime(\'now\')), "name" varchar NOT NULL, "appName" varchar NOT NULL, "projectId" varchar(21) NOT NULL, "value" text NOT NULL)') - await queryRunner.query('INSERT INTO "app_connection"("id", "created", "updated", "name", "appName", "projectId", "value") SELECT "id", "created", "updated", "name", "appName", "projectId", "value" FROM "temporary_app_connection"') - await queryRunner.query('DROP TABLE "temporary_app_connection"') - await queryRunner.query('CREATE UNIQUE INDEX "idx_app_connection_project_id_and_name" ON "app_connection" ("projectId", "name") ') - await queryRunner.query('DROP INDEX "idx_project_owner_id"') - await queryRunner.query('ALTER TABLE "project" RENAME TO "temporary_project"') - await queryRunner.query('CREATE TABLE "project" ("id" varchar(21) PRIMARY KEY NOT NULL, "created" datetime NOT NULL DEFAULT (datetime(\'now\')), "updated" datetime NOT NULL DEFAULT (datetime(\'now\')), "ownerId" varchar(21) NOT NULL, "displayName" varchar NOT NULL, "notifyStatus" varchar NOT NULL)') - await queryRunner.query('INSERT INTO "project"("id", "created", "updated", "ownerId", "displayName", "notifyStatus") SELECT "id", "created", "updated", "ownerId", "displayName", "notifyStatus" FROM "temporary_project"') - await queryRunner.query('DROP TABLE "temporary_project"') - await queryRunner.query('CREATE INDEX "idx_project_owner_id" ON "project" ("ownerId") ') - await queryRunner.query('DROP INDEX "idx_run_project_id_flow_id_environment_status_created_desc"') - await queryRunner.query('DROP INDEX "idx_run_project_id_flow_id_environment_created_desc"') - await queryRunner.query('DROP INDEX "idx_run_project_id_environment_status_created_desc"') - await queryRunner.query('DROP INDEX "idx_run_project_id_environment_created_desc"') - await queryRunner.query('ALTER TABLE "flow_run" RENAME TO "temporary_flow_run"') - await queryRunner.query('CREATE TABLE "flow_run" ("id" varchar(21) PRIMARY KEY NOT NULL, "created" datetime NOT NULL DEFAULT (datetime(\'now\')), "updated" datetime NOT NULL DEFAULT (datetime(\'now\')), "projectId" varchar(21) NOT NULL, "flowId" varchar(21) NOT NULL, "flowVersionId" varchar(21) NOT NULL, "environment" varchar, "flowDisplayName" varchar NOT NULL, "logsFileId" varchar(21), "status" varchar NOT NULL, "tasks" integer, "startTime" datetime NOT NULL, "finishTime" datetime, "pauseMetadata" text)') - await queryRunner.query('INSERT INTO "flow_run"("id", "created", "updated", "projectId", "flowId", "flowVersionId", "environment", "flowDisplayName", "logsFileId", "status", "tasks", "startTime", "finishTime", "pauseMetadata") SELECT "id", "created", "updated", "projectId", "flowId", "flowVersionId", "environment", "flowDisplayName", "logsFileId", "status", "tasks", "startTime", "finishTime", "pauseMetadata" FROM "temporary_flow_run"') - await queryRunner.query('DROP TABLE "temporary_flow_run"') - await queryRunner.query('CREATE INDEX "idx_run_project_id_flow_id_environment_status_created_desc" ON "flow_run" ("projectId", "flowId", "environment", "status", "created") ') - await queryRunner.query('CREATE INDEX "idx_run_project_id_flow_id_environment_created_desc" ON "flow_run" ("projectId", "flowId", "environment", "created") ') - await queryRunner.query('CREATE INDEX "idx_run_project_id_environment_status_created_desc" ON "flow_run" ("projectId", "environment", "status", "created") ') - await queryRunner.query('CREATE INDEX "idx_run_project_id_environment_created_desc" ON "flow_run" ("projectId", "environment", "created") ') - await queryRunner.query('DROP INDEX "idx_flow_version_flow_id"') - await queryRunner.query('ALTER TABLE "flow_version" RENAME TO "temporary_flow_version"') - await queryRunner.query('CREATE TABLE "flow_version" ("id" varchar(21) PRIMARY KEY NOT NULL, "created" datetime NOT NULL DEFAULT (datetime(\'now\')), "updated" datetime NOT NULL DEFAULT (datetime(\'now\')), "flowId" varchar(21) NOT NULL, "displayName" varchar NOT NULL, "trigger" text, "updatedBy" varchar, "valid" boolean NOT NULL, "state" varchar NOT NULL)') - await queryRunner.query('INSERT INTO "flow_version"("id", "created", "updated", "flowId", "displayName", "trigger", "updatedBy", "valid", "state") SELECT "id", "created", "updated", "flowId", "displayName", "trigger", "updatedBy", "valid", "state" FROM "temporary_flow_version"') - await queryRunner.query('DROP TABLE "temporary_flow_version"') - await queryRunner.query('CREATE INDEX "idx_flow_version_flow_id" ON "flow_version" ("flowId") ') - await queryRunner.query('DROP INDEX "idx_flow_folder_id"') - await queryRunner.query('DROP INDEX "idx_flow_project_id"') - await queryRunner.query('ALTER TABLE "flow" RENAME TO "temporary_flow"') - await queryRunner.query('CREATE TABLE "flow" ("id" varchar(21) PRIMARY KEY NOT NULL, "created" datetime NOT NULL DEFAULT (datetime(\'now\')), "updated" datetime NOT NULL DEFAULT (datetime(\'now\')), "projectId" varchar(21) NOT NULL, "folderId" varchar(21))') - await queryRunner.query('INSERT INTO "flow"("id", "created", "updated", "projectId", "folderId") SELECT "id", "created", "updated", "projectId", "folderId" FROM "temporary_flow"') - await queryRunner.query('DROP TABLE "temporary_flow"') - await queryRunner.query('CREATE INDEX "idx_flow_folder_id" ON "flow" ("folderId") ') - await queryRunner.query('CREATE INDEX "idx_flow_project_id" ON "flow" ("projectId") ') - await queryRunner.query('ALTER TABLE "file" RENAME TO "temporary_file"') - await queryRunner.query('CREATE TABLE "file" ("id" varchar(21) PRIMARY KEY NOT NULL, "created" datetime NOT NULL DEFAULT (datetime(\'now\')), "updated" datetime NOT NULL DEFAULT (datetime(\'now\')), "projectId" varchar(21), "data" blob NOT NULL)') - await queryRunner.query('INSERT INTO "file"("id", "created", "updated", "projectId", "data") SELECT "id", "created", "updated", "projectId", "data" FROM "temporary_file"') - await queryRunner.query('DROP TABLE "temporary_file"') - await queryRunner.query('DROP INDEX "idx_flow_instance_project_id_flow_id"') - await queryRunner.query('ALTER TABLE "flow_instance" RENAME TO "temporary_flow_instance"') - await queryRunner.query('CREATE TABLE "flow_instance" ("id" varchar(21) PRIMARY KEY NOT NULL, "created" datetime NOT NULL DEFAULT (datetime(\'now\')), "updated" datetime NOT NULL DEFAULT (datetime(\'now\')), "projectId" varchar(21) NOT NULL, "flowId" varchar(21) NOT NULL, "flowVersionId" varchar(21) NOT NULL, "status" varchar NOT NULL, "schedule" text, CONSTRAINT "REL_cb897f5e48cc3cba1418966326" UNIQUE ("flowId"), CONSTRAINT "REL_ec72f514c21734fb7a08797d75" UNIQUE ("flowVersionId"))') - await queryRunner.query('INSERT INTO "flow_instance"("id", "created", "updated", "projectId", "flowId", "flowVersionId", "status", "schedule") SELECT "id", "created", "updated", "projectId", "flowId", "flowVersionId", "status", "schedule" FROM "temporary_flow_instance"') - await queryRunner.query('DROP TABLE "temporary_flow_instance"') - await queryRunner.query('CREATE UNIQUE INDEX "idx_flow_instance_project_id_flow_id" ON "flow_instance" ("projectId", "flowId") ') - await queryRunner.query('DROP INDEX "idx_trigger_event_flow_id"') - await queryRunner.query('ALTER TABLE "trigger_event" RENAME TO "temporary_trigger_event"') - await queryRunner.query('CREATE TABLE "trigger_event" ("id" varchar(21) PRIMARY KEY NOT NULL, "created" datetime NOT NULL DEFAULT (datetime(\'now\')), "updated" datetime NOT NULL DEFAULT (datetime(\'now\')), "flowId" varchar(21) NOT NULL, "projectId" varchar(21) NOT NULL, "sourceName" varchar NOT NULL, "payload" text)') - await queryRunner.query('INSERT INTO "trigger_event"("id", "created", "updated", "flowId", "projectId", "sourceName", "payload") SELECT "id", "created", "updated", "flowId", "projectId", "sourceName", "payload" FROM "temporary_trigger_event"') - await queryRunner.query('DROP TABLE "temporary_trigger_event"') - await queryRunner.query('CREATE INDEX "idx_trigger_event_flow_id" ON "trigger_event" ("flowId") ') - await queryRunner.query('DROP INDEX "idx_piece_metadata_name_project_id_version"') - await queryRunner.query('DROP TABLE "piece_metadata"') - await queryRunner.query('DROP INDEX "idx_folder_project_id"') - await queryRunner.query('DROP TABLE "folder"') - await queryRunner.query('DROP INDEX "idx_webhook_simulation_flow_id"') - await queryRunner.query('DROP TABLE "webhook_simulation"') - await queryRunner.query('DROP INDEX "idx_app_connection_project_id_and_name"') - await queryRunner.query('DROP TABLE "app_connection"') - await queryRunner.query('DROP TABLE "user"') - await queryRunner.query('DROP TABLE "store-entry"') - await queryRunner.query('DROP INDEX "idx_project_owner_id"') - await queryRunner.query('DROP TABLE "project"') - await queryRunner.query('DROP INDEX "idx_run_project_id_flow_id_environment_status_created_desc"') - await queryRunner.query('DROP INDEX "idx_run_project_id_flow_id_environment_created_desc"') - await queryRunner.query('DROP INDEX "idx_run_project_id_environment_status_created_desc"') - await queryRunner.query('DROP INDEX "idx_run_project_id_environment_created_desc"') - await queryRunner.query('DROP TABLE "flow_run"') - await queryRunner.query('DROP INDEX "idx_flow_version_flow_id"') - await queryRunner.query('DROP TABLE "flow_version"') - await queryRunner.query('DROP INDEX "idx_flow_folder_id"') - await queryRunner.query('DROP INDEX "idx_flow_project_id"') - await queryRunner.query('DROP TABLE "flow"') - await queryRunner.query('DROP TABLE "flag"') - await queryRunner.query('DROP TABLE "file"') - await queryRunner.query('DROP INDEX "idx_app_event_project_id_appName_identifier_value_event"') - await queryRunner.query('DROP INDEX "idx_app_event_routing_flow_id"') - await queryRunner.query('DROP TABLE "app_event_routing"') - await queryRunner.query('DROP INDEX "idx_flow_instance_project_id_flow_id"') - await queryRunner.query('DROP TABLE "flow_instance"') - await queryRunner.query('DROP INDEX "idx_trigger_event_flow_id"') - await queryRunner.query('DROP TABLE "trigger_event"') - } - -} diff --git a/packages/backend/src/app/database/migration/sqlite/1691706020626-add-app-connection-type-to-top-level.ts b/packages/backend/src/app/database/migration/sqlite/1691706020626-add-app-connection-type-to-top-level.ts deleted file mode 100644 index 621e3e4860..0000000000 --- a/packages/backend/src/app/database/migration/sqlite/1691706020626-add-app-connection-type-to-top-level.ts +++ /dev/null @@ -1,55 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm' -import { decryptObject } from '../../../helper/encryption' -import { logger } from '../../../helper/logger' - -type AppConnectionValue = { - type: string -} - -export class AddAppConnectionTypeToTopLevel1691706020626 implements MigrationInterface { - name = 'AddAppConnectionTypeToTopLevel1691706020626' - - public async up(queryRunner: QueryRunner): Promise { - logger.info('AddAppConnectionTypeToTopLevel1691706020626 up') - - await queryRunner.query('DROP INDEX "idx_app_connection_project_id_and_name"') - await queryRunner.query('CREATE TABLE "temporary_app_connection" ("id" varchar(21) PRIMARY KEY NOT NULL, "created" datetime NOT NULL DEFAULT (datetime(\'now\')), "updated" datetime NOT NULL DEFAULT (datetime(\'now\')), "name" varchar NOT NULL, "appName" varchar NOT NULL, "projectId" varchar(21) NOT NULL, "value" text NOT NULL, "type" varchar, CONSTRAINT "fk_app_connection_app_project_id" FOREIGN KEY ("projectId") REFERENCES "project" ("id") ON DELETE CASCADE ON UPDATE NO ACTION)') - await queryRunner.query('INSERT INTO "temporary_app_connection"("id", "created", "updated", "name", "appName", "projectId", "value") SELECT "id", "created", "updated", "name", "appName", "projectId", "value" FROM "app_connection"') - await queryRunner.query('DROP TABLE "app_connection"') - await queryRunner.query('ALTER TABLE "temporary_app_connection" RENAME TO "app_connection"') - - const connections = await queryRunner.query('SELECT * FROM app_connection') - - for (const currentConnection of connections) { - try { - const connectionValue = decryptObject(JSON.parse(currentConnection.value)) - await queryRunner.query(`UPDATE "app_connection" SET "type" = '${connectionValue.type}' WHERE id = '${currentConnection.id}'`) - } - catch (e) { - logger.error(e) - } - } - - await queryRunner.query('CREATE TABLE "temporary_app_connection" ("id" varchar(21) PRIMARY KEY NOT NULL, "created" datetime NOT NULL DEFAULT (datetime(\'now\')), "updated" datetime NOT NULL DEFAULT (datetime(\'now\')), "name" varchar NOT NULL, "appName" varchar NOT NULL, "projectId" varchar(21) NOT NULL, "value" text NOT NULL, "type" varchar NOT NULL, CONSTRAINT "fk_app_connection_app_project_id" FOREIGN KEY ("projectId") REFERENCES "project" ("id") ON DELETE CASCADE ON UPDATE NO ACTION)') - await queryRunner.query('INSERT INTO "temporary_app_connection"("id", "created", "updated", "name", "appName", "projectId", "value", "type") SELECT "id", "created", "updated", "name", "appName", "projectId", "value", "type" FROM "app_connection"') - await queryRunner.query('DROP TABLE "app_connection"') - await queryRunner.query('ALTER TABLE "temporary_app_connection" RENAME TO "app_connection"') - await queryRunner.query('CREATE UNIQUE INDEX "idx_app_connection_project_id_and_name" ON "app_connection" ("projectId", "name") ') - - logger.info('AddAppConnectionTypeToTopLevel1691706020626 finished') - } - - public async down(queryRunner: QueryRunner): Promise { - logger.info('AddAppConnectionTypeToTopLevel1691706020626 down') - - await queryRunner.query('DROP INDEX "idx_app_connection_project_id_and_name"') - await queryRunner.query('ALTER TABLE "app_connection" RENAME TO "temporary_app_connection"') - await queryRunner.query('CREATE TABLE "app_connection" ("id" varchar(21) PRIMARY KEY NOT NULL, "created" datetime NOT NULL DEFAULT (datetime(\'now\')), "updated" datetime NOT NULL DEFAULT (datetime(\'now\')), "name" varchar NOT NULL, "appName" varchar NOT NULL, "projectId" varchar(21) NOT NULL, "value" text NOT NULL, CONSTRAINT "fk_app_connection_app_project_id" FOREIGN KEY ("projectId") REFERENCES "project" ("id") ON DELETE CASCADE ON UPDATE NO ACTION)') - await queryRunner.query('INSERT INTO "app_connection"("id", "created", "updated", "name", "appName", "projectId", "value") SELECT "id", "created", "updated", "name", "appName", "projectId", "value" FROM "temporary_app_connection"') - await queryRunner.query('DROP TABLE "temporary_app_connection"') - await queryRunner.query('CREATE UNIQUE INDEX "idx_app_connection_project_id_and_name" ON "app_connection" ("projectId", "name") ') - - logger.info('AddAppConnectionTypeToTopLevel1691706020626 finished') - } - -} diff --git a/packages/backend/src/app/database/migration/sqlite/1692056190942-AddTagsToRunSqlite.ts b/packages/backend/src/app/database/migration/sqlite/1692056190942-AddTagsToRunSqlite.ts deleted file mode 100644 index 22522dc961..0000000000 --- a/packages/backend/src/app/database/migration/sqlite/1692056190942-AddTagsToRunSqlite.ts +++ /dev/null @@ -1,44 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm' - -export class AddTagsToRunSqlite1692056190942 implements MigrationInterface { - name = 'AddTagsToRunSqlite1692056190942' - - public async up(queryRunner: QueryRunner): Promise { - if (await migrationRan('AddTagsToRunSqlite31692056190942', queryRunner)) { - return - } - await queryRunner.query('DROP INDEX "idx_run_project_id_flow_id_environment_status_created_desc"') - await queryRunner.query('DROP INDEX "idx_run_project_id_flow_id_environment_created_desc"') - await queryRunner.query('DROP INDEX "idx_run_project_id_environment_status_created_desc"') - await queryRunner.query('DROP INDEX "idx_run_project_id_environment_created_desc"') - await queryRunner.query('CREATE TABLE "temporary_flow_run" ("id" varchar(21) PRIMARY KEY NOT NULL, "created" datetime NOT NULL DEFAULT (datetime(\'now\')), "updated" datetime NOT NULL DEFAULT (datetime(\'now\')), "projectId" varchar(21) NOT NULL, "flowId" varchar(21) NOT NULL, "flowVersionId" varchar(21) NOT NULL, "environment" varchar, "flowDisplayName" varchar NOT NULL, "logsFileId" varchar(21), "status" varchar NOT NULL, "tasks" integer, "startTime" datetime NOT NULL, "finishTime" datetime, "pauseMetadata" text, "tags" text, CONSTRAINT "fk_flow_run_flow_id" FOREIGN KEY ("flowId") REFERENCES "flow" ("id") ON DELETE CASCADE ON UPDATE NO ACTION, CONSTRAINT "fk_flow_run_project_id" FOREIGN KEY ("projectId") REFERENCES "project" ("id") ON DELETE CASCADE ON UPDATE NO ACTION)') - await queryRunner.query('INSERT INTO "temporary_flow_run"("id", "created", "updated", "projectId", "flowId", "flowVersionId", "environment", "flowDisplayName", "logsFileId", "status", "tasks", "startTime", "finishTime", "pauseMetadata") SELECT "id", "created", "updated", "projectId", "flowId", "flowVersionId", "environment", "flowDisplayName", "logsFileId", "status", "tasks", "startTime", "finishTime", "pauseMetadata" FROM "flow_run"') - await queryRunner.query('DROP TABLE "flow_run"') - await queryRunner.query('ALTER TABLE "temporary_flow_run" RENAME TO "flow_run"') - await queryRunner.query('CREATE INDEX "idx_run_project_id_flow_id_environment_status_created_desc" ON "flow_run" ("projectId", "flowId", "environment", "status", "created") ') - await queryRunner.query('CREATE INDEX "idx_run_project_id_flow_id_environment_created_desc" ON "flow_run" ("projectId", "flowId", "environment", "created") ') - await queryRunner.query('CREATE INDEX "idx_run_project_id_environment_status_created_desc" ON "flow_run" ("projectId", "environment", "status", "created") ') - await queryRunner.query('CREATE INDEX "idx_run_project_id_environment_created_desc" ON "flow_run" ("projectId", "environment", "created") ') - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query('DROP INDEX "idx_run_project_id_environment_created_desc"') - await queryRunner.query('DROP INDEX "idx_run_project_id_environment_status_created_desc"') - await queryRunner.query('DROP INDEX "idx_run_project_id_flow_id_environment_created_desc"') - await queryRunner.query('DROP INDEX "idx_run_project_id_flow_id_environment_status_created_desc"') - await queryRunner.query('ALTER TABLE "flow_run" RENAME TO "temporary_flow_run"') - await queryRunner.query('CREATE TABLE "flow_run" ("id" varchar(21) PRIMARY KEY NOT NULL, "created" datetime NOT NULL DEFAULT (datetime(\'now\')), "updated" datetime NOT NULL DEFAULT (datetime(\'now\')), "projectId" varchar(21) NOT NULL, "flowId" varchar(21) NOT NULL, "flowVersionId" varchar(21) NOT NULL, "environment" varchar, "flowDisplayName" varchar NOT NULL, "logsFileId" varchar(21), "status" varchar NOT NULL, "tasks" integer, "startTime" datetime NOT NULL, "finishTime" datetime, "pauseMetadata" text, CONSTRAINT "fk_flow_run_flow_id" FOREIGN KEY ("flowId") REFERENCES "flow" ("id") ON DELETE CASCADE ON UPDATE NO ACTION, CONSTRAINT "fk_flow_run_project_id" FOREIGN KEY ("projectId") REFERENCES "project" ("id") ON DELETE CASCADE ON UPDATE NO ACTION)') - await queryRunner.query('INSERT INTO "flow_run"("id", "created", "updated", "projectId", "flowId", "flowVersionId", "environment", "flowDisplayName", "logsFileId", "status", "tasks", "startTime", "finishTime", "pauseMetadata") SELECT "id", "created", "updated", "projectId", "flowId", "flowVersionId", "environment", "flowDisplayName", "logsFileId", "status", "tasks", "startTime", "finishTime", "pauseMetadata" FROM "temporary_flow_run"') - await queryRunner.query('DROP TABLE "temporary_flow_run"') - await queryRunner.query('CREATE INDEX "idx_run_project_id_environment_created_desc" ON "flow_run" ("projectId", "environment", "created") ') - await queryRunner.query('CREATE INDEX "idx_run_project_id_environment_status_created_desc" ON "flow_run" ("projectId", "environment", "status", "created") ') - await queryRunner.query('CREATE INDEX "idx_run_project_id_flow_id_environment_created_desc" ON "flow_run" ("projectId", "flowId", "environment", "created") ') - await queryRunner.query('CREATE INDEX "idx_run_project_id_flow_id_environment_status_created_desc" ON "flow_run" ("projectId", "flowId", "environment", "status", "created") ') - } - -} - -async function migrationRan(migration: string, queryRunner: QueryRunner): Promise { - const result = await queryRunner.query('SELECT * from migrations where name = ?', [migration]) - return result.length > 0 -} \ No newline at end of file diff --git a/packages/backend/src/app/database/migration/sqlite/1692958076906-AddStepFileSqlite.ts b/packages/backend/src/app/database/migration/sqlite/1692958076906-AddStepFileSqlite.ts deleted file mode 100644 index 7f62efc766..0000000000 --- a/packages/backend/src/app/database/migration/sqlite/1692958076906-AddStepFileSqlite.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm' - -export class AddStepFileSqlite1692958076906 implements MigrationInterface { - name = 'AddStepFileSqlite1692958076906' - - public async up(queryRunner: QueryRunner): Promise { - if (await migrationRan('AddStepFileSqlite31692958076906', queryRunner)) { - return - } - await queryRunner.query('CREATE TABLE "step_file" ("id" varchar(21) PRIMARY KEY NOT NULL, "created" datetime NOT NULL DEFAULT (datetime(\'now\')), "updated" datetime NOT NULL DEFAULT (datetime(\'now\')), "flowId" varchar(21) NOT NULL, "projectId" varchar(21) NOT NULL, "name" varchar NOT NULL, "size" integer NOT NULL, "stepName" varchar NOT NULL, "data" blob NOT NULL)') - await queryRunner.query('CREATE UNIQUE INDEX "step_file_project_id_flow_id_step_name_name" ON "step_file" ("projectId", "flowId", "stepName", "name") ') - await queryRunner.query('DROP INDEX "step_file_project_id_flow_id_step_name_name"') - await queryRunner.query('CREATE TABLE "temporary_step_file" ("id" varchar(21) PRIMARY KEY NOT NULL, "created" datetime NOT NULL DEFAULT (datetime(\'now\')), "updated" datetime NOT NULL DEFAULT (datetime(\'now\')), "flowId" varchar(21) NOT NULL, "projectId" varchar(21) NOT NULL, "name" varchar NOT NULL, "size" integer NOT NULL, "stepName" varchar NOT NULL, "data" blob NOT NULL, CONSTRAINT "fk_step_file_project_id" FOREIGN KEY ("projectId") REFERENCES "project" ("id") ON DELETE CASCADE ON UPDATE NO ACTION, CONSTRAINT "fk_step_file_flow_id" FOREIGN KEY ("flowId") REFERENCES "flow" ("id") ON DELETE CASCADE ON UPDATE NO ACTION)') - await queryRunner.query('INSERT INTO "temporary_step_file"("id", "created", "updated", "flowId", "projectId", "name", "size", "stepName", "data") SELECT "id", "created", "updated", "flowId", "projectId", "name", "size", "stepName", "data" FROM "step_file"') - await queryRunner.query('DROP TABLE "step_file"') - await queryRunner.query('ALTER TABLE "temporary_step_file" RENAME TO "step_file"') - await queryRunner.query('CREATE UNIQUE INDEX "step_file_project_id_flow_id_step_name_name" ON "step_file" ("projectId", "flowId", "stepName", "name") ') - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query('DROP INDEX "step_file_project_id_flow_id_step_name_name"') - await queryRunner.query('ALTER TABLE "step_file" RENAME TO "temporary_step_file"') - await queryRunner.query('CREATE TABLE "step_file" ("id" varchar(21) PRIMARY KEY NOT NULL, "created" datetime NOT NULL DEFAULT (datetime(\'now\')), "updated" datetime NOT NULL DEFAULT (datetime(\'now\')), "flowId" varchar(21) NOT NULL, "projectId" varchar(21) NOT NULL, "name" varchar NOT NULL, "size" integer NOT NULL, "stepName" varchar NOT NULL, "data" blob NOT NULL)') - await queryRunner.query('INSERT INTO "step_file"("id", "created", "updated", "flowId", "projectId", "name", "size", "stepName", "data") SELECT "id", "created", "updated", "flowId", "projectId", "name", "size", "stepName", "data" FROM "temporary_step_file"') - await queryRunner.query('DROP TABLE "temporary_step_file"') - await queryRunner.query('CREATE UNIQUE INDEX "step_file_project_id_flow_id_step_name_name" ON "step_file" ("projectId", "flowId", "stepName", "name") ') - await queryRunner.query('DROP INDEX "step_file_project_id_flow_id_step_name_name"') - await queryRunner.query('DROP TABLE "step_file"') - } - -} - -async function migrationRan(migration: string, queryRunner: QueryRunner): Promise { - const result = await queryRunner.query('SELECT * from migrations where name = ?', [migration]) - return result.length > 0 -} \ No newline at end of file diff --git a/packages/backend/src/app/database/migration/sqlite/1693402376520-AddStatusToConnectionsSqlite.ts b/packages/backend/src/app/database/migration/sqlite/1693402376520-AddStatusToConnectionsSqlite.ts deleted file mode 100644 index 5eb722a5d8..0000000000 --- a/packages/backend/src/app/database/migration/sqlite/1693402376520-AddStatusToConnectionsSqlite.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm' - -export class AddStatusToConnectionsSqlite1693402376520 implements MigrationInterface { - name = 'AddStatusToConnectionsSqlite1693402376520' - - public async up(queryRunner: QueryRunner): Promise { - if (await migrationRan('AddStatusToConnectionsSqlite31693402376520', queryRunner)) { - return - } - await queryRunner.query('DROP INDEX "idx_app_connection_project_id_and_name"') - await queryRunner.query('CREATE TABLE "temporary_app_connection" ("id" varchar(21) PRIMARY KEY NOT NULL, "created" datetime NOT NULL DEFAULT (datetime(\'now\')), "updated" datetime NOT NULL DEFAULT (datetime(\'now\')), "name" varchar NOT NULL, "appName" varchar NOT NULL, "projectId" varchar(21) NOT NULL, "value" text NOT NULL, "type" varchar NOT NULL, "status" varchar NOT NULL DEFAULT (\'ACTIVE\'), CONSTRAINT "fk_app_connection_app_project_id" FOREIGN KEY ("projectId") REFERENCES "project" ("id") ON DELETE CASCADE ON UPDATE NO ACTION)') - await queryRunner.query('INSERT INTO "temporary_app_connection"("id", "created", "updated", "name", "appName", "projectId", "value", "type") SELECT "id", "created", "updated", "name", "appName", "projectId", "value", "type" FROM "app_connection"') - await queryRunner.query('DROP TABLE "app_connection"') - await queryRunner.query('ALTER TABLE "temporary_app_connection" RENAME TO "app_connection"') - await queryRunner.query('CREATE UNIQUE INDEX "idx_app_connection_project_id_and_name" ON "app_connection" ("projectId", "name") ') - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query('DROP INDEX "idx_app_connection_project_id_and_name"') - await queryRunner.query('ALTER TABLE "app_connection" RENAME TO "temporary_app_connection"') - await queryRunner.query('CREATE TABLE "app_connection" ("id" varchar(21) PRIMARY KEY NOT NULL, "created" datetime NOT NULL DEFAULT (datetime(\'now\')), "updated" datetime NOT NULL DEFAULT (datetime(\'now\')), "name" varchar NOT NULL, "appName" varchar NOT NULL, "projectId" varchar(21) NOT NULL, "value" text NOT NULL, "type" varchar NOT NULL, CONSTRAINT "fk_app_connection_app_project_id" FOREIGN KEY ("projectId") REFERENCES "project" ("id") ON DELETE CASCADE ON UPDATE NO ACTION)') - await queryRunner.query('INSERT INTO "app_connection"("id", "created", "updated", "name", "appName", "projectId", "value", "type") SELECT "id", "created", "updated", "name", "appName", "projectId", "value", "type" FROM "temporary_app_connection"') - await queryRunner.query('DROP TABLE "temporary_app_connection"') - await queryRunner.query('CREATE UNIQUE INDEX "idx_app_connection_project_id_and_name" ON "app_connection" ("projectId", "name") ') - } - -} - - -async function migrationRan(migration: string, queryRunner: QueryRunner): Promise { - const result = await queryRunner.query('SELECT * from migrations where name = ?', [migration]) - return result.length > 0 -} diff --git a/packages/backend/src/app/database/migration/sqlite/1693774053027-AddImageUrlAndTitleToUser.ts b/packages/backend/src/app/database/migration/sqlite/1693774053027-AddImageUrlAndTitleToUser.ts deleted file mode 100644 index b7a643b409..0000000000 --- a/packages/backend/src/app/database/migration/sqlite/1693774053027-AddImageUrlAndTitleToUser.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm' - -export class AddImageUrlAndTitleToUser1693774053027 implements MigrationInterface { - name = 'AddImageUrlAndTitleToUser1693774053027' - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query('CREATE TABLE "temporary_user" ("id" varchar(21) PRIMARY KEY NOT NULL, "created" datetime NOT NULL DEFAULT (datetime(\'now\')), "updated" datetime NOT NULL DEFAULT (datetime(\'now\')), "email" varchar NOT NULL, "firstName" varchar NOT NULL, "lastName" varchar NOT NULL, "password" varchar NOT NULL, "status" varchar NOT NULL, "trackEvents" boolean, "newsLetter" boolean, "imageUrl" varchar, "title" varchar, CONSTRAINT "UQ_e12875dfb3b1d92d7d7c5377e22" UNIQUE ("email"))') - await queryRunner.query('INSERT INTO "temporary_user"("id", "created", "updated", "email", "firstName", "lastName", "password", "status", "trackEvents", "newsLetter") SELECT "id", "created", "updated", "email", "firstName", "lastName", "password", "status", "trackEvents", "newsLetter" FROM "user"') - await queryRunner.query('DROP TABLE "user"') - await queryRunner.query('ALTER TABLE "temporary_user" RENAME TO "user"') - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query('ALTER TABLE "user" RENAME TO "temporary_user"') - await queryRunner.query('CREATE TABLE "user" ("id" varchar(21) PRIMARY KEY NOT NULL, "created" datetime NOT NULL DEFAULT (datetime(\'now\')), "updated" datetime NOT NULL DEFAULT (datetime(\'now\')), "email" varchar NOT NULL, "firstName" varchar NOT NULL, "lastName" varchar NOT NULL, "password" varchar NOT NULL, "status" varchar NOT NULL, "trackEvents" boolean, "newsLetter" boolean, CONSTRAINT "UQ_e12875dfb3b1d92d7d7c5377e22" UNIQUE ("email"))') - await queryRunner.query('INSERT INTO "user"("id", "created", "updated", "email", "firstName", "lastName", "password", "status", "trackEvents", "newsLetter") SELECT "id", "created", "updated", "email", "firstName", "lastName", "password", "status", "trackEvents", "newsLetter" FROM "temporary_user"') - await queryRunner.query('DROP TABLE "temporary_user"') - } - -} diff --git a/packages/backend/src/app/database/migration/sqlite/1694695212159-file-type-compression.ts b/packages/backend/src/app/database/migration/sqlite/1694695212159-file-type-compression.ts deleted file mode 100644 index 8a13eac3b7..0000000000 --- a/packages/backend/src/app/database/migration/sqlite/1694695212159-file-type-compression.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm' -import { logger } from '../../../helper/logger' - -export class FileTypeCompression1694695212159 implements MigrationInterface { - name = 'FileTypeCompression1694695212159' - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query('CREATE TABLE "temporary_file" ("id" varchar(21) PRIMARY KEY NOT NULL, "created" datetime NOT NULL DEFAULT (datetime(\'now\')), "updated" datetime NOT NULL DEFAULT (datetime(\'now\')), "projectId" varchar(21), "data" blob NOT NULL, "type" varchar NOT NULL DEFAULT (\'UNKNOWN\'), "compression" varchar NOT NULL DEFAULT (\'NONE\'), CONSTRAINT "fk_file_project_id" FOREIGN KEY ("projectId") REFERENCES "project" ("id") ON DELETE CASCADE ON UPDATE NO ACTION)') - await queryRunner.query('INSERT INTO "temporary_file"("id", "created", "updated", "projectId", "data") SELECT "id", "created", "updated", "projectId", "data" FROM "file"') - await queryRunner.query('DROP TABLE "file"') - await queryRunner.query('ALTER TABLE "temporary_file" RENAME TO "file"') - - logger.info('[FileTypeCompression1694695212159] up') - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query('ALTER TABLE "file" RENAME TO "temporary_file"') - await queryRunner.query('CREATE TABLE "file" ("id" varchar(21) PRIMARY KEY NOT NULL, "created" datetime NOT NULL DEFAULT (datetime(\'now\')), "updated" datetime NOT NULL DEFAULT (datetime(\'now\')), "projectId" varchar(21), "data" blob NOT NULL, CONSTRAINT "fk_file_project_id" FOREIGN KEY ("projectId") REFERENCES "project" ("id") ON DELETE CASCADE ON UPDATE NO ACTION)') - await queryRunner.query('INSERT INTO "file"("id", "created", "updated", "projectId", "data") SELECT "id", "created", "updated", "projectId", "data" FROM "temporary_file"') - await queryRunner.query('DROP TABLE "temporary_file"') - - logger.info('[FileTypeCompression1694695212159] down') - } - -} diff --git a/packages/backend/src/app/database/migration/sqlite/1696016228398-add-piece-type-and-package-type-to-piece-metadata.ts b/packages/backend/src/app/database/migration/sqlite/1696016228398-add-piece-type-and-package-type-to-piece-metadata.ts deleted file mode 100644 index 0b4e752422..0000000000 --- a/packages/backend/src/app/database/migration/sqlite/1696016228398-add-piece-type-and-package-type-to-piece-metadata.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm' -import { logger } from '../../../helper/logger' - -export class AddPieceTypeAndPackageTypeToPieceMetadata1696016228398 implements MigrationInterface { - name = 'AddPieceTypeAndPackageTypeToPieceMetadata1696016228398' - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query('CREATE TABLE "temporary_piece_metadata" ("id" varchar(21) PRIMARY KEY NOT NULL, "created" datetime NOT NULL DEFAULT (datetime(\'now\')), "updated" datetime NOT NULL DEFAULT (datetime(\'now\')), "name" varchar NOT NULL, "displayName" varchar NOT NULL, "logoUrl" varchar NOT NULL, "description" varchar, "projectId" varchar, "version" varchar NOT NULL, "minimumSupportedRelease" varchar NOT NULL, "maximumSupportedRelease" varchar NOT NULL, "auth" text, "actions" text NOT NULL, "triggers" text NOT NULL, "pieceType" varchar, "packageType" varchar, CONSTRAINT "fk_piece_metadata_project_id" FOREIGN KEY ("projectId") REFERENCES "project" ("id") ON DELETE CASCADE ON UPDATE NO ACTION)') - await queryRunner.query('INSERT INTO "temporary_piece_metadata"("id", "created", "updated", "name", "displayName", "logoUrl", "description", "projectId", "version", "minimumSupportedRelease", "maximumSupportedRelease", "auth", "actions", "triggers") SELECT "id", "created", "updated", "name", "displayName", "logoUrl", "description", "projectId", "version", "minimumSupportedRelease", "maximumSupportedRelease", "auth", "actions", "triggers" FROM "piece_metadata"') - - await queryRunner.query('DROP INDEX "idx_piece_metadata_name_project_id_version"') - await queryRunner.query('DROP TABLE "piece_metadata"') - - await queryRunner.query('UPDATE "temporary_piece_metadata" SET "pieceType" = \'OFFICIAL\' WHERE "projectId" IS NULL') - await queryRunner.query('UPDATE "temporary_piece_metadata" SET "pieceType" = \'CUSTOM\' WHERE "projectId" IS NOT NULL') - await queryRunner.query('UPDATE "temporary_piece_metadata" SET "packageType" = \'REGISTRY\'') - - await queryRunner.query('CREATE TABLE "temporary_piece_metadata_two" ("id" varchar(21) PRIMARY KEY NOT NULL, "created" datetime NOT NULL DEFAULT (datetime(\'now\')), "updated" datetime NOT NULL DEFAULT (datetime(\'now\')), "name" varchar NOT NULL, "displayName" varchar NOT NULL, "logoUrl" varchar NOT NULL, "description" varchar, "projectId" varchar, "version" varchar NOT NULL, "minimumSupportedRelease" varchar NOT NULL, "maximumSupportedRelease" varchar NOT NULL, "auth" text, "actions" text NOT NULL, "triggers" text NOT NULL, "pieceType" varchar NOT NULL, "packageType" varchar NOT NULL, CONSTRAINT "fk_piece_metadata_project_id" FOREIGN KEY ("projectId") REFERENCES "project" ("id") ON DELETE CASCADE ON UPDATE NO ACTION)') - await queryRunner.query('INSERT INTO "temporary_piece_metadata_two"("id", "created", "updated", "name", "displayName", "logoUrl", "description", "projectId", "version", "minimumSupportedRelease", "maximumSupportedRelease", "auth", "actions", "triggers", "pieceType", "packageType") SELECT "id", "created", "updated", "name", "displayName", "logoUrl", "description", "projectId", "version", "minimumSupportedRelease", "maximumSupportedRelease", "auth", "actions", "triggers", "pieceType", "packageType" FROM "temporary_piece_metadata"') - - await queryRunner.query('DROP TABLE "temporary_piece_metadata"') - - await queryRunner.query('ALTER TABLE "temporary_piece_metadata_two" RENAME TO "piece_metadata"') - await queryRunner.query('CREATE UNIQUE INDEX "idx_piece_metadata_name_project_id_version" ON "piece_metadata" ("name", "version", "projectId") ') - - logger.info('AddPieceTypeAndPackageTypeToPieceMetadata1696016228398: up') - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query('DROP INDEX "idx_piece_metadata_name_project_id_version"') - await queryRunner.query('ALTER TABLE "piece_metadata" RENAME TO "temporary_piece_metadata"') - await queryRunner.query('CREATE TABLE "piece_metadata" ("id" varchar(21) PRIMARY KEY NOT NULL, "created" datetime NOT NULL DEFAULT (datetime(\'now\')), "updated" datetime NOT NULL DEFAULT (datetime(\'now\')), "name" varchar NOT NULL, "displayName" varchar NOT NULL, "logoUrl" varchar NOT NULL, "description" varchar, "projectId" varchar, "version" varchar NOT NULL, "minimumSupportedRelease" varchar NOT NULL, "maximumSupportedRelease" varchar NOT NULL, "auth" text, "actions" text NOT NULL, "triggers" text NOT NULL, CONSTRAINT "fk_piece_metadata_project_id" FOREIGN KEY ("projectId") REFERENCES "project" ("id") ON DELETE CASCADE ON UPDATE NO ACTION)') - await queryRunner.query('INSERT INTO "piece_metadata"("id", "created", "updated", "name", "displayName", "logoUrl", "description", "projectId", "version", "minimumSupportedRelease", "maximumSupportedRelease", "auth", "actions", "triggers") SELECT "id", "created", "updated", "name", "displayName", "logoUrl", "description", "projectId", "version", "minimumSupportedRelease", "maximumSupportedRelease", "auth", "actions", "triggers" FROM "temporary_piece_metadata"') - await queryRunner.query('DROP TABLE "temporary_piece_metadata"') - await queryRunner.query('CREATE UNIQUE INDEX "idx_piece_metadata_name_project_id_version" ON "piece_metadata" ("name", "version", "projectId") ') - - logger.info('AddPieceTypeAndPackageTypeToPieceMetadata1696016228398: down') - } - -} diff --git a/packages/backend/src/app/database/migration/sqlite/1696029443045-AddChatBotSqlite.ts b/packages/backend/src/app/database/migration/sqlite/1696029443045-AddChatBotSqlite.ts deleted file mode 100644 index 476f6227b5..0000000000 --- a/packages/backend/src/app/database/migration/sqlite/1696029443045-AddChatBotSqlite.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm' - -export class AddChatBotSqlite1696029443045 implements MigrationInterface { - name = 'AddChatBotSqlite1696029443045' - - public async up(queryRunner: QueryRunner): Promise { - if (await migrationRan('AddChatBotSqlite31696029443045', queryRunner)) { - return - } - await queryRunner.query('CREATE TABLE "chatbot" ("id" varchar(21) PRIMARY KEY NOT NULL, "created" datetime NOT NULL DEFAULT (datetime(\'now\')), "updated" datetime NOT NULL DEFAULT (datetime(\'now\')), "type" varchar NOT NULL, "displayName" varchar NOT NULL, "projectId" varchar NOT NULL, "connectionId" varchar, "visibilityStatus" varchar NOT NULL, "dataSources" text NOT NULL, "prompt" varchar)') - await queryRunner.query('CREATE TABLE "temporary_chatbot" ("id" varchar(21) PRIMARY KEY NOT NULL, "created" datetime NOT NULL DEFAULT (datetime(\'now\')), "updated" datetime NOT NULL DEFAULT (datetime(\'now\')), "type" varchar NOT NULL, "displayName" varchar NOT NULL, "projectId" varchar NOT NULL, "connectionId" varchar, "visibilityStatus" varchar NOT NULL, "dataSources" text NOT NULL, "prompt" varchar, CONSTRAINT "FK_d2f5f245c27541cd70f13f169eb" FOREIGN KEY ("projectId") REFERENCES "project" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION, CONSTRAINT "FK_13f7ad52cefa43433864732c384" FOREIGN KEY ("connectionId") REFERENCES "app_connection" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION)') - await queryRunner.query('INSERT INTO "temporary_chatbot"("id", "created", "updated", "type", "displayName", "projectId", "connectionId", "visibilityStatus", "dataSources", "prompt") SELECT "id", "created", "updated", "type", "displayName", "projectId", "connectionId", "visibilityStatus", "dataSources", "prompt" FROM "chatbot"') - await queryRunner.query('DROP TABLE "chatbot"') - await queryRunner.query('ALTER TABLE "temporary_chatbot" RENAME TO "chatbot"') - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query('ALTER TABLE "chatbot" RENAME TO "temporary_chatbot"') - await queryRunner.query('CREATE TABLE "chatbot" ("id" varchar(21) PRIMARY KEY NOT NULL, "created" datetime NOT NULL DEFAULT (datetime(\'now\')), "updated" datetime NOT NULL DEFAULT (datetime(\'now\')), "type" varchar NOT NULL, "displayName" varchar NOT NULL, "projectId" varchar NOT NULL, "connectionId" varchar, "visibilityStatus" varchar NOT NULL, "dataSources" text NOT NULL, "prompt" varchar)') - await queryRunner.query('INSERT INTO "chatbot"("id", "created", "updated", "type", "displayName", "projectId", "connectionId", "visibilityStatus", "dataSources", "prompt") SELECT "id", "created", "updated", "type", "displayName", "projectId", "connectionId", "visibilityStatus", "dataSources", "prompt" FROM "temporary_chatbot"') - await queryRunner.query('DROP TABLE "temporary_chatbot"') - await queryRunner.query('DROP TABLE "chatbot"') - } - -} - -async function migrationRan(migration: string, queryRunner: QueryRunner): Promise { - const result = await queryRunner.query('SELECT * from migrations where name = ?', [migration]) - return result.length > 0 -} diff --git a/packages/backend/src/app/ee/authentication/authentication-service/hooks/enterprise-authentication-service-hooks.ts b/packages/backend/src/app/ee/authentication/authentication-service/hooks/enterprise-authentication-service-hooks.ts deleted file mode 100644 index 88e5e3bc1c..0000000000 --- a/packages/backend/src/app/ee/authentication/authentication-service/hooks/enterprise-authentication-service-hooks.ts +++ /dev/null @@ -1,74 +0,0 @@ -import { - AuthenticationServiceHooks, -} from '../../../../authentication/authentication-service/hooks/authentication-service-hooks' -import { flagService } from '../../../../flags/flag.service' -import { ApFlagId, ProjectType } from '@activepieces/shared' -import { platformService } from '../../../platform/platform.service' -import { userService } from '../../../../user/user-service' -import { authenticationHelper } from './authentication-helper' -import { projectService } from '../../../../project/project-service' -import { enforceLimits } from '../../../helper/license-validator' - -const DEFAULT_PLATFORM_NAME = 'platform' - -export const enterpriseAuthenticationServiceHooks: AuthenticationServiceHooks = { - async preSignIn({ email, platformId, provider }) { - await authenticationHelper.assertEmailAuthIsEnabled({ platformId, provider }) - await authenticationHelper.assertDomainIsAllowed({ email, platformId }) - }, - async preSignUp({ email, platformId, provider }) { - await authenticationHelper.assertEmailAuthIsEnabled({ platformId, provider }) - await authenticationHelper.assertUserIsInvitedAndDomainIsAllowed({ email, platformId }) - }, - async postSignUp({ user }) { - const platformCreated = await flagService.getOne(ApFlagId.PLATFORM_CREATED) - if (platformCreated?.value) { - const { project, token } = await authenticationHelper.getProjectAndTokenOrThrow(user) - return { - user, - project, - token, - } - } - - const project = await projectService.create({ - displayName: `${user.firstName}'s Project`, - ownerId: user.id, - platformId: undefined, - type: ProjectType.STANDALONE, - }) - - const platform = await platformService.add({ - ownerId: user.id, - projectId: project.id, - name: DEFAULT_PLATFORM_NAME, - }) - - await userService.updatePlatformId({ id: user.id, platformId: platform.id }) - - await enforceLimits() - - await flagService.save({ - id: ApFlagId.PLATFORM_CREATED, - value: true, - }) - - await authenticationHelper.autoVerifyUserIfEligible(user) - const updatedUser = await userService.getOneOrFail({ id: user.id }) - const { project: updatedProject, token } = await authenticationHelper.getProjectAndTokenOrThrow(updatedUser) - return { - user: updatedUser, - project: updatedProject, - token, - } - }, - - async postSignIn({ user }) { - const { project, token } = await authenticationHelper.getProjectAndTokenOrThrow(user) - return { - user, - project, - token, - } - }, -} diff --git a/packages/backend/src/app/ee/authentication/ee-authorization.ts b/packages/backend/src/app/ee/authentication/ee-authorization.ts deleted file mode 100644 index 1ced65986c..0000000000 --- a/packages/backend/src/app/ee/authentication/ee-authorization.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { ActivepiecesError, ErrorCode, PlatformRole, isNil } from '@activepieces/shared' -import { onRequestAsyncHookHandler } from 'fastify' - -const USER_NOT_ALLOWED_TO_PERFORM_OPERATION_ERROR = new ActivepiecesError({ - code: ErrorCode.AUTHORIZATION, - params: {}, -}) - -export const platformMustBeOwnedByCurrentUser: onRequestAsyncHookHandler = async (request, _res) => { - const platformId = request.principal.platform?.id - - if (isNil(platformId)) { - throw USER_NOT_ALLOWED_TO_PERFORM_OPERATION_ERROR - } - - const canEditPlatform = request.principal.platform?.role === PlatformRole.OWNER - if (!canEditPlatform) { - throw USER_NOT_ALLOWED_TO_PERFORM_OPERATION_ERROR - } -} diff --git a/packages/backend/src/app/ee/database/migrations/postgres/1685053959806-MakeStripeSubscriptionNullable.ts b/packages/backend/src/app/ee/database/migrations/postgres/1685053959806-MakeStripeSubscriptionNullable.ts deleted file mode 100644 index 655e71a6b4..0000000000 --- a/packages/backend/src/app/ee/database/migrations/postgres/1685053959806-MakeStripeSubscriptionNullable.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm' - -export class MakeStripeSubscriptionNullable1685053959806 implements MigrationInterface { - name = 'MakeStripeSubscriptionNullable1685053959806' - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query('ALTER TABLE "project_plan" ALTER COLUMN "stripeSubscriptionId" DROP NOT NULL') - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query('ALTER TABLE "project_plan" ADD "name" character varying NOT NULL') - } - -} diff --git a/packages/backend/src/app/ee/database/migrations/postgres/1685538145476-addTemplates.ts b/packages/backend/src/app/ee/database/migrations/postgres/1685538145476-addTemplates.ts deleted file mode 100644 index 51eaa5935f..0000000000 --- a/packages/backend/src/app/ee/database/migrations/postgres/1685538145476-addTemplates.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm' - -export class AddTemplates1685538145476 implements MigrationInterface { - name = 'AddTemplates1685538145476' - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query('CREATE TABLE "flow_template" ("id" character varying(21) NOT NULL, "created" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "updated" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "name" character varying NOT NULL, "description" character varying NOT NULL, "template" jsonb NOT NULL, "tags" character varying array NOT NULL, "pieces" character varying array NOT NULL, CONSTRAINT "PK_fcacbf8776a0a3337eb8eca7478" PRIMARY KEY ("id"))') - await queryRunner.query('CREATE INDEX "idx_flow_template_tags" ON "flow_template" ("tags") ') - await queryRunner.query('CREATE INDEX "idx_flow_template_pieces" ON "flow_template" ("pieces") ') - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query('DROP INDEX "public"."idx_flow_template_pieces"') - await queryRunner.query('DROP INDEX "public"."idx_flow_template_tags"') - await queryRunner.query('DROP TABLE "flow_template"') - } - -} diff --git a/packages/backend/src/app/ee/database/migrations/postgres/1685991260335-ChangeToJsonToPeserveKeys.ts b/packages/backend/src/app/ee/database/migrations/postgres/1685991260335-ChangeToJsonToPeserveKeys.ts deleted file mode 100644 index 9545ba35bd..0000000000 --- a/packages/backend/src/app/ee/database/migrations/postgres/1685991260335-ChangeToJsonToPeserveKeys.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm' - -export class ChangeToJsonToKeepKeysOrder1685991260335 implements MigrationInterface { - name = 'ChangeToJsonToKeepKeysOrder1685991260335' - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query('ALTER TABLE "piece_metadata" DROP COLUMN "actions"') - await queryRunner.query('ALTER TABLE "piece_metadata" ADD "actions" json NOT NULL') - await queryRunner.query('ALTER TABLE "piece_metadata" DROP COLUMN "triggers"') - await queryRunner.query('ALTER TABLE "piece_metadata" ADD "triggers" json NOT NULL') - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query('ALTER TABLE "piece_metadata" DROP COLUMN "triggers"') - await queryRunner.query('ALTER TABLE "piece_metadata" ADD "triggers" jsonb NOT NULL') - await queryRunner.query('ALTER TABLE "piece_metadata" DROP COLUMN "actions"') - await queryRunner.query('ALTER TABLE "piece_metadata" ADD "actions" jsonb NOT NULL') - } - -} diff --git a/packages/backend/src/app/ee/database/migrations/postgres/1686133672743-AddPinnedAndBlogUrlToTemplates.ts b/packages/backend/src/app/ee/database/migrations/postgres/1686133672743-AddPinnedAndBlogUrlToTemplates.ts deleted file mode 100644 index b649eeb381..0000000000 --- a/packages/backend/src/app/ee/database/migrations/postgres/1686133672743-AddPinnedAndBlogUrlToTemplates.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm' - -export class AddPinnedAndBlogUrlToTemplates1686133672743 implements MigrationInterface { - name = 'AddPinnedAndBlogUrlToTemplates1686133672743' - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query('ALTER TABLE "flow_template" ADD "pinned" boolean NOT NULL') - await queryRunner.query('ALTER TABLE "flow_template" ADD "blogUrl" character varying NOT NULL') - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query('ALTER TABLE "flow_template" DROP COLUMN "blogUrl"') - await queryRunner.query('ALTER TABLE "flow_template" DROP COLUMN "pinned"') - } - -} diff --git a/packages/backend/src/app/ee/database/migrations/postgres/1686154285890-add_pinned_order.ts b/packages/backend/src/app/ee/database/migrations/postgres/1686154285890-add_pinned_order.ts deleted file mode 100644 index bf352b5d2e..0000000000 --- a/packages/backend/src/app/ee/database/migrations/postgres/1686154285890-add_pinned_order.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm' - -export class AddPinnedOrder1686154285890 implements MigrationInterface { - name = 'AddPinnedOrder1686154285890' - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query('ALTER TABLE "flow_template" DROP COLUMN "pinned"') - await queryRunner.query('ALTER TABLE "flow_template" ADD "pinnedOrder" integer') - await queryRunner.query('ALTER TABLE "flow_template" ALTER COLUMN "blogUrl" DROP NOT NULL') - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query('ALTER TABLE "flow_template" ALTER COLUMN "blogUrl" SET NOT NULL') - await queryRunner.query('ALTER TABLE "flow_template" DROP COLUMN "pinnedOrder"') - await queryRunner.query('ALTER TABLE "flow_template" ADD "pinned" boolean NOT NULL') - } - -} diff --git a/packages/backend/src/app/ee/database/migrations/postgres/1688083336934-AddProjectIdToTemplate.ts b/packages/backend/src/app/ee/database/migrations/postgres/1688083336934-AddProjectIdToTemplate.ts deleted file mode 100644 index fecac01ce1..0000000000 --- a/packages/backend/src/app/ee/database/migrations/postgres/1688083336934-AddProjectIdToTemplate.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm' -import { logger } from '../../../../helper/logger' - -export class AddProjectIdToTemplate1688083336934 implements MigrationInterface { - name = 'AddProjectIdToTemplate1688083336934' - - public async up(queryRunner: QueryRunner): Promise { - logger.info('Running migration AddProjectIdToTemplate1688083336934') - await queryRunner.query('ALTER TABLE "flow_template" ADD "projectId" character varying') - await queryRunner.query('ALTER TABLE "flow_template" ADD CONSTRAINT "fk_flow_template_project_id" FOREIGN KEY ("projectId") REFERENCES "project"("id") ON DELETE CASCADE ON UPDATE NO ACTION') - logger.info('Finished migration AddProjectIdToTemplate1688083336934') - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query('ALTER TABLE "flow_template" DROP CONSTRAINT "fk_flow_template_project_id"') - await queryRunner.query('ALTER TABLE "flow_template" DROP COLUMN "projectId"') - } - -} diff --git a/packages/backend/src/app/ee/database/migrations/postgres/1688739844617-AddBillingParameters.ts b/packages/backend/src/app/ee/database/migrations/postgres/1688739844617-AddBillingParameters.ts deleted file mode 100644 index 25e1b60b90..0000000000 --- a/packages/backend/src/app/ee/database/migrations/postgres/1688739844617-AddBillingParameters.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm' - -export class AddBillingParameters1688739844617 implements MigrationInterface { - name = 'AddBillingParameters1688739844617' - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query('ALTER TABLE "project_plan" ADD "minimumPollingInterval" integer NOT NULL DEFAULT 5') - await queryRunner.query('ALTER TABLE "project_plan" ADD "activeFlows" integer NOT NULL DEFAULT 100') - await queryRunner.query('ALTER TABLE "project_plan" ADD "connections" integer NOT NULL DEFAULT 100') - await queryRunner.query('ALTER TABLE "project_plan" ADD "teamMembers" integer NOT NULL DEFAULT 1') - await queryRunner.query('ALTER TABLE "project_usage" ADD "activeFlows" integer NOT NULL DEFAULT 0') - await queryRunner.query('ALTER TABLE "project_usage" ADD "connections" integer NOT NULL DEFAULT 0') - await queryRunner.query('ALTER TABLE "project_usage" ADD "teamMembers" integer NOT NULL DEFAULT 0') - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query('ALTER TABLE "project_usage" DROP COLUMN "teamMembers"') - await queryRunner.query('ALTER TABLE "project_usage" DROP COLUMN "connections"') - await queryRunner.query('ALTER TABLE "project_usage" DROP COLUMN "activeFlows"') - await queryRunner.query('ALTER TABLE "project_plan" DROP COLUMN "teamMembers"') - await queryRunner.query('ALTER TABLE "project_plan" DROP COLUMN "connections"') - await queryRunner.query('ALTER TABLE "project_plan" DROP COLUMN "activeFlows"') - await queryRunner.query('ALTER TABLE "project_plan" DROP COLUMN "minimumPollingInterval"') - } - -} diff --git a/packages/backend/src/app/ee/database/migrations/postgres/1689177797092-AddProjectMembers.ts b/packages/backend/src/app/ee/database/migrations/postgres/1689177797092-AddProjectMembers.ts deleted file mode 100644 index 893ade954a..0000000000 --- a/packages/backend/src/app/ee/database/migrations/postgres/1689177797092-AddProjectMembers.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm' - -export class AddProjectMembers1689177797092 implements MigrationInterface { - name = 'AddProjectMembers1689177797092' - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query('CREATE TABLE "project_member" ("id" character varying(21) NOT NULL, "created" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "updated" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "userId" character varying(21) NOT NULL, "projectId" character varying(21) NOT NULL, "role" character varying NOT NULL, "status" character varying NOT NULL, CONSTRAINT "PK_64dba8e9dcf96ce383cfd19d6fb" PRIMARY KEY ("id"))') - await queryRunner.query('CREATE UNIQUE INDEX "idx_project_member_project_id_user_id" ON "project_member" ("projectId", "userId") ') - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query('DROP INDEX "public"."idx_project_member_project_id_user_id"') - await queryRunner.query('DROP TABLE "project_member"') - } - -} diff --git a/packages/backend/src/app/ee/database/migrations/postgres/1689336533370-AddTasksPerDays.ts b/packages/backend/src/app/ee/database/migrations/postgres/1689336533370-AddTasksPerDays.ts deleted file mode 100644 index f295a175c8..0000000000 --- a/packages/backend/src/app/ee/database/migrations/postgres/1689336533370-AddTasksPerDays.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm' - -export class AddTasksPerDays1689336533370 implements MigrationInterface { - name = 'AddTasksPerDays1689336533370' - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query('ALTER TABLE "project_plan" ADD "tasksPerDay" integer') - await queryRunner.query('ALTER TABLE "project_plan" ALTER COLUMN "minimumPollingInterval" DROP DEFAULT') - await queryRunner.query('ALTER TABLE "project_plan" ALTER COLUMN "activeFlows" DROP DEFAULT') - await queryRunner.query('ALTER TABLE "project_plan" ALTER COLUMN "connections" DROP DEFAULT') - await queryRunner.query('ALTER TABLE "project_plan" ALTER COLUMN "teamMembers" DROP DEFAULT') - await queryRunner.query('ALTER TABLE "project_usage" ALTER COLUMN "activeFlows" DROP DEFAULT') - await queryRunner.query('ALTER TABLE "project_usage" ALTER COLUMN "connections" DROP DEFAULT') - await queryRunner.query('ALTER TABLE "project_usage" ALTER COLUMN "teamMembers" DROP DEFAULT') - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query('ALTER TABLE "project_usage" ALTER COLUMN "teamMembers" SET DEFAULT \'0\'') - await queryRunner.query('ALTER TABLE "project_usage" ALTER COLUMN "connections" SET DEFAULT \'0\'') - await queryRunner.query('ALTER TABLE "project_usage" ALTER COLUMN "activeFlows" SET DEFAULT \'0\'') - await queryRunner.query('ALTER TABLE "project_plan" ALTER COLUMN "teamMembers" SET DEFAULT \'1\'') - await queryRunner.query('ALTER TABLE "project_plan" ALTER COLUMN "connections" SET DEFAULT \'100\'') - await queryRunner.query('ALTER TABLE "project_plan" ALTER COLUMN "activeFlows" SET DEFAULT \'100\'') - await queryRunner.query('ALTER TABLE "project_plan" ALTER COLUMN "minimumPollingInterval" SET DEFAULT \'5\'') - await queryRunner.query('ALTER TABLE "project_plan" DROP COLUMN "tasksPerDay"') - } - -} diff --git a/packages/backend/src/app/ee/database/migrations/postgres/1689806173642-RemoveCalculatedMetrics.ts b/packages/backend/src/app/ee/database/migrations/postgres/1689806173642-RemoveCalculatedMetrics.ts deleted file mode 100644 index 2391f88356..0000000000 --- a/packages/backend/src/app/ee/database/migrations/postgres/1689806173642-RemoveCalculatedMetrics.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm' - -export class RemoveCalculatedMetrics1689806173642 implements MigrationInterface { - name = 'RemoveCalculatedMetrics1689806173642' - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query('ALTER TABLE "project_usage" DROP COLUMN "activeFlows"') - await queryRunner.query('ALTER TABLE "project_usage" DROP COLUMN "connections"') - await queryRunner.query('ALTER TABLE "project_usage" DROP COLUMN "teamMembers"') - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query('ALTER TABLE "project_usage" ADD "teamMembers" integer NOT NULL') - await queryRunner.query('ALTER TABLE "project_usage" ADD "connections" integer NOT NULL') - await queryRunner.query('ALTER TABLE "project_usage" ADD "activeFlows" integer NOT NULL') - } - -} diff --git a/packages/backend/src/app/ee/database/migrations/postgres/1690459469381-AddReferral.ts b/packages/backend/src/app/ee/database/migrations/postgres/1690459469381-AddReferral.ts deleted file mode 100644 index 2e30f45a4c..0000000000 --- a/packages/backend/src/app/ee/database/migrations/postgres/1690459469381-AddReferral.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm' - -export class AddReferral1690459469381 implements MigrationInterface { - name = 'AddReferral1690459469381' - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query('CREATE TABLE "referal" ("id" character varying(21) NOT NULL, "created" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "updated" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "referredUserId" character varying(21) NOT NULL, "referringUserId" character varying(21) NOT NULL, CONSTRAINT "PK_567787298ed6c13527df7887096" PRIMARY KEY ("id"))') - await queryRunner.query('CREATE UNIQUE INDEX "idx_referral_referring_user_id" ON "referal" ("referredUserId", "referringUserId") ') - await queryRunner.query('ALTER TABLE "referal" ADD CONSTRAINT "fk_referral_referred_user_id" FOREIGN KEY ("referredUserId") REFERENCES "user"("id") ON DELETE CASCADE ON UPDATE NO ACTION') - await queryRunner.query('ALTER TABLE "referal" ADD CONSTRAINT "fk_referral_referring_user_id" FOREIGN KEY ("referringUserId") REFERENCES "user"("id") ON DELETE CASCADE ON UPDATE NO ACTION') - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query('ALTER TABLE "referal" DROP CONSTRAINT "fk_referral_referring_user_id"') - await queryRunner.query('ALTER TABLE "referal" DROP CONSTRAINT "fk_referral_referred_user_id"') - await queryRunner.query('DROP INDEX "public"."idx_referral_referring_user_id"') - await queryRunner.query('DROP TABLE "referal"') - } - -} diff --git a/packages/backend/src/app/ee/database/migrations/postgres/1694379223109-flow-template-add-user-id-and-image-url.ts b/packages/backend/src/app/ee/database/migrations/postgres/1694379223109-flow-template-add-user-id-and-image-url.ts deleted file mode 100644 index 9623c80d28..0000000000 --- a/packages/backend/src/app/ee/database/migrations/postgres/1694379223109-flow-template-add-user-id-and-image-url.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm' -import { logger } from '../../../../helper/logger' - -export class FlowTemplateAddUserIdAndImageUrl1694379223109 implements MigrationInterface { - name = 'FlowTemplateAddUserIdAndImageUrl1694379223109' - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query('ALTER TABLE "flow_template" DROP COLUMN "pinnedOrder"') - await queryRunner.query('ALTER TABLE "flow_template" ADD "userId" character varying') - await queryRunner.query('ALTER TABLE "flow_template" ADD "imageUrl" character varying') - await queryRunner.query('ALTER TABLE "flow_template" DROP CONSTRAINT "fk_flow_template_project_id"') - await queryRunner.query('ALTER TABLE "flow_template" ALTER COLUMN "projectId" SET NOT NULL') - await queryRunner.query('ALTER TABLE "flow_template" ADD CONSTRAINT "fk_flow_template_project_id" FOREIGN KEY ("projectId") REFERENCES "project"("id") ON DELETE CASCADE ON UPDATE NO ACTION') - await queryRunner.query('ALTER TABLE "flow_template" ADD CONSTRAINT "fk_flow_template_user_id" FOREIGN KEY ("userId") REFERENCES "user"("id") ON DELETE CASCADE ON UPDATE NO ACTION') - - logger.info('FlowTemplateAddUserIdAndImageUrl1694379223109 up') - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query('ALTER TABLE "flow_template" DROP CONSTRAINT "fk_flow_template_user_id"') - await queryRunner.query('ALTER TABLE "flow_template" DROP CONSTRAINT "fk_flow_template_project_id"') - await queryRunner.query('ALTER TABLE "flow_template" ALTER COLUMN "projectId" DROP NOT NULL') - await queryRunner.query('ALTER TABLE "flow_template" ADD CONSTRAINT "fk_flow_template_project_id" FOREIGN KEY ("projectId") REFERENCES "project"("id") ON DELETE CASCADE ON UPDATE NO ACTION') - await queryRunner.query('ALTER TABLE "flow_template" DROP COLUMN "imageUrl"') - await queryRunner.query('ALTER TABLE "flow_template" DROP COLUMN "userId"') - await queryRunner.query('ALTER TABLE "flow_template" ADD "pinnedOrder" integer') - - logger.info('FlowTemplateAddUserIdAndImageUrl1694379223109 down') - } - -} diff --git a/packages/backend/src/app/ee/database/migrations/postgres/1694381968985-project-member-relations.ts b/packages/backend/src/app/ee/database/migrations/postgres/1694381968985-project-member-relations.ts deleted file mode 100644 index 71e45f2793..0000000000 --- a/packages/backend/src/app/ee/database/migrations/postgres/1694381968985-project-member-relations.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm' -import { logger } from '../../../../helper/logger' - -export class ProjectMemberRelations1694381968985 implements MigrationInterface { - name = 'ProjectMemberRelations1694381968985' - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query('ALTER TABLE "project_member" ADD CONSTRAINT "fk_project_member_user_id" FOREIGN KEY ("userId") REFERENCES "user"("id") ON DELETE CASCADE ON UPDATE NO ACTION') - await queryRunner.query('ALTER TABLE "project_member" ADD CONSTRAINT "fk_project_member_project_id" FOREIGN KEY ("projectId") REFERENCES "project"("id") ON DELETE CASCADE ON UPDATE NO ACTION') - - logger.info('ProjectMemberRelations1694381968985 up') - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query('ALTER TABLE "project_member" DROP CONSTRAINT "fk_project_member_project_id"') - await queryRunner.query('ALTER TABLE "project_member" DROP CONSTRAINT "fk_project_member_user_id"') - - logger.info('ProjectMemberRelations1694381968985 down') - } - -} diff --git a/packages/backend/src/app/ee/database/migrations/postgres/1694604120205-AddFeaturedDescriptionAndFlagToTemplates.ts b/packages/backend/src/app/ee/database/migrations/postgres/1694604120205-AddFeaturedDescriptionAndFlagToTemplates.ts deleted file mode 100644 index 727109f0d4..0000000000 --- a/packages/backend/src/app/ee/database/migrations/postgres/1694604120205-AddFeaturedDescriptionAndFlagToTemplates.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm' - -export class AddFeaturedDescriptionAndFlagToTemplates1694604120205 implements MigrationInterface { - name = 'AddFeaturedDescriptionAndFlagToTemplates1694604120205' - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query('ALTER TABLE "flow_template" ADD "isFeatured" boolean') - await queryRunner.query('ALTER TABLE "flow_template" ADD "featuredDescription" character varying') - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query('ALTER TABLE "flow_template" DROP COLUMN "featuredDescription"') - await queryRunner.query('ALTER TABLE "flow_template" DROP COLUMN "isFeatured"') - } - -} diff --git a/packages/backend/src/app/ee/database/migrations/postgres/1694902537045-ModifyBilling.ts b/packages/backend/src/app/ee/database/migrations/postgres/1694902537045-ModifyBilling.ts deleted file mode 100644 index ae8f49e2a9..0000000000 --- a/packages/backend/src/app/ee/database/migrations/postgres/1694902537045-ModifyBilling.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm' - -export class ModifyBilling1694902537045 implements MigrationInterface { - name = 'ModifyBilling1694902537045' - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query('ALTER TABLE "project_plan" RENAME COLUMN "name" TO "flowPlanName"') - await queryRunner.query('ALTER TABLE "project_plan" ADD "botPlanName" character varying NOT NULL DEFAULT \'free\'') - await queryRunner.query('ALTER TABLE "project_plan" ADD "bots" integer NOT NULL DEFAULT 1') - await queryRunner.query('ALTER TABLE "project_plan" ADD "datasourcesSize" integer NOT NULL DEFAULT 10485760') - await queryRunner.query('ALTER TABLE "project_usage" ADD "datasourcesSize" integer NOT NULL DEFAULT \'0\'') - await queryRunner.query('ALTER TABLE "project_usage" ADD "bots" integer NOT NULL DEFAULT \'0\'') - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query('ALTER TABLE "project_usage" DROP COLUMN "bots"') - await queryRunner.query('ALTER TABLE "project_usage" DROP COLUMN "datasourcesSize"') - await queryRunner.query('ALTER TABLE "project_plan" DROP COLUMN "datasourcesSize"') - await queryRunner.query('ALTER TABLE "project_plan" DROP COLUMN "bots"') - await queryRunner.query('ALTER TABLE "project_plan" DROP COLUMN "botPlanName"') - await queryRunner.query('ALTER TABLE "project_plan" DROP COLUMN "flowPlanName"') - await queryRunner.query('ALTER TABLE "project_plan" ADD "name" character varying NOT NULL') - } -} diff --git a/packages/backend/src/app/ee/database/migrations/postgres/1695916063833-AddDatasourcesLimit.ts b/packages/backend/src/app/ee/database/migrations/postgres/1695916063833-AddDatasourcesLimit.ts deleted file mode 100644 index 25eb537288..0000000000 --- a/packages/backend/src/app/ee/database/migrations/postgres/1695916063833-AddDatasourcesLimit.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm' - -export class AddDatasourcesLimit1695916063833 implements MigrationInterface { - name = 'AddDatasourcesLimit1695916063833' - - public async up(queryRunner: QueryRunner): Promise { - // Add the "datasources" column with a default value of 1 - await queryRunner.query('ALTER TABLE "project_plan" ADD "datasources" integer NOT NULL DEFAULT 1') - } - - public async down(queryRunner: QueryRunner): Promise { - // Remove the "datasources" column - await queryRunner.query('ALTER TABLE "project_plan" DROP COLUMN "datasources"') - } - -} diff --git a/packages/backend/src/app/ee/flow-template/platform-flow-template.module.ts b/packages/backend/src/app/ee/flow-template/platform-flow-template.module.ts deleted file mode 100644 index a0b6a50994..0000000000 --- a/packages/backend/src/app/ee/flow-template/platform-flow-template.module.ts +++ /dev/null @@ -1,123 +0,0 @@ -import { flowTemplateService } from './flow-template.service' -import { ListFlowTemplatesRequest, ALL_PRINICPAL_TYPES, PrincipalType, TemplateType, ActivepiecesError, ErrorCode, assertNotNullOrUndefined, Principal } from '@activepieces/shared' -import { Static, Type } from '@sinclair/typebox' -import { FastifyPluginAsyncTypebox } from '@fastify/type-provider-typebox' -import { CreateFlowTemplateRequest } from '@activepieces/ee-shared' -import { platformService } from '../platform/platform.service' -import { StatusCodes } from 'http-status-codes' -import { system } from '../../helper/system/system' -import { SystemProp } from '../../helper/system/system-prop' - -export const platformFlowTemplateModule: FastifyPluginAsyncTypebox = async (app) => { - await app.register(flowTemplateController, { prefix: '/v1/flow-templates' }) -} - -const GetIdParams = Type.Object({ - id: Type.String(), -}) -type GetIdParams = Static - - -const flowTemplateController: FastifyPluginAsyncTypebox = async (fastify) => { - - fastify.get('/:id', { - config: { - allowedPrincipals: ALL_PRINICPAL_TYPES, - }, - schema: { - params: GetIdParams, - }, - }, async (request) => { - return flowTemplateService.getOrThrow(request.params.id) - }) - - fastify.get('/', { - config: { - allowedPrincipals: ALL_PRINICPAL_TYPES, - }, - schema: { - querystring: ListFlowTemplatesRequest, - }, - }, async (request) => { - const platformId = request.principal.platform?.id ?? system.getOrThrow(SystemProp.CLOUD_PLATFORM_ID) - return flowTemplateService.list(platformId, request.query) - }) - - fastify.post('/', { - config: { - allowedPrincipals: [PrincipalType.USER], - }, - schema: { - body: CreateFlowTemplateRequest, - }, - }, async (request) => { - const { type } = request.body - if (type === TemplateType.PLATFORM) { - await assertUserIsPlatformOwner({ - platformId: request.principal.platform?.id, - userId: request.principal.id, - }) - } - return flowTemplateService.upsert(request.principal.platform?.id, request.principal.projectId, request.body) - }) - fastify.delete('/:id', { - config: { - allowedPrincipals: [PrincipalType.USER], - }, - schema: { - params: GetIdParams, - }, - }, async (request, reply) => { - await assertUserCanDeleteTemplate({ - templateId: request.params.id, - userId: request.principal.id, - principal: request.principal, - }) - await flowTemplateService.delete({ - id: request.params.id, - }) - return reply.status(StatusCodes.NO_CONTENT).send() - - }) -} - -async function assertUserCanDeleteTemplate({ - templateId, - userId, - principal, -}: { templateId: string, userId: string, principal: Principal }): Promise { - const template = await flowTemplateService.getOrThrow(templateId) - switch (template.type) { - case TemplateType.PLATFORM: - await assertUserIsPlatformOwner({ - platformId: template.platformId, - userId, - }) - break - case TemplateType.PROJECT: - if (template.projectId !== principal.projectId) { - throw new ActivepiecesError({ - code: ErrorCode.AUTHORIZATION, - params: {}, - }) - } - break - } -} - -async function assertUserIsPlatformOwner({ - platformId, - userId, -}: { platformId?: string, userId: string }): Promise { - assertNotNullOrUndefined(platformId, 'platformId') - const userOwner = await platformService.checkUserIsOwner({ - platformId, - userId, - }) - if (!userOwner) { - throw new ActivepiecesError({ - code: ErrorCode.AUTHORIZATION, - params: {}, - }) - } -} \ No newline at end of file diff --git a/packages/backend/src/app/ee/flow-worker/cloud-flow-worker-hooks.ts b/packages/backend/src/app/ee/flow-worker/cloud-flow-worker-hooks.ts deleted file mode 100644 index 01ede85c47..0000000000 --- a/packages/backend/src/app/ee/flow-worker/cloud-flow-worker-hooks.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { ActivepiecesError, ApEdition, ErrorCode, ExecutionOutputStatus } from '@activepieces/shared' -import { getEdition } from '../../helper/secret-helper' -import { flowRunService } from '../../flows/flow-run/flow-run-service' -import { captureException } from '@sentry/node' -import { FlowWorkerHooks } from '../../workers/flow-worker/flow-worker-hooks' -import { tasksLimit } from '../billing/limits/tasks-limit' - -export const platformWorkerHooks: FlowWorkerHooks = { - async preExecute({ projectId, runId }: { projectId: string, runId: string }): Promise { - const edition = getEdition() - if ([ApEdition.CLOUD, ApEdition.ENTERPRISE].includes(edition)) { - try { - await tasksLimit.limit({ - projectId, - }) - } - catch (e: unknown) { - if (e instanceof ActivepiecesError && (e as ActivepiecesError).error.code === ErrorCode.QUOTA_EXCEEDED) { - await flowRunService.finish({ flowRunId: runId, status: ExecutionOutputStatus.QUOTA_EXCEEDED, tasks: 0, logsFileId: null, tags: [] }) - return - } - else { - captureException(e) - } - } - } - }, -} \ No newline at end of file diff --git a/packages/backend/src/app/ee/oauth-apps/oauth-app.module.ts b/packages/backend/src/app/ee/oauth-apps/oauth-app.module.ts deleted file mode 100644 index 5d4dda54e1..0000000000 --- a/packages/backend/src/app/ee/oauth-apps/oauth-app.module.ts +++ /dev/null @@ -1,81 +0,0 @@ -import { FastifyPluginAsyncTypebox, Static, Type } from '@fastify/type-provider-typebox' -import { oauthAppService } from './oauth-app.service' -import { ListOAuth2AppRequest, OAuthApp, UpsertOAuth2AppRequest } from '@activepieces/ee-shared' -import { SeekPage, assertNotNullOrUndefined } from '@activepieces/shared' -import { platformMustBeOwnedByCurrentUser } from '../authentication/ee-authorization' -import { StatusCodes } from 'http-status-codes' - -export const oauthAppModule: FastifyPluginAsyncTypebox = async (app) => { - await app.register(readOauthAppModule) - await app.register(writeOauthAppModule) -} - -const readOauthAppModule: FastifyPluginAsyncTypebox = async (app) => { - await app.register(readOauthAppController, { prefix: '/v1/oauth-apps' }) -} - -const readOauthAppController: FastifyPluginAsyncTypebox = async (app) => { - - app.get('/', { - schema: { - querystring: ListOAuth2AppRequest, - response: { - [StatusCodes.OK]: SeekPage(OAuthApp), - }, - }, - }, - async (request) => { - const platformId = request.principal.platform?.id - assertNotNullOrUndefined(platformId, 'platformId') - return oauthAppService.list({ - platformId, - request: request.query, - }) - }, - ) -} - -const writeOauthAppModule: FastifyPluginAsyncTypebox = async (app) => { - app.addHook('preHandler', platformMustBeOwnedByCurrentUser) - await app.register(oauthAppController, { prefix: '/v1/oauth-apps' }) -} - -const oauthAppController: FastifyPluginAsyncTypebox = async (app) => { - - app.post('/', { - schema: { - body: UpsertOAuth2AppRequest, - }, - }, - async (request) => { - const platformId = request.principal.platform?.id - assertNotNullOrUndefined(platformId, 'platformId') - return oauthAppService.upsert({ - platformId, - request: request.body, - }) - }, - ) - - - app.delete('/:id', { - schema: { - params: GetIdParams, - }, - }, - async (request) => { - const platformId = request.principal.platform?.id - assertNotNullOrUndefined(platformId, 'platformId') - return oauthAppService.delete({ - platformId, - id: request.params.id, - }) - }, - ) -} - -const GetIdParams = Type.Object({ - id: Type.String(), -}) - -type GetIdParams = Static diff --git a/packages/backend/src/app/ee/oauth-apps/oauth-app.service.ts b/packages/backend/src/app/ee/oauth-apps/oauth-app.service.ts deleted file mode 100644 index 77cca58d43..0000000000 --- a/packages/backend/src/app/ee/oauth-apps/oauth-app.service.ts +++ /dev/null @@ -1,53 +0,0 @@ -import { ListOAuth2AppRequest, OAuthApp, UpsertOAuth2AppRequest } from '@activepieces/ee-shared' -import { OAuthAppEntity, OAuthAppWithSecret } from './oauth-app.entity' -import { databaseConnection } from '../../database/database-connection' -import { paginationHelper } from '../../helper/pagination/pagination-utils' -import { buildPaginator } from '../../helper/pagination/build-paginator' -import { ActivepiecesError, ErrorCode, SeekPage, apId, deleteProps, isNil } from '@activepieces/shared' -import { decryptString, encryptString } from '../../helper/encryption' - -const oauthRepo = databaseConnection.getRepository(OAuthAppEntity) - -export const oauthAppService = { - async upsert({ platformId, request }: { platformId: string, request: UpsertOAuth2AppRequest }): Promise { - await oauthRepo.upsert({ platformId, ...request, clientSecret: encryptString(request.clientSecret), id: apId() }, ['platformId', 'pieceName']) - const connection = await oauthRepo.findOneByOrFail({ platformId, pieceName: request.pieceName }) - return deleteProps(connection, ['clientSecret']) - }, - async getWithSecret({ platformId, pieceName, clientId }: { platformId: string, pieceName: string, clientId?: string }): Promise { - const oauthApp = await oauthRepo.findOneByOrFail({ platformId, pieceName, clientId }) - return { - ...oauthApp, - clientSecret: decryptString(oauthApp.clientSecret), - } - }, - async list({ request, platformId }: { platformId: string, request: ListOAuth2AppRequest }): Promise> { - const decodedCursor = paginationHelper.decodeCursor(request.cursor ?? null) - const paginator = buildPaginator({ - entity: OAuthAppEntity, - query: { - limit: request.limit ?? 10, - order: 'ASC', - afterCursor: decodedCursor.nextCursor, - beforeCursor: decodedCursor.previousCursor, - }, - }) - const { data, cursor } = await paginator.paginate(oauthRepo.createQueryBuilder('oauth_app').where({ platformId })) - return paginationHelper.createPage( - data, - cursor, - ) - }, - async delete({ platformId, id }: { platformId: string, id: string }): Promise { - const oauthApp = await oauthRepo.findOneBy({ platformId, id }) - if (isNil(oauthApp)) { - throw new ActivepiecesError({ - code: ErrorCode.ENTITY_NOT_FOUND, - params: { - message: `OAuth with id ${id} not found`, - }, - }) - } - await oauthRepo.delete({ platformId, id }) - }, -} \ No newline at end of file diff --git a/packages/backend/src/app/ee/pieces/platform-piece-module.ts b/packages/backend/src/app/ee/pieces/platform-piece-module.ts deleted file mode 100644 index c0236469d6..0000000000 --- a/packages/backend/src/app/ee/pieces/platform-piece-module.ts +++ /dev/null @@ -1,59 +0,0 @@ -import { FastifyPluginAsyncTypebox, Type } from '@fastify/type-provider-typebox' -import { FastifyPluginCallbackTypebox } from '@fastify/type-provider-typebox' -import { ActivepiecesError, AddPieceRequestBody, EndpointScope, ErrorCode, PieceScope, PlatformRole, Principal, PrincipalType } from '@activepieces/shared' -import { pieceService } from '../../pieces/piece-service' -import { StatusCodes } from 'http-status-codes' - -export const platformPieceModule: FastifyPluginAsyncTypebox = async (app) => { - await app.register(platformPieceController, { prefix: '/v1/pieces' }) -} - -const platformPieceController: FastifyPluginCallbackTypebox = (app, _opts, done) => { - app.post('/', { - config: { - allowedPrincipals: [PrincipalType.USER, PrincipalType.SERVICE], - scope: EndpointScope.PLATFORM, - }, - schema: { - tags: ['pieces'], - summary: 'Add a piece to a platform', - description: 'Add a piece to a platform', - body: AddPieceRequestBody, - response: { - [StatusCodes.CREATED]: Type.Object({}), - }, - }, - }, async (req, reply) => { - const platformId = req.principal.platform?.id - assertPrincipalIsPlatformOwner(req.body.scope, req.principal) - assertProjectScopeOnlyAllowedForUser(req.body.scope, req.principal) - await pieceService.installPiece(platformId, req.principal.projectId, req.body) - await reply.status(StatusCodes.CREATED).send({}) - }) - - done() -} - -function assertPrincipalIsPlatformOwner(scope: PieceScope, principal: Principal): void { - if (scope == PieceScope.PLATFORM) { - if (principal.platform?.role !== PlatformRole.OWNER) { - throw new ActivepiecesError({ - code: ErrorCode.ENGINE_OPERATION_FAILURE, - params: { - message: 'Principal is not platform owner', - }, - }) - } - } -} - -function assertProjectScopeOnlyAllowedForUser(scope: PieceScope, principal: Principal): void { - if (scope === PieceScope.PROJECT && principal.type !== PrincipalType.USER) { - throw new ActivepiecesError({ - code: ErrorCode.ENGINE_OPERATION_FAILURE, - params: { - message: 'Project scope is only allowed for user token', - }, - }) - } -} \ No newline at end of file diff --git a/packages/backend/src/app/ee/projects/platform-user-project-controller.ts b/packages/backend/src/app/ee/projects/platform-user-project-controller.ts deleted file mode 100644 index c84182bcf7..0000000000 --- a/packages/backend/src/app/ee/projects/platform-user-project-controller.ts +++ /dev/null @@ -1,73 +0,0 @@ -import { ActivepiecesError, ErrorCode, PlatformRole, PrincipalType, SeekPage, isNil } from '@activepieces/shared' -import { FastifyPluginCallbackTypebox, Type } from '@fastify/type-provider-typebox' -import { platformProjectService } from './platform-project-service' -import { accessTokenManager } from '../../authentication/lib/access-token-manager' -import { platformService } from '../platform/platform.service' -import { StatusCodes } from 'http-status-codes' -import { ProjectWithUsageAndPlanResponse } from '@activepieces/ee-shared' - -export const usersProjectController: FastifyPluginCallbackTypebox = (fastify, _opts, done) => { - - fastify.get('/', ListProjectRequestForUser, async (request) => { - return platformProjectService.getAll({ - ownerId: request.principal.id, - platformId: request.query.platformId, - }) - }) - - fastify.post('/:projectId/token', SwitchTokenRequestForUser, async (request) => { - const allProjects = await platformProjectService.getAll({ - ownerId: request.principal.id, - }) - const project = allProjects.data.find((project) => project.id === request.params.projectId) - if (!project) { - throw new ActivepiecesError({ - code: ErrorCode.ENTITY_NOT_FOUND, - params: { - entityId: request.params.projectId, - entityType: 'project', - }, - }) - } - const platform = isNil(project.platformId) ? null : await platformService.getOne(project.platformId) - return { - token: await accessTokenManager.generateToken({ - id: request.principal.id, - type: request.principal.type, - projectId: request.params.projectId, - projectType: project.type, - platform: isNil(platform) ? undefined : { - id: platform.id, - role: platform.ownerId === request.principal.id ? PlatformRole.OWNER : PlatformRole.MEMBER, - }, - }), - } - }) - - done() -} - -const SwitchTokenRequestForUser = { - config: { - allowedPrincipals: [PrincipalType.USER], - }, - schema: { - params: Type.Object({ - projectId: Type.String(), - }), - }, -} - -const ListProjectRequestForUser = { - config: { - allowedPrincipals: [PrincipalType.USER], - }, - schema: { - response: { - [StatusCodes.OK]: SeekPage(ProjectWithUsageAndPlanResponse), - }, - querystring: Type.Object({ - platformId: Type.Optional(Type.String()), - }), - }, -} diff --git a/packages/backend/src/app/flow-templates/community-flow-template.module.ts b/packages/backend/src/app/flow-templates/community-flow-template.module.ts deleted file mode 100644 index 24dc6ebd71..0000000000 --- a/packages/backend/src/app/flow-templates/community-flow-template.module.ts +++ /dev/null @@ -1,58 +0,0 @@ -import { ListFlowTemplatesRequest, ALL_PRINICPAL_TYPES, isNil } from '@activepieces/shared' -import { FastifyPluginAsyncTypebox } from '@fastify/type-provider-typebox' -import { system } from '../helper/system/system' -import { SystemProp } from '../helper/system/system-prop' -import { paginationHelper } from '../helper/pagination/pagination-utils' - -export const communityFlowTemplateModule: FastifyPluginAsyncTypebox = async (app) => { - await app.register(flowTemplateController, { prefix: '/v1/flow-templates' }) -} - -const flowTemplateController: FastifyPluginAsyncTypebox = async (fastify) => { - - fastify.get('/', { - config: { - allowedPrincipals: ALL_PRINICPAL_TYPES, - }, - schema: { - querystring: ListFlowTemplatesRequest, - }, - }, async (request) => { - const templateSource = system.get(SystemProp.TEMPLATES_SOURCE_URL) - if (isNil(templateSource)) { - return paginationHelper.createPage([], null) - } - const queryString = convertToQueryString(request.query) - const url = `${templateSource}?${queryString}` - const response = await fetch(url, { - method: 'GET', - headers: { - 'Content-Type': 'application/json', - }, - }) - const templates = await response.json() - return templates - }) - - -} - - -function convertToQueryString(params: ListFlowTemplatesRequest): string { - const searchParams = new URLSearchParams() - - Object.entries(params).forEach(([key, value]) => { - if (Array.isArray(value)) { - value.forEach(val => { - if (!isNil(val)) { - searchParams.append(key, val) - } - }) - } - else if (!isNil(value)) { - searchParams.set(key, value.toString()) - } - }) - - return searchParams.toString() -} \ No newline at end of file diff --git a/packages/backend/src/app/flows/flow/flow-version.controller.ts b/packages/backend/src/app/flows/flow/flow-version.controller.ts deleted file mode 100755 index 0f6917567a..0000000000 --- a/packages/backend/src/app/flows/flow/flow-version.controller.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { - ListFlowVersionRequest, - SeekPage, -} from '@activepieces/shared' -import { StatusCodes } from 'http-status-codes' -import { flowService } from './flow.service' -import { FastifyPluginAsyncTypebox, Type } from '@fastify/type-provider-typebox' -import { flowVersionService } from '../flow-version/flow-version.service' -import { FlowVersionMetadata } from '@activepieces/shared' - -const DEFUALT_PAGE_SIZE = 10 - -export const flowVersionController: FastifyPluginAsyncTypebox = async (fastify) => { - - fastify.get('/:flowId/versions', { - schema: { - params: Type.Object({ - flowId: Type.String(), - }), - querystring: ListFlowVersionRequest, - response: { - [StatusCodes.OK]: SeekPage(FlowVersionMetadata), - }, - }, - - }, async (request) => { - const flow = await flowService.getOneOrThrow({ id: request.params.flowId, projectId: request.principal.projectId }) - return flowVersionService.list({ - flowId: flow.id, - limit: request.query.limit ?? DEFUALT_PAGE_SIZE, - cursorRequest: request.query.cursor ?? null, - }) - }) - - -} diff --git a/packages/backend/src/app/flows/step-file/step-file.module.ts b/packages/backend/src/app/flows/step-file/step-file.module.ts deleted file mode 100644 index cb9d5d8f0c..0000000000 --- a/packages/backend/src/app/flows/step-file/step-file.module.ts +++ /dev/null @@ -1,83 +0,0 @@ -import { FastifyPluginAsyncTypebox } from '@fastify/type-provider-typebox' -import { entitiesMustBeOwnedByCurrentProject } from '../../authentication/authorization' -import { Type } from '@sinclair/typebox' -import { stepFileService } from './step-file.service' -import { ALL_PRINICPAL_TYPES, PrincipalType, StepFileUpsert } from '@activepieces/shared' -import { StatusCodes } from 'http-status-codes' - -export const stepFileModule: FastifyPluginAsyncTypebox = async (app) => { - app.addHook('preSerialization', entitiesMustBeOwnedByCurrentProject) - await app.register(stepFileController, { prefix: '/v1/step-files' }) -} - -export const stepFileController: FastifyPluginAsyncTypebox = async (app) => { - - app.get('/signed', { - config: { - allowedPrincipals: ALL_PRINICPAL_TYPES, - }, - schema: { - querystring: Type.Object({ - token: Type.String(), - }), - }, - }, async (request, reply) => { - const stepFile = await stepFileService.getByToken(request.query.token) - await reply.header('Content-Disposition', `attachment; filename="${stepFile?.name}"`) - .type('application/octet-stream') - .status(StatusCodes.OK) - .send(stepFile?.data) - }) - - app.get('/:id', { - config: { - allowedPrincipals: [PrincipalType.WORKER], - }, - schema: { - params: Type.Object({ - id: Type.String(), - }), - }, - }, async (request, reply) => { - const stepFile = await stepFileService.get({ - projectId: request.principal.projectId, - id: request.params.id, - }) - return reply.header('Content-Disposition', `attachment; filename="${stepFile?.name}"`) - .type('application/octet-stream') - .status(StatusCodes.OK) - .send(stepFile?.data) - }) - - app.post('/', { - config: { - allowedPrincipals: [PrincipalType.WORKER], - }, - schema: { - body: StepFileUpsert, - }, - }, async (request) => { - return stepFileService.upsert({ - hostname: request.hostname, - projectId: request.principal.projectId, - request: request.body, - }) - }) - - app.delete('/:id', { - config: { - allowedPrincipals: [PrincipalType.WORKER], - }, - schema: { - params: Type.Object({ - id: Type.String(), - }), - }, - }, async (request) => { - return stepFileService.delete({ - projectId: request.principal.projectId, - id: request.params.id, - }) - }) - -} diff --git a/packages/backend/src/app/helper/audit-events/index.ts b/packages/backend/src/app/helper/audit-events/index.ts deleted file mode 100644 index a48b4e7415..0000000000 --- a/packages/backend/src/app/helper/audit-events/index.ts +++ /dev/null @@ -1,45 +0,0 @@ - -import { ApplicationEventName } from '@activepieces/ee-shared' -import { AppConnection, Folder, PopulatedFlow } from '@activepieces/shared' -import { FastifyRequest } from 'fastify' - - -export type CreateAuditEventParam = { - action: ApplicationEventName.UPDATED_FOLDER | ApplicationEventName.DELETED_FOLDER | ApplicationEventName.CREATED_FOLDER - folder: Folder - userId: string -} | { - action: ApplicationEventName.UPSERTED_CONNECTION | ApplicationEventName.DELETED_CONNECTION - connection: AppConnection - userId: string -} | { - action: ApplicationEventName.CREATED_FLOW | ApplicationEventName.DELETED_FLOW - flow: PopulatedFlow - userId: string -} | { - action: ApplicationEventName.SIGNED_IN | ApplicationEventName.SIGNED_UP | ApplicationEventName.RESET_PASSWORD | ApplicationEventName.VERIFIED_EMAIL - userId: string - projectId: string -} - - -let hooks: ApplicationEventHooks = { - async send(_request, _params) { - return - }, -} - -export const eventsHooks = { - set(newHooks: ApplicationEventHooks): void { - hooks = newHooks - }, - - get(): ApplicationEventHooks { - return hooks - }, -} - - -export type ApplicationEventHooks = { - send(request: FastifyRequest, params: CreateAuditEventParam): void -} \ No newline at end of file diff --git a/packages/backend/src/app/helper/domain-helper.ts b/packages/backend/src/app/helper/domain-helper.ts deleted file mode 100644 index 2bc8f59580..0000000000 --- a/packages/backend/src/app/helper/domain-helper.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { getServerUrl } from './network-utils' -import { system } from './system/system' -import { SystemProp } from './system/system-prop' - -type DomainHelper = { - constructFrontendUrlFromRequest({ domain, path }: { domain: string, path: string }): Promise - constructApiUrlFromRequest({ domain, path }: { domain: string, path: string }): Promise -} - -let _domainHelper: DomainHelper = { - async constructApiUrlFromRequest({ path }: { domain: string, path: string }): Promise { - return `${await getServerUrl()}${path}` - }, - async constructFrontendUrlFromRequest({ path }: { domain: string, path: string }): Promise { - const frontendUrl = system.getOrThrow(SystemProp.FRONTEND_URL) - return `${frontendUrl}${frontendUrl.endsWith('/') ? '' : '/'}${path}` - }, -} -export const domainHelper = { - set(newHelper: DomainHelper): void { - _domainHelper = newHelper - }, - get(): DomainHelper { - return _domainHelper - }, - -} - diff --git a/packages/backend/src/app/helper/exception-handler.ts b/packages/backend/src/app/helper/exception-handler.ts deleted file mode 100644 index 3e6697013b..0000000000 --- a/packages/backend/src/app/helper/exception-handler.ts +++ /dev/null @@ -1,24 +0,0 @@ -import * as Sentry from '@sentry/node' -import { system } from './system/system' -import { logger } from './logger' -import { SystemProp } from './system/system-prop' - -const sentryDsn = system.get(SystemProp.SENTRY_DSN) - -export const initilizeSentry = () => { - if (sentryDsn) { - logger.info('Initializing Sentry') - Sentry.init({ - dsn: sentryDsn, - tracesSampleRate: 0.2, - }) - } -} - -export const exceptionHandler = { - handle: async (e: unknown) => { - if (sentryDsn) { - Sentry.captureException(e) - } - }, -} \ No newline at end of file diff --git a/packages/backend/src/app/helper/openapi/openapi.controller.ts b/packages/backend/src/app/helper/openapi/openapi.controller.ts deleted file mode 100644 index 860ad9d036..0000000000 --- a/packages/backend/src/app/helper/openapi/openapi.controller.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { FastifyInstance } from 'fastify' - -export const openapiController = async (fastify: FastifyInstance) => { - fastify.get( - '/', - async () => { - return JSON.stringify(fastify.swagger(), null, 2) - }, - ) -} \ No newline at end of file diff --git a/packages/backend/src/app/helper/system/system-prop.ts b/packages/backend/src/app/helper/system/system-prop.ts deleted file mode 100644 index 1dd25f1b79..0000000000 --- a/packages/backend/src/app/helper/system/system-prop.ts +++ /dev/null @@ -1,80 +0,0 @@ -export enum SystemProp { - API_KEY = 'API_KEY', - APP_WEBHOOK_SECRETS = 'APP_WEBHOOK_SECRETS', - API_RATE_LIMIT_AUTHN_ENABLED = 'API_RATE_LIMIT_AUTHN_ENABLED', - API_RATE_LIMIT_AUTHN_MAX = 'API_RATE_LIMIT_AUTHN_MAX', - API_RATE_LIMIT_AUTHN_WINDOW = 'API_RATE_LIMIT_AUTHN_WINDOW', - CACHE_PATH = 'CACHE_PATH', - CLIENT_REAL_IP_HEADER = 'CLIENT_REAL_IP_HEADER', - CLOUD_AUTH_ENABLED = 'CLOUD_AUTH_ENABLED', - CODE_SANDBOX_TYPE = 'CODE_SANDBOX_TYPE', - CONFIG_PATH = 'CONFIG_PATH', - DB_TYPE = 'DB_TYPE', - EDITION = 'EDITION', - ENCRYPTION_KEY = 'ENCRYPTION_KEY', - ENGINE_EXECUTABLE_PATH = 'ENGINE_EXECUTABLE_PATH', - ENRICH_ERROR_CONTEXT = 'ENRICH_ERROR_CONTEXT', - ENVIRONMENT = 'ENVIRONMENT', - EXECUTION_MODE = 'EXECUTION_MODE', - FLOW_WORKER_CONCURRENCY = 'FLOW_WORKER_CONCURRENCY', - FRONTEND_URL = 'FRONTEND_URL', - JWT_SECRET = 'JWT_SECRET', - LICENSE_KEY = 'LICENSE_KEY', - LOG_LEVEL = 'LOG_LEVEL', - LOG_PRETTY = 'LOG_PRETTY', - LOKI_PASSWORD = 'LOKI_PASSWORD', - LOKI_URL = 'LOKI_URL', - LOKI_USERNAME = 'LOKI_USERNAME', - NOTIFICATION_URL = 'NOTIFICATION_URL', - OPENAI_API_KEY = 'OPENAI_API_KEY', - OPENAI_API_BASE_URL = 'OPENAI_API_BASE_URL', - PIECES_SOURCE = 'PIECES_SOURCE', - POSTGRES_URL = 'POSTGRES_URL', - POSTGRES_DATABASE = 'POSTGRES_DATABASE', - POSTGRES_HOST = 'POSTGRES_HOST', - POSTGRES_PASSWORD = 'POSTGRES_PASSWORD', - POSTGRES_PORT = 'POSTGRES_PORT', - POSTGRES_SSL_CA = 'POSTGRES_SSL_CA', - POSTGRES_USERNAME = 'POSTGRES_USERNAME', - POSTGRES_USE_SSL = 'POSTGRES_USE_SSL', - QUEUE_MODE = 'QUEUE_MODE', - QUEUE_UI_ENABLED = 'QUEUE_UI_ENABLED', - QUEUE_UI_PASSWORD = 'QUEUE_UI_PASSWORD', - QUEUE_UI_USERNAME = 'QUEUE_UI_USERNAME', - REDIS_DB = 'REDIS_DB', - REDIS_HOST = 'REDIS_HOST', - REDIS_PASSWORD = 'REDIS_PASSWORD', - REDIS_PORT = 'REDIS_PORT', - REDIS_URL = 'REDIS_URL', - REDIS_USER = 'REDIS_USER', - REDIS_USE_SSL = 'REDIS_USE_SSL', - SANDBOX_MEMORY_LIMIT = 'SANDBOX_MEMORY_LIMIT', - SANDBOX_RUN_TIME_SECONDS = 'SANDBOX_RUN_TIME_SECONDS', - SIGN_UP_ENABLED = 'SIGN_UP_ENABLED', - SMTP_HOST = 'SMTP_HOST', - SMTP_PASSWORD = 'SMTP_PASSWORD', - SMTP_PORT = 'SMTP_PORT', - SMTP_USERNAME = 'SMTP_USERNAME', - SMTP_SENDER_NAME = 'SMTP_SENDER_NAME', - SMTP_SENDER_EMAIL = 'SMTP_SENDER_EMAIL', - SMTP_USE_SSL = 'SMTP_USE_SSL', - STATS_ENABLED = 'STATS_ENABLED', - TELEMETRY_ENABLED = 'TELEMETRY_ENABLED', - TEMPLATES_SOURCE_URL = 'TEMPLATES_SOURCE_URL', - TRIGGER_DEFAULT_POLL_INTERVAL = 'TRIGGER_DEFAULT_POLL_INTERVAL', - WEBHOOK_TIMEOUT_SECONDS = 'WEBHOOK_TIMEOUT_SECONDS', - WEBHOOK_URL = 'WEBHOOK_URL', - - // ENTERPRISE ONLY - APPSUMO_TOKEN = 'APPSUMO_TOKEN', - BILLING_SETTINGS = 'BILLING_SETTINGS', - FIREBASE_ADMIN_CREDENTIALS = 'FIREBASE_ADMIN_CREDENTIALS', - FIREBASE_HASH_PARAMETERS = 'FIREBASE_HASH_PARAMETERS', - PACKAGE_ARCHIVE_PATH = 'PACKAGE_ARCHIVE_PATH', - SENTRY_DSN = 'SENTRY_DSN', - STRIPE_SECRET_KEY = 'STRIPE_SECRET_KEY', - STRIPE_WEBHOOK_SECRET = 'STRIPE_WEBHOOK_SECRET', - - // CLOUD_ONLY - CLOUD_PLATFORM_ID = 'CLOUD_PLATFORM_ID', -} diff --git a/packages/backend/src/app/helper/system/system.ts b/packages/backend/src/app/helper/system/system.ts deleted file mode 100644 index 2711593114..0000000000 --- a/packages/backend/src/app/helper/system/system.ts +++ /dev/null @@ -1,140 +0,0 @@ -import { - ActivepiecesError, - ApEnvironment, - CodeSandboxType, - ErrorCode, - isNil, -} from '@activepieces/shared' -import { SystemProp } from './system-prop' -import { loadEncryptionKey } from '../encryption' -import path from 'path' -import os from 'os' - -export enum PiecesSource { - CLOUD_AND_DB = 'CLOUD_AND_DB', - DB = 'DB', - FILE = 'FILE', -} - -export enum QueueMode { - REDIS = 'REDIS', - MEMORY = 'MEMORY', -} - -export enum DatabaseType { - POSTGRES = 'POSTGRES', - SQLITE3 = 'SQLITE3', -} - -const systemPropDefaultValues: Partial> = { - [SystemProp.API_RATE_LIMIT_AUTHN_ENABLED]: 'true', - [SystemProp.API_RATE_LIMIT_AUTHN_MAX]: '50', - [SystemProp.API_RATE_LIMIT_AUTHN_WINDOW]: '1 minute', - [SystemProp.CLIENT_REAL_IP_HEADER]: 'x-real-ip', - [SystemProp.CLOUD_AUTH_ENABLED]: 'true', - [SystemProp.CODE_SANDBOX_TYPE]: CodeSandboxType.NO_OP, - [SystemProp.CONFIG_PATH]: path.join(os.homedir(), '.activepieces'), - [SystemProp.DB_TYPE]: DatabaseType.POSTGRES, - [SystemProp.EDITION]: 'ce', - [SystemProp.ENGINE_EXECUTABLE_PATH]: 'dist/packages/engine/main.js', - [SystemProp.ENVIRONMENT]: 'prod', - [SystemProp.EXECUTION_MODE]: 'UNSANDBOXED', - [SystemProp.FLOW_WORKER_CONCURRENCY]: '10', - [SystemProp.LOG_LEVEL]: 'info', - [SystemProp.LOG_PRETTY]: 'false', - [SystemProp.PACKAGE_ARCHIVE_PATH]: 'dist/archives', - [SystemProp.PIECES_SOURCE]: PiecesSource.CLOUD_AND_DB, - [SystemProp.QUEUE_MODE]: QueueMode.REDIS, - [SystemProp.SANDBOX_MEMORY_LIMIT]: '131072', - [SystemProp.SANDBOX_RUN_TIME_SECONDS]: '600', - [SystemProp.SIGN_UP_ENABLED]: 'false', - [SystemProp.STATS_ENABLED]: 'false', - [SystemProp.TELEMETRY_ENABLED]: 'true', - [SystemProp.TEMPLATES_SOURCE_URL]: 'https://cloud.activepieces.com/api/v1/flow-templates', - [SystemProp.TRIGGER_DEFAULT_POLL_INTERVAL]: '5', -} - -export const system = { - get(prop: SystemProp): T | undefined { - return getEnvVar(prop) as T | undefined - }, - - getNumber(prop: SystemProp): number | null { - const stringNumber = getEnvVar(prop) - - if (!stringNumber) { - return null - } - - const parsedNumber = Number.parseInt(stringNumber, 10) - - if (Number.isNaN(parsedNumber)) { - return null - } - - return parsedNumber - }, - - getBoolean(prop: SystemProp): boolean | undefined { - const value = getEnvVar(prop) - - if (isNil(value)) { - return undefined - } - return value === 'true' - }, - - getOrThrow(prop: SystemProp): T { - const value = getEnvVar(prop) as T | undefined - - if (value === undefined) { - throw new ActivepiecesError( - { - code: ErrorCode.SYSTEM_PROP_NOT_DEFINED, - params: { - prop, - }, - }, - `System property AP_${prop} is not defined, please check the documentation`, - ) - } - - return value - }, -} - -const getEnvVar = (prop: SystemProp): string | undefined => { - return process.env[`AP_${prop}`] ?? systemPropDefaultValues[prop] -} - -export const validateEnvPropsOnStartup = async (): Promise => { - const codeSandboxType = system.get(SystemProp.CODE_SANDBOX_TYPE) - const executionMode = system.get(SystemProp.EXECUTION_MODE) - const signedUpEnabled = - system.getBoolean(SystemProp.SIGN_UP_ENABLED) ?? false - const queueMode = system.getOrThrow(SystemProp.QUEUE_MODE) - const environment = system.get(SystemProp.ENVIRONMENT) - await loadEncryptionKey(queueMode) - - if ( - executionMode === ExecutionMode.UNSANDBOXED && - codeSandboxType !== CodeSandboxType.V8_ISOLATE && - signedUpEnabled && - environment === ApEnvironment.PRODUCTION - ) { - throw new ActivepiecesError( - { - code: ErrorCode.SYSTEM_PROP_INVALID, - params: { - prop: SystemProp.EXECUTION_MODE, - }, - }, - 'Allowing users to sign up is not allowed in unsandboxed mode, please check the configuration section in the documentation', - ) - } -} - -export enum ExecutionMode { - SANDBOXED = 'SANDBOXED', - UNSANDBOXED = 'UNSANDBOXED', -} diff --git a/packages/backend/src/app/pieces/base-piece-module.ts b/packages/backend/src/app/pieces/base-piece-module.ts deleted file mode 100644 index c48ff82036..0000000000 --- a/packages/backend/src/app/pieces/base-piece-module.ts +++ /dev/null @@ -1,155 +0,0 @@ -import { FastifyPluginAsyncTypebox, Type } from '@fastify/type-provider-typebox' -import { ALL_PRINICPAL_TYPES, ActivepiecesError, ApEdition, ErrorCode, GetPieceRequestParams, GetPieceRequestQuery, GetPieceRequestWithScopeParams, ListPiecesRequestQuery, PieceCategory, PieceOptionRequest, PrincipalType } from '@activepieces/shared' -import { engineHelper } from '../helper/engine-helper' -import { system } from '../helper/system/system' -import { SystemProp } from '../helper/system/system-prop' -import { getPiecePackage, pieceMetadataService } from './piece-metadata-service' -import { PieceMetadata } from '@activepieces/pieces-framework' -import { flagService } from '../flags/flag.service' -import { PieceMetadataModel, PieceMetadataModelSummary } from './piece-metadata-entity' -import { flowService } from '../flows/flow/flow.service' - -export const pieceModule: FastifyPluginAsyncTypebox = async (app) => { - await app.register(basePiecesController, { prefix: '/v1/pieces' }) -} - -const statsEnabled = system.getBoolean(SystemProp.STATS_ENABLED) - -const basePiecesController: FastifyPluginAsyncTypebox = async (app) => { - - app.get('/categories', { - config: { - allowedPrincipals: ALL_PRINICPAL_TYPES, - }, - schema: { - querystring: ListPiecesRequestQuery, - }, - }, async (): Promise => { - return Object.values(PieceCategory) - }) - - app.get('/', { - config: { - allowedPrincipals: ALL_PRINICPAL_TYPES, - }, - schema: { - querystring: ListPiecesRequestQuery, - }, - }, async (req): Promise => { - const latestRelease = await flagService.getCurrentRelease() - const release = req.query.release ?? latestRelease - const edition = req.query.edition ?? ApEdition.COMMUNITY - const pieceMetadataSummary = await pieceMetadataService.list({ - release, - includeHidden: req.query.includeHidden ?? false, - projectId: req.principal.projectId, - platformId: req.principal.platform?.id, - edition, - categories: req.query.categories, - searchQuery: req.query.searchQuery, - sortBy: req.query.sortBy, - orderBy: req.query.orderBy, - }) - return pieceMetadataSummary - }) - - app.get('/:scope/:name', { - config: { - allowedPrincipals: ALL_PRINICPAL_TYPES, - }, - schema: { - params: GetPieceRequestWithScopeParams, - querystring: GetPieceRequestQuery, - }, - }, async (req): Promise => { - const { name, scope } = req.params - const { version } = req.query - - const decodeScope = decodeURIComponent(scope) - const decodedName = decodeURIComponent(name) - return pieceMetadataService.getOrThrow({ - projectId: req.principal.type === PrincipalType.UNKNOWN ? undefined : req.principal.projectId, - name: `${decodeScope}/${decodedName}`, - version, - }) - }) - - app.get('/:name', { - config: { - allowedPrincipals: ALL_PRINICPAL_TYPES, - }, - schema: { - params: GetPieceRequestParams, - querystring: GetPieceRequestQuery, - }, - }, async (req): Promise => { - const { name } = req.params - const { version } = req.query - - const decodedName = decodeURIComponent(name) - return pieceMetadataService.getOrThrow({ - projectId: req.principal.type === PrincipalType.UNKNOWN ? undefined : req.principal.projectId, - name: decodedName, - version, - }) - }) - - app.post('/options', { - schema: { - body: PieceOptionRequest, - }, - }, async (req) => { - const { packageType, pieceType, pieceName, pieceVersion, propertyName, stepName, input, flowVersionId, flowId } = req.body - const { projectId } = req.principal - const flow = await flowService.getOnePopulatedOrThrow({ - projectId, - id: flowId, - versionId: flowVersionId, - }) - const { result } = await engineHelper.executeProp({ - piece: await getPiecePackage(projectId, { - packageType, - pieceType, - pieceName, - pieceVersion, - }), - flowVersion: flow.version, - propertyName, - stepName, - input, - projectId, - }) - - return result - }) - - app.get('/stats', { - config: { - allowedPrincipals: ALL_PRINICPAL_TYPES, - }, - }, async () => { - if (!statsEnabled) { - throw new ActivepiecesError({ - code: ErrorCode.ENTITY_NOT_FOUND, - params: { - message: 'not found', - }, - }) - } - - return pieceMetadataService.stats() - }) - - app.delete('/:id', { - schema: { - params: Type.Object({ - id: Type.String(), - }), - }, - }, async (req): Promise => { - return pieceMetadataService.delete({ - projectId: req.principal.projectId, - id: req.params.id, - }) - }) -} diff --git a/packages/backend/src/app/pieces/community-piece-module.ts b/packages/backend/src/app/pieces/community-piece-module.ts deleted file mode 100644 index cecd73e04e..0000000000 --- a/packages/backend/src/app/pieces/community-piece-module.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { FastifyPluginAsyncTypebox } from '@fastify/type-provider-typebox' -import { AddPieceRequestBody, PrincipalType } from '@activepieces/shared' -import { pieceService } from './piece-service' -import { PieceMetadataModel } from './piece-metadata-entity' -import { StatusCodes } from 'http-status-codes' - -export const communityPiecesModule: FastifyPluginAsyncTypebox = async (app) => { - await app.register(communityPiecesController, { prefix: '/v1/pieces' }) -} - -const communityPiecesController: FastifyPluginAsyncTypebox = async (app) => { - app.post('/', { - config: { - allowedPrincipals: [PrincipalType.USER], - }, - schema: { - body: AddPieceRequestBody, - }, - }, async (req, res): Promise => { - const platformId = req.principal.platform?.id - const projectId = req.principal.projectId - const pieceMetadata = await pieceService.installPiece(platformId, projectId, req.body) - return res.code(StatusCodes.CREATED).send(pieceMetadata) - }) - -} diff --git a/packages/backend/src/app/pieces/piece-metadata-entity.ts b/packages/backend/src/app/pieces/piece-metadata-entity.ts deleted file mode 100644 index 72c6af76de..0000000000 --- a/packages/backend/src/app/pieces/piece-metadata-entity.ts +++ /dev/null @@ -1,127 +0,0 @@ -import { EntitySchema } from 'typeorm' -import { PieceMetadata, PieceMetadataSummary } from '@activepieces/pieces-framework' -import { ApId, BaseModel, FileId, PackageType, PieceType, Project, ProjectId } from '@activepieces/shared' -import { ARRAY_COLUMN_TYPE, ApIdSchema, BaseColumnSchemaPart, COLLATION, JSON_COLUMN_TYPE, isPostgres } from '../database/database-common' - -type PiecePackageMetadata = { - projectId?: ProjectId - pieceType: PieceType - packageType: PackageType - archiveId?: FileId -} - -export type PieceMetadataModel = PieceMetadata & PiecePackageMetadata - -export type PieceMetadataModelSummary = PieceMetadataSummary & PiecePackageMetadata - -export type PieceMetadataSchema = BaseModel & PieceMetadataModel - -type PieceMetadataSchemaWithRelations = PieceMetadataSchema & { - project: Project -} - -export const PieceMetadataEntity = new EntitySchema({ - name: 'piece_metadata', - columns: { - ...BaseColumnSchemaPart, - name: { - type: String, - nullable: false, - }, - displayName: { - type: String, - nullable: false, - }, - logoUrl: { - type: String, - nullable: false, - }, - description: { - type: String, - nullable: true, - }, - projectId: { - type: String, - nullable: true, - }, - platformId: { - type: String, - nullable: true, - }, - version: { - type: String, - nullable: false, - collation: COLLATION, - }, - minimumSupportedRelease: { - type: String, - nullable: false, - collation: COLLATION, - }, - maximumSupportedRelease: { - type: String, - nullable: false, - collation: COLLATION, - }, - auth: { - type: JSON_COLUMN_TYPE, - nullable: true, - }, - actions: { - type: JSON_COLUMN_TYPE, - nullable: false, - }, - triggers: { - type: JSON_COLUMN_TYPE, - nullable: false, - }, - pieceType: { - type: String, - nullable: false, - }, - categories: { - type: ARRAY_COLUMN_TYPE, - nullable: true, - array: isPostgres(), - }, - packageType: { - type: String, - nullable: false, - }, - archiveId: { - ...ApIdSchema, - nullable: true, - }, - }, - indices: [ - { - name: 'idx_piece_metadata_name_project_id_version', - columns: ['name', 'version', 'projectId'], - unique: true, - }, - ], - relations: { - project: { - type: 'many-to-one', - target: 'project', - cascade: true, - onDelete: 'CASCADE', - joinColumn: { - name: 'projectId', - foreignKeyConstraintName: 'fk_piece_metadata_project_id', - }, - nullable: true, - }, - archiveId: { - type: 'one-to-one', - target: 'file', - onDelete: 'NO ACTION', - onUpdate: 'NO ACTION', - joinColumn: { - name: 'archiveId', - referencedColumnName: 'id', - foreignKeyConstraintName: 'fk_piece_metadata_file', - }, - }, - }, -}) diff --git a/packages/backend/src/app/pieces/piece-metadata-service/hooks/piece-filtering.ts b/packages/backend/src/app/pieces/piece-metadata-service/hooks/piece-filtering.ts deleted file mode 100644 index 7d314efe9c..0000000000 --- a/packages/backend/src/app/pieces/piece-metadata-service/hooks/piece-filtering.ts +++ /dev/null @@ -1,41 +0,0 @@ -import { PieceCategory } from '@activepieces/shared' -import { PieceMetadataSchema } from '../../piece-metadata-entity' -import Fuse from 'fuse.js' - -export const filterPiecesBasedUser = ({ searchQuery, pieces, categories }: { categories: PieceCategory[] | undefined, searchQuery: string | undefined, pieces: PieceMetadataSchema[] }): PieceMetadataSchema[] => { - return filterBasedOnCategories({ - categories, - pieces: filterBasedOnSearchQuery({ searchQuery, pieces }), - }) -} - -const filterBasedOnSearchQuery = ({ searchQuery, pieces }: { searchQuery: string | undefined, pieces: PieceMetadataSchema[] }): PieceMetadataSchema[] => { - if (!searchQuery) { - return pieces - } - const fuse = new Fuse(pieces, { - isCaseSensitive: false, - shouldSort: true, - keys: [{ - name: 'name', - weight: 5, - }, { - name: 'description', - weight: 5, - }], - threshold: 0.3, - }) - - return fuse.search(searchQuery).map(({ item }) => pieces.find(p => p.name === item.name)!) -} - -const filterBasedOnCategories = ({ categories, pieces }: { categories: PieceCategory[] | undefined, pieces: PieceMetadataSchema[] }): PieceMetadataSchema[] => { - if (!categories) { - return pieces - } - - return pieces.filter(p => { - return categories.some(item => (p.categories ?? []).includes(item)) - }) -} - diff --git a/packages/backend/src/app/webhooks/webhook-simulation/webhook-simulation-entity.ts b/packages/backend/src/app/webhooks/webhook-simulation/webhook-simulation-entity.ts deleted file mode 100644 index 732d43bf47..0000000000 --- a/packages/backend/src/app/webhooks/webhook-simulation/webhook-simulation-entity.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { EntitySchema } from 'typeorm' -import { WebhookSimulation } from '@activepieces/shared' -import { ApIdSchema, BaseColumnSchemaPart } from '../../database/database-common' - -export type WebhookSimulationSchema = WebhookSimulation - -export const WebhookSimulationEntity = new EntitySchema({ - name: 'webhook_simulation', - columns: { - ...BaseColumnSchemaPart, - flowId: ApIdSchema, - projectId: ApIdSchema, - }, - indices: [ - { - name: 'idx_webhook_simulation_flow_id', - columns: ['flowId'], - unique: true, - }, - ], -}) diff --git a/packages/backend/src/app/workers/flow-worker/flow-queue.ts b/packages/backend/src/app/workers/flow-worker/flow-queue.ts deleted file mode 100755 index f263a747a0..0000000000 --- a/packages/backend/src/app/workers/flow-worker/flow-queue.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { QueueMode, system } from '../../helper/system/system' -import { SystemProp } from '../../helper/system/system-prop' -import { inMemoryQueueManager } from './queues/memory/memory-queue' -import { redisQueueManager } from './queues/redis/redis-queue' - -const queueMode = system.get(SystemProp.QUEUE_MODE) -export const flowQueue = queueMode === QueueMode.MEMORY ? inMemoryQueueManager : redisQueueManager - diff --git a/packages/backend/src/assets/emails/invitation-email.html b/packages/backend/src/assets/emails/invitation-email.html deleted file mode 100644 index 30fd3463c5..0000000000 --- a/packages/backend/src/assets/emails/invitation-email.html +++ /dev/null @@ -1,157 +0,0 @@ - - - - - - - - - - - - - - - Finish creating your account - - - - - -
- -
 ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ 
- - - - - - - - - diff --git a/packages/backend/src/assets/emails/quota-100.html b/packages/backend/src/assets/emails/quota-100.html deleted file mode 100644 index f6e2b2d8c7..0000000000 --- a/packages/backend/src/assets/emails/quota-100.html +++ /dev/null @@ -1,161 +0,0 @@ - - - - - - - - - - - - - - - - - - - -
- -
 ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ 
- - - - - - - - - \ No newline at end of file diff --git a/packages/backend/src/assets/emails/quota-50.html b/packages/backend/src/assets/emails/quota-50.html deleted file mode 100644 index ed405e7228..0000000000 --- a/packages/backend/src/assets/emails/quota-50.html +++ /dev/null @@ -1,161 +0,0 @@ - - - - - - - - - - - - - - - - - - - -
- -
 ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ 
- - - - - - - - - \ No newline at end of file diff --git a/packages/backend/src/assets/emails/quota-90.html b/packages/backend/src/assets/emails/quota-90.html deleted file mode 100644 index b12889edf9..0000000000 --- a/packages/backend/src/assets/emails/quota-90.html +++ /dev/null @@ -1,161 +0,0 @@ - - - - - - - - - - - - - - - - - - - -
- -
 ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ 
- - - - - - - - - \ No newline at end of file diff --git a/packages/backend/src/assets/emails/reset-password.html b/packages/backend/src/assets/emails/reset-password.html deleted file mode 100644 index fedc1154cd..0000000000 --- a/packages/backend/src/assets/emails/reset-password.html +++ /dev/null @@ -1,347 +0,0 @@ - - - - - - - - - - - - - - - - Reset your {{platformName}} password - - - - - - -
- -
- -
-  ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌  -
- - - - - - - - - - diff --git a/packages/backend/src/assets/emails/verify-email.html b/packages/backend/src/assets/emails/verify-email.html deleted file mode 100644 index 969634db14..0000000000 --- a/packages/backend/src/assets/emails/verify-email.html +++ /dev/null @@ -1,340 +0,0 @@ - - - - - - - - - - - - - - - - Set up your {{platformName}} account - - - - - - -
-
- -
-  ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌  -
- - - - - - - - - - diff --git a/packages/backend/src/assets/invalid-code.js b/packages/backend/src/assets/invalid-code.js deleted file mode 100755 index 3a2cbacc85..0000000000 --- a/packages/backend/src/assets/invalid-code.js +++ /dev/null @@ -1,3 +0,0 @@ -exports.code = async (params) => { - throw new Error("${ERROR_MESSAGE}"); -}; diff --git a/packages/backend/types/redis-lock.d.ts b/packages/backend/types/redis-lock.d.ts deleted file mode 100644 index 7f651b982e..0000000000 --- a/packages/backend/types/redis-lock.d.ts +++ /dev/null @@ -1,4 +0,0 @@ -declare module 'redis-lock' { - function redisLock(client: unknown, retryDelay: number): (lockId: string) => Promise<() => Promise> - export default redisLock -} diff --git a/packages/engine/.eslintrc.json b/packages/engine/.eslintrc.json index ea84d181ad..56155b0231 100644 --- a/packages/engine/.eslintrc.json +++ b/packages/engine/.eslintrc.json @@ -1,6 +1,6 @@ { "extends": [ - "../backend/.eslintrc.json" + "../server/api/.eslintrc.json" ], "overrides": [ { diff --git a/packages/backend/.env b/packages/server/api/.env similarity index 100% rename from packages/backend/.env rename to packages/server/api/.env diff --git a/packages/backend/.env.tests b/packages/server/api/.env.tests similarity index 100% rename from packages/backend/.env.tests rename to packages/server/api/.env.tests diff --git a/packages/server/api/.eslintrc.json b/packages/server/api/.eslintrc.json new file mode 100644 index 0000000000..8ad5b758c9 --- /dev/null +++ b/packages/server/api/.eslintrc.json @@ -0,0 +1,74 @@ +{ + "extends": [ + "../../../.eslintrc.json", + "plugin:@typescript-eslint/eslint-recommended", + "plugin:@typescript-eslint/recommended", + "plugin:@typescript-eslint/strict" + ], + "ignorePatterns": ["!**/*"], + "overrides": [ + { + "files": ["*.ts", "*.js"], + "parserOptions": { + "project": ["packages/server/api/tsconfig.*?.json"] + }, + "rules": { + "no-console": "error", + "object-shorthand": "error", + "@typescript-eslint/switch-exhaustiveness-check": "error", + "@typescript-eslint/brace-style": ["error", "stroustrup"], + "@typescript-eslint/comma-dangle": ["error", "always-multiline"], + "@typescript-eslint/indent": ["error", 4], + "@typescript-eslint/quotes": ["error", "single"], + "@typescript-eslint/semi": ["error", "never"], + "@typescript-eslint/consistent-type-definitions": ["error", "type"], + "@typescript-eslint/no-explicit-any": "error", + "@typescript-eslint/no-redundant-type-constituents": "error", + "@typescript-eslint/await-thenable": "error", + "@typescript-eslint/adjacent-overload-signatures": "error", + "@typescript-eslint/comma-spacing": "error", + "@typescript-eslint/type-annotation-spacing": "error", + "@typescript-eslint/block-spacing": "error", + "@typescript-eslint/func-call-spacing": "error", + "@typescript-eslint/key-spacing": "error", + "@typescript-eslint/object-curly-spacing": ["error", "always"], + "@typescript-eslint/space-before-blocks": "error", + "@typescript-eslint/member-delimiter-style": [ + "error", + { + "multiline": { + "delimiter": "none" + }, + "singleline": { + "delimiter": "comma", + "requireLast": false + } + } + ], + "@typescript-eslint/no-unused-vars": [ + "error", + { + "varsIgnorePattern": "^_", + "argsIgnorePattern": "^_" + } + ], + "@typescript-eslint/space-before-function-paren": [ + "error", + { + "anonymous": "always", + "named": "never", + "asyncArrow": "always" + } + ], + "@typescript-eslint/space-infix-ops": "error", + "@typescript-eslint/keyword-spacing": "error", + "@typescript-eslint/explicit-function-return-type": "warn", + "@typescript-eslint/no-floating-promises": "error", + "@typescript-eslint/no-misused-promises": "warn", + "no-return-await": "off", + "@typescript-eslint/return-await": ["error", "in-try-catch"], + "default-case-last": "error" + } + } + ] +} diff --git a/packages/backend/README.md b/packages/server/api/README.md similarity index 54% rename from packages/backend/README.md rename to packages/server/api/README.md index ccee3f7e83..be5a690539 100644 --- a/packages/backend/README.md +++ b/packages/server/api/README.md @@ -5,5 +5,5 @@ ### Generate database migrations ```sh -npx nx db-migration backend -- --name migration-name +npx nx db-migration server-api -- --name migration-name ``` diff --git a/packages/backend/jest.config.ts b/packages/server/api/jest.config.ts similarity index 67% rename from packages/backend/jest.config.ts rename to packages/server/api/jest.config.ts index 63ea25861b..9bd683dc45 100644 --- a/packages/backend/jest.config.ts +++ b/packages/server/api/jest.config.ts @@ -1,7 +1,7 @@ /* eslint-disable */ export default { - displayName: 'backend', - preset: '../../jest.preset.js', + displayName: 'server-api', + preset: '../../../jest.preset.js', globals: {}, testEnvironment: 'node', transform: { @@ -13,5 +13,5 @@ export default { ], }, moduleFileExtensions: ['ts', 'js', 'html'], - coverageDirectory: '../../coverage/packages/backend', + coverageDirectory: '../../../coverage/packages/server/api', }; diff --git a/packages/backend/project.json b/packages/server/api/project.json similarity index 55% rename from packages/backend/project.json rename to packages/server/api/project.json index c299f9e20b..d742ce9cd2 100644 --- a/packages/backend/project.json +++ b/packages/server/api/project.json @@ -1,7 +1,7 @@ { - "name": "backend", - "$schema": "../../node_modules/nx/schemas/project-schema.json", - "sourceRoot": "packages/backend/src", + "name": "server-api", + "$schema": "../../../node_modules/nx/schemas/project-schema.json", + "sourceRoot": "packages/server/api/src", "projectType": "application", "implicitDependencies": ["engine"], "targets": { @@ -11,11 +11,11 @@ "options": { "target": "node", "compiler": "tsc", - "outputPath": "dist/packages/backend", - "main": "packages/backend/src/main.ts", - "tsConfig": "packages/backend/tsconfig.app.json", - "assets": ["packages/backend/src/assets"], - "webpackConfig": "packages/backend/webpack.config.js", + "outputPath": "dist/packages/server/api", + "main": "packages/server/api/src/main.ts", + "tsConfig": "packages/server/api/tsconfig.app.json", + "assets": ["packages/server/api/src/assets"], + "webpackConfig": "packages/server/api/webpack.config.js", "isolatedConfig": true, "generatePackageJson": true, "babelUpwardRootMode": true @@ -31,12 +31,12 @@ "serve": { "executor": "@nx/js:node", "options": { - "buildTarget": "backend:build", + "buildTarget": "server-api:build", "host": "0.0.0.0" }, "configurations": { "production": { - "buildTarget": "backend:build:production" + "buildTarget": "server-api:build:production" } } }, @@ -44,47 +44,47 @@ "executor": "@nx/eslint:lint", "outputs": ["{options.outputFile}"], "options": { - "lintFilePatterns": ["packages/backend/**/*.ts"] + "lintFilePatterns": ["packages/server/api/**/*.ts"] } }, "test-ce": { "executor": "@nx/jest:jest", "outputs": ["{workspaceRoot}/coverage/{projectRoot}"], "options": { - "jestConfig": "packages/backend/jest.config.ts", + "jestConfig": "packages/server/api/jest.config.ts", "passWithNoTests": false, "bail": true, - "testPathPattern": ["packages/backend/test/integration/ce"] + "testPathPattern": ["packages/server/api/test/integration/ce"] } }, "test-cloud": { "executor": "@nx/jest:jest", "outputs": ["{workspaceRoot}/coverage/{projectRoot}"], "options": { - "jestConfig": "packages/backend/jest.config.ts", + "jestConfig": "packages/server/api/jest.config.ts", "passWithNoTests": false, "bail": true, - "testPathPattern": ["packages/backend/test/integration/cloud"] + "testPathPattern": ["packages/server/api/test/integration/cloud"] } }, "test-ee": { "executor": "@nx/jest:jest", "outputs": ["{workspaceRoot}/coverage/{projectRoot}"], "options": { - "jestConfig": "packages/backend/jest.config.ts", + "jestConfig": "packages/server/api/jest.config.ts", "passWithNoTests": false, "bail": true, - "testPathPattern": ["packages/backend/test/integration/ee"] + "testPathPattern": ["packages/server/api/test/integration/ee"] } }, "test": { "executor": "nx:run-commands", "options": { "commands": [ - "nx build backend", - "export $(cat packages/backend/.env.tests | xargs) && AP_EDITION=cloud nx test-cloud backend --output-style stream-without-prefixes", - "export $(cat packages/backend/.env.tests | xargs) && AP_EDITION=ce nx test-ce backend --output-style stream-without-prefixes", - "export $(cat packages/backend/.env.tests | xargs) && AP_EDITION=ee nx test-ee backend --output-style stream-without-prefixes" + "nx build server-api", + "export $(cat packages/server/api/.env.tests | xargs) && AP_EDITION=cloud nx test-cloud server-api --output-style stream-without-prefixes", + "export $(cat packages/server/api/.env.tests | xargs) && AP_EDITION=ce nx test-ce server-api --output-style stream-without-prefixes", + "export $(cat packages/server/api/.env.tests | xargs) && AP_EDITION=ee nx test-ee server-api --output-style stream-without-prefixes" ], "parallel": false } @@ -95,13 +95,13 @@ "db": { "executor": "nx:run-commands", "options": { - "command": "ts-node -r tsconfig-paths/register -P packages/backend/tsconfig.app.json ./node_modules/typeorm/cli.js" + "command": "ts-node -r tsconfig-paths/register -P packages/server/api/tsconfig.app.json ./node_modules/typeorm/cli.js" } }, "db-migration": { "executor": "nx:run-commands", "options": { - "command": "nx db backend -- migration:generate -p -d packages/backend/src/app/database/database-connection.ts packages/backend/src/app/database/migration/{args.name}" + "command": "nx db server-api -- migration:generate -p -d packages/server/api/src/app/database/database-connection.ts packages/server/api/src/app/database/migration/{args.name}" } } }, diff --git a/packages/backend/src/app/app-connection/app-connection-service/app-connection-hooks.ts b/packages/server/api/src/app/app-connection/app-connection-service/app-connection-hooks.ts similarity index 93% rename from packages/backend/src/app/app-connection/app-connection-service/app-connection-hooks.ts rename to packages/server/api/src/app/app-connection/app-connection-service/app-connection-hooks.ts index 361f6946f0..e3f3bc23d0 100644 --- a/packages/backend/src/app/app-connection/app-connection-service/app-connection-hooks.ts +++ b/packages/server/api/src/app/app-connection/app-connection-service/app-connection-hooks.ts @@ -1,11 +1,10 @@ - export type AppConnectionHooks = { preUpsert({ projectId }: { projectId: string }): Promise } const emptyHooks: AppConnectionHooks = { async preUpsert() { - // DO NOTHING + // DO NOTHING }, } @@ -18,4 +17,4 @@ export const appConnectionsHooks = { getHooks() { return hooks }, -} \ No newline at end of file +} diff --git a/packages/backend/src/app/app-connection/app-connection-service/app-connection-service.ts b/packages/server/api/src/app/app-connection/app-connection-service/app-connection-service.ts similarity index 96% rename from packages/backend/src/app/app-connection/app-connection-service/app-connection-service.ts rename to packages/server/api/src/app/app-connection/app-connection-service/app-connection-service.ts index 0823d3f40d..90e3b4e568 100644 --- a/packages/backend/src/app/app-connection/app-connection-service/app-connection-service.ts +++ b/packages/server/api/src/app/app-connection/app-connection-service/app-connection-service.ts @@ -22,11 +22,14 @@ import { AppConnectionSchema, } from '../app-connection.entity' import { decryptObject, encryptObject } from '../../helper/encryption' -import { captureException, logger } from '../../helper/logger' +import { exceptionHandler, logger } from 'server-shared' import { isNil } from '@activepieces/shared' import { engineHelper } from '../../helper/engine-helper' import { acquireLock } from '../../helper/lock' -import { getPiecePackage, pieceMetadataService } from '../../pieces/piece-metadata-service' +import { + getPiecePackage, + pieceMetadataService, +} from '../../pieces/piece-metadata-service' import { appConnectionsHooks } from './app-connection-hooks' import { oauth2Util } from './oauth2/oauth2-util' import { oauth2Handler } from './oauth2' @@ -35,7 +38,9 @@ const repo = databaseConnection.getRepository(AppConnectionEntity) export const appConnectionService = { async upsert(params: UpsertParams): Promise { - await appConnectionsHooks.getHooks().preUpsert({ projectId: params.projectId }) + await appConnectionsHooks + .getHooks() + .preUpsert({ projectId: params.projectId }) const { projectId, request } = params @@ -148,7 +153,7 @@ export const appConnectionService = { data.forEach((encryptedConnection) => { const apConnection: AppConnection = - decryptConnection(encryptedConnection) + decryptConnection(encryptedConnection) promises.push( new Promise((resolve) => { return resolve(apConnection) @@ -173,9 +178,9 @@ const validateConnectionValue = async ( params: ValidateConnectionValueParams, ): Promise => { const { connection, projectId } = params - + switch (connection.value.type) { - case AppConnectionType.PLATFORM_OAUTH2:{ + case AppConnectionType.PLATFORM_OAUTH2: { const tokenUrl = await oauth2Util.getOAuth2TokenUrl({ projectId, pieceName: connection.pieceName, @@ -196,7 +201,7 @@ const validateConnectionValue = async ( }, }) } - case AppConnectionType.CLOUD_OAUTH2:{ + case AppConnectionType.CLOUD_OAUTH2: { const tokenUrl = await oauth2Util.getOAuth2TokenUrl({ projectId, pieceName: connection.pieceName, @@ -216,7 +221,7 @@ const validateConnectionValue = async ( }, }) } - case AppConnectionType.OAUTH2:{ + case AppConnectionType.OAUTH2: { const tokenUrl = await oauth2Util.getOAuth2TokenUrl({ projectId, pieceName: connection.pieceName, @@ -251,7 +256,6 @@ const validateConnectionValue = async ( return connection.value } - function decryptConnection( encryptedConnection: AppConnectionSchema, ): AppConnection { @@ -274,8 +278,7 @@ const engineValidateAuth = async ( version: undefined, }) - - const engineResponse = await engineHelper.executeValidateAuth( { + const engineResponse = await engineHelper.executeValidateAuth({ piece: await getPiecePackage(projectId, { pieceName, pieceVersion: pieceMetadata.version, @@ -350,7 +353,7 @@ async function lockAndRefreshConnection({ return refreshedAppConnection } catch (e) { - captureException(e) + exceptionHandler.handle(e) if (!isNil(appConnection)) { appConnection.status = AppConnectionStatus.ERROR await repo.update(appConnection.id, { @@ -404,8 +407,6 @@ async function refresh(connection: AppConnection): Promise { return connection } - - type UpsertParams = { projectId: ProjectId request: UpsertAppConnectionRequestBody diff --git a/packages/backend/src/app/app-connection/app-connection-service/oauth2/index.ts b/packages/server/api/src/app/app-connection/app-connection-service/oauth2/index.ts similarity index 52% rename from packages/backend/src/app/app-connection/app-connection-service/oauth2/index.ts rename to packages/server/api/src/app/app-connection/app-connection-service/oauth2/index.ts index 327700be70..b09c7539ca 100644 --- a/packages/backend/src/app/app-connection/app-connection-service/oauth2/index.ts +++ b/packages/server/api/src/app/app-connection/app-connection-service/oauth2/index.ts @@ -1,13 +1,24 @@ -import { AppConnectionType, PlatformOAuth2ConnectionValue } from '@activepieces/shared' +import { + AppConnectionType, + PlatformOAuth2ConnectionValue, +} from '@activepieces/shared' import { cloudOAuth2Service } from './services/cloud-oauth2-service' import { credentialsOauth2Service } from './services/credentials-oauth2-service' -import { ClaimOAuth2Request, OAuth2Service, RefreshOAuth2Request } from './oauth2-service' +import { + ClaimOAuth2Request, + OAuth2Service, + RefreshOAuth2Request, +} from './oauth2-service' const unimplementedService: OAuth2Service = { - claim: async (_req: ClaimOAuth2Request): Promise => { + claim: async ( + _req: ClaimOAuth2Request, + ): Promise => { throw new Error('Unimplemented platform oauth') }, - refresh: async (_req: RefreshOAuth2Request): Promise => { + refresh: async ( + _req: RefreshOAuth2Request, + ): Promise => { throw new Error('Unimplemented platform oauth') }, } @@ -18,7 +29,10 @@ export const oauth2Handler = { [AppConnectionType.PLATFORM_OAUTH2]: unimplementedService, } - -export function setPlatformOAuthService({ service }: { service: OAuth2Service }) { +export function setPlatformOAuthService({ + service, +}: { + service: OAuth2Service +}) { oauth2Handler[AppConnectionType.PLATFORM_OAUTH2] = service -} \ No newline at end of file +} diff --git a/packages/backend/src/app/app-connection/app-connection-service/oauth2/oauth2-service.ts b/packages/server/api/src/app/app-connection/app-connection-service/oauth2/oauth2-service.ts similarity index 70% rename from packages/backend/src/app/app-connection/app-connection-service/oauth2/oauth2-service.ts rename to packages/server/api/src/app/app-connection/app-connection-service/oauth2/oauth2-service.ts index 69223223f1..269d54f237 100644 --- a/packages/backend/src/app/app-connection/app-connection-service/oauth2/oauth2-service.ts +++ b/packages/server/api/src/app/app-connection/app-connection-service/oauth2/oauth2-service.ts @@ -1,10 +1,16 @@ import { OAuth2AuthorizationMethod } from '@activepieces/pieces-framework' -import { BaseOAuth2ConnectionValue, OAuth2GrantType } from '@activepieces/shared' +import { + BaseOAuth2ConnectionValue, + OAuth2GrantType, +} from '@activepieces/shared' -export type OAuth2Service = { - claim(request: ClaimOAuth2Request): Promise - refresh(request: RefreshOAuth2Request): Promise -} +export type OAuth2Service = + { + claim(request: ClaimOAuth2Request): Promise + refresh( + request: RefreshOAuth2Request + ): Promise + } export type RefreshOAuth2Request = { pieceName: string @@ -29,4 +35,3 @@ export type ClaimOAuth2Request = { pieceName: string request: OAuth2RequestBody } - diff --git a/packages/backend/src/app/app-connection/app-connection-service/oauth2/oauth2-util.ts b/packages/server/api/src/app/app-connection/app-connection-service/oauth2/oauth2-util.ts similarity index 74% rename from packages/backend/src/app/app-connection/app-connection-service/oauth2/oauth2-util.ts rename to packages/server/api/src/app/app-connection/app-connection-service/oauth2/oauth2-util.ts index 9fb17a2722..1b5c5c7c1e 100644 --- a/packages/backend/src/app/app-connection/app-connection-service/oauth2/oauth2-util.ts +++ b/packages/server/api/src/app/app-connection/app-connection-service/oauth2/oauth2-util.ts @@ -1,5 +1,12 @@ import { PropertyType } from '@activepieces/pieces-framework' -import { ActivepiecesError, BaseOAuth2ConnectionValue, ErrorCode, OAuth2GrantType, assertNotNullOrUndefined, deleteProps } from '@activepieces/shared' +import { + ActivepiecesError, + BaseOAuth2ConnectionValue, + ErrorCode, + OAuth2GrantType, + assertNotNullOrUndefined, + deleteProps, +} from '@activepieces/shared' import { pieceMetadataService } from '../../../pieces/piece-metadata-service' export const oauth2Util = { @@ -11,7 +18,10 @@ export const oauth2Util = { function isExpired(connection: BaseOAuth2ConnectionValue): boolean { const secondsSinceEpoch = Math.round(Date.now() / 1000) const grantType = connection.grant_type ?? OAuth2GrantType.AUTHORIZATION_CODE - if (grantType === OAuth2GrantType.AUTHORIZATION_CODE && !connection.refresh_token) { + if ( + grantType === OAuth2GrantType.AUTHORIZATION_CODE && + !connection.refresh_token + ) { return false } // Salesforce doesn't provide an 'expires_in' field, as it is dynamic per organization; therefore, it's necessary for us to establish a low threshold and consistently refresh it. @@ -22,7 +32,15 @@ function isExpired(connection: BaseOAuth2ConnectionValue): boolean { ) } -async function getOAuth2TokenUrl({ projectId, pieceName, props }: { projectId: string, pieceName: string, props?: Record }): Promise { +async function getOAuth2TokenUrl({ + projectId, + pieceName, + props, +}: { + projectId: string + pieceName: string + props?: Record +}): Promise { const pieceMetadata = await pieceMetadataService.getOrThrow({ name: pieceName, projectId, @@ -43,8 +61,10 @@ async function getOAuth2TokenUrl({ projectId, pieceName, props }: { projectId: s } } - -function resolveUrl(url: string, props: Record | undefined): string { +function resolveUrl( + url: string, + props: Record | undefined, +): string { if (!props) { return url } @@ -54,7 +74,9 @@ function resolveUrl(url: string, props: Record | undefined): st return url } -function formatOAuth2Response(response: Omit): BaseOAuth2ConnectionValue { +function formatOAuth2Response( + response: Omit, +): BaseOAuth2ConnectionValue { const secondsSinceEpoch = Math.round(Date.now() / 1000) const formattedResponse: BaseOAuth2ConnectionValue = { ...response, @@ -71,4 +93,3 @@ function formatOAuth2Response(response: Omit = { refresh, claim, } -async function refresh({ pieceName, connectionValue }: RefreshOAuth2Request): Promise { +async function refresh({ + pieceName, + connectionValue, +}: RefreshOAuth2Request): Promise { const requestBody = { refreshToken: connectionValue.refresh_token, pieceName, @@ -20,7 +32,11 @@ async function refresh({ pieceName, connectionValue }: RefreshOAuth2Request { +async function claim({ + request, + pieceName, +}: ClaimOAuth2Request): Promise { try { const cloudRequest: ClaimWithCloudRequest = { code: request.code, @@ -40,9 +59,15 @@ async function claim({ request, pieceName }: ClaimOAuth2Request): Promise('https://secrets.activepieces.com/claim', cloudRequest, { - timeout: 10000, - })).data + const value = ( + await axios.post( + 'https://secrets.activepieces.com/claim', + cloudRequest, + { + timeout: 10000, + }, + ) + ).data return { ...value, token_url: request.tokenUrl, diff --git a/packages/backend/src/app/app-connection/app-connection-service/oauth2/services/credentials-oauth2-service.ts b/packages/server/api/src/app/app-connection/app-connection-service/oauth2/services/credentials-oauth2-service.ts similarity index 82% rename from packages/backend/src/app/app-connection/app-connection-service/oauth2/services/credentials-oauth2-service.ts rename to packages/server/api/src/app/app-connection/app-connection-service/oauth2/services/credentials-oauth2-service.ts index aba394b429..1ffebc01c1 100644 --- a/packages/backend/src/app/app-connection/app-connection-service/oauth2/services/credentials-oauth2-service.ts +++ b/packages/server/api/src/app/app-connection/app-connection-service/oauth2/services/credentials-oauth2-service.ts @@ -1,18 +1,31 @@ import { OAuth2AuthorizationMethod } from '@activepieces/pieces-framework' -import { ActivepiecesError, AppConnectionType, BaseOAuth2ConnectionValue, ErrorCode, OAuth2ConnectionValueWithApp, OAuth2GrantType, isNil } from '@activepieces/shared' +import { + ActivepiecesError, + AppConnectionType, + BaseOAuth2ConnectionValue, + ErrorCode, + OAuth2ConnectionValueWithApp, + OAuth2GrantType, + isNil, +} from '@activepieces/shared' import axios from 'axios' import { oauth2Util } from '../oauth2-util' -import { logger } from '../../../../helper/logger' -import { ClaimOAuth2Request, OAuth2Service, RefreshOAuth2Request } from '../oauth2-service' +import { logger } from 'server-shared' +import { + ClaimOAuth2Request, + OAuth2Service, + RefreshOAuth2Request, +} from '../oauth2-service' +export const credentialsOauth2Service: OAuth2Service = + { + refresh, + claim, + } -export const credentialsOauth2Service: OAuth2Service = { - refresh, - claim, -} - - -async function claim({ request }: ClaimOAuth2Request): Promise { +async function claim({ + request, +}: ClaimOAuth2Request): Promise { try { const grantType = request.grantType ?? OAuth2GrantType.AUTHORIZATION_CODE const body: Record = { @@ -35,7 +48,7 @@ async function claim({ request }: ClaimOAuth2Request): Promise, -): Promise { +async function refresh({ + connectionValue, +}: RefreshOAuth2Request): Promise { const appConnection = connectionValue if (!oauth2Util.isExpired(appConnection)) { return appConnection } - const grantType = connectionValue.grant_type ?? OAuth2GrantType.AUTHORIZATION_CODE + const grantType = + connectionValue.grant_type ?? OAuth2GrantType.AUTHORIZATION_CODE const body: Record = {} switch (grantType) { - case OAuth2GrantType.AUTHORIZATION_CODE: { + case OAuth2GrantType.AUTHORIZATION_CODE: { body.grant_type = 'refresh_token' body.refresh_token = appConnection.refresh_token break @@ -109,7 +121,7 @@ async function refresh( accept: 'application/json', } const authorizationMethod = - appConnection.authorization_method || OAuth2AuthorizationMethod.BODY + appConnection.authorization_method || OAuth2AuthorizationMethod.BODY switch (authorizationMethod) { case OAuth2AuthorizationMethod.BODY: body.client_id = appConnection.client_id @@ -148,9 +160,9 @@ function mergeNonNull( appConnection: OAuth2ConnectionValueWithApp, oAuth2Response: BaseOAuth2ConnectionValue, ): OAuth2ConnectionValueWithApp { - const formattedOAuth2Response: Partial = Object.fromEntries( - Object.entries(oAuth2Response) - .filter(([, value]) => !isNil(value)), + const formattedOAuth2Response: Partial = + Object.fromEntries( + Object.entries(oAuth2Response).filter(([, value]) => !isNil(value)), ) return { diff --git a/packages/server/api/src/app/app-connection/app-connection-worker-controller.ts b/packages/server/api/src/app/app-connection/app-connection-worker-controller.ts new file mode 100644 index 0000000000..23291691ad --- /dev/null +++ b/packages/server/api/src/app/app-connection/app-connection-worker-controller.ts @@ -0,0 +1,52 @@ +import { + ActivepiecesError, + AppConnection, + ErrorCode, + isNil, +} from '@activepieces/shared' +import { + FastifyPluginCallbackTypebox, + Type, +} from '@fastify/type-provider-typebox' +import { allowWorkersOnly } from '../authentication/authorization' +import { appConnectionService } from './app-connection-service/app-connection-service' + +export const appConnectionWorkerController: FastifyPluginCallbackTypebox = ( + app, + _opts, + done, +) => { + app.addHook('preHandler', allowWorkersOnly) + + app.get( + '/:connectionName', + GetAppConnectionRequest, + async (request): Promise => { + const appConnection = await appConnectionService.getOne({ + projectId: request.principal.projectId, + name: request.params.connectionName, + }) + + if (isNil(appConnection)) { + throw new ActivepiecesError({ + code: ErrorCode.APP_CONNECTION_NOT_FOUND, + params: { + id: request.params.connectionName, + }, + }) + } + + return appConnection + }, + ) + + done() +} + +const GetAppConnectionRequest = { + schema: { + params: Type.Object({ + connectionName: Type.String(), + }), + }, +} diff --git a/packages/backend/src/app/app-connection/app-connection.controller.ts b/packages/server/api/src/app/app-connection/app-connection.controller.ts similarity index 57% rename from packages/backend/src/app/app-connection/app-connection.controller.ts rename to packages/server/api/src/app/app-connection/app-connection.controller.ts index 960e3ba9c1..18f88d8826 100644 --- a/packages/backend/src/app/app-connection/app-connection.controller.ts +++ b/packages/server/api/src/app/app-connection/app-connection.controller.ts @@ -7,13 +7,20 @@ import { SeekPage, UpsertAppConnectionRequestBody, } from '@activepieces/shared' -import { FastifyPluginCallbackTypebox, Type } from '@fastify/type-provider-typebox' +import { + FastifyPluginCallbackTypebox, + Type, +} from '@fastify/type-provider-typebox' import { StatusCodes } from 'http-status-codes' import { appConnectionService } from './app-connection-service/app-connection-service' -import { eventsHooks } from '../helper/audit-events' +import { eventsHooks } from '../helper/application-events' import { ApplicationEventName } from '@activepieces/ee-shared' -export const appConnectionController: FastifyPluginCallbackTypebox = (app, _opts, done) => { +export const appConnectionController: FastifyPluginCallbackTypebox = ( + app, + _opts, + done, +) => { app.post('/', UpsertAppConnectionRequest, async (request, reply) => { const appConnection = await appConnectionService.upsert({ projectId: request.principal.projectId, @@ -24,51 +31,63 @@ export const appConnectionController: FastifyPluginCallbackTypebox = (app, _opts connection: appConnection, userId: request.principal.id, }) - await reply.status(StatusCodes.CREATED).send(removeSensitiveData(appConnection)) + await reply + .status(StatusCodes.CREATED) + .send(removeSensitiveData(appConnection)) }) + app.get( + '/', + ListAppConnectionsRequest, + async (request): Promise> => { + const { pieceName, cursor, limit } = request.query - app.get('/', ListAppConnectionsRequest, async (request): Promise> => { - const { pieceName, cursor, limit } = request.query - - const appConnections = await appConnectionService.list({ - projectId: request.principal.projectId, - pieceName, - cursorRequest: cursor ?? null, - limit: limit ?? DEFAULT_PAGE_SIZE, - }) + const appConnections = await appConnectionService.list({ + projectId: request.principal.projectId, + pieceName, + cursorRequest: cursor ?? null, + limit: limit ?? DEFAULT_PAGE_SIZE, + }) - const appConnectionsWithoutSensitiveData: SeekPage = { + const appConnectionsWithoutSensitiveData: SeekPage = + { ...appConnections, data: appConnections.data.map(removeSensitiveData), } - return appConnectionsWithoutSensitiveData - }) + return appConnectionsWithoutSensitiveData + }, + ) - app.delete('/:id', DeleteAppConnectionRequest, async (request, reply): Promise => { - const connection = await appConnectionService.getOneOrThrow({ - id: request.params.id, - projectId: request.principal.projectId, - }) - eventsHooks.get().send(request, { - action: ApplicationEventName.DELETED_CONNECTION, - connection, - userId: request.principal.id, - }) - await appConnectionService.delete({ - id: request.params.id, - projectId: request.principal.projectId, - }) - await reply.status(StatusCodes.NO_CONTENT).send() - }) + app.delete( + '/:id', + DeleteAppConnectionRequest, + async (request, reply): Promise => { + const connection = await appConnectionService.getOneOrThrow({ + id: request.params.id, + projectId: request.principal.projectId, + }) + eventsHooks.get().send(request, { + action: ApplicationEventName.DELETED_CONNECTION, + connection, + userId: request.principal.id, + }) + await appConnectionService.delete({ + id: request.params.id, + projectId: request.principal.projectId, + }) + await reply.status(StatusCodes.NO_CONTENT).send() + }, + ) done() } const DEFAULT_PAGE_SIZE = 10 -const removeSensitiveData = (appConnection: AppConnection): AppConnectionWithoutSensitiveData => { +const removeSensitiveData = ( + appConnection: AppConnection, +): AppConnectionWithoutSensitiveData => { const { value: _, ...appConnectionWithoutSensitiveData } = appConnection return appConnectionWithoutSensitiveData as AppConnectionWithoutSensitiveData } diff --git a/packages/backend/src/app/app-connection/app-connection.entity.ts b/packages/server/api/src/app/app-connection/app-connection.entity.ts similarity index 82% rename from packages/backend/src/app/app-connection/app-connection.entity.ts rename to packages/server/api/src/app/app-connection/app-connection.entity.ts index 8561a69adc..848ac51583 100644 --- a/packages/backend/src/app/app-connection/app-connection.entity.ts +++ b/packages/server/api/src/app/app-connection/app-connection.entity.ts @@ -1,9 +1,20 @@ -import { AppConnection, AppConnectionStatus, Project } from '@activepieces/shared' +import { + AppConnection, + AppConnectionStatus, + Project, +} from '@activepieces/shared' import { EntitySchema } from 'typeorm' -import { ApIdSchema, BaseColumnSchemaPart, JSONB_COLUMN_TYPE } from '../database/database-common' +import { + ApIdSchema, + BaseColumnSchemaPart, + JSONB_COLUMN_TYPE, +} from '../database/database-common' import { EncryptedObject } from '../helper/encryption' -export type AppConnectionSchema = Omit & { project: Project, value: EncryptedObject } +export type AppConnectionSchema = Omit & { + project: Project + value: EncryptedObject +} export const AppConnectionEntity = new EntitySchema({ name: 'app_connection', diff --git a/packages/backend/src/app/app-connection/app-connection.module.ts b/packages/server/api/src/app/app-connection/app-connection.module.ts old mode 100755 new mode 100644 similarity index 69% rename from packages/backend/src/app/app-connection/app-connection.module.ts rename to packages/server/api/src/app/app-connection/app-connection.module.ts index c7da9e4a90..b7547b3b6f --- a/packages/backend/src/app/app-connection/app-connection.module.ts +++ b/packages/server/api/src/app/app-connection/app-connection.module.ts @@ -6,6 +6,10 @@ import { entitiesMustBeOwnedByCurrentProject } from '../authentication/authoriza export const appConnectionModule: FastifyPluginAsyncTypebox = async (app) => { app.addHook('preSerialization', entitiesMustBeOwnedByCurrentProject) - await app.register(appConnectionController, { prefix: '/v1/app-connections' }) - await app.register(appConnectionWorkerController, { prefix: '/v1/worker/app-connections' }) + await app.register(appConnectionController, { + prefix: '/v1/app-connections', + }) + await app.register(appConnectionWorkerController, { + prefix: '/v1/worker/app-connections', + }) } diff --git a/packages/backend/src/app/app-event-routing/app-event-routing.entity.ts b/packages/server/api/src/app/app-event-routing/app-event-routing.entity.ts similarity index 100% rename from packages/backend/src/app/app-event-routing/app-event-routing.entity.ts rename to packages/server/api/src/app/app-event-routing/app-event-routing.entity.ts diff --git a/packages/backend/src/app/app-event-routing/app-event-routing.module.ts b/packages/server/api/src/app/app-event-routing/app-event-routing.module.ts old mode 100755 new mode 100644 similarity index 81% rename from packages/backend/src/app/app-event-routing/app-event-routing.module.ts rename to packages/server/api/src/app/app-event-routing/app-event-routing.module.ts index 67fea1ee95..82be3dc627 --- a/packages/backend/src/app/app-event-routing/app-event-routing.module.ts +++ b/packages/server/api/src/app/app-event-routing/app-event-routing.module.ts @@ -1,9 +1,13 @@ import { FastifyRequest } from 'fastify' import { webhookService } from '../webhooks/webhook-service' import { appEventRoutingService } from './app-event-routing.service' -import { logger } from '../helper/logger' +import { logger } from 'server-shared' import { ALL_PRINICPAL_TYPES, isNil } from '@activepieces/shared' -import { ActivepiecesError, ErrorCode, EventPayload } from '@activepieces/shared' +import { + ActivepiecesError, + ErrorCode, + EventPayload, +} from '@activepieces/shared' import { flowService } from '../flows/flow/flow.service' import { AppEventRouting } from './app-event-routing.entity' import { slack } from '@activepieces/piece-slack' @@ -28,8 +32,9 @@ export const appEventRoutingModule: FastifyPluginAsyncTypebox = async (app) => { await app.register(appEventRoutingController, { prefix: '/v1/app-events' }) } -export const appEventRoutingController: FastifyPluginAsyncTypebox = async (fastify) => { - +export const appEventRoutingController: FastifyPluginAsyncTypebox = async ( + fastify, +) => { fastify.all( '/:pieceUrl', { @@ -67,27 +72,36 @@ export const appEventRoutingController: FastifyPluginAsyncTypebox = async (fasti }) } const pieceName = pieceNames[pieceUrl] - const { reply, event, identifierValue } = piece.events!.parseAndReply({ payload: eventPayload }) + const { reply, event, identifierValue } = piece.events!.parseAndReply({ + payload: eventPayload, + }) - logger.debug(`Received event ${event} with identifier ${identifierValue} in app ${pieceName}`) + logger.debug( + `Received event ${event} with identifier ${identifierValue} in app ${pieceName}`, + ) if (event && identifierValue) { const listeners = await appEventRoutingService.listListeners({ appName: pieceName, event, identifierValue, }) - listeners.map(listener => { + listeners.map((listener) => { return callback(listener, eventPayload) }) } - return requestReply.status(200).headers(reply?.headers ?? {}).send(reply?.body ?? {}) + return requestReply + .status(200) + .headers(reply?.headers ?? {}) + .send(reply?.body ?? {}) }, ) - } async function callback(listener: AppEventRouting, eventPayload: EventPayload) { - const flow = await flowService.getOneOrThrow({ projectId: listener.projectId, id: listener.flowId }) + const flow = await flowService.getOneOrThrow({ + projectId: listener.projectId, + id: listener.flowId, + }) return webhookService.callback({ flow, payload: eventPayload, diff --git a/packages/server/api/src/app/app-event-routing/app-event-routing.service.ts b/packages/server/api/src/app/app-event-routing/app-event-routing.service.ts new file mode 100644 index 0000000000..8353b2b507 --- /dev/null +++ b/packages/server/api/src/app/app-event-routing/app-event-routing.service.ts @@ -0,0 +1,83 @@ +import { apId, FlowId, ProjectId } from '@activepieces/shared' +import { databaseConnection } from '../database/database-connection' +import { + AppEventRouting, + AppEventRoutingEntity, +} from './app-event-routing.entity' +import { logger } from 'server-shared' +import { system, SystemProp } from 'server-shared' + +const appEventRoutingRepo = databaseConnection.getRepository( + AppEventRoutingEntity, +) + +export const appEventRoutingService = { + async listListeners({ + appName, + event, + identifierValue, + }: { + appName: string + event: string + identifierValue: string + }): Promise { + return appEventRoutingRepo.findBy({ appName, event, identifierValue }) + }, + async createListeners({ + appName, + events, + identifierValue, + flowId, + projectId, + }: { + appName: string + events: string[] + identifierValue: string + flowId: FlowId + projectId: ProjectId + }): Promise { + logger.info( + `Creating listeners for ${appName}, events=${events}, identifierValue=${identifierValue}`, + ) + const upsertCommands: Promise[] = [] + events.forEach((event) => { + const upsert = appEventRoutingRepo.upsert( + { + id: apId(), + appName, + event, + identifierValue, + flowId, + projectId, + }, + ['appName', 'event', 'identifierValue', 'projectId'], + ) + upsertCommands.push(upsert) + }) + await Promise.all(upsertCommands) + }, + async deleteListeners({ + projectId, + flowId, + }: { + projectId: ProjectId + flowId: FlowId + }): Promise { + await appEventRoutingRepo.delete({ + projectId, + flowId, + }) + }, + async getAppWebhookUrl({ + appName, + }: { + appName: string + }): Promise { + const webhookUrl = system.get(SystemProp.WEBHOOK_URL) + if (webhookUrl) { + return `${webhookUrl}/v1/app-events/${appName}` + } + const frontendUrl = system.get(SystemProp.FRONTEND_URL) + return `${frontendUrl}/api/v1/app-events/${appName}` + }, +} diff --git a/packages/backend/src/app/app.ts b/packages/server/api/src/app/app.ts similarity index 81% rename from packages/backend/src/app/app.ts rename to packages/server/api/src/app/app.ts index 6695cd079a..d35d323914 100644 --- a/packages/backend/src/app/app.ts +++ b/packages/server/api/src/app/app.ts @@ -16,14 +16,22 @@ import { webhookModule } from './webhooks/webhook-module' import { errorHandler } from './helper/error-handler' import { appConnectionModule } from './app-connection/app-connection.module' import swagger from '@fastify/swagger' -import { logger } from './helper/logger' +import { logger } from 'server-shared' import { appEventRoutingModule } from './app-event-routing/app-event-routing.module' import { triggerEventModule } from './flows/trigger-events/trigger-event.module' import { fastifyRawBody } from 'fastify-raw-body' import { stepFileModule } from './flows/step-file/step-file.module' import { rbacAuthMiddleware } from './ee/authentication/rbac-auth-middleware' import { userModule } from './user/user.module' -import { ApEdition, AppConnectionWithoutSensitiveData, Flow } from '@activepieces/shared' +import { + ActivepiecesError, + ApEdition, + ApEnvironment, + AppConnectionWithoutSensitiveData, + CodeSandboxType, + ErrorCode, + Flow, +} from '@activepieces/shared' import { appConnectionsHooks } from './app-connection/app-connection-service/app-connection-hooks' import { authenticationModule } from './authentication/authentication.module' import { cloudAppConnectionsHooks } from './ee/app-connections/cloud-app-connection-service' @@ -33,7 +41,7 @@ import { connectionKeyModule } from './ee/connection-keys/connection-key.module' import { platformRunHooks } from './ee/flow-run/cloud-flow-run-hooks' import { platformFlowTemplateModule } from './ee/flow-template/platform-flow-template.module' import { platformWorkerHooks } from './ee/flow-worker/cloud-flow-worker-hooks' -import { initilizeSentry } from './helper/exception-handler' +import { initilizeSentry } from 'server-shared' import { adminPieceModule } from './ee/pieces/admin-piece-module' import { platformPieceServiceHooks } from './ee/pieces/piece-service/platform-piece-service-hooks' import { platformModule } from './ee/platform/platform.module' @@ -53,7 +61,6 @@ import { setupBullMQBoard } from './workers/flow-worker/queues/redis/redis-queue import { signingKeyModule } from './ee/signing-key/signing-key-module' import { managedAuthnModule } from './ee/managed-authn/managed-authn-module' import { oauthAppModule } from './ee/oauth-apps/oauth-app.module' -import { validateEnvPropsOnStartup } from './helper/system/system' import { platformOAuth2Service } from './ee/app-connections/platform-oauth2-service' import { setPlatformOAuthService } from './app-connection/app-connection-service/oauth2' import { pieceMetadataServiceHooks } from './pieces/piece-metadata-service/hooks' @@ -68,7 +75,11 @@ import { enterpriseLocalAuthnModule } from './ee/authentication/enterprise-local import { billingModule } from './ee/billing/billing/billing.module' import { federatedAuthModule } from './ee/authentication/federated-authn/federated-authn-module' import fastifyFavicon from 'fastify-favicon' -import { ProjectMember, ProjectWithUsageAndPlanResponse, GitRepoWithoutSenestiveData } from '@activepieces/ee-shared' +import { + ProjectMember, + ProjectWithUsageAndPlanResponse, + GitRepoWithoutSenestiveData, +} from '@activepieces/ee-shared' import { apiKeyModule } from './ee/api-keys/api-key-module' import { domainHelper } from './helper/domain-helper' import { platformDomainHelper } from './ee/helper/platform-domain-helper' @@ -83,9 +94,11 @@ import { Socket } from 'socket.io' import { accessTokenManager } from './authentication/lib/access-token-manager' import { websocketService } from './websockets/websockets.service' import { rateLimitModule } from './core/security/rate-limit' -import { eventsHooks } from './helper/audit-events' +import { eventsHooks } from './helper/application-events' import { auditLogService } from './ee/audit-logs/audit-event-service' import { auditEventModule } from './ee/audit-logs/audit-event-module' +import { ExecutionMode, QueueMode, SystemProp, system } from 'server-shared' +import { loadEncryptionKey } from './helper/encryption' export const setupApp = async (): Promise => { const app = fastify({ @@ -116,10 +129,10 @@ export const setupApp = async (): Promise => { components: { schemas: { 'project-member': ProjectMember, - 'project': ProjectWithUsageAndPlanResponse, - 'flow': Flow, + project: ProjectWithUsageAndPlanResponse, + flow: Flow, 'app-connection': AppConnectionWithoutSensitiveData, - 'piece': PieceMetadata, + piece: PieceMetadata, 'git-repo': GitRepoWithoutSenestiveData, }, }, @@ -140,17 +153,14 @@ export const setupApp = async (): Promise => { methods: ['*'], }) - await app.register( - fastifyMultipart, - { - attachFieldsToBody: 'keyValues', - // eslint-disable-next-line @typescript-eslint/no-explicit-any - async onFile(part: any) { - const buffer = await part.toBuffer() - part.value = buffer - }, + await app.register(fastifyMultipart, { + attachFieldsToBody: 'keyValues', + // eslint-disable-next-line @typescript-eslint/no-explicit-any + async onFile(part: any) { + const buffer = await part.toBuffer() + part.value = buffer }, - ) + }) await app.register(fastifyRawBody, { field: 'rawBody', @@ -160,7 +170,7 @@ export const setupApp = async (): Promise => { routes: [], }) - await app.register(formBody, { parser: str => qs.parse(str) }) + await app.register(formBody, { parser: (str) => qs.parse(str) }) await app.register(rateLimitModule) await app.register(fastifySocketIO, { @@ -170,18 +180,20 @@ export const setupApp = async (): Promise => { }) app.io.use((socket: Socket, next: (err?: Error) => void) => { - accessTokenManager.extractPrincipal(socket.handshake.auth.token).then(() => { - next() - }).catch(() => { - next(new Error('Authentication error')) - }) + accessTokenManager + .extractPrincipal(socket.handshake.auth.token) + .then(() => { + next() + }) + .catch(() => { + next(new Error('Authentication error')) + }) }) app.io.on('connection', (socket: Socket) => { websocketService.init(socket) }) - app.addHook('onRequest', async (request, reply) => { const route = app.hasRoute({ method: request.method as HTTPMethods, @@ -221,22 +233,33 @@ export const setupApp = async (): Promise => { app.get( '/redirect', async ( - request: FastifyRequest<{ Querystring: { code: string } }>, reply, + request: FastifyRequest<{ Querystring: { code: string } }>, + reply, ) => { const params = { - 'code': request.query.code, + code: request.query.code, } if (!params.code) { return reply.send('The code is missing in url') } else { - return reply.type('text/html').send(` Redirect succuesfully, this window should close now`) + return reply + .type('text/html') + .send( + ` Redirect succuesfully, this window should close now`, + ) } }, ) // SurveyMonkey - app.addContentTypeParser('application/vnd.surveymonkey.response.v1+json', { parseAs: 'string' }, app.getDefaultJsonParser('ignore', 'ignore')) + app.addContentTypeParser( + 'application/vnd.surveymonkey.response.v1+json', + { parseAs: 'string' }, + app.getDefaultJsonParser('ignore', 'ignore'), + ) await validateEnvPropsOnStartup() const edition = getEdition() @@ -323,3 +346,33 @@ export const setupApp = async (): Promise => { return app } + + +const validateEnvPropsOnStartup = async (): Promise => { + const codeSandboxType = system.get( + SystemProp.CODE_SANDBOX_TYPE, + ) + const executionMode = system.get(SystemProp.EXECUTION_MODE) + const signedUpEnabled = + system.getBoolean(SystemProp.SIGN_UP_ENABLED) ?? false + const queueMode = system.getOrThrow(SystemProp.QUEUE_MODE) + const environment = system.get(SystemProp.ENVIRONMENT) + await loadEncryptionKey(queueMode) + + if ( + executionMode === ExecutionMode.UNSANDBOXED && + codeSandboxType !== CodeSandboxType.V8_ISOLATE && + signedUpEnabled && + environment === ApEnvironment.PRODUCTION + ) { + throw new ActivepiecesError( + { + code: ErrorCode.SYSTEM_PROP_INVALID, + params: { + prop: SystemProp.EXECUTION_MODE, + }, + }, + 'Allowing users to sign up is not allowed in unsandboxed mode, please check the configuration section in the documentation', + ) + } +} \ No newline at end of file diff --git a/packages/backend/src/app/authentication/authentication-service/hooks/authentication-service-hooks.ts b/packages/server/api/src/app/authentication/authentication-service/hooks/authentication-service-hooks.ts similarity index 99% rename from packages/backend/src/app/authentication/authentication-service/hooks/authentication-service-hooks.ts rename to packages/server/api/src/app/authentication/authentication-service/hooks/authentication-service-hooks.ts index fdc39befc2..240b35620c 100644 --- a/packages/backend/src/app/authentication/authentication-service/hooks/authentication-service-hooks.ts +++ b/packages/server/api/src/app/authentication/authentication-service/hooks/authentication-service-hooks.ts @@ -5,7 +5,6 @@ export enum Provider { FEDERATED = 'FEDERATED', } - export type AuthenticationServiceHooks = { preSignIn(p: PreParams): Promise preSignUp(p: PreParams): Promise diff --git a/packages/backend/src/app/authentication/authentication-service/hooks/community-service-hooks.ts b/packages/server/api/src/app/authentication/authentication-service/hooks/community-service-hooks.ts similarity index 91% rename from packages/backend/src/app/authentication/authentication-service/hooks/community-service-hooks.ts rename to packages/server/api/src/app/authentication/authentication-service/hooks/community-service-hooks.ts index 307eaf72f4..119d502a5e 100644 --- a/packages/backend/src/app/authentication/authentication-service/hooks/community-service-hooks.ts +++ b/packages/server/api/src/app/authentication/authentication-service/hooks/community-service-hooks.ts @@ -1,17 +1,21 @@ -import { PrincipalType, Project, ProjectType, User } from '@activepieces/shared' +import { + PrincipalType, + Project, + ProjectType, + User, +} from '@activepieces/shared' import { projectService } from '../../../project/project-service' import { AuthenticationServiceHooks } from './authentication-service-hooks' import { accessTokenManager } from '../../lib/access-token-manager' export const communityAuthenticationServiceHooks: AuthenticationServiceHooks = { async preSignIn() { - // Empty + // Empty }, async preSignUp() { - // Empty + // Empty }, async postSignUp({ user }) { - const project = await projectService.create({ displayName: `${user.firstName}'s Project`, ownerId: user.id, @@ -47,7 +51,6 @@ export const communityAuthenticationServiceHooks: AuthenticationServiceHooks = { }, } - const getProject = async (user: User): Promise => { return projectService.getUserProjectOrThrow(user.id) } diff --git a/packages/backend/src/app/authentication/authentication-service/hooks/index.ts b/packages/server/api/src/app/authentication/authentication-service/hooks/index.ts similarity index 100% rename from packages/backend/src/app/authentication/authentication-service/hooks/index.ts rename to packages/server/api/src/app/authentication/authentication-service/hooks/index.ts diff --git a/packages/backend/src/app/authentication/authentication-service/index.ts b/packages/server/api/src/app/authentication/authentication-service/index.ts similarity index 79% rename from packages/backend/src/app/authentication/authentication-service/index.ts rename to packages/server/api/src/app/authentication/authentication-service/index.ts index c75cb60479..2ae4f1cbd2 100644 --- a/packages/backend/src/app/authentication/authentication-service/index.ts +++ b/packages/server/api/src/app/authentication/authentication-service/index.ts @@ -1,13 +1,24 @@ import { QueryFailedError } from 'typeorm' -import { AuthenticationResponse, UserStatus, ActivepiecesError, ErrorCode, isNil, User, ApFlagId, Project, TelemetryEventName, UserId, ApEnvironment } from '@activepieces/shared' +import { + AuthenticationResponse, + UserStatus, + ActivepiecesError, + ErrorCode, + isNil, + User, + ApFlagId, + Project, + TelemetryEventName, + UserId, + ApEnvironment, +} from '@activepieces/shared' import { userService } from '../../user/user-service' import { passwordHasher } from '../lib/password-hasher' import { authenticationServiceHooks as hooks } from './hooks' import { generateRandomPassword } from '../../helper/crypto' import { flagService } from '../../flags/flag.service' -import { system } from '../../helper/system/system' -import { SystemProp } from '../../helper/system/system-prop' -import { logger } from '../../helper/logger' +import { SystemProp, system } from 'server-shared' +import { logger } from 'server-shared' import { telemetry } from '../../helper/telemetry.utils' import { Provider } from './hooks/authentication-service-hooks' @@ -39,13 +50,14 @@ export const authenticationService = { userPassword: user.password, }) - return this.signInResponse({ user, }) }, - async federatedAuthn(params: FederatedAuthnParams): Promise { + async federatedAuthn( + params: FederatedAuthnParams, + ): Promise { const existingUser = await userService.getByPlatformAndEmail({ platformId: params.platformId, email: params.email, @@ -74,7 +86,10 @@ export const authenticationService = { }) }, - async signUpResponse({ user, referringUserId }: SignUpResponseParams): Promise { + async signUpResponse({ + user, + referringUserId, + }: SignUpResponseParams): Promise { const authnResponse = await hooks.get().postSignUp({ user, referringUserId, @@ -84,7 +99,8 @@ export const authenticationService = { const userWithoutPassword = removePasswordPropFromUser(authnResponse.user) await sendTelemetry({ - user, project: authnResponse.project, + user, + project: authnResponse.project, }) await saveNewsLetterSubscriber(user) @@ -95,7 +111,9 @@ export const authenticationService = { } }, - async signInResponse({ user }: SignInResponseParams): Promise { + async signInResponse({ + user, + }: SignInResponseParams): Promise { const authnResponse = await hooks.get().postSignIn({ user, }) @@ -119,7 +137,6 @@ const assertSignUpIsEnabled = async (): Promise => { params: {}, }) } - } const createUser = async (params: SignUpParams): Promise => { @@ -153,7 +170,9 @@ const createUser = async (params: SignUpParams): Promise => { } } -const assertUserIsAllowedToSignIn: (user: User | null) => asserts user is User = (user) => { +const assertUserIsAllowedToSignIn: ( + user: User | null +) => asserts user is User = (user) => { if (isNil(user)) { throw new ActivepiecesError({ code: ErrorCode.INVALID_CREDENTIALS, @@ -178,8 +197,14 @@ const assertUserIsAllowedToSignIn: (user: User | null) => asserts user is User = } } -const assertPasswordMatches = async ({ requestPassword, userPassword }: AssertPasswordsMatchParams): Promise => { - const passwordMatches = await passwordHasher.compare(requestPassword, userPassword) +const assertPasswordMatches = async ({ + requestPassword, + userPassword, +}: AssertPasswordsMatchParams): Promise => { + const passwordMatches = await passwordHasher.compare( + requestPassword, + userPassword, + ) if (!passwordMatches) { throw new ActivepiecesError({ @@ -194,7 +219,10 @@ const removePasswordPropFromUser = (user: User): Omit => { return filteredUser } -const sendTelemetry = async ({ user, project }: SendTelemetryParams): Promise => { +const sendTelemetry = async ({ + user, + project, +}: SendTelemetryParams): Promise => { try { await telemetry.identify(user, project.id) @@ -215,19 +243,28 @@ const sendTelemetry = async ({ user, project }: SendTelemetryParams): Promise { - const isPlatformUserOrNotSubscribed = (!isNil(user.platformId) && !flagService.isCloudPlatform(user.platformId)) || !user.newsLetter + const isPlatformUserOrNotSubscribed = + (!isNil(user.platformId) && + !flagService.isCloudPlatform(user.platformId)) || + !user.newsLetter const environment = system.get(SystemProp.ENVIRONMENT) - if (isPlatformUserOrNotSubscribed || environment !== ApEnvironment.PRODUCTION) { + if ( + isPlatformUserOrNotSubscribed || + environment !== ApEnvironment.PRODUCTION + ) { return } try { - const response = await fetch('https://us-central1-activepieces-b3803.cloudfunctions.net/addContact', { - method: 'POST', - headers: { - 'Content-Type': 'application/json', + const response = await fetch( + 'https://us-central1-activepieces-b3803.cloudfunctions.net/addContact', + { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ email: user.email }), }, - body: JSON.stringify({ email: user.email }), - }) + ) return await response.json() } catch (error) { @@ -239,8 +276,6 @@ type SendTelemetryParams = { project: Project } - - type NewUser = Omit type SignUpParams = { diff --git a/packages/backend/src/app/authentication/authentication.controller.ts b/packages/server/api/src/app/authentication/authentication.controller.ts old mode 100755 new mode 100644 similarity index 84% rename from packages/backend/src/app/authentication/authentication.controller.ts rename to packages/server/api/src/app/authentication/authentication.controller.ts index 7c7560d75a..11485621f4 --- a/packages/backend/src/app/authentication/authentication.controller.ts +++ b/packages/server/api/src/app/authentication/authentication.controller.ts @@ -3,14 +3,20 @@ import { RateLimitOptions } from '@fastify/rate-limit' import { authenticationService } from './authentication-service' import { resolvePlatformIdForRequest } from '../ee/platform/lib/platform-utils' import { getEdition } from '../helper/secret-helper' -import { ApEdition, SignUpRequest, SignInRequest, ALL_PRINICPAL_TYPES } from '@activepieces/shared' -import { system } from '../helper/system/system' -import { SystemProp } from '../helper/system/system-prop' +import { + ApEdition, + SignUpRequest, + SignInRequest, + ALL_PRINICPAL_TYPES, +} from '@activepieces/shared' +import { system, SystemProp } from 'server-shared' import { Provider } from './authentication-service/hooks/authentication-service-hooks' const edition = getEdition() -export const authenticationController: FastifyPluginAsyncTypebox = async (app) => { +export const authenticationController: FastifyPluginAsyncTypebox = async ( + app, +) => { app.post('/sign-up', SignUpRequestOptions, async (request) => { const platformId = await resolvePlatformIdForRequest(request) @@ -34,7 +40,10 @@ export const authenticationController: FastifyPluginAsyncTypebox = async (app) = } const rateLimitOptions: RateLimitOptions = { - max: Number.parseInt(system.getOrThrow(SystemProp.API_RATE_LIMIT_AUTHN_MAX), 10), + max: Number.parseInt( + system.getOrThrow(SystemProp.API_RATE_LIMIT_AUTHN_MAX), + 10, + ), timeWindow: system.getOrThrow(SystemProp.API_RATE_LIMIT_AUTHN_WINDOW), } diff --git a/packages/backend/src/app/authentication/authentication.module.ts b/packages/server/api/src/app/authentication/authentication.module.ts old mode 100755 new mode 100644 similarity index 70% rename from packages/backend/src/app/authentication/authentication.module.ts rename to packages/server/api/src/app/authentication/authentication.module.ts index a2eac24945..d6906b7bad --- a/packages/backend/src/app/authentication/authentication.module.ts +++ b/packages/server/api/src/app/authentication/authentication.module.ts @@ -2,5 +2,7 @@ import { FastifyPluginAsyncTypebox } from '@fastify/type-provider-typebox' import { authenticationController } from './authentication.controller' export const authenticationModule: FastifyPluginAsyncTypebox = async (app) => { - await app.register(authenticationController, { prefix: '/v1/authentication' }) + await app.register(authenticationController, { + prefix: '/v1/authentication', + }) } diff --git a/packages/backend/src/app/authentication/authorization.ts b/packages/server/api/src/app/authentication/authorization.ts similarity index 83% rename from packages/backend/src/app/authentication/authorization.ts rename to packages/server/api/src/app/authentication/authorization.ts index b8b9385ff7..12fb989a52 100644 --- a/packages/backend/src/app/authentication/authorization.ts +++ b/packages/server/api/src/app/authentication/authorization.ts @@ -1,6 +1,11 @@ -import { ActivepiecesError, ErrorCode, PrincipalType, isObject } from '@activepieces/shared' +import { + ActivepiecesError, + ErrorCode, + PrincipalType, + isObject, +} from '@activepieces/shared' import { onRequestHookHandler, preSerializationHookHandler } from 'fastify' -import { logger } from '../helper/logger' +import { logger } from 'server-shared' // TODO REMOVE export const allowWorkersOnly: onRequestHookHandler = (request, _res, done) => { @@ -26,8 +31,13 @@ export function extractResourceName(url: string): string | undefined { * the `projectId` property value does not match the principal's `projectId`. * Otherwise, does nothing. */ -export const entitiesMustBeOwnedByCurrentProject: preSerializationHookHandler = (request, _response, payload, done) => { - logger.trace({ payload, principal: request.principal, route: request.routeConfig }, 'entitiesMustBeOwnedByCurrentProject') +export const entitiesMustBeOwnedByCurrentProject: preSerializationHookHandler< +Payload | null +> = (request, _response, payload, done) => { + logger.trace( + { payload, principal: request.principal, route: request.routeConfig }, + 'entitiesMustBeOwnedByCurrentProject', + ) if (isObject(payload)) { const principalProjectId = request.principal.projectId @@ -39,7 +49,7 @@ export const entitiesMustBeOwnedByCurrentProject: preSerializationHookHandler { + const someEntityNotOwnedByCurrentProject = payload.data.some((entity) => { return 'projectId' in entity && entity.projectId !== principalProjectId }) diff --git a/packages/backend/src/app/authentication/lib/access-token-manager.ts b/packages/server/api/src/app/authentication/lib/access-token-manager.ts old mode 100755 new mode 100644 similarity index 99% rename from packages/backend/src/app/authentication/lib/access-token-manager.ts rename to packages/server/api/src/app/authentication/lib/access-token-manager.ts index 3adb305f1f..e871567595 --- a/packages/backend/src/app/authentication/lib/access-token-manager.ts +++ b/packages/server/api/src/app/authentication/lib/access-token-manager.ts @@ -2,7 +2,6 @@ import { Principal, assertNotNullOrUndefined } from '@activepieces/shared' import { ActivepiecesError, ErrorCode } from '@activepieces/shared' import { jwtUtils } from '../../helper/jwt-utils' - export const accessTokenManager = { async generateToken(principal: Principal): Promise { const secret = await jwtUtils.getJwtSecret() diff --git a/packages/backend/src/app/authentication/lib/password-hasher.ts b/packages/server/api/src/app/authentication/lib/password-hasher.ts old mode 100755 new mode 100644 similarity index 67% rename from packages/backend/src/app/authentication/lib/password-hasher.ts rename to packages/server/api/src/app/authentication/lib/password-hasher.ts index a60e3ccd1b..347932ac7d --- a/packages/backend/src/app/authentication/lib/password-hasher.ts +++ b/packages/server/api/src/app/authentication/lib/password-hasher.ts @@ -1,8 +1,7 @@ import { assertNotNullOrUndefined } from '@activepieces/shared' import bcrypt from 'bcrypt' import { FirebaseScrypt } from 'firebase-scrypt' -import { system } from '../../helper/system/system' -import { SystemProp } from '../../helper/system/system-prop' +import { SystemProp, system } from 'server-shared' const SALT_ROUNDS = 10 const SCRYPT_SEPERATOR = '~' @@ -12,7 +11,10 @@ export const passwordHasher = { return bcrypt.hash(plainTextPassword, SALT_ROUNDS) }, - compare: async (plainTextPassword: string, hashedPassword: string): Promise => { + compare: async ( + plainTextPassword: string, + hashedPassword: string, + ): Promise => { assertNotNullOrUndefined(plainTextPassword, 'plainTextPassword') assertNotNullOrUndefined(hashedPassword, 'hashedPassword') if (isBcryptHash(hashedPassword)) { @@ -20,15 +22,23 @@ export const passwordHasher = { } if (isScrypt(hashedPassword)) { const salt = hashedPassword.split(SCRYPT_SEPERATOR)[1] - const rawHashedPassword = hashedPassword.split(SCRYPT_SEPERATOR)[0].substring('$scrypt$'.length) + const rawHashedPassword = hashedPassword + .split(SCRYPT_SEPERATOR)[0] + .substring('$scrypt$'.length) return compareScrypt(plainTextPassword, salt, rawHashedPassword) } return false }, } -async function compareScrypt(password: string, salt: string, hashedPassword: string): Promise { - const firebaseParameter = JSON.parse(system.getOrThrow(SystemProp.FIREBASE_HASH_PARAMETERS)) +async function compareScrypt( + password: string, + salt: string, + hashedPassword: string, +): Promise { + const firebaseParameter = JSON.parse( + system.getOrThrow(SystemProp.FIREBASE_HASH_PARAMETERS), + ) const firebaseScrypt = new FirebaseScrypt(firebaseParameter) return firebaseScrypt.verify(password, salt, hashedPassword) } @@ -39,4 +49,4 @@ function isBcryptHash(hash: string): boolean { function isScrypt(hash: string): boolean { return hash.startsWith('$scrypt$') -} \ No newline at end of file +} diff --git a/packages/backend/src/app/copilot/copilot.controller.ts b/packages/server/api/src/app/copilot/copilot.controller.ts old mode 100755 new mode 100644 similarity index 76% rename from packages/backend/src/app/copilot/copilot.controller.ts rename to packages/server/api/src/app/copilot/copilot.controller.ts index 5bb6240126..a5f7878d4a --- a/packages/backend/src/app/copilot/copilot.controller.ts +++ b/packages/server/api/src/app/copilot/copilot.controller.ts @@ -1,5 +1,8 @@ import { copilotService } from './copilot.service' -import { FastifyPluginCallbackTypebox, Type } from '@fastify/type-provider-typebox' +import { + FastifyPluginCallbackTypebox, + Type, +} from '@fastify/type-provider-typebox' const GenerateCodeRequest = { schema: { @@ -9,7 +12,11 @@ const GenerateCodeRequest = { }, } -export const copilotController: FastifyPluginCallbackTypebox = (app, _options, done): void => { +export const copilotController: FastifyPluginCallbackTypebox = ( + app, + _options, + done, +): void => { app.post('/code', GenerateCodeRequest, async (req, res) => { const { prompt } = req.body @@ -18,4 +25,4 @@ export const copilotController: FastifyPluginCallbackTypebox = (app, _options, d }) done() -} \ No newline at end of file +} diff --git a/packages/backend/src/app/copilot/copilot.module.ts b/packages/server/api/src/app/copilot/copilot.module.ts old mode 100755 new mode 100644 similarity index 99% rename from packages/backend/src/app/copilot/copilot.module.ts rename to packages/server/api/src/app/copilot/copilot.module.ts index 16fe6ffad9..086f54d260 --- a/packages/backend/src/app/copilot/copilot.module.ts +++ b/packages/server/api/src/app/copilot/copilot.module.ts @@ -3,4 +3,4 @@ import { copilotController } from './copilot.controller' export const copilotModule: FastifyPluginAsyncTypebox = async (app) => { await app.register(copilotController, { prefix: '/v1/copilot' }) -} \ No newline at end of file +} diff --git a/packages/backend/src/app/copilot/copilot.service.ts b/packages/server/api/src/app/copilot/copilot.service.ts old mode 100755 new mode 100644 similarity index 64% rename from packages/backend/src/app/copilot/copilot.service.ts rename to packages/server/api/src/app/copilot/copilot.service.ts index b0ec9e683c..48f71f3f05 --- a/packages/backend/src/app/copilot/copilot.service.ts +++ b/packages/server/api/src/app/copilot/copilot.service.ts @@ -1,9 +1,11 @@ import { assertNotNullOrUndefined } from '@activepieces/shared' -import { logger } from '../helper/logger' +import { logger } from 'server-shared' import OpenAI from 'openai' -import { system } from '../helper/system/system' -import { SystemProp } from '../helper/system/system-prop' -import { ChatCompletionMessageParam, ChatCompletionTool } from 'openai/resources' +import { system, SystemProp } from 'server-shared' +import { + ChatCompletionMessageParam, + ChatCompletionTool, +} from 'openai/resources' type GenerateCodeParams = { prompt: string @@ -37,8 +39,14 @@ export const copilotService = { }, temperature: 1, }) - assertNotNullOrUndefined(result.choices[0].message.tool_calls, 'OpenAICodeResponse') - logger.debug({ response: result.choices[0].message.tool_calls[0] }, '[CopilotService#generateCode] Response received...') + assertNotNullOrUndefined( + result.choices[0].message.tool_calls, + 'OpenAICodeResponse', + ) + logger.debug( + { response: result.choices[0].message.tool_calls[0] }, + '[CopilotService#generateCode] Response received...', + ) return result.choices[0].message.tool_calls[0].function.arguments }, @@ -78,7 +86,8 @@ export const copilotService = { description: 'The packages imported in the code snippet', items: { type: 'string', - description: 'The name of the package, e.g axios, lodash, etc.', + description: + 'The name of the package, e.g axios, lodash, etc.', }, }, }, @@ -109,38 +118,44 @@ You will use import to import any libraries you need. You will be penalized for }, { role: 'user', - content: 'I want code that will combine 2 arrays and only return the unique elements', + content: + 'I want code that will combine 2 arrays and only return the unique elements', }, { role: 'assistant', content: null, function_call: { name: 'generate_code', - arguments: '{ "code": "export const code = async (inputs) => {***NEW_LINE*** const combinedArray = [...inputs.array1, ...inputs.array2]***NEW_LINE*** const uniqueArray = Array.from(new Set(combinedArray))***NEW_LINE*** return uniqueArray***NEW_LINE***};", "inputs": [ { "key": "array1", "value": "[1,2,3]" }, { "key": "array2", "value": "[4,5,6]" } ], "packages": [] }', + arguments: + '{ "code": "export const code = async (inputs) => {***NEW_LINE*** const combinedArray = [...inputs.array1, ...inputs.array2]***NEW_LINE*** const uniqueArray = Array.from(new Set(combinedArray))***NEW_LINE*** return uniqueArray***NEW_LINE***};", "inputs": [ { "key": "array1", "value": "[1,2,3]" }, { "key": "array2", "value": "[4,5,6]" } ], "packages": [] }', }, }, { role: 'user', - content: 'Write me a piece of code that splits the user\'s first name from his last name in a full name string received in inputs.', + content: + 'Write me a piece of code that splits the user\'s first name from his last name in a full name string received in inputs.', }, { role: 'assistant', content: null, function_call: { name: 'generate_code', - arguments: '{ "code": "export const code = async (inputs) => {***NEW_LINE*** const nameParts = inputs.fullName.split(\' \')***NEW_LINE*** const firstName = nameParts[0]***NEW_LINE*** const lastName = nameParts.slice(1).join(\'\')***NEW_LINE*** return { firstName, lastName }***NEW_LINE***};", "inputs": [ { "key": "fullName","value": "John Doe" } ], "packages": [] }', + arguments: + '{ "code": "export const code = async (inputs) => {***NEW_LINE*** const nameParts = inputs.fullName.split(\' \')***NEW_LINE*** const firstName = nameParts[0]***NEW_LINE*** const lastName = nameParts.slice(1).join(\'\')***NEW_LINE*** return { firstName, lastName }***NEW_LINE***};", "inputs": [ { "key": "fullName","value": "John Doe" } ], "packages": [] }', }, }, { role: 'user', - content: 'from an array of objects, take the created_at property for each object and print it as an ISO string', + content: + 'from an array of objects, take the created_at property for each object and print it as an ISO string', }, { role: 'assistant', content: null, function_call: { - 'name': 'generate_code', - 'arguments': '{ "code": "export const code = async (inputs) => {***NEW_LINE*** const isoStrings = inputs.array.map(obj => new Date(obj.created_at).toISOString())***NEW_LINE*** return isoStrings;***NEW_LINE***};", "inputs": [ { "key": "array","value": "[{ "created_at": "2022-01-14T12:34:56Z" }, { "created_at": "2022-01-15T09:45:30Z" } ]" } ], "packages": [] }', + name: 'generate_code', + arguments: + '{ "code": "export const code = async (inputs) => {***NEW_LINE*** const isoStrings = inputs.array.map(obj => new Date(obj.created_at).toISOString())***NEW_LINE*** return isoStrings;***NEW_LINE***};", "inputs": [ { "key": "array","value": "[{ "created_at": "2022-01-14T12:34:56Z" }, { "created_at": "2022-01-15T09:45:30Z" } ]" } ], "packages": [] }', }, }, { @@ -152,7 +167,8 @@ You will use import to import any libraries you need. You will be penalized for content: null, function_call: { name: 'generate_code', - arguments: '{ "code": "export const code = async (inputs) => {***NEW_LINE*** return \'Hi\'***NEW_LINE***};", "inputs": [], "packages": [] }', + arguments: + '{ "code": "export const code = async (inputs) => {***NEW_LINE*** return \'Hi\'***NEW_LINE***};", "inputs": [], "packages": [] }', }, }, { @@ -164,19 +180,22 @@ You will use import to import any libraries you need. You will be penalized for content: null, function_call: { name: 'generate_code', - arguments: '{ "code": "export const code = async (inputs) => {***NEW_LINE*** return \'How are you?\'***NEW_LINE***};", "inputs": [], "packages": [] }', + arguments: + '{ "code": "export const code = async (inputs) => {***NEW_LINE*** return \'How are you?\'***NEW_LINE***};", "inputs": [], "packages": [] }', }, }, { role: 'user', - content: 'Using axios, send a GET request to https://cloud.activepieces.com/api/v1/pieces', + content: + 'Using axios, send a GET request to https://cloud.activepieces.com/api/v1/pieces', }, { role: 'assistant', content: null, function_call: { name: 'generate_code', - arguments: '{ "code": "import axios from \'axios\'***NEW_LINE***export const code = async (inputs) => {***NEW_LINE*** const response = await axios.get(\'https://cloud.activepieces.com/api/v1/pieces\');***NEW_LINE*** return response.data;***NEW_LINE***};", "inputs": [], "packages": ["axios"] }', + arguments: + '{ "code": "import axios from \'axios\'***NEW_LINE***export const code = async (inputs) => {***NEW_LINE*** const response = await axios.get(\'https://cloud.activepieces.com/api/v1/pieces\');***NEW_LINE*** return response.data;***NEW_LINE***};", "inputs": [], "packages": ["axios"] }', }, }, ] diff --git a/packages/backend/src/app/core/db/repo-factory.ts b/packages/server/api/src/app/core/db/repo-factory.ts similarity index 64% rename from packages/backend/src/app/core/db/repo-factory.ts rename to packages/server/api/src/app/core/db/repo-factory.ts index c8a2c158f7..162a37bedd 100644 --- a/packages/backend/src/app/core/db/repo-factory.ts +++ b/packages/server/api/src/app/core/db/repo-factory.ts @@ -1,11 +1,18 @@ -import { Repository, EntityManager, ObjectLiteral, EntitySchema } from 'typeorm' +import { + Repository, + EntityManager, + ObjectLiteral, + EntitySchema, +} from 'typeorm' import { databaseConnection } from '../../database/database-connection' /** * If given an {@link EntityManager}, returns a {@link Repository} for the current transaction. * Otherwise, returns the {@link Repository} for the default connection. */ -type RepoGetter = (entityManager?: EntityManager) => Repository +type RepoGetter = ( + entityManager?: EntityManager +) => Repository const instances = new Map() @@ -14,14 +21,18 @@ const instances = new Map() * @param entity The entity to create a {@link RepoGetter} for. * @returns A {@link RepoGetter} for the given entity. */ -export const repoFactory = (entity: EntitySchema): RepoGetter => { +export const repoFactory = ( + entity: EntitySchema, +): RepoGetter => { if (instances.has(entity)) { return instances.get(entity) as RepoGetter } const newInstance: RepoGetter = (entityManager?: EntityManager) => { - return entityManager?.getRepository(entity) - ?? databaseConnection.getRepository(entity) + return ( + entityManager?.getRepository(entity) ?? + databaseConnection.getRepository(entity) + ) } instances.set(entity, newInstance as RepoGetter) diff --git a/packages/backend/src/app/core/db/transaction.ts b/packages/server/api/src/app/core/db/transaction.ts similarity index 58% rename from packages/backend/src/app/core/db/transaction.ts rename to packages/server/api/src/app/core/db/transaction.ts index 1dabf03ac0..529f3f903c 100644 --- a/packages/backend/src/app/core/db/transaction.ts +++ b/packages/server/api/src/app/core/db/transaction.ts @@ -1,6 +1,8 @@ import { EntityManager } from 'typeorm' import { databaseConnection } from '../../database/database-connection' -export const transaction = async (operation: (entityManager: EntityManager) => Promise): Promise => { +export const transaction = async ( + operation: (entityManager: EntityManager) => Promise, +): Promise => { return databaseConnection.transaction(operation) } diff --git a/packages/backend/src/app/core/request/request-utils.ts b/packages/server/api/src/app/core/request/request-utils.ts similarity index 100% rename from packages/backend/src/app/core/request/request-utils.ts rename to packages/server/api/src/app/core/request/request-utils.ts diff --git a/packages/backend/src/app/core/security/authn/access-token-authn-handler.ts b/packages/server/api/src/app/core/security/authn/access-token-authn-handler.ts similarity index 100% rename from packages/backend/src/app/core/security/authn/access-token-authn-handler.ts rename to packages/server/api/src/app/core/security/authn/access-token-authn-handler.ts diff --git a/packages/backend/src/app/core/security/authn/anonymous-authn-handler.ts b/packages/server/api/src/app/core/security/authn/anonymous-authn-handler.ts similarity index 78% rename from packages/backend/src/app/core/security/authn/anonymous-authn-handler.ts rename to packages/server/api/src/app/core/security/authn/anonymous-authn-handler.ts index 4038537ad5..9a98d824d4 100644 --- a/packages/backend/src/app/core/security/authn/anonymous-authn-handler.ts +++ b/packages/server/api/src/app/core/security/authn/anonymous-authn-handler.ts @@ -1,6 +1,12 @@ import { FastifyRequest } from 'fastify' import { BaseSecurityHandler } from '../security-handler' -import { Principal, PrincipalType, ProjectType, apId, isNil } from '@activepieces/shared' +import { + Principal, + PrincipalType, + ProjectType, + apId, + isNil, +} from '@activepieces/shared' export class AnonymousAuthnHandler extends BaseSecurityHandler { protected canHandle(_request: FastifyRequest): Promise { @@ -8,7 +14,7 @@ export class AnonymousAuthnHandler extends BaseSecurityHandler { } protected doHandle(request: FastifyRequest): Promise { - const principal = request.principal as (Principal | undefined) + const principal = request.principal as Principal | undefined if (isNil(principal)) { request.principal = { diff --git a/packages/backend/src/app/core/security/authn/app-sumo-authn-handler.ts b/packages/server/api/src/app/core/security/authn/app-sumo-authn-handler.ts similarity index 100% rename from packages/backend/src/app/core/security/authn/app-sumo-authn-handler.ts rename to packages/server/api/src/app/core/security/authn/app-sumo-authn-handler.ts diff --git a/packages/backend/src/app/core/security/authn/global-api-key-authn-handler.ts b/packages/server/api/src/app/core/security/authn/global-api-key-authn-handler.ts similarity index 77% rename from packages/backend/src/app/core/security/authn/global-api-key-authn-handler.ts rename to packages/server/api/src/app/core/security/authn/global-api-key-authn-handler.ts index a26d2caedc..79b6d7cb10 100644 --- a/packages/backend/src/app/core/security/authn/global-api-key-authn-handler.ts +++ b/packages/server/api/src/app/core/security/authn/global-api-key-authn-handler.ts @@ -1,15 +1,21 @@ import { FastifyRequest } from 'fastify' import { BaseSecurityHandler } from '../security-handler' -import { system } from '../../../helper/system/system' -import { SystemProp } from '../../../helper/system/system-prop' -import { ActivepiecesError, ErrorCode, PrincipalType, apId, isNil } from '@activepieces/shared' +import { SystemProp, system } from 'server-shared' +import { + ActivepiecesError, + ErrorCode, + PrincipalType, + apId, + isNil, +} from '@activepieces/shared' export class GlobalApiKeyAuthnHandler extends BaseSecurityHandler { private static readonly HEADER_NAME = 'api-key' private static readonly API_KEY = system.get(SystemProp.API_KEY) protected canHandle(request: FastifyRequest): Promise { - const routeMatches = request.headers[GlobalApiKeyAuthnHandler.HEADER_NAME] !== undefined + const routeMatches = + request.headers[GlobalApiKeyAuthnHandler.HEADER_NAME] !== undefined return Promise.resolve(routeMatches) } diff --git a/packages/backend/src/app/core/security/authn/platform-api-key-authn-handler.ts b/packages/server/api/src/app/core/security/authn/platform-api-key-authn-handler.ts similarity index 77% rename from packages/backend/src/app/core/security/authn/platform-api-key-authn-handler.ts rename to packages/server/api/src/app/core/security/authn/platform-api-key-authn-handler.ts index 76e7877a52..f0a0cd9112 100644 --- a/packages/backend/src/app/core/security/authn/platform-api-key-authn-handler.ts +++ b/packages/server/api/src/app/core/security/authn/platform-api-key-authn-handler.ts @@ -1,6 +1,18 @@ import { FastifyRequest } from 'fastify' import { BaseSecurityHandler } from '../security-handler' -import { ActivepiecesError, EndpointScope, ErrorCode, PlatformRole, Principal, PrincipalType, Project, ProjectId, ProjectType, isNil, isObject } from '@activepieces/shared' +import { + ActivepiecesError, + EndpointScope, + ErrorCode, + PlatformRole, + Principal, + PrincipalType, + Project, + ProjectId, + ProjectType, + isNil, + isObject, +} from '@activepieces/shared' import { apiKeyService } from '../../../ee/api-keys/api-key-service' import { nanoid } from 'nanoid' import { ApiKey } from '@activepieces/ee-shared' @@ -19,7 +31,10 @@ export class PlatformApiKeyAuthnHandler extends BaseSecurityHandler { protected canHandle(request: FastifyRequest): Promise { const prefix = `${PlatformApiKeyAuthnHandler.HEADER_PREFIX}${PlatformApiKeyAuthnHandler.API_KEY_PREFIX}` - const routeMatches = request.headers[PlatformApiKeyAuthnHandler.HEADER_NAME]?.startsWith(prefix) ?? false + const routeMatches = + request.headers[PlatformApiKeyAuthnHandler.HEADER_NAME]?.startsWith( + prefix, + ) ?? false return Promise.resolve(routeMatches) } @@ -47,7 +62,10 @@ export class PlatformApiKeyAuthnHandler extends BaseSecurityHandler { return apiKeyValue } - private async createPrincipal(request: FastifyRequest, apiKey: ApiKey): Promise { + private async createPrincipal( + request: FastifyRequest, + apiKey: ApiKey, + ): Promise { const principal: Principal = { id: apiKey.id, type: PrincipalType.SERVICE, @@ -82,9 +100,12 @@ export class PlatformApiKeyAuthnHandler extends BaseSecurityHandler { } } - private async extractProjectIdOrThrow(request: FastifyRequest): Promise { - const projectId = requestUtils.extractProjectId(request) ?? - await this.extractProjectIdFromResource(request) + private async extractProjectIdOrThrow( + request: FastifyRequest, + ): Promise { + const projectId = + requestUtils.extractProjectId(request) ?? + (await this.extractProjectIdFromResource(request)) if (isNil(projectId)) { throw new ActivepiecesError({ @@ -98,12 +119,14 @@ export class PlatformApiKeyAuthnHandler extends BaseSecurityHandler { return projectId } - private async extractProjectIdFromResource(request: FastifyRequest): Promise { + private async extractProjectIdFromResource( + request: FastifyRequest, + ): Promise { const oneResourceRoute = - request.routerPath.includes(':id') && - isObject(request.params) && - 'id' in request.params && - typeof request.params.id === 'string' + request.routerPath.includes(':id') && + isObject(request.params) && + 'id' in request.params && + typeof request.params.id === 'string' if (!oneResourceRoute) { return undefined @@ -114,7 +137,10 @@ export class PlatformApiKeyAuthnHandler extends BaseSecurityHandler { return this.getProjectIdFromResource(resourceName, id) } - private async getProjectIdFromResource(resource: string | undefined, id: string): Promise { + private async getProjectIdFromResource( + resource: string | undefined, + id: string, + ): Promise { const tableName = this.getTableNameFromResource(resource) if (isNil(tableName)) { return undefined @@ -125,7 +151,9 @@ export class PlatformApiKeyAuthnHandler extends BaseSecurityHandler { return entity?.projectId } - private getTableNameFromResource(resource: string | undefined): string | undefined { + private getTableNameFromResource( + resource: string | undefined, + ): string | undefined { if (isNil(resource)) { return undefined } @@ -140,7 +168,10 @@ export class PlatformApiKeyAuthnHandler extends BaseSecurityHandler { return undefined } - private assertApiKeyAndProjectBelongToSamePlatform(project: Project, apiKey: ApiKey): void { + private assertApiKeyAndProjectBelongToSamePlatform( + project: Project, + apiKey: ApiKey, + ): void { if (project.platformId !== apiKey.platformId) { throw new ActivepiecesError({ code: ErrorCode.AUTHORIZATION, diff --git a/packages/backend/src/app/core/security/authz/principal-type-authz-handler.ts b/packages/server/api/src/app/core/security/authz/principal-type-authz-handler.ts similarity index 79% rename from packages/backend/src/app/core/security/authz/principal-type-authz-handler.ts rename to packages/server/api/src/app/core/security/authz/principal-type-authz-handler.ts index 7ca4ddbb3b..f6862d02a0 100644 --- a/packages/backend/src/app/core/security/authz/principal-type-authz-handler.ts +++ b/packages/server/api/src/app/core/security/authz/principal-type-authz-handler.ts @@ -1,6 +1,10 @@ import { FastifyRequest } from 'fastify' import { BaseSecurityHandler } from '../security-handler' -import { ActivepiecesError, ErrorCode, PrincipalType } from '@activepieces/shared' +import { + ActivepiecesError, + ErrorCode, + PrincipalType, +} from '@activepieces/shared' export class PrincipalTypeAuthzHandler extends BaseSecurityHandler { private static readonly IGNORED_ROUTES = [ @@ -17,8 +21,8 @@ export class PrincipalTypeAuthzHandler extends BaseSecurityHandler { protected canHandle(request: FastifyRequest): Promise { const requestMatches = - !PrincipalTypeAuthzHandler.IGNORED_ROUTES.includes(request.routerPath) && - !request.routerPath.startsWith('/ui') + !PrincipalTypeAuthzHandler.IGNORED_ROUTES.includes(request.routerPath) && + !request.routerPath.startsWith('/ui') return Promise.resolve(requestMatches) } @@ -26,7 +30,8 @@ export class PrincipalTypeAuthzHandler extends BaseSecurityHandler { protected doHandle(request: FastifyRequest): Promise { const principalType = request.principal.type const configuredPrincipals = request.routeConfig.allowedPrincipals - const defaultPrincipals = PrincipalTypeAuthzHandler.DEFAULT_ALLOWED_PRINCIPAL_TYPES + const defaultPrincipals = + PrincipalTypeAuthzHandler.DEFAULT_ALLOWED_PRINCIPAL_TYPES const allowedPrincipals = configuredPrincipals ?? defaultPrincipals const principalTypeNotAllowed = !allowedPrincipals.includes(principalType) diff --git a/packages/backend/src/app/core/security/authz/project-authz-handler.ts b/packages/server/api/src/app/core/security/authz/project-authz-handler.ts similarity index 95% rename from packages/backend/src/app/core/security/authz/project-authz-handler.ts rename to packages/server/api/src/app/core/security/authz/project-authz-handler.ts index 8b8bb263b5..7b31c8ffce 100644 --- a/packages/backend/src/app/core/security/authz/project-authz-handler.ts +++ b/packages/server/api/src/app/core/security/authz/project-authz-handler.ts @@ -16,7 +16,9 @@ export class ProjectAuthzHandler extends BaseSecurityHandler { ] protected canHandle(request: FastifyRequest): Promise { - const requestMatches = !ProjectAuthzHandler.IGNORED_ROUTES.includes(request.routerPath) + const requestMatches = !ProjectAuthzHandler.IGNORED_ROUTES.includes( + request.routerPath, + ) return Promise.resolve(requestMatches) } diff --git a/packages/backend/src/app/core/security/rate-limit.ts b/packages/server/api/src/app/core/security/rate-limit.ts similarity index 52% rename from packages/backend/src/app/core/security/rate-limit.ts rename to packages/server/api/src/app/core/security/rate-limit.ts index 3ab1b13012..763e75e11a 100644 --- a/packages/backend/src/app/core/security/rate-limit.ts +++ b/packages/server/api/src/app/core/security/rate-limit.ts @@ -3,24 +3,28 @@ import { FastifyPluginAsyncTypebox } from '@fastify/type-provider-typebox' import FastifyPlugin from 'fastify-plugin' import { Redis } from 'ioredis' import { createRedisClient } from '../../database/redis-connection' -import { QueueMode, system } from '../../helper/system/system' -import { SystemProp } from '../../helper/system/system-prop' +import { QueueMode, SystemProp, system } from 'server-shared' import { extractClientRealIp } from '../../helper/network-utils' -const API_RATE_LIMIT_AUTHN_ENABLED = system.getBoolean(SystemProp.API_RATE_LIMIT_AUTHN_ENABLED) +const API_RATE_LIMIT_AUTHN_ENABLED = system.getBoolean( + SystemProp.API_RATE_LIMIT_AUTHN_ENABLED, +) -export const rateLimitModule: FastifyPluginAsyncTypebox = FastifyPlugin(async (app) => { - if (API_RATE_LIMIT_AUTHN_ENABLED) { - await app.register(RateLimitPlugin, { - global: false, - keyGenerator: extractClientRealIp, - redis: getRedisClient(), - }) - } -}) +export const rateLimitModule: FastifyPluginAsyncTypebox = FastifyPlugin( + async (app) => { + if (API_RATE_LIMIT_AUTHN_ENABLED) { + await app.register(RateLimitPlugin, { + global: false, + keyGenerator: extractClientRealIp, + redis: getRedisClient(), + }) + } + }, +) const getRedisClient = (): Redis | undefined => { - const redisIsNotConfigured = system.get(SystemProp.QUEUE_MODE) !== QueueMode.REDIS + const redisIsNotConfigured = + system.get(SystemProp.QUEUE_MODE) !== QueueMode.REDIS if (redisIsNotConfigured) { return undefined diff --git a/packages/backend/src/app/core/security/security-handler-chain.ts b/packages/server/api/src/app/core/security/security-handler-chain.ts similarity index 91% rename from packages/backend/src/app/core/security/security-handler-chain.ts rename to packages/server/api/src/app/core/security/security-handler-chain.ts index c0b9dd4270..6ee674c243 100644 --- a/packages/backend/src/app/core/security/security-handler-chain.ts +++ b/packages/server/api/src/app/core/security/security-handler-chain.ts @@ -21,7 +21,9 @@ const AUTHZ_HANDLERS = [ new ProjectAuthzHandler(), ] -export const securityHandlerChain = async (request: FastifyRequest): Promise => { +export const securityHandlerChain = async ( + request: FastifyRequest, +): Promise => { await executeAuthnHandlers(request) await executeAuthzHandlers(request) } @@ -48,6 +50,6 @@ const executeAuthzHandlers = async (request: FastifyRequest): Promise => { } const checkWhetherPrincipalIsPopulated = (request: FastifyRequest): boolean => { - const principal = request.principal as (Principal | undefined) + const principal = request.principal as Principal | undefined return principal !== undefined } diff --git a/packages/backend/src/app/core/security/security-handler.ts b/packages/server/api/src/app/core/security/security-handler.ts similarity index 100% rename from packages/backend/src/app/core/security/security-handler.ts rename to packages/server/api/src/app/core/security/security-handler.ts diff --git a/packages/backend/src/app/database/database-common.ts b/packages/server/api/src/app/database/database-common.ts old mode 100755 new mode 100644 similarity index 91% rename from packages/backend/src/app/database/database-common.ts rename to packages/server/api/src/app/database/database-common.ts index 142877498d..4237bd5f62 --- a/packages/backend/src/app/database/database-common.ts +++ b/packages/server/api/src/app/database/database-common.ts @@ -1,6 +1,5 @@ import { EntitySchemaColumnOptions } from 'typeorm' -import { DatabaseType, system } from '../helper/system/system' -import { SystemProp } from '../helper/system/system-prop' +import { DatabaseType, SystemProp, system } from 'server-shared' const databaseType = system.get(SystemProp.DB_TYPE) diff --git a/packages/backend/src/app/database/database-connection.ts b/packages/server/api/src/app/database/database-connection.ts old mode 100755 new mode 100644 similarity index 90% rename from packages/backend/src/app/database/database-connection.ts rename to packages/server/api/src/app/database/database-connection.ts index a2ec503870..e958544a05 --- a/packages/backend/src/app/database/database-connection.ts +++ b/packages/server/api/src/app/database/database-connection.ts @@ -19,9 +19,13 @@ import { AppSumoEntity } from '../ee/appsumo/appsumo.entity' import { ReferralEntity } from '../ee/referrals/referral.entity' import { createPostgresDataSource } from './postgres-connection' import { createSqlLiteDataSource } from './sqlite-connection' -import { DatabaseType, system } from '../helper/system/system' -import { SystemProp } from '../helper/system/system-prop' -import { ArrayContains, EntitySchema, ObjectLiteral, SelectQueryBuilder } from 'typeorm' +import { DatabaseType, SystemProp, system } from 'server-shared' +import { + ArrayContains, + EntitySchema, + ObjectLiteral, + SelectQueryBuilder, +} from 'typeorm' import { StepFileEntity } from '../flows/step-file/step-file.entity' import { ProjectUsageEntity } from '../ee/billing/project-usage/project-usage.entity' import { ProjectMemberEntity } from '../ee/project-members/project-member.entity' @@ -123,11 +127,15 @@ export const commonProperties = { } export const databaseConnection = - databaseType === DatabaseType.SQLITE3 - ? createSqlLiteDataSource() - : createPostgresDataSource() + databaseType === DatabaseType.SQLITE3 + ? createSqlLiteDataSource() + : createPostgresDataSource() -export function APArrayContains(columnName: string, values: string[], query: SelectQueryBuilder): SelectQueryBuilder { +export function APArrayContains( + columnName: string, + values: string[], + query: SelectQueryBuilder, +): SelectQueryBuilder { const databaseType = system.get(SystemProp.DB_TYPE) switch (databaseType) { case DatabaseType.POSTGRES: @@ -135,7 +143,9 @@ export function APArrayContains(columnName: string, val [columnName]: ArrayContains(values), }) case DatabaseType.SQLITE3: { - const likeConditions = values.map((tag, index) => `flow_run.tags LIKE :tag${index}`).join(' AND ') + const likeConditions = values + .map((tag, index) => `flow_run.tags LIKE :tag${index}`) + .join(' AND ') const likeParams = values.reduce((params, tag, index) => { return { ...params, diff --git a/packages/backend/src/app/database/migration/common/1696245170061-add-piece-type-and-package-type-to-flow-version.ts b/packages/server/api/src/app/database/migration/common/1696245170061-add-piece-type-and-package-type-to-flow-version.ts similarity index 52% rename from packages/backend/src/app/database/migration/common/1696245170061-add-piece-type-and-package-type-to-flow-version.ts rename to packages/server/api/src/app/database/migration/common/1696245170061-add-piece-type-and-package-type-to-flow-version.ts index b29d8f6c28..c11a2d32a3 100644 --- a/packages/backend/src/app/database/migration/common/1696245170061-add-piece-type-and-package-type-to-flow-version.ts +++ b/packages/server/api/src/app/database/migration/common/1696245170061-add-piece-type-and-package-type-to-flow-version.ts @@ -1,27 +1,44 @@ import { MigrationInterface, QueryRunner } from 'typeorm' -import { logger } from '../../../helper/logger' +import { logger } from 'server-shared' -export class AddPieceTypeAndPackageTypeToFlowVersion1696245170061 implements MigrationInterface { +export class AddPieceTypeAndPackageTypeToFlowVersion1696245170061 +implements MigrationInterface { public async up(queryRunner: QueryRunner): Promise { - // Execute raw SQL query to fetch IDs of FlowVersion records - const flowVersionIds = await queryRunner.query('SELECT id FROM flow_version') - logger.info('AddPieceTypeAndPackageTypeToFlowVersion1696245170061: found ' + flowVersionIds.length + ' versions') + // Execute raw SQL query to fetch IDs of FlowVersion records + const flowVersionIds = await queryRunner.query( + 'SELECT id FROM flow_version', + ) + logger.info( + 'AddPieceTypeAndPackageTypeToFlowVersion1696245170061: found ' + + flowVersionIds.length + + ' versions', + ) let updatedFlows = 0 for (const { id } of flowVersionIds) { // Fetch FlowVersion record by ID - const flowVersion = await queryRunner.query('SELECT * FROM flow_version WHERE id = $1', [id]) + const flowVersion = await queryRunner.query( + 'SELECT * FROM flow_version WHERE id = $1', + [id], + ) if (flowVersion.length > 0) { const updated = traverseAndUpdateSubFlow( addPackageTypeAndPieceTypeToPieceStepSettings, flowVersion[0].trigger, ) if (updated) { - await queryRunner.query('UPDATE flow_version SET trigger = $1 WHERE id = $2', [flowVersion[0].trigger, flowVersion[0].id]) + await queryRunner.query( + 'UPDATE flow_version SET trigger = $1 WHERE id = $2', + [flowVersion[0].trigger, flowVersion[0].id], + ) } } updatedFlows++ if (updatedFlows % 100 === 0) { - logger.info('AddPieceTypeAndPackageTypeToFlowVersion1696245170061: ' + updatedFlows + ' flows updated') + logger.info( + 'AddPieceTypeAndPackageTypeToFlowVersion1696245170061: ' + + updatedFlows + + ' flows updated', + ) } } @@ -29,11 +46,16 @@ export class AddPieceTypeAndPackageTypeToFlowVersion1696245170061 implements Mig } public async down(queryRunner: QueryRunner): Promise { - // Execute raw SQL query to fetch IDs of FlowVersion records - const flowVersionIds = await queryRunner.query('SELECT id FROM flow_version') + // Execute raw SQL query to fetch IDs of FlowVersion records + const flowVersionIds = await queryRunner.query( + 'SELECT id FROM flow_version', + ) for (const { id } of flowVersionIds) { // Fetch FlowVersion record by ID - const flowVersion = await queryRunner.query('SELECT * FROM flow_version WHERE id = $1', [id]) + const flowVersion = await queryRunner.query( + 'SELECT * FROM flow_version WHERE id = $1', + [id], + ) if (flowVersion.length > 0) { const updated = traverseAndUpdateSubFlow( @@ -41,7 +63,10 @@ export class AddPieceTypeAndPackageTypeToFlowVersion1696245170061 implements Mig flowVersion[0].trigger, ) if (updated) { - await queryRunner.query('UPDATE flow_version SET trigger = $1 WHERE id = $2', [flowVersion[0].trigger, flowVersion[0].id]) + await queryRunner.query( + 'UPDATE flow_version SET trigger = $1 WHERE id = $2', + [flowVersion[0].trigger, flowVersion[0].id], + ) } } } @@ -50,7 +75,10 @@ export class AddPieceTypeAndPackageTypeToFlowVersion1696245170061 implements Mig } } -const traverseAndUpdateSubFlow = (updater: (s: PieceStep) => void, root?: Step): boolean => { +const traverseAndUpdateSubFlow = ( + updater: (s: PieceStep) => void, + root?: Step, +): boolean => { if (!root) { return false } @@ -59,11 +87,14 @@ const traverseAndUpdateSubFlow = (updater: (s: PieceStep) => void, root?: Step): switch (root.type) { case 'BRANCH': - updated = traverseAndUpdateSubFlow(updater, root.onSuccessAction) || updated - updated = traverseAndUpdateSubFlow(updater, root.onFailureAction) || updated + updated = + traverseAndUpdateSubFlow(updater, root.onSuccessAction) || updated + updated = + traverseAndUpdateSubFlow(updater, root.onFailureAction) || updated break case 'LOOP_ON_ITEMS': - updated = traverseAndUpdateSubFlow(updater, root.firstLoopAction) || updated + updated = + traverseAndUpdateSubFlow(updater, root.firstLoopAction) || updated break case 'PIECE': case 'PIECE_TRIGGER': @@ -78,25 +109,29 @@ const traverseAndUpdateSubFlow = (updater: (s: PieceStep) => void, root?: Step): return updated } -const addPackageTypeAndPieceTypeToPieceStepSettings = (pieceStep: PieceStep): void => { +const addPackageTypeAndPieceTypeToPieceStepSettings = ( + pieceStep: PieceStep, +): void => { pieceStep.settings.packageType = 'REGISTRY' pieceStep.settings.pieceType = 'OFFICIAL' } -const removePackageTypeAndPieceTypeFromPieceStepSettings = (pieceStep: PieceStep): void => { +const removePackageTypeAndPieceTypeFromPieceStepSettings = ( + pieceStep: PieceStep, +): void => { delete pieceStep.settings.packageType delete pieceStep.settings.pieceType } type StepType = - | 'BRANCH' - | 'CODE' - | 'EMPTY' - | 'LOOP_ON_ITEMS' - | 'MISSING' - | 'PIECE' - | 'PIECE_TRIGGER' - | 'WEBHOOK' + | 'BRANCH' + | 'CODE' + | 'EMPTY' + | 'LOOP_ON_ITEMS' + | 'MISSING' + | 'PIECE' + | 'PIECE_TRIGGER' + | 'WEBHOOK' type BaseStep = { type: T @@ -121,8 +156,4 @@ type PieceStep = BaseStep<'PIECE' | 'PIECE_TRIGGER'> & { type GenericStep = BaseStep<'CODE' | 'EMPTY' | 'MISSING' | 'WEBHOOK'> -type Step = - | BranchStep - | LoopOnItemsStep - | GenericStep - | PieceStep +type Step = BranchStep | LoopOnItemsStep | GenericStep | PieceStep diff --git a/packages/backend/src/app/database/migration/common/1696245170062-add-piece-type-and-package-type-to-flow-template.ts b/packages/server/api/src/app/database/migration/common/1696245170062-add-piece-type-and-package-type-to-flow-template.ts similarity index 65% rename from packages/backend/src/app/database/migration/common/1696245170062-add-piece-type-and-package-type-to-flow-template.ts rename to packages/server/api/src/app/database/migration/common/1696245170062-add-piece-type-and-package-type-to-flow-template.ts index fc6d754297..91a05753d3 100644 --- a/packages/backend/src/app/database/migration/common/1696245170062-add-piece-type-and-package-type-to-flow-template.ts +++ b/packages/server/api/src/app/database/migration/common/1696245170062-add-piece-type-and-package-type-to-flow-template.ts @@ -1,7 +1,7 @@ import { MigrationInterface, QueryRunner } from 'typeorm' -import { logger } from '../../../helper/logger' - -export class AddPieceTypeAndPackageTypeToFlowTemplate1696245170062 implements MigrationInterface { +import { logger } from 'server-shared' +export class AddPieceTypeAndPackageTypeToFlowTemplate1696245170062 +implements MigrationInterface { public async up(queryRunner: QueryRunner): Promise { const connection = queryRunner.connection const templates = await connection.query('SELECT * FROM flow_template') @@ -11,7 +11,10 @@ export class AddPieceTypeAndPackageTypeToFlowTemplate1696245170062 implements Mi template.template.trigger, ) if (updated) { - await connection.query('UPDATE flow_template SET template = $1 WHERE id = $2', [template.template, template.id]) + await connection.query( + 'UPDATE flow_template SET template = $1 WHERE id = $2', + [template.template, template.id], + ) } } logger.info('AddPieceTypeAndPackageTypeToFlowTemplate1696245170062: up') @@ -26,14 +29,20 @@ export class AddPieceTypeAndPackageTypeToFlowTemplate1696245170062 implements Mi template.template.trigger, ) if (updated) { - await connection.query('UPDATE flow_template SET template = $1 WHERE id = $2', [template.template, template.id]) + await connection.query( + 'UPDATE flow_template SET template = $1 WHERE id = $2', + [template.template, template.id], + ) } } logger.info('AddPieceTypeAndPackageTypeToFlowTemplate1696245170062: down') } } -const traverseAndUpdateSubFlow = (updater: (s: PieceStep) => void, root?: Step): boolean => { +const traverseAndUpdateSubFlow = ( + updater: (s: PieceStep) => void, + root?: Step, +): boolean => { if (!root) { return false } @@ -42,11 +51,14 @@ const traverseAndUpdateSubFlow = (updater: (s: PieceStep) => void, root?: Step): switch (root.type) { case 'BRANCH': - updated = traverseAndUpdateSubFlow(updater, root.onSuccessAction) || updated - updated = traverseAndUpdateSubFlow(updater, root.onFailureAction) || updated + updated = + traverseAndUpdateSubFlow(updater, root.onSuccessAction) || updated + updated = + traverseAndUpdateSubFlow(updater, root.onFailureAction) || updated break case 'LOOP_ON_ITEMS': - updated = traverseAndUpdateSubFlow(updater, root.firstLoopAction) || updated + updated = + traverseAndUpdateSubFlow(updater, root.firstLoopAction) || updated break case 'PIECE': case 'PIECE_TRIGGER': @@ -61,25 +73,29 @@ const traverseAndUpdateSubFlow = (updater: (s: PieceStep) => void, root?: Step): return updated } -const addPackageTypeAndPieceTypeToPieceStepSettings = (pieceStep: PieceStep): void => { +const addPackageTypeAndPieceTypeToPieceStepSettings = ( + pieceStep: PieceStep, +): void => { pieceStep.settings.packageType = 'REGISTRY' pieceStep.settings.pieceType = 'OFFICIAL' } -const removePackageTypeAndPieceTypeFromPieceStepSettings = (pieceStep: PieceStep): void => { +const removePackageTypeAndPieceTypeFromPieceStepSettings = ( + pieceStep: PieceStep, +): void => { delete pieceStep.settings.packageType delete pieceStep.settings.pieceType } type StepType = - | 'BRANCH' - | 'CODE' - | 'EMPTY' - | 'LOOP_ON_ITEMS' - | 'MISSING' - | 'PIECE' - | 'PIECE_TRIGGER' - | 'WEBHOOK' + | 'BRANCH' + | 'CODE' + | 'EMPTY' + | 'LOOP_ON_ITEMS' + | 'MISSING' + | 'PIECE' + | 'PIECE_TRIGGER' + | 'WEBHOOK' type BaseStep = { type: T @@ -104,8 +120,4 @@ type PieceStep = BaseStep<'PIECE' | 'PIECE_TRIGGER'> & { type GenericStep = BaseStep<'CODE' | 'EMPTY' | 'MISSING' | 'WEBHOOK'> -type Step = - | BranchStep - | LoopOnItemsStep - | GenericStep - | PieceStep +type Step = BranchStep | LoopOnItemsStep | GenericStep | PieceStep diff --git a/packages/server/api/src/app/database/migration/common/1697969398200-store-code-inside-flow.ts b/packages/server/api/src/app/database/migration/common/1697969398200-store-code-inside-flow.ts new file mode 100644 index 0000000000..fd3b60f518 --- /dev/null +++ b/packages/server/api/src/app/database/migration/common/1697969398200-store-code-inside-flow.ts @@ -0,0 +1,265 @@ +import { MigrationInterface, QueryRunner } from 'typeorm' +import { logger } from 'server-shared' +import { isNil } from '@activepieces/shared' +import decompress from 'decompress' + +type FunctionTransformer = ( + s: CodeStep, + fileRepo: QueryRunner, + flowId: string, + flowVersionId: string +) => Promise + +export class StoreCodeInsideFlow1697969398200 implements MigrationInterface { + public async up(queryRunner: QueryRunner): Promise { + await this.processFlowVersions(queryRunner, flattenCodeStep) + await this.processFlowTemplates(queryRunner, flattenCodeStep) + + logger.info('StoreCodeInsideFlow1697969398200: up finished') + } + + public async down(queryRunner: QueryRunner): Promise { + await this.processFlowVersions(queryRunner, removeNewCodeField) + await this.processFlowTemplates(queryRunner, removeNewCodeField) + + logger.info('StoreCodeInsideFlow1697969398200: down finished') + } + + private async processFlowVersions( + queryRunner: QueryRunner, + stepFunction: FunctionTransformer, + ) { + const flowVersionIds = await queryRunner.query( + 'SELECT id FROM flow_version', + ) + + for (const { id } of flowVersionIds) { + const flowVersion = await this.findFlowVersionById(queryRunner, id) + + if (flowVersion) { + const updated = await traverseAndUpdateSubFlow( + stepFunction, + flowVersion.trigger, + queryRunner, + flowVersion.flowId, + flowVersion.id, + ) + + if (updated) { + await this.updateFlowVersion( + queryRunner, + flowVersion.id, + flowVersion, + ) + } + } + } + } + + private async processFlowTemplates( + queryRunner: QueryRunner, + stepFunction: FunctionTransformer, + ) { + // Check if the "flow_template" table exists + const doesTableExist = await queryRunner.hasTable('flow_template') + + if (doesTableExist) { + logger.info( + 'StoreCodeInsideFlow1697969398200: flow template table exists', + ) + + const templates = await queryRunner.query('SELECT * FROM flow_template') + for (const template of templates) { + const updated = await traverseAndUpdateSubFlow( + stepFunction, + template.template.trigger, + queryRunner, + template.projectId, + template.id, + ) + + if (updated) { + await queryRunner.query( + 'UPDATE flow_template SET template = $1 WHERE id = $2', + [template.template, template.id], + ) + } + } + } + } + + private async findFlowVersionById( + queryRunner: QueryRunner, + id: string, + ): Promise { + const flowVersion = await queryRunner.query( + 'SELECT * FROM flow_version WHERE id = $1', + [id], + ) + return flowVersion[0] + } + + private async updateFlowVersion( + queryRunner: QueryRunner, + id: string, + flowVersion: FlowVersion, + ): Promise { + await queryRunner.query( + 'UPDATE flow_version SET "flowId" = $1, trigger = $2 WHERE id = $3', + [flowVersion.flowId, flowVersion.trigger, id], + ) + } +} + +const traverseAndUpdateSubFlow = async ( + updater: FunctionTransformer, + root: Step | undefined, + queryRunner: QueryRunner, + flowId: string, + flowVersionId: string, +): Promise => { + if (!root) { + return false + } + + let updated = false + + switch (root.type) { + case 'BRANCH': + updated = + (await traverseAndUpdateSubFlow( + updater, + root.onSuccessAction, + queryRunner, + flowId, + flowVersionId, + )) || updated + updated = + (await traverseAndUpdateSubFlow( + updater, + root.onFailureAction, + queryRunner, + flowId, + flowVersionId, + )) || updated + break + case 'LOOP_ON_ITEMS': + updated = + (await traverseAndUpdateSubFlow( + updater, + root.firstLoopAction, + queryRunner, + flowId, + flowVersionId, + )) || updated + break + case 'CODE': + await updater(root, queryRunner, flowId, flowVersionId) + updated = true + break + default: + break + } + + updated = + (await traverseAndUpdateSubFlow( + updater, + root.nextAction, + queryRunner, + flowId, + flowVersionId, + )) || updated + return updated +} + +const flattenCodeStep = async ( + codeStep: CodeStep, + queryRunner: QueryRunner, + flowVersionId: string, + flowId: string, +): Promise => { + const sourceCodeId = codeStep.settings.artifactSourceId + const sourceCode = codeStep.settings.sourceCode + if (!isNil(sourceCodeId) && isNil(sourceCode)) { + const [file] = await queryRunner.query('SELECT * FROM file WHERE id = $1', [ + sourceCodeId, + ]) + if (isNil(file)) { + logger.warn( + `StoreCodeInsideFlow1697969398100: file not found for file id ${sourceCodeId} in flow ${flowId} of flow version ${flowVersionId}`, + ) + return + } + const buffer = await decompress(file.data) + const code = buffer.find( + (f: { path: string | string[] }) => + f.path.includes('index.ts') || f.path.includes('index.js'), + ) + const packageJson = buffer.find((f: { path: string | string[] }) => + f.path.includes('package.json'), + ) + if (isNil(code) || isNil(packageJson)) { + logger.warn( + `StoreCodeInsideFlow1697969398100: code or package.json not found for file ${file.id} in flow ${flowId} of flow version ${flowVersionId}`, + ) + return + } + codeStep.settings.sourceCode = { + code: code.data.toString('utf-8'), + packageJson: packageJson.data.toString('utf-8'), + } + } +} + +const removeNewCodeField = async ( + codeStep: CodeStep, + _queryRunner: QueryRunner, +): Promise => { + delete codeStep.settings.sourceCode +} + +type StepType = + | 'BRANCH' + | 'CODE' + | 'EMPTY' + | 'LOOP_ON_ITEMS' + | 'MISSING' + | 'PIECE' + | 'PIECE_TRIGGER' + | 'WEBHOOK' + +type BaseStep = { + type: T + nextAction?: Step +} + +type BranchStep = BaseStep<'BRANCH'> & { + onFailureAction?: Step + onSuccessAction?: Step +} + +type LoopOnItemsStep = BaseStep<'LOOP_ON_ITEMS'> & { + firstLoopAction?: Step +} + +type CodeStep = BaseStep<'CODE'> & { + settings: { + artifactSourceId: string + sourceCode?: { + code: string + packageJson: string + } + } +} + +type GenericStep = BaseStep< +'PIECE' | 'PIECE_TRIGGER' | 'EMPTY' | 'MISSING' | 'WEBHOOK' +> + +type Step = BranchStep | LoopOnItemsStep | GenericStep | CodeStep + +type FlowVersion = { + id: string + flowId: string + trigger?: Step +} diff --git a/packages/backend/src/app/database/migration/common/1699818680567-update-user-status-rename-shadow-to-invited.ts b/packages/server/api/src/app/database/migration/common/1699818680567-update-user-status-rename-shadow-to-invited.ts similarity index 86% rename from packages/backend/src/app/database/migration/common/1699818680567-update-user-status-rename-shadow-to-invited.ts rename to packages/server/api/src/app/database/migration/common/1699818680567-update-user-status-rename-shadow-to-invited.ts index 34872a1973..228d90cc85 100644 --- a/packages/backend/src/app/database/migration/common/1699818680567-update-user-status-rename-shadow-to-invited.ts +++ b/packages/server/api/src/app/database/migration/common/1699818680567-update-user-status-rename-shadow-to-invited.ts @@ -1,7 +1,8 @@ import { MigrationInterface, QueryRunner } from 'typeorm' -import { logger } from '../../../helper/logger' +import { logger } from 'server-shared' -export class UpdateUserStatusRenameShadowToInvited1699818680567 implements MigrationInterface { +export class UpdateUserStatusRenameShadowToInvited1699818680567 +implements MigrationInterface { name = 'UpdateUserStatusRenameShadowToInvited1699818680567' public async up(queryRunner: QueryRunner): Promise { diff --git a/packages/backend/src/app/database/migration/common/1701096458822-add-partial-unique-index-for-email-and-platform-id-is-null.ts b/packages/server/api/src/app/database/migration/common/1701096458822-add-partial-unique-index-for-email-and-platform-id-is-null.ts similarity index 67% rename from packages/backend/src/app/database/migration/common/1701096458822-add-partial-unique-index-for-email-and-platform-id-is-null.ts rename to packages/server/api/src/app/database/migration/common/1701096458822-add-partial-unique-index-for-email-and-platform-id-is-null.ts index d58aea0ec7..bc358ae7a7 100644 --- a/packages/backend/src/app/database/migration/common/1701096458822-add-partial-unique-index-for-email-and-platform-id-is-null.ts +++ b/packages/server/api/src/app/database/migration/common/1701096458822-add-partial-unique-index-for-email-and-platform-id-is-null.ts @@ -1,7 +1,8 @@ import { MigrationInterface, QueryRunner } from 'typeorm' -import { logger } from '../../../helper/logger' +import { logger } from 'server-shared' -export class AddPartialUniqueIndexForEmailAndPlatformIdIsNull1701096458822 implements MigrationInterface { +export class AddPartialUniqueIndexForEmailAndPlatformIdIsNull1701096458822 +implements MigrationInterface { name = 'AddPartialUniqueIndexForEmailAndPlatformIdIsNull1701096458822' public async up(queryRunner: QueryRunner): Promise { @@ -10,7 +11,9 @@ export class AddPartialUniqueIndexForEmailAndPlatformIdIsNull1701096458822 imple ON "user"("email") WHERE "platformId" IS NULL `) - logger.info('AddPartialUniqueIndexForEmailAndPlatformIdIsNull1701096458822 up') + logger.info( + 'AddPartialUniqueIndexForEmailAndPlatformIdIsNull1701096458822 up', + ) } public async down(queryRunner: QueryRunner): Promise { @@ -18,7 +21,8 @@ export class AddPartialUniqueIndexForEmailAndPlatformIdIsNull1701096458822 imple DROP INDEX "user_partial_unique_email_platform_id_is_null" `) - logger.info('AddPartialUniqueIndexForEmailAndPlatformIdIsNull1701096458822 down') + logger.info( + 'AddPartialUniqueIndexForEmailAndPlatformIdIsNull1701096458822 down', + ) } - } diff --git a/packages/backend/src/app/database/migration/common/1707087022764-add-trigger-test-strategy.ts b/packages/server/api/src/app/database/migration/common/1707087022764-add-trigger-test-strategy.ts similarity index 80% rename from packages/backend/src/app/database/migration/common/1707087022764-add-trigger-test-strategy.ts rename to packages/server/api/src/app/database/migration/common/1707087022764-add-trigger-test-strategy.ts index 2ecd66ccaa..6d13534cfe 100644 --- a/packages/backend/src/app/database/migration/common/1707087022764-add-trigger-test-strategy.ts +++ b/packages/server/api/src/app/database/migration/common/1707087022764-add-trigger-test-strategy.ts @@ -1,5 +1,5 @@ import { MigrationInterface, QueryRunner } from 'typeorm' -import { logger } from '../../../helper/logger' +import { logger } from 'server-shared' export class AddTriggerTestStrategy1707087022764 implements MigrationInterface { name = 'AddTriggerTestStrategy1707087022764' @@ -27,16 +27,25 @@ export class AddTriggerTestStrategy1707087022764 implements MigrationInterface { logger.info({ name: 'AddTriggerTestStrategy1707087022764' }, 'down') } - } -const getAllPieceMetadataIds = async (queryRunner: QueryRunner): Promise => { - const queryResult: { id: string }[] = await queryRunner.query('SELECT id FROM piece_metadata') +const getAllPieceMetadataIds = async ( + queryRunner: QueryRunner, +): Promise => { + const queryResult: { id: string }[] = await queryRunner.query( + 'SELECT id FROM piece_metadata', + ) return queryResult.map(({ id }) => id) } -const getPieceMetadataById = async (queryRunner: QueryRunner, id: string): Promise => { - const queryResult = await queryRunner.query('SELECT id, triggers FROM piece_metadata WHERE id = $1', [id]) +const getPieceMetadataById = async ( + queryRunner: QueryRunner, + id: string, +): Promise => { + const queryResult = await queryRunner.query( + 'SELECT id, triggers FROM piece_metadata WHERE id = $1', + [id], + ) return queryResult[0] } @@ -58,7 +67,10 @@ const removeTestStrategyFromTriggers = (pieceMetadata: PieceMetadata): void => { } } -const updatePieceMetadata = async (queryRunner: QueryRunner, pieceMetadata: PieceMetadata): Promise => { +const updatePieceMetadata = async ( + queryRunner: QueryRunner, + pieceMetadata: PieceMetadata, +): Promise => { await queryRunner.query( 'UPDATE piece_metadata SET triggers = $1 WHERE id = $2', [pieceMetadata.triggers, pieceMetadata.id], diff --git a/packages/server/api/src/app/database/migration/postgres/1674788714498-FlowAndFileProjectId.ts b/packages/server/api/src/app/database/migration/postgres/1674788714498-FlowAndFileProjectId.ts new file mode 100644 index 0000000000..35fbdf28d6 --- /dev/null +++ b/packages/server/api/src/app/database/migration/postgres/1674788714498-FlowAndFileProjectId.ts @@ -0,0 +1,122 @@ +import { logger } from 'server-shared' +import { MigrationInterface, QueryRunner } from 'typeorm' + +export class FlowAndFileProjectId1674788714498 implements MigrationInterface { + public async up(queryRunner: QueryRunner): Promise { + logger.info('FlowAndFileProjectId1674788714498: started') + + const flowTableExistsQueryResponse: { exists: boolean }[] = + await queryRunner.query( + `SELECT exists ( + SELECT FROM information_schema.tables + WHERE table_schema = 'public' + AND table_name = 'flow' + )`, + ) + + const flowTableNotExist = + flowTableExistsQueryResponse && + flowTableExistsQueryResponse.length > 0 && + !flowTableExistsQueryResponse[0].exists + + if (flowTableNotExist) { + logger.info('FlowAndFileProjectId1674788714498: skipped') + return + } + + const flows = await queryRunner.query('SELECT * FROM flow') + for (let i = 0; i < flows.length; ++i) { + const currentFlow = flows[i] + const collection = await queryRunner.query( + 'SELECT * FROM collection WHERE id = $1', + [currentFlow.collectionId], + ) + currentFlow.projectId = collection[0].projectId + await queryRunner.query( + 'UPDATE flow SET "projectId" = $1 WHERE id = $2', + [currentFlow.projectId, currentFlow.id], + ) + } + + const flowVersions = await queryRunner.query('SELECT * FROM flow_version') + for (let i = 0; i < flowVersions.length; ++i) { + const currentFlowVersion = flowVersions[i] + const currentFlow = await queryRunner.query( + 'SELECT * FROM flow WHERE id = $1', + [currentFlowVersion.flowId], + ) + let action = currentFlowVersion.trigger?.nextAction + while (action !== undefined && action !== null) { + if (action.type === 'CODE') { + const packagedFileId = action.settings.artifactPackagedId + if (packagedFileId !== undefined && packagedFileId !== null) { + const packagedFileToUpdate = await queryRunner.query( + 'SELECT * FROM file WHERE id = $1', + [packagedFileId], + ) + if (packagedFileToUpdate.length === 0) { + logger.error( + 'Found an old packaged artifact file id without file ' + + packagedFileId + + ' and for flow ' + + currentFlow[0].id, + ) + } + else { + packagedFileToUpdate[0].projectId = currentFlow[0].projectId + await queryRunner.query( + 'UPDATE file SET "projectId" = $1 WHERE id = $2', + [packagedFileToUpdate[0].projectId, packagedFileId], + ) + } + } + const sourceFileId = action.settings.artifactSourceId + if (sourceFileId !== undefined && sourceFileId !== null) { + const sourceFileToUpdate = await queryRunner.query( + 'SELECT * FROM file WHERE id = $1', + [sourceFileId], + ) + if (sourceFileToUpdate.length === 0) { + logger.error( + 'Found an old source artifact file id without file ' + + sourceFileId + + ' and for flow ' + + currentFlow[0].id, + ) + } + else { + sourceFileToUpdate[0].projectId = currentFlow[0].projectId + await queryRunner.query( + 'UPDATE file SET "projectId" = $1 WHERE id = $2', + [sourceFileToUpdate[0].projectId, sourceFileId], + ) + } + } + } + action = action.nextAction + } + } + + const flowRuns = await queryRunner.query('SELECT * FROM flow_run') + for (let i = 0; i < flowRuns.length; ++i) { + const currentFlowRun = flowRuns[i] + if ( + currentFlowRun.logsFileId !== undefined && + currentFlowRun.logsFileId !== null + ) { + const logFlowRunFile = await queryRunner.query( + 'SELECT * FROM file WHERE id = $1', + [currentFlowRun.logsFileId], + ) + logFlowRunFile[0].projectId = currentFlowRun.projectId + await queryRunner.query( + 'UPDATE file SET "projectId" = $1 WHERE id = $2', + [logFlowRunFile[0].projectId, logFlowRunFile[0].id], + ) + } + } + } + + // eslint-disable-next-line @typescript-eslint/no-empty-function + public async down(): Promise {} +} diff --git a/packages/server/api/src/app/database/migration/postgres/1676238396411-initialize-schema.ts b/packages/server/api/src/app/database/migration/postgres/1676238396411-initialize-schema.ts new file mode 100644 index 0000000000..4496e885cd --- /dev/null +++ b/packages/server/api/src/app/database/migration/postgres/1676238396411-initialize-schema.ts @@ -0,0 +1,213 @@ +import { MigrationInterface, QueryRunner } from 'typeorm' +import { logger } from 'server-shared' + +export class initializeSchema1676238396411 implements MigrationInterface { + name = 'initializeSchema1676238396411' + + public async up(queryRunner: QueryRunner): Promise { + logger.info('initializeSchema1676238396411: started') + + const userTableExistsQueryResponse: { exists: boolean }[] = + await queryRunner.query( + `SELECT exists ( + SELECT FROM information_schema.tables + WHERE table_schema = 'public' + AND table_name = 'user' + )`, + ) + + const userTableExists = + userTableExistsQueryResponse && + userTableExistsQueryResponse.length > 0 && + userTableExistsQueryResponse[0].exists + + if (userTableExists) { + logger.info('initializeSchema1676238396411: skipped') + return + } + + await queryRunner.query( + 'CREATE TABLE "collection" ("id" character varying(21) NOT NULL, "created" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "updated" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "projectId" character varying(21) NOT NULL, CONSTRAINT "PK_ad3f485bbc99d875491f44d7c85" PRIMARY KEY ("id"))', + ) + await queryRunner.query( + 'CREATE INDEX "idx_collection_project_id" ON "collection" ("projectId") ', + ) + await queryRunner.query( + 'CREATE TABLE "collection_version" ("id" character varying(21) NOT NULL, "created" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "updated" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "displayName" character varying NOT NULL, "collectionId" character varying(21) NOT NULL, "configs" jsonb NOT NULL, "state" character varying NOT NULL, CONSTRAINT "PK_76c769e96c091b478e3c338a0ac" PRIMARY KEY ("id"))', + ) + await queryRunner.query( + 'CREATE INDEX "idx_collection_version_collection_id" ON "collection_version" ("collectionId") ', + ) + await queryRunner.query( + 'CREATE TABLE "file" ("id" character varying(21) NOT NULL, "created" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "updated" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "projectId" character varying(21), "data" bytea NOT NULL, CONSTRAINT "PK_36b46d232307066b3a2c9ea3a1d" PRIMARY KEY ("id"))', + ) + await queryRunner.query( + 'CREATE TABLE "flag" ("id" character varying(21) NOT NULL, "created" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "updated" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "value" jsonb NOT NULL, CONSTRAINT "PK_17b74257294fdfd221178a132d4" PRIMARY KEY ("id"))', + ) + await queryRunner.query( + 'CREATE TABLE "flow" ("id" character varying(21) NOT NULL, "created" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "updated" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "projectId" character varying(21), "collectionId" character varying(21) NOT NULL, CONSTRAINT "PK_6c2ad4a3e86394cd9bb7a80a228" PRIMARY KEY ("id"))', + ) + await queryRunner.query( + 'CREATE INDEX "idx_flow_collection_id" ON "flow" ("collectionId") ', + ) + await queryRunner.query( + 'CREATE TABLE "flow_version" ("id" character varying(21) NOT NULL, "created" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "updated" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "flowId" character varying(21) NOT NULL, "displayName" character varying NOT NULL, "trigger" jsonb, "valid" boolean NOT NULL, "state" character varying NOT NULL, CONSTRAINT "PK_2f20a52dcddf98d3fafe621a9f5" PRIMARY KEY ("id"))', + ) + await queryRunner.query( + 'CREATE INDEX "idx_flow_version_flow_id" ON "flow_version" ("flowId") ', + ) + await queryRunner.query( + 'CREATE TABLE "instance" ("id" character varying(21) NOT NULL, "created" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "updated" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "projectId" character varying(21) NOT NULL, "collectionId" character varying(21) NOT NULL, "collectionVersionId" character varying(21) NOT NULL, "flowIdToVersionId" jsonb NOT NULL, "status" character varying NOT NULL, CONSTRAINT "REL_183c020130aa172f58c6a0c647" UNIQUE ("collectionVersionId"), CONSTRAINT "REL_6b75536fbdf7d8dc967fc350ff" UNIQUE ("collectionId"), CONSTRAINT "PK_eaf60e4a0c399c9935413e06474" PRIMARY KEY ("id"))', + ) + await queryRunner.query( + 'CREATE INDEX "idx_instance_project_id" ON "instance" ("projectId") ', + ) + await queryRunner.query( + 'CREATE UNIQUE INDEX "idx_instance_collection_id" ON "instance" ("collectionId") ', + ) + await queryRunner.query( + 'CREATE TABLE "flow_run" ("id" character varying(21) NOT NULL, "created" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "updated" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "projectId" character varying(21) NOT NULL, "flowId" character varying(21) NOT NULL, "collectionId" character varying(21) NOT NULL, "flowVersionId" character varying(21) NOT NULL, "collectionVersionId" character varying(21) NOT NULL, "environment" character varying, "flowDisplayName" character varying NOT NULL, "collectionDisplayName" character varying NOT NULL, "logsFileId" character varying(21), "status" character varying NOT NULL, "startTime" TIMESTAMP WITH TIME ZONE NOT NULL, "finishTime" TIMESTAMP WITH TIME ZONE, CONSTRAINT "PK_858b1dd0d1055c44261ae00d45b" PRIMARY KEY ("id"))', + ) + await queryRunner.query( + 'CREATE INDEX "idx_run_project_id" ON "flow_run" ("projectId") ', + ) + await queryRunner.query( + 'CREATE TABLE "project" ("id" character varying(21) NOT NULL, "created" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "updated" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "ownerId" character varying(21) NOT NULL, "displayName" character varying NOT NULL, CONSTRAINT "PK_4d68b1358bb5b766d3e78f32f57" PRIMARY KEY ("id"))', + ) + await queryRunner.query( + 'CREATE INDEX "idx_project_owner_id" ON "project" ("ownerId") ', + ) + await queryRunner.query( + 'CREATE TABLE "store-entry" ("id" character varying(21) NOT NULL, "created" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "updated" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "key" character varying NOT NULL, "collectionId" character varying(21) NOT NULL, "value" jsonb NOT NULL, CONSTRAINT "PK_afb44ca7c0b4606b19deb1680d6" PRIMARY KEY ("id"))', + ) + await queryRunner.query( + 'CREATE TABLE "user" ("id" character varying(21) NOT NULL, "created" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "updated" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "email" character varying NOT NULL, "firstName" character varying NOT NULL, "lastName" character varying NOT NULL, "password" character varying NOT NULL, "status" character varying NOT NULL, "trackEvents" boolean, "newsLetter" boolean, CONSTRAINT "UQ_e12875dfb3b1d92d7d7c5377e22" UNIQUE ("email"), CONSTRAINT "PK_cace4a159ff9f2512dd42373760" PRIMARY KEY ("id"))', + ) + await queryRunner.query( + 'CREATE TABLE "app_connection" ("id" character varying(21) NOT NULL, "created" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "updated" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "name" character varying NOT NULL, "appName" character varying NOT NULL, "projectId" character varying(21) NOT NULL, "value" jsonb NOT NULL, CONSTRAINT "PK_9efa2d6633ecc57cc5adeafa039" PRIMARY KEY ("id"))', + ) + await queryRunner.query( + 'CREATE UNIQUE INDEX "idx_app_connection_project_id_and_app_name_and_name" ON "app_connection" ("projectId", "appName", "name") ', + ) + await queryRunner.query( + 'CREATE UNIQUE INDEX "idx_app_connection_project_id_and_name" ON "app_connection" ("projectId", "name") ', + ) + await queryRunner.query( + 'ALTER TABLE "collection" ADD CONSTRAINT "fk_collection_project_id" FOREIGN KEY ("projectId") REFERENCES "project"("id") ON DELETE CASCADE ON UPDATE NO ACTION', + ) + await queryRunner.query( + 'ALTER TABLE "collection_version" ADD CONSTRAINT "fk_collection_version_collection_id" FOREIGN KEY ("collectionId") REFERENCES "collection"("id") ON DELETE CASCADE ON UPDATE NO ACTION', + ) + await queryRunner.query( + 'ALTER TABLE "file" ADD CONSTRAINT "fk_file_project_id" FOREIGN KEY ("projectId") REFERENCES "project"("id") ON DELETE CASCADE ON UPDATE NO ACTION', + ) + await queryRunner.query( + 'ALTER TABLE "flow" ADD CONSTRAINT "fk_flow_project_id" FOREIGN KEY ("projectId") REFERENCES "project"("id") ON DELETE CASCADE ON UPDATE NO ACTION', + ) + await queryRunner.query( + 'ALTER TABLE "flow" ADD CONSTRAINT "fk_flow_collection_id" FOREIGN KEY ("collectionId") REFERENCES "collection"("id") ON DELETE CASCADE ON UPDATE NO ACTION', + ) + await queryRunner.query( + 'ALTER TABLE "flow_version" ADD CONSTRAINT "fk_flow_version_flow" FOREIGN KEY ("flowId") REFERENCES "flow"("id") ON DELETE CASCADE ON UPDATE NO ACTION', + ) + await queryRunner.query( + 'ALTER TABLE "instance" ADD CONSTRAINT "fk_instance_collection_version" FOREIGN KEY ("collectionVersionId") REFERENCES "collection_version"("id") ON DELETE CASCADE ON UPDATE NO ACTION', + ) + await queryRunner.query( + 'ALTER TABLE "instance" ADD CONSTRAINT "fk_instance_collection" FOREIGN KEY ("collectionId") REFERENCES "collection"("id") ON DELETE CASCADE ON UPDATE NO ACTION', + ) + await queryRunner.query( + 'ALTER TABLE "flow_run" ADD CONSTRAINT "fk_flow_run_project_id" FOREIGN KEY ("projectId") REFERENCES "project"("id") ON DELETE CASCADE ON UPDATE NO ACTION', + ) + await queryRunner.query( + 'ALTER TABLE "flow_run" ADD CONSTRAINT "fk_flow_run_flow_id" FOREIGN KEY ("flowId") REFERENCES "flow"("id") ON DELETE CASCADE ON UPDATE NO ACTION', + ) + await queryRunner.query( + 'ALTER TABLE "flow_run" ADD CONSTRAINT "fk_flow_run_collection_id" FOREIGN KEY ("collectionId") REFERENCES "collection"("id") ON DELETE CASCADE ON UPDATE NO ACTION', + ) + await queryRunner.query( + 'ALTER TABLE "flow_run" ADD CONSTRAINT "fk_flow_run_collection_version_id" FOREIGN KEY ("collectionVersionId") REFERENCES "collection_version"("id") ON DELETE CASCADE ON UPDATE NO ACTION', + ) + await queryRunner.query( + 'ALTER TABLE "project" ADD CONSTRAINT "fk_project_owner_id" FOREIGN KEY ("ownerId") REFERENCES "user"("id") ON DELETE NO ACTION ON UPDATE NO ACTION', + ) + await queryRunner.query( + 'ALTER TABLE "app_connection" ADD CONSTRAINT "fk_app_connection_app_project_id" FOREIGN KEY ("projectId") REFERENCES "project"("id") ON DELETE CASCADE ON UPDATE NO ACTION', + ) + + logger.info('initializeSchema1676238396411: completed') + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query( + 'ALTER TABLE "app_connection" DROP CONSTRAINT "fk_app_connection_app_project_id"', + ) + await queryRunner.query( + 'ALTER TABLE "project" DROP CONSTRAINT "fk_project_owner_id"', + ) + await queryRunner.query( + 'ALTER TABLE "flow_run" DROP CONSTRAINT "fk_flow_run_collection_version_id"', + ) + await queryRunner.query( + 'ALTER TABLE "flow_run" DROP CONSTRAINT "fk_flow_run_collection_id"', + ) + await queryRunner.query( + 'ALTER TABLE "flow_run" DROP CONSTRAINT "fk_flow_run_flow_id"', + ) + await queryRunner.query( + 'ALTER TABLE "flow_run" DROP CONSTRAINT "fk_flow_run_project_id"', + ) + await queryRunner.query( + 'ALTER TABLE "instance" DROP CONSTRAINT "fk_instance_collection"', + ) + await queryRunner.query( + 'ALTER TABLE "instance" DROP CONSTRAINT "fk_instance_collection_version"', + ) + await queryRunner.query( + 'ALTER TABLE "flow_version" DROP CONSTRAINT "fk_flow_version_flow"', + ) + await queryRunner.query( + 'ALTER TABLE "flow" DROP CONSTRAINT "fk_flow_collection_id"', + ) + await queryRunner.query( + 'ALTER TABLE "flow" DROP CONSTRAINT "fk_flow_project_id"', + ) + await queryRunner.query( + 'ALTER TABLE "file" DROP CONSTRAINT "fk_file_project_id"', + ) + await queryRunner.query( + 'ALTER TABLE "collection_version" DROP CONSTRAINT "fk_collection_version_collection_id"', + ) + await queryRunner.query( + 'ALTER TABLE "collection" DROP CONSTRAINT "fk_collection_project_id"', + ) + await queryRunner.query( + 'DROP INDEX "public"."idx_app_connection_project_id_and_name"', + ) + await queryRunner.query( + 'DROP INDEX "public"."idx_app_connection_project_id_and_app_name_and_name"', + ) + await queryRunner.query('DROP TABLE "app_connection"') + await queryRunner.query('DROP TABLE "user"') + await queryRunner.query('DROP TABLE "store-entry"') + await queryRunner.query('DROP INDEX "public"."idx_project_owner_id"') + await queryRunner.query('DROP TABLE "project"') + await queryRunner.query('DROP INDEX "public"."idx_run_project_id"') + await queryRunner.query('DROP TABLE "flow_run"') + await queryRunner.query('DROP INDEX "public"."idx_instance_collection_id"') + await queryRunner.query('DROP INDEX "public"."idx_instance_project_id"') + await queryRunner.query('DROP TABLE "instance"') + await queryRunner.query('DROP INDEX "public"."idx_flow_version_flow_id"') + await queryRunner.query('DROP TABLE "flow_version"') + await queryRunner.query('DROP INDEX "public"."idx_flow_collection_id"') + await queryRunner.query('DROP TABLE "flow"') + await queryRunner.query('DROP TABLE "flag"') + await queryRunner.query('DROP TABLE "file"') + await queryRunner.query( + 'DROP INDEX "public"."idx_collection_version_collection_id"', + ) + await queryRunner.query('DROP TABLE "collection_version"') + await queryRunner.query('DROP INDEX "public"."idx_collection_project_id"') + await queryRunner.query('DROP TABLE "collection"') + } +} diff --git a/packages/backend/src/app/database/migration/postgres/1676505294811-encrypt-credentials.ts b/packages/server/api/src/app/database/migration/postgres/1676505294811-encrypt-credentials.ts similarity index 70% rename from packages/backend/src/app/database/migration/postgres/1676505294811-encrypt-credentials.ts rename to packages/server/api/src/app/database/migration/postgres/1676505294811-encrypt-credentials.ts index fc6d331cf9..fad3cdefd9 100644 --- a/packages/backend/src/app/database/migration/postgres/1676505294811-encrypt-credentials.ts +++ b/packages/server/api/src/app/database/migration/postgres/1676505294811-encrypt-credentials.ts @@ -1,15 +1,18 @@ import { MigrationInterface, QueryRunner } from 'typeorm' import { decryptObject, encryptObject } from '../../../helper/encryption' -import { logger } from '../../../helper/logger' +import { logger } from 'server-shared' export class encryptCredentials1676505294811 implements MigrationInterface { - public async up(queryRunner: QueryRunner): Promise { logger.info('encryptCredentials1676505294811 up: started') const connections = await queryRunner.query('SELECT * FROM app_connection') for (const currentConnection of connections) { currentConnection.value = encryptObject(currentConnection.value) - await queryRunner.query(`UPDATE app_connection SET value = '${JSON.stringify(currentConnection.value)}' WHERE id = ${currentConnection.id}`) + await queryRunner.query( + `UPDATE app_connection SET value = '${JSON.stringify( + currentConnection.value, + )}' WHERE id = ${currentConnection.id}`, + ) } logger.info('encryptCredentials1676505294811 up: finished') } @@ -20,7 +23,11 @@ export class encryptCredentials1676505294811 implements MigrationInterface { for (const currentConnection of connections) { try { currentConnection.value = decryptObject(currentConnection.value) - await queryRunner.query(`UPDATE app_connection SET value = '${JSON.stringify(currentConnection.value)}' WHERE id = ${currentConnection.id}`) + await queryRunner.query( + `UPDATE app_connection SET value = '${JSON.stringify( + currentConnection.value, + )}' WHERE id = ${currentConnection.id}`, + ) } catch (e) { logger.error(e) @@ -28,5 +35,4 @@ export class encryptCredentials1676505294811 implements MigrationInterface { } logger.info('encryptCredentials1676505294811 down: finished') } - } diff --git a/packages/backend/src/app/database/migration/postgres/1676649852890-remove-store-action.ts b/packages/server/api/src/app/database/migration/postgres/1676649852890-remove-store-action.ts similarity index 73% rename from packages/backend/src/app/database/migration/postgres/1676649852890-remove-store-action.ts rename to packages/server/api/src/app/database/migration/postgres/1676649852890-remove-store-action.ts index 076c647e47..08a10a48f6 100644 --- a/packages/backend/src/app/database/migration/postgres/1676649852890-remove-store-action.ts +++ b/packages/server/api/src/app/database/migration/postgres/1676649852890-remove-store-action.ts @@ -1,8 +1,7 @@ import { MigrationInterface, QueryRunner } from 'typeorm' -import { logger } from '../../../helper/logger' +import { logger } from 'server-shared' export class removeStoreAction1676649852890 implements MigrationInterface { - public async up(queryRunner: QueryRunner): Promise { logger.info('Running migration removeStoreAction1676649852890') const flowVersions = await queryRunner.query('SELECT * FROM flow_version') @@ -33,11 +32,19 @@ export class removeStoreAction1676649852890 implements MigrationInterface { } if (changed) { - await queryRunner.query(`UPDATE flow_version SET trigger = '${JSON.stringify(currentFlowVersion.trigger)}' WHERE id = ${currentFlowVersion.id}`) + await queryRunner.query( + `UPDATE flow_version SET trigger = '${JSON.stringify( + currentFlowVersion.trigger, + )}' WHERE id = ${currentFlowVersion.id}`, + ) } } - logger.info('Finished running migration removeStoreAction1676649852890, changed ' + count + ' actions') + logger.info( + 'Finished running migration removeStoreAction1676649852890, changed ' + + count + + ' actions', + ) } public async down(queryRunner: QueryRunner): Promise { @@ -47,7 +54,10 @@ export class removeStoreAction1676649852890 implements MigrationInterface { let changed = false let action = currentFlowVersion.trigger?.nextAction while (action !== undefined && action !== null) { - if (action.type === 'PIECE' && action.settings.pieceName === 'storage') { + if ( + action.type === 'PIECE' && + action.settings.pieceName === 'storage' + ) { action.type = 'STORAGE' action.settings = { operation: action.setings.operation.toUpperCase(), @@ -59,9 +69,12 @@ export class removeStoreAction1676649852890 implements MigrationInterface { action = action.nextAction } if (changed) { - await queryRunner.query(`UPDATE flow_version SET trigger = '${JSON.stringify(currentFlowVersion.trigger)}' WHERE id = ${currentFlowVersion.id}`) + await queryRunner.query( + `UPDATE flow_version SET trigger = '${JSON.stringify( + currentFlowVersion.trigger, + )}' WHERE id = ${currentFlowVersion.id}`, + ) } } } - } diff --git a/packages/server/api/src/app/database/migration/postgres/1677286751592-billing.ts b/packages/server/api/src/app/database/migration/postgres/1677286751592-billing.ts new file mode 100644 index 0000000000..acace7c6e4 --- /dev/null +++ b/packages/server/api/src/app/database/migration/postgres/1677286751592-billing.ts @@ -0,0 +1,58 @@ +import { MigrationInterface, QueryRunner } from 'typeorm' +import { logger } from 'server-shared' + +export class billing1677286751592 implements MigrationInterface { + name = 'billing1677286751592' + + public async up(queryRunner: QueryRunner): Promise { + logger.info('Running migration billing1677286751592') + await queryRunner.query( + 'DROP INDEX "public"."idx_app_connection_project_id_and_app_name_and_name"', + ) + await queryRunner.query( + 'CREATE TABLE "project_plan" ("id" character varying(21) NOT NULL, "created" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "updated" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "projectId" character varying(21) NOT NULL, "name" character varying NOT NULL, "stripeCustomerId" character varying NOT NULL, "stripeSubscriptionId" character varying NOT NULL, "tasks" integer NOT NULL, "subscriptionStartDatetime" TIMESTAMP WITH TIME ZONE NOT NULL, CONSTRAINT "REL_4f52e89612966d95843e4158bb" UNIQUE ("projectId"), CONSTRAINT "PK_759d33fce71c95de832df935841" PRIMARY KEY ("id"))', + ) + await queryRunner.query( + 'CREATE UNIQUE INDEX "idx_plan_project_id" ON "project_plan" ("projectId") ', + ) + await queryRunner.query( + 'CREATE UNIQUE INDEX "idx_plan_stripe_customer_id" ON "project_plan" ("stripeCustomerId") ', + ) + await queryRunner.query( + 'CREATE TABLE "project_usage" ("id" character varying(21) NOT NULL, "created" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "updated" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "projectId" character varying(21) NOT NULL, "consumedTasks" integer NOT NULL, "nextResetDatetime" TIMESTAMP WITH TIME ZONE NOT NULL, CONSTRAINT "REL_c407fc9b2bfb44515af69d575a" UNIQUE ("projectId"), CONSTRAINT "PK_100c1959e9dc487c4cadbf9cb56" PRIMARY KEY ("id"))', + ) + await queryRunner.query( + 'CREATE UNIQUE INDEX "idx_project_usage_project_id" ON "project_usage" ("projectId") ', + ) + await queryRunner.query( + 'ALTER TABLE "project_plan" ADD CONSTRAINT "fk_project_plan_project_id" FOREIGN KEY ("projectId") REFERENCES "project"("id") ON DELETE CASCADE ON UPDATE NO ACTION', + ) + await queryRunner.query( + 'ALTER TABLE "project_usage" ADD CONSTRAINT "fk_project_usage_project_id" FOREIGN KEY ("projectId") REFERENCES "project"("id") ON DELETE CASCADE ON UPDATE NO ACTION', + ) + logger.info('Finished migration billing1677286751592') + } + + public async down(queryRunner: QueryRunner): Promise { + logger.info('rolling back migration billing1677286751592') + await queryRunner.query( + 'ALTER TABLE "project_usage" DROP CONSTRAINT "fk_project_usage_project_id"', + ) + await queryRunner.query( + 'ALTER TABLE "project_plan" DROP CONSTRAINT "fk_project_plan_project_id"', + ) + await queryRunner.query( + 'DROP INDEX "public"."idx_project_usage_project_id"', + ) + await queryRunner.query('DROP TABLE "project_usage"') + await queryRunner.query( + 'DROP INDEX "public"."idx_plan_stripe_customer_id"', + ) + await queryRunner.query('DROP INDEX "public"."idx_plan_project_id"') + await queryRunner.query('DROP TABLE "project_plan"') + await queryRunner.query( + 'CREATE UNIQUE INDEX "idx_app_connection_project_id_and_app_name_and_name" ON "app_connection" ("name", "appName", "projectId") ', + ) + logger.info('Finished rolling back billing1677286751592') + } +} diff --git a/packages/backend/src/app/database/migration/postgres/1677521257188-add-version-to-piece-steps.ts b/packages/server/api/src/app/database/migration/postgres/1677521257188-add-version-to-piece-steps.ts similarity index 78% rename from packages/backend/src/app/database/migration/postgres/1677521257188-add-version-to-piece-steps.ts rename to packages/server/api/src/app/database/migration/postgres/1677521257188-add-version-to-piece-steps.ts index a3bf2972fb..4027e22cbf 100644 --- a/packages/backend/src/app/database/migration/postgres/1677521257188-add-version-to-piece-steps.ts +++ b/packages/server/api/src/app/database/migration/postgres/1677521257188-add-version-to-piece-steps.ts @@ -1,11 +1,10 @@ import { MigrationInterface, QueryRunner } from 'typeorm' -import { logger } from '../../../helper/logger' +import { logger } from 'server-shared' const FLOW_VERSION_TABLE = 'flow_version' const PIECE_TYPE = 'PIECE' export class addVersionToPieceSteps1677521257188 implements MigrationInterface { - public async up(queryRunner: QueryRunner): Promise { logger.info('addVersionToPieceSteps1677521257188, started') @@ -25,7 +24,10 @@ export class addVersionToPieceSteps1677521257188 implements MigrationInterface { } if (update) { - await queryRunner.query(`UPDATE ${FLOW_VERSION_TABLE} SET trigger = $1 WHERE id = $2`, [flowVersion.trigger, flowVersion.id]) + await queryRunner.query( + `UPDATE ${FLOW_VERSION_TABLE} SET trigger = $1 WHERE id = $2`, + [flowVersion.trigger, flowVersion.id], + ) } } @@ -51,11 +53,13 @@ export class addVersionToPieceSteps1677521257188 implements MigrationInterface { } if (update) { - await queryRunner.query(`UPDATE ${FLOW_VERSION_TABLE} SET trigger = $1 WHERE id = $2`, [flowVersion.trigger, flowVersion.id]) + await queryRunner.query( + `UPDATE ${FLOW_VERSION_TABLE} SET trigger = $1 WHERE id = $2`, + [flowVersion.trigger, flowVersion.id], + ) } } logger.info('addVersionToPieceSteps1677521257188, finished') } - } diff --git a/packages/server/api/src/app/database/migration/postgres/1677894800372-product-embed.ts b/packages/server/api/src/app/database/migration/postgres/1677894800372-product-embed.ts new file mode 100644 index 0000000000..74869a8a8e --- /dev/null +++ b/packages/server/api/src/app/database/migration/postgres/1677894800372-product-embed.ts @@ -0,0 +1,62 @@ +import { MigrationInterface, QueryRunner } from 'typeorm' +import { logger } from 'server-shared' + +export class productEmbed1677894800372 implements MigrationInterface { + name = 'productEmbed1677894800372' + + public async up(queryRunner: QueryRunner): Promise { + const appCredentialExistsQuery: { exists: boolean }[] = + await queryRunner.query( + `SELECT exists ( + SELECT FROM information_schema.tables + WHERE table_schema = 'public' + AND table_name = 'app_credential' + )`, + ) + + const appCredentialExists = + appCredentialExistsQuery && + appCredentialExistsQuery.length > 0 && + appCredentialExistsQuery[0].exists + + if (appCredentialExists) { + logger.info('initializeSchema1676238396411: skipped') + return + } + await queryRunner.query( + 'CREATE TABLE "app_credential" ("id" character varying(21) NOT NULL, "created" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "updated" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "appName" character varying NOT NULL, "projectId" character varying(21) NOT NULL, "settings" jsonb NOT NULL, CONSTRAINT "PK_62eb102bb75a05d2951796a3b46" PRIMARY KEY ("id"))', + ) + await queryRunner.query( + 'CREATE UNIQUE INDEX "idx_app_credentials_projectId_appName" ON "app_credential" ("appName", "projectId") ', + ) + await queryRunner.query( + 'CREATE TABLE "connection_key" ("id" character varying(21) NOT NULL, "created" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "updated" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "projectId" character varying(21) NOT NULL, "settings" jsonb NOT NULL, CONSTRAINT "PK_4dcf1d9ae4ba5eb261a6c775ad2" PRIMARY KEY ("id"))', + ) + await queryRunner.query( + 'CREATE INDEX "idx_connection_key_project_id" ON "connection_key" ("projectId") ', + ) + await queryRunner.query( + 'ALTER TABLE "app_credential" ADD CONSTRAINT "FK_d82bfb4c7432a69dc2419083a0e" FOREIGN KEY ("projectId") REFERENCES "project"("id") ON DELETE NO ACTION ON UPDATE NO ACTION', + ) + await queryRunner.query( + 'ALTER TABLE "connection_key" ADD CONSTRAINT "FK_03177dc6779e6e147866d43c050" FOREIGN KEY ("projectId") REFERENCES "project"("id") ON DELETE NO ACTION ON UPDATE NO ACTION', + ) + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query( + 'DROP INDEX "public"."idx_connection_key_project_id"', + ) + await queryRunner.query('DROP TABLE "connection_key"') + await queryRunner.query( + 'DROP INDEX "public"."idx_app_credentials_projectId_appName"', + ) + await queryRunner.query('DROP TABLE "app_credential"') + await queryRunner.query( + 'ALTER TABLE "connection_key" DROP CONSTRAINT "FK_03177dc6779e6e147866d43c050"', + ) + await queryRunner.query( + 'ALTER TABLE "app_credential" DROP CONSTRAINT "FK_d82bfb4c7432a69dc2419083a0e"', + ) + } +} diff --git a/packages/server/api/src/app/database/migration/postgres/1678382946390-add-event-routing.ts b/packages/server/api/src/app/database/migration/postgres/1678382946390-add-event-routing.ts new file mode 100644 index 0000000000..de4278ddf2 --- /dev/null +++ b/packages/server/api/src/app/database/migration/postgres/1678382946390-add-event-routing.ts @@ -0,0 +1,32 @@ +import { MigrationInterface, QueryRunner } from 'typeorm' +import { logger } from 'server-shared' + +export class addEventRouting1678382946390 implements MigrationInterface { + name = 'addEventRouting1678382946390' + + public async up(queryRunner: QueryRunner): Promise { + logger.info('Running migration addEventRouting1678382946390') + await queryRunner.query( + 'CREATE TABLE "app_event_routing" ("id" character varying(21) NOT NULL, "created" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "updated" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "appName" character varying NOT NULL, "projectId" character varying(21) NOT NULL, "flowId" character varying(21) NOT NULL, "identifierValue" character varying NOT NULL, "event" character varying NOT NULL, CONSTRAINT "PK_2107df2b2faf9d50435f9d5acd7" PRIMARY KEY ("id"))', + ) + await queryRunner.query( + 'CREATE INDEX "idx_app_event_routing_flow_id" ON "app_event_routing" ("flowId") ', + ) + await queryRunner.query( + 'CREATE UNIQUE INDEX "idx_app_event_project_id_appName_identifier_value_event" ON "app_event_routing" ("appName", "projectId", "identifierValue", "event") ', + ) + logger.info('Finished migration addEventRouting1678382946390') + } + + public async down(queryRunner: QueryRunner): Promise { + logger.info('Rolling Back migration addEventRouting1678382946390') + await queryRunner.query( + 'DROP INDEX "public"."idx_app_event_project_id_appName_identifier_value_event"', + ) + await queryRunner.query( + 'DROP INDEX "public"."idx_app_event_routing_flow_id"', + ) + await queryRunner.query('DROP TABLE "app_event_routing"') + logger.info('Finished Rolling Back migration addEventRouting1678382946390') + } +} diff --git a/packages/server/api/src/app/database/migration/postgres/1678492809093-removeCollectionVersion.ts b/packages/server/api/src/app/database/migration/postgres/1678492809093-removeCollectionVersion.ts new file mode 100644 index 0000000000..cf6eab777a --- /dev/null +++ b/packages/server/api/src/app/database/migration/postgres/1678492809093-removeCollectionVersion.ts @@ -0,0 +1,84 @@ +import { MigrationInterface, QueryRunner } from 'typeorm' +import { logger } from 'server-shared' + +export class removeCollectionVersion1678492809093 +implements MigrationInterface { + name = 'removeCollectionVersion1678492809093' + + public async up(queryRunner: QueryRunner): Promise { + logger.info('Running migration removeCollectionVersion1678492809093') + await queryRunner.query( + 'ALTER TABLE "instance" DROP CONSTRAINT "fk_instance_collection_version"', + ) + await queryRunner.query( + 'ALTER TABLE "flow_run" DROP CONSTRAINT "fk_flow_run_collection_version_id"', + ) + await queryRunner.query( + 'ALTER TABLE "instance" DROP CONSTRAINT "REL_183c020130aa172f58c6a0c647"', + ) + await queryRunner.query( + 'ALTER TABLE "instance" DROP COLUMN "collectionVersionId"', + ) + await queryRunner.query( + 'ALTER TABLE "flow_run" DROP COLUMN "collectionVersionId"', + ) + await queryRunner.query( + 'ALTER TABLE "collection" ADD "displayName" character varying', + ) + const collections = await queryRunner.query( + 'SELECT * FROM public.collection', + ) + + for (let i = 0; i < collections.length; ++i) { + let currentCollection = collections[i] + const latestCollectionVersionQuery = ` + SELECT * FROM public.collection_version + WHERE "collectionId" = '${currentCollection.id}' + ORDER BY created DESC + LIMIT 1 + ` + const [latestCollectionVersion] = await queryRunner.query( + latestCollectionVersionQuery, + ) + + let displayName = 'Untitled' + if (latestCollectionVersion) { + displayName = latestCollectionVersion.displayName + } + + currentCollection = { + ...currentCollection, + displayName, + } + + const updateCollectionQuery = ` + UPDATE public.collection + SET displayName = '${displayName}' + WHERE id = '${currentCollection.id}' + ` + await queryRunner.query(updateCollectionQuery) + } + logger.info('Finished migration removeCollectionVersion1678492809093') + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query( + 'ALTER TABLE "collection" DROP COLUMN "displayName"', + ) + await queryRunner.query( + 'ALTER TABLE "flow_run" ADD "collectionVersionId" character varying(21) NOT NULL', + ) + await queryRunner.query( + 'ALTER TABLE "instance" ADD "collectionVersionId" character varying(21) NOT NULL', + ) + await queryRunner.query( + 'ALTER TABLE "instance" ADD CONSTRAINT "REL_183c020130aa172f58c6a0c647" UNIQUE ("collectionVersionId")', + ) + await queryRunner.query( + 'ALTER TABLE "flow_run" ADD CONSTRAINT "fk_flow_run_collection_version_id" FOREIGN KEY ("collectionVersionId") REFERENCES "collection_version"("id") ON DELETE CASCADE ON UPDATE NO ACTION', + ) + await queryRunner.query( + 'ALTER TABLE "instance" ADD CONSTRAINT "fk_instance_collection_version" FOREIGN KEY ("collectionVersionId") REFERENCES "collection_version"("id") ON DELETE CASCADE ON UPDATE NO ACTION', + ) + } +} diff --git a/packages/server/api/src/app/database/migration/postgres/1678621361185-addtriggerevents.ts b/packages/server/api/src/app/database/migration/postgres/1678621361185-addtriggerevents.ts new file mode 100644 index 0000000000..310714c3ee --- /dev/null +++ b/packages/server/api/src/app/database/migration/postgres/1678621361185-addtriggerevents.ts @@ -0,0 +1,34 @@ +import { MigrationInterface, QueryRunner } from 'typeorm' +import { logger } from 'server-shared' + +export class addtriggerevents1678621361185 implements MigrationInterface { + name = 'addtriggerevents1678621361185' + + public async up(queryRunner: QueryRunner): Promise { + logger.info('addtriggerevents1678621361185 up: started') + await queryRunner.query( + 'CREATE TABLE "trigger_event" ("id" character varying(21) NOT NULL, "created" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "updated" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "flowId" character varying(21) NOT NULL, "projectId" character varying(21) NOT NULL, "sourceName" character varying NOT NULL, "payload" jsonb NOT NULL, CONSTRAINT "PK_79bbc8c2af95776e801c7eaab11" PRIMARY KEY ("id"))', + ) + await queryRunner.query( + 'CREATE INDEX "idx_trigger_event_flow_id" ON "trigger_event" ("flowId") ', + ) + await queryRunner.query( + 'ALTER TABLE "trigger_event" ADD CONSTRAINT "fk_trigger_event_project_id" FOREIGN KEY ("projectId") REFERENCES "project"("id") ON DELETE CASCADE ON UPDATE NO ACTION', + ) + await queryRunner.query( + 'ALTER TABLE "trigger_event" ADD CONSTRAINT "fk_trigger_event_flow_id" FOREIGN KEY ("flowId") REFERENCES "flow"("id") ON DELETE CASCADE ON UPDATE NO ACTION', + ) + logger.info('addtriggerevents1678621361185 up: finished') + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query( + 'ALTER TABLE "trigger_event" DROP CONSTRAINT "fk_trigger_event_flow_id"', + ) + await queryRunner.query( + 'ALTER TABLE "trigger_event" DROP CONSTRAINT "fk_trigger_event_project_id"', + ) + await queryRunner.query('DROP INDEX "public"."idx_trigger_event_flow_id"') + await queryRunner.query('DROP TABLE "trigger_event"') + } +} diff --git a/packages/backend/src/app/database/migration/postgres/1678928503715-bump-fix-piece-versions.ts b/packages/server/api/src/app/database/migration/postgres/1678928503715-bump-fix-piece-versions.ts similarity index 84% rename from packages/backend/src/app/database/migration/postgres/1678928503715-bump-fix-piece-versions.ts rename to packages/server/api/src/app/database/migration/postgres/1678928503715-bump-fix-piece-versions.ts index 772b5bf112..57794dffb6 100644 --- a/packages/backend/src/app/database/migration/postgres/1678928503715-bump-fix-piece-versions.ts +++ b/packages/server/api/src/app/database/migration/postgres/1678928503715-bump-fix-piece-versions.ts @@ -1,5 +1,5 @@ import { MigrationInterface, QueryRunner } from 'typeorm' -import { logger } from '../../../helper/logger' +import { logger } from 'server-shared' const FLOW_VERSION_TABLE = 'flow_version' const APP_CONNECTION_TABLE = 'app_connection' @@ -19,8 +19,6 @@ type Step = { } export class bumpFixPieceVersions1678928503715 implements MigrationInterface { - - public async up(queryRunner: QueryRunner): Promise { logger.info('bumpFixPieceVersions1678928503715, started') @@ -32,12 +30,17 @@ export class bumpFixPieceVersions1678928503715 implements MigrationInterface { const update = updateStep(step) if (update) { count++ - await queryRunner.query(`UPDATE ${FLOW_VERSION_TABLE} SET "trigger" = $1 WHERE id = $2`, [flowVersion.trigger, flowVersion.id]) + await queryRunner.query( + `UPDATE ${FLOW_VERSION_TABLE} SET "trigger" = $1 WHERE id = $2`, + [flowVersion.trigger, flowVersion.id], + ) } } let connectionCount = 0 - const appConnections = await queryRunner.query(`SELECT * FROM ${APP_CONNECTION_TABLE}`) + const appConnections = await queryRunner.query( + `SELECT * FROM ${APP_CONNECTION_TABLE}`, + ) for (const appConnection of appConnections) { let update = false if (appConnection.appName === 'google_sheets') { @@ -74,16 +77,24 @@ export class bumpFixPieceVersions1678928503715 implements MigrationInterface { } if (update) { connectionCount++ - await queryRunner.query(`UPDATE ${APP_CONNECTION_TABLE} SET "appName" = $1 WHERE id = $2`, [appConnection.appName, appConnection.id]) + await queryRunner.query( + `UPDATE ${APP_CONNECTION_TABLE} SET "appName" = $1 WHERE id = $2`, + [appConnection.appName, appConnection.id], + ) } } - logger.info('bumpFixPieceVersions1678928503715, finished bumping ' + count + ' flows ' + ' and connections count ' + connectionCount) + logger.info( + 'bumpFixPieceVersions1678928503715, finished bumping ' + + count + + ' flows ' + + ' and connections count ' + + connectionCount, + ) } public async down(): Promise { - // Ignored + // Ignored } - } function updateStep(step: Step | undefined): boolean { diff --git a/packages/backend/src/app/database/migration/postgres/1679014156667-migrate-schedule.ts b/packages/server/api/src/app/database/migration/postgres/1679014156667-migrate-schedule.ts similarity index 75% rename from packages/backend/src/app/database/migration/postgres/1679014156667-migrate-schedule.ts rename to packages/server/api/src/app/database/migration/postgres/1679014156667-migrate-schedule.ts index 64c7f04c3b..097605414e 100644 --- a/packages/backend/src/app/database/migration/postgres/1679014156667-migrate-schedule.ts +++ b/packages/server/api/src/app/database/migration/postgres/1679014156667-migrate-schedule.ts @@ -1,9 +1,8 @@ import { MigrationInterface, QueryRunner } from 'typeorm' -import { logger } from '../../../helper/logger' +import { logger } from 'server-shared' const FLOW_VERSION_TABLE = 'flow_version' export class migrateSchedule1679014156667 implements MigrationInterface { - public async up(queryRunner: QueryRunner): Promise { logger.info('migrateSchedule1679014156667, started') @@ -23,11 +22,13 @@ export class migrateSchedule1679014156667 implements MigrationInterface { pieceVersion: '0.0.2', } count++ - await queryRunner.query(`UPDATE ${FLOW_VERSION_TABLE} SET trigger = $1 WHERE id = $2`, [flowVersion.trigger, flowVersion.id]) + await queryRunner.query( + `UPDATE ${FLOW_VERSION_TABLE} SET trigger = $1 WHERE id = $2`, + [flowVersion.trigger, flowVersion.id], + ) } } logger.info('migrateSchedule1679014156667, finished flows ' + count) - } public async down(queryRunner: QueryRunner): Promise { @@ -45,11 +46,15 @@ export class migrateSchedule1679014156667 implements MigrationInterface { cronExpression: step.settings.input.cronExpression, } count++ - await queryRunner.query(`UPDATE ${FLOW_VERSION_TABLE} SET trigger = $1 WHERE id = $2`, [flowVersion.trigger, flowVersion.id]) + await queryRunner.query( + `UPDATE ${FLOW_VERSION_TABLE} SET trigger = $1 WHERE id = $2`, + [flowVersion.trigger, flowVersion.id], + ) } } } - logger.info('rolling back migrateSchedule1679014156667, finished flows ' + count) + logger.info( + 'rolling back migrateSchedule1679014156667, finished flows ' + count, + ) } - } diff --git a/packages/backend/src/app/database/migration/postgres/1680563747425-add-notifications-status.ts b/packages/server/api/src/app/database/migration/postgres/1680563747425-add-notifications-status.ts similarity index 56% rename from packages/backend/src/app/database/migration/postgres/1680563747425-add-notifications-status.ts rename to packages/server/api/src/app/database/migration/postgres/1680563747425-add-notifications-status.ts index c03f888fbe..920453384e 100644 --- a/packages/backend/src/app/database/migration/postgres/1680563747425-add-notifications-status.ts +++ b/packages/server/api/src/app/database/migration/postgres/1680563747425-add-notifications-status.ts @@ -1,18 +1,23 @@ import { MigrationInterface, QueryRunner } from 'typeorm' -import { logger } from '../../../helper/logger' +import { logger } from 'server-shared' export class addNotificationsStatus1680563747425 implements MigrationInterface { name = 'addNotificationsStatus1680563747425' public async up(queryRunner: QueryRunner): Promise { logger.info('Running migration: addNotificationsStatus1680563747425') - await queryRunner.query('ALTER TABLE "project" ADD "notifications" character varying') - await queryRunner.query('UPDATE "project" SET "notifications" = \'ALWAYS\'') + await queryRunner.query( + 'ALTER TABLE "project" ADD "notifications" character varying', + ) + await queryRunner.query( + 'UPDATE "project" SET "notifications" = \'ALWAYS\'', + ) logger.info('Completed migration: addNotificationsStatus1680563747425') } public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query('ALTER TABLE "project" DROP COLUMN "notifications"') + await queryRunner.query( + 'ALTER TABLE "project" DROP COLUMN "notifications"', + ) } - } diff --git a/packages/server/api/src/app/database/migration/postgres/1680698259291-create-webhook-simulation-schema.ts b/packages/server/api/src/app/database/migration/postgres/1680698259291-create-webhook-simulation-schema.ts new file mode 100644 index 0000000000..6541ec6b68 --- /dev/null +++ b/packages/server/api/src/app/database/migration/postgres/1680698259291-create-webhook-simulation-schema.ts @@ -0,0 +1,22 @@ +import { MigrationInterface, QueryRunner } from 'typeorm' + +export class CreateWebhookSimulationSchema1680698259291 +implements MigrationInterface { + name = 'CreateWebhookSimulationSchema1680698259291' + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query( + 'CREATE TABLE "webhook_simulation" ("id" character varying(21) NOT NULL, "created" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "updated" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "flowId" character varying(21) NOT NULL, "projectId" character varying(21) NOT NULL, CONSTRAINT "PK_6854a1ac9a5b24810b29aaf0f43" PRIMARY KEY ("id"))', + ) + await queryRunner.query( + 'CREATE UNIQUE INDEX "idx_webhook_simulation_flow_id" ON "webhook_simulation" ("flowId") ', + ) + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query( + 'DROP INDEX "public"."idx_webhook_simulation_flow_id"', + ) + await queryRunner.query('DROP TABLE "webhook_simulation"') + } +} diff --git a/packages/server/api/src/app/database/migration/postgres/1680986182074-RemoveCollections.ts b/packages/server/api/src/app/database/migration/postgres/1680986182074-RemoveCollections.ts new file mode 100644 index 0000000000..7d8e2fe37e --- /dev/null +++ b/packages/server/api/src/app/database/migration/postgres/1680986182074-RemoveCollections.ts @@ -0,0 +1,191 @@ +import { MigrationInterface, QueryRunner } from 'typeorm' +import { logger } from 'server-shared' +import { apId } from '@activepieces/shared' + +export class RemoveCollections1680986182074 implements MigrationInterface { + name = 'RemoveCollections1680986182074' + + public async up(queryRunner: QueryRunner): Promise { + logger.info('Running RemoveCollections1680986182074 migration') + // Data Queries + await queryRunner.query(` + UPDATE "store-entry" + SET "collectionId" = "collection"."projectId" + FROM "collection" + WHERE "store-entry"."collectionId" = "collection"."id"; + `) + await queryRunner.query( + 'CREATE TABLE "folder" ("id" character varying(21) NOT NULL, "created" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "updated" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "displayName" character varying NOT NULL, "projectId" character varying(21) NOT NULL, CONSTRAINT "PK_6278a41a706740c94c02e288df8" PRIMARY KEY ("id"))', + ) + await queryRunner.query( + 'CREATE INDEX "idx_folder_project_id" ON "folder" ("projectId") ', + ) + await queryRunner.query( + 'ALTER TABLE "flow" ADD "folderId" character varying(21)', + ) + + let countFolders = 0 + const collections = await queryRunner.query('SELECT * FROM "collection"') + for (const collection of collections) { + const randomId = apId() + await queryRunner.query( + 'INSERT INTO "folder" ("id", "created", "updated", "displayName", "projectId") VALUES ($1, NOW(), NOW(), $2, $3)', + [randomId, collection.displayName, collection.projectId], + ) + await queryRunner.query( + `UPDATE "flow" SET "folderId" = '${randomId}' WHERE "collectionId" = '${collection.id}'`, + ) + countFolders++ + } + logger.info( + `RemoveCollections1680986182074 Migrated ${countFolders} folders`, + ) + // Schema Queries + await queryRunner.query( + 'ALTER TABLE "flow" DROP CONSTRAINT "fk_flow_collection_id"', + ) + await queryRunner.query( + 'ALTER TABLE "flow_run" DROP CONSTRAINT "fk_flow_run_collection_id"', + ) + await queryRunner.query('DROP INDEX "public"."idx_flow_collection_id"') + await queryRunner.query( + 'ALTER TABLE "store-entry" RENAME COLUMN "collectionId" TO "projectId"', + ) + await queryRunner.query( + 'CREATE TABLE "flow_instance" ("id" character varying(21) NOT NULL, "created" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "updated" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "projectId" character varying(21) NOT NULL, "flowId" character varying(21) NOT NULL, "flowVersionId" character varying(21) NOT NULL, "status" character varying NOT NULL, CONSTRAINT "REL_cb897f5e48cc3cba1418966326" UNIQUE ("flowId"), CONSTRAINT "REL_ec72f514c21734fb7a08797d75" UNIQUE ("flowVersionId"), CONSTRAINT "PK_5b0308060b7de5abec61ac5d2db" PRIMARY KEY ("id"))', + ) + await queryRunner.query( + 'CREATE UNIQUE INDEX "idx_flow_instance_project_id_flow_id" ON "flow_instance" ("projectId", "flowId") ', + ) + await queryRunner.query('ALTER TABLE "flow" DROP COLUMN "collectionId"') + await queryRunner.query( + 'ALTER TABLE "flow_run" DROP COLUMN "collectionId"', + ) + await queryRunner.query( + 'ALTER TABLE "flow_run" DROP COLUMN "collectionDisplayName"', + ) + await queryRunner.query( + 'ALTER TABLE "flow" DROP CONSTRAINT "fk_flow_project_id"', + ) + await queryRunner.query( + 'ALTER TABLE "flow" ALTER COLUMN "projectId" SET NOT NULL', + ) + await queryRunner.query( + 'CREATE INDEX "idx_flow_project_id" ON "flow" ("projectId") ', + ) + await queryRunner.query( + 'CREATE INDEX "idx_flow_folder_id" ON "flow" ("folderId") ', + ) + await queryRunner.query( + 'ALTER TABLE "flow_instance" ADD CONSTRAINT "fk_flow_instance_flow" FOREIGN KEY ("flowId") REFERENCES "flow"("id") ON DELETE CASCADE ON UPDATE NO ACTION', + ) + await queryRunner.query( + 'ALTER TABLE "flow_instance" ADD CONSTRAINT "fk_flow_instance_flow_version" FOREIGN KEY ("flowVersionId") REFERENCES "flow_version"("id") ON DELETE CASCADE ON UPDATE NO ACTION', + ) + await queryRunner.query( + 'ALTER TABLE "flow" ADD CONSTRAINT "fk_flow_folder_id" FOREIGN KEY ("folderId") REFERENCES "folder"("id") ON DELETE SET NULL ON UPDATE NO ACTION', + ) + await queryRunner.query( + 'ALTER TABLE "flow" ADD CONSTRAINT "fk_flow_project_id" FOREIGN KEY ("projectId") REFERENCES "project"("id") ON DELETE CASCADE ON UPDATE NO ACTION', + ) + await queryRunner.query( + 'ALTER TABLE "folder" ADD CONSTRAINT "fk_folder_project" FOREIGN KEY ("projectId") REFERENCES "project"("id") ON DELETE CASCADE ON UPDATE NO ACTION', + ) + + // Migrate Flow Instances + const instances = await queryRunner.query('SELECT * FROM "instance"') + let count = 0 + let failed = 0 + for (const instance of instances) { + const flowIdToVersionId = instance.flowIdToVersionId + for (const flowId of Object.keys(flowIdToVersionId)) { + const flowVersionId = flowIdToVersionId[flowId] + const randomId = apId() + + const flowExists = await queryRunner.query( + `SELECT EXISTS(SELECT 1 FROM "flow" WHERE "id" = '${flowId}')`, + ) + const flowVersionExists = await queryRunner.query( + `SELECT EXISTS(SELECT 1 FROM "flow_version" WHERE "id" = '${flowVersionId}')`, + ) + if (!flowExists[0].exists || !flowVersionExists[0].exists) { + failed++ + logger.info( + `Skipping flow instance ${instance.id} because flow ${flowId} or flow version ${flowVersionId} does not exist`, + ) + } + else { + await queryRunner.query( + `INSERT INTO "flow_instance" ("id", "created", "updated", "projectId", "flowId", "flowVersionId", "status") VALUES ('${randomId}', 'NOW()', 'NOW()', '${instance.projectId}', '${flowId}', '${flowVersionId}', '${instance.status}')`, + ) + count++ + } + } + } + + logger.info( + `Finished Running RemoveCollections1680986182074 migration with ${count} flow instances migrated and ${failed} failed`, + ) + } + + public async down(queryRunner: QueryRunner): Promise { + // Schema Queries + await queryRunner.query( + 'ALTER TABLE "folder" DROP CONSTRAINT "fk_folder_project"', + ) + await queryRunner.query( + 'ALTER TABLE "flow" DROP CONSTRAINT "fk_flow_project_id"', + ) + await queryRunner.query( + 'ALTER TABLE "flow" DROP CONSTRAINT "fk_flow_folder_id"', + ) + await queryRunner.query( + 'ALTER TABLE "flow_instance" DROP CONSTRAINT "fk_flow_instance_flow_version"', + ) + await queryRunner.query( + 'ALTER TABLE "flow_instance" DROP CONSTRAINT "fk_flow_instance_flow"', + ) + await queryRunner.query('DROP INDEX "public"."idx_flow_folder_id"') + await queryRunner.query('DROP INDEX "public"."idx_flow_project_id"') + await queryRunner.query( + 'ALTER TABLE "flow" ALTER COLUMN "projectId" DROP NOT NULL', + ) + await queryRunner.query( + 'ALTER TABLE "flow" ADD CONSTRAINT "fk_flow_project_id" FOREIGN KEY ("projectId") REFERENCES "project"("id") ON DELETE CASCADE ON UPDATE NO ACTION', + ) + await queryRunner.query('ALTER TABLE "flow" DROP COLUMN "folderId"') + await queryRunner.query( + 'ALTER TABLE "flow_run" ADD "collectionDisplayName" character varying NOT NULL', + ) + await queryRunner.query( + 'ALTER TABLE "flow_run" ADD "collectionId" character varying(21) NOT NULL', + ) + await queryRunner.query( + 'ALTER TABLE "flow" ADD "collectionId" character varying(21) NOT NULL', + ) + await queryRunner.query('DROP INDEX "public"."idx_folder_project_id"') + await queryRunner.query('DROP TABLE "folder"') + await queryRunner.query( + 'DROP INDEX "public"."idx_flow_instance_project_id_flow_id"', + ) + await queryRunner.query('DROP TABLE "flow_instance"') + await queryRunner.query( + 'ALTER TABLE "store-entry" RENAME COLUMN "projectId" TO "collectionId"', + ) + await queryRunner.query( + 'CREATE INDEX "idx_flow_collection_id" ON "flow" ("collectionId") ', + ) + await queryRunner.query( + 'ALTER TABLE "flow_run" ADD CONSTRAINT "fk_flow_run_collection_id" FOREIGN KEY ("collectionId") REFERENCES "collection"("id") ON DELETE CASCADE ON UPDATE NO ACTION', + ) + await queryRunner.query( + 'ALTER TABLE "flow" ADD CONSTRAINT "fk_flow_collection_id" FOREIGN KEY ("collectionId") REFERENCES "collection"("id") ON DELETE CASCADE ON UPDATE NO ACTION', + ) + // Data queries + await queryRunner.query(` + UPDATE "store-entry" + SET "collectionId" = "collection"."id" + FROM "collection" + WHERE "store-entry"."collectionId" = "collection"."projectId";`) + } +} diff --git a/packages/server/api/src/app/database/migration/postgres/1681019096716-StoreAllPeriods.ts b/packages/server/api/src/app/database/migration/postgres/1681019096716-StoreAllPeriods.ts new file mode 100644 index 0000000000..4dedc5960a --- /dev/null +++ b/packages/server/api/src/app/database/migration/postgres/1681019096716-StoreAllPeriods.ts @@ -0,0 +1,32 @@ +import { MigrationInterface, QueryRunner } from 'typeorm' +import { logger } from 'server-shared' + +export class StoreAllPeriods1681019096716 implements MigrationInterface { + name = 'StoreAllPeriods1681019096716' + + public async up(queryRunner: QueryRunner): Promise { + logger.info('Running StoreAllPeriods1681019096716') + await queryRunner.query( + 'ALTER TABLE "project_usage" DROP CONSTRAINT "REL_c407fc9b2bfb44515af69d575a"', + ) + await queryRunner.query( + 'DROP INDEX "public"."idx_project_usage_project_id"', + ) + await queryRunner.query( + 'CREATE INDEX "idx_project_usage_project_id" ON "project_usage" ("projectId") ', + ) + logger.info('Finished Running StoreAllPeriods1681019096716') + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query( + 'ALTER TABLE "project_usage" ADD CONSTRAINT "REL_c407fc9b2bfb44515af69d575a" UNIQUE ("projectId")', + ) + await queryRunner.query( + 'DROP INDEX "public"."idx_project_usage_project_id"', + ) + await queryRunner.query( + 'CREATE UNIQUE INDEX "idx_project_usage_project_id" ON "project_usage" ("projectId") ', + ) + } +} diff --git a/packages/backend/src/app/database/migration/postgres/1681107443963-AddInputUiInfo.ts b/packages/server/api/src/app/database/migration/postgres/1681107443963-AddInputUiInfo.ts similarity index 84% rename from packages/backend/src/app/database/migration/postgres/1681107443963-AddInputUiInfo.ts rename to packages/server/api/src/app/database/migration/postgres/1681107443963-AddInputUiInfo.ts index 4bff092e23..111a4813e6 100644 --- a/packages/backend/src/app/database/migration/postgres/1681107443963-AddInputUiInfo.ts +++ b/packages/server/api/src/app/database/migration/postgres/1681107443963-AddInputUiInfo.ts @@ -1,6 +1,6 @@ import { FlowVersion } from '@activepieces/shared' import { MigrationInterface, QueryRunner } from 'typeorm' -import { logger } from '../../../helper/logger' +import { logger } from 'server-shared' type Step = { type: string @@ -20,7 +20,9 @@ export class AddInputUiInfo1681107443963 implements MigrationInterface { logger.info('AddInputUiInfo1681107443963, started') let count = 0 - const flowVersions = await queryRunner.query(`SELECT * FROM ${FLOW_VERSION_TABLE}`) + const flowVersions = await queryRunner.query( + `SELECT * FROM ${FLOW_VERSION_TABLE}`, + ) for (const flowVersion of flowVersions) { const steps = getAllSteps(flowVersion as FlowVersion) @@ -35,7 +37,10 @@ export class AddInputUiInfo1681107443963 implements MigrationInterface { } if (changed) { count++ - await queryRunner.query(`UPDATE ${FLOW_VERSION_TABLE} SET flow_version = $1 WHERE id = $2`, [flowVersion, flowVersion.id]) + await queryRunner.query( + `UPDATE ${FLOW_VERSION_TABLE} SET flow_version = $1 WHERE id = $2`, + [flowVersion, flowVersion.id], + ) } } logger.info('AddInputUiInfo1681107443963, finished flows ' + count) diff --git a/packages/server/api/src/app/database/migration/postgres/1683040965874-allow-nullable-store-entry.ts b/packages/server/api/src/app/database/migration/postgres/1683040965874-allow-nullable-store-entry.ts new file mode 100644 index 0000000000..a8d43503a1 --- /dev/null +++ b/packages/server/api/src/app/database/migration/postgres/1683040965874-allow-nullable-store-entry.ts @@ -0,0 +1,26 @@ +import { MigrationInterface, QueryRunner } from 'typeorm' +import { logger } from 'server-shared' +export class AllowNullableStoreEntryAndTrigger1683040965874 +implements MigrationInterface { + name = 'AllowNullableStoreEntryAndTrigger1683040965874' + + public async up(queryRunner: QueryRunner): Promise { + logger.info('AllowNullableStoreEntryAndTrigger1683040965874, started') + await queryRunner.query( + 'ALTER TABLE "store-entry" ALTER COLUMN "value" DROP NOT NULL', + ) + await queryRunner.query( + 'ALTER TABLE "trigger_event" ALTER COLUMN "payload" DROP NOT NULL', + ) + logger.info('AllowNullableStoreEntryAndTrigger1683040965874, ended') + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query( + 'ALTER TABLE "trigger_event" ALTER COLUMN "payload" SET NOT NULL', + ) + await queryRunner.query( + 'ALTER TABLE "store-entry" ALTER COLUMN "value" SET NOT NULL', + ) + } +} diff --git a/packages/backend/src/app/database/migration/postgres/1683195711242-rename-notifications.ts b/packages/server/api/src/app/database/migration/postgres/1683195711242-rename-notifications.ts similarity index 61% rename from packages/backend/src/app/database/migration/postgres/1683195711242-rename-notifications.ts rename to packages/server/api/src/app/database/migration/postgres/1683195711242-rename-notifications.ts index 29a7f925ef..9fa3a72d7a 100644 --- a/packages/backend/src/app/database/migration/postgres/1683195711242-rename-notifications.ts +++ b/packages/server/api/src/app/database/migration/postgres/1683195711242-rename-notifications.ts @@ -1,17 +1,20 @@ import { MigrationInterface, QueryRunner } from 'typeorm' -import { logger } from '../../../helper/logger' +import { logger } from 'server-shared' export class RenameNotifications1683195711242 implements MigrationInterface { name = 'RenameNotifications1683195711242' public async up(queryRunner: QueryRunner): Promise { logger.info('Running migration: RenameNotifications1683195711242') - await queryRunner.query('ALTER TABLE "project" RENAME COLUMN "notifications" TO "notifyStatus"') + await queryRunner.query( + 'ALTER TABLE "project" RENAME COLUMN "notifications" TO "notifyStatus"', + ) logger.info('Migration complete: RenameNotifications1683195711242') } - + public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query('ALTER TABLE "project" RENAME COLUMN "notifyStatus" TO "notifications"') + await queryRunner.query( + 'ALTER TABLE "project" RENAME COLUMN "notifyStatus" TO "notifications"', + ) } - } diff --git a/packages/server/api/src/app/database/migration/postgres/1683199709317-list-flow-runs-indices.ts b/packages/server/api/src/app/database/migration/postgres/1683199709317-list-flow-runs-indices.ts new file mode 100644 index 0000000000..18c61a6545 --- /dev/null +++ b/packages/server/api/src/app/database/migration/postgres/1683199709317-list-flow-runs-indices.ts @@ -0,0 +1,39 @@ +import { MigrationInterface, QueryRunner } from 'typeorm' + +export class ListFlowRunsIndices1683199709317 implements MigrationInterface { + name = 'ListFlowRunsIndices1683199709317' + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query('DROP INDEX "public"."idx_run_project_id"') + await queryRunner.query( + 'CREATE INDEX "idx_run_project_id_environment_created_desc" ON "flow_run" ("projectId", "environment", "created" DESC) ', + ) + await queryRunner.query( + 'CREATE INDEX "idx_run_project_id_environment_status_created_desc" ON "flow_run" ("projectId", "environment", "status", "created" DESC) ', + ) + await queryRunner.query( + 'CREATE INDEX "idx_run_project_id_flow_id_environment_created_desc" ON "flow_run" ("projectId", "flowId", "environment", "created" DESC) ', + ) + await queryRunner.query( + 'CREATE INDEX "idx_run_project_id_flow_id_environment_status_created_desc" ON "flow_run" ("projectId", "flowId", "environment", "status", "created" DESC) ', + ) + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query( + 'DROP INDEX "public"."idx_run_project_id_flow_id_environment_status_created_desc"', + ) + await queryRunner.query( + 'DROP INDEX "public"."idx_run_project_id_flow_id_environment_created_desc"', + ) + await queryRunner.query( + 'DROP INDEX "public"."idx_run_project_id_environment_status_created_desc"', + ) + await queryRunner.query( + 'DROP INDEX "public"."idx_run_project_id_environment_created_desc"', + ) + await queryRunner.query( + 'CREATE INDEX "idx_run_project_id" ON "flow_run" ("projectId") ', + ) + } +} diff --git a/packages/server/api/src/app/database/migration/postgres/1683458275525-project-notify-status-not-null.ts b/packages/server/api/src/app/database/migration/postgres/1683458275525-project-notify-status-not-null.ts new file mode 100644 index 0000000000..05edd5f505 --- /dev/null +++ b/packages/server/api/src/app/database/migration/postgres/1683458275525-project-notify-status-not-null.ts @@ -0,0 +1,29 @@ +import { MigrationInterface, QueryRunner } from 'typeorm' +import { logger } from 'server-shared' + +export class ProjectNotifyStatusNotNull1683458275525 +implements MigrationInterface { + name = 'ProjectNotifyStatusNotNull1683458275525' + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query( + 'UPDATE "project" SET "notifyStatus" = \'ALWAYS\' WHERE "notifyStatus" IS NULL', + ) + await queryRunner.query( + 'ALTER TABLE "project" ALTER COLUMN "notifyStatus" SET NOT NULL', + ) + + logger.info('[ProjectNotifyStatusNotNull1683458275525] up') + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query( + 'ALTER TABLE "project" ALTER COLUMN "notifyStatus" DROP NOT NULL', + ) + await queryRunner.query( + 'UPDATE "project" SET "notifyStatus" = NULL WHERE "notifyStatus" = \'ALWAYS\'', + ) + + logger.info('[ProjectNotifyStatusNotNull1683458275525] down') + } +} diff --git a/packages/backend/src/app/database/migration/postgres/1683552928243-flow-run-pause-metadata.ts b/packages/server/api/src/app/database/migration/postgres/1683552928243-flow-run-pause-metadata.ts similarity index 78% rename from packages/backend/src/app/database/migration/postgres/1683552928243-flow-run-pause-metadata.ts rename to packages/server/api/src/app/database/migration/postgres/1683552928243-flow-run-pause-metadata.ts index 1a0adb8b0f..1c882b2eb1 100644 --- a/packages/backend/src/app/database/migration/postgres/1683552928243-flow-run-pause-metadata.ts +++ b/packages/server/api/src/app/database/migration/postgres/1683552928243-flow-run-pause-metadata.ts @@ -1,5 +1,5 @@ import { MigrationInterface, QueryRunner } from 'typeorm' -import { logger } from '../../../helper/logger' +import { logger } from 'server-shared' export class FlowRunPauseMetadata1683552928243 implements MigrationInterface { name = 'FlowRunPauseMetadata1683552928243' @@ -11,9 +11,10 @@ export class FlowRunPauseMetadata1683552928243 implements MigrationInterface { } public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query('ALTER TABLE "flow_run" DROP COLUMN "pauseMetadata"') + await queryRunner.query( + 'ALTER TABLE "flow_run" DROP COLUMN "pauseMetadata"', + ) logger.info('[FlowRunPauseMetadata1683552928243] down') } - } diff --git a/packages/backend/src/app/database/migration/postgres/1683898241599-ChangeVariableSyntax.ts b/packages/server/api/src/app/database/migration/postgres/1683898241599-ChangeVariableSyntax.ts similarity index 72% rename from packages/backend/src/app/database/migration/postgres/1683898241599-ChangeVariableSyntax.ts rename to packages/server/api/src/app/database/migration/postgres/1683898241599-ChangeVariableSyntax.ts index 62bbc41d6e..9c5305f514 100644 --- a/packages/backend/src/app/database/migration/postgres/1683898241599-ChangeVariableSyntax.ts +++ b/packages/server/api/src/app/database/migration/postgres/1683898241599-ChangeVariableSyntax.ts @@ -1,38 +1,51 @@ import { MigrationInterface, QueryRunner } from 'typeorm' -import { logger } from '../../../helper/logger' +import { logger } from 'server-shared' const FLOW_VERSION_TABLE = 'flow_version' export class ChangeVariableSyntax1683898241599 implements MigrationInterface { - public async up(queryRunner: QueryRunner): Promise { logger.info('ChangeVariableSyntax1683898241599, started') - const flowVersions = await queryRunner.query(`SELECT * FROM ${FLOW_VERSION_TABLE}`) + const flowVersions = await queryRunner.query( + `SELECT * FROM ${FLOW_VERSION_TABLE}`, + ) let count = 0 for (const flowVersion of flowVersions) { const step = flowVersion.trigger const update = updateStep(step, true) if (update) { count++ - await queryRunner.query(`UPDATE ${FLOW_VERSION_TABLE} SET trigger = $1 WHERE id = $2`, [flowVersion.trigger, flowVersion.id]) + await queryRunner.query( + `UPDATE ${FLOW_VERSION_TABLE} SET trigger = $1 WHERE id = $2`, + [flowVersion.trigger, flowVersion.id], + ) } } - logger.info(`ChangeVariableSyntax1683898241599, updated ${count} flow versions`) + logger.info( + `ChangeVariableSyntax1683898241599, updated ${count} flow versions`, + ) } public async down(queryRunner: QueryRunner): Promise { logger.info('ChangeVariableSyntax1683898241599 down, started') - const flowVersions = await queryRunner.query(`SELECT * FROM ${FLOW_VERSION_TABLE}`) + const flowVersions = await queryRunner.query( + `SELECT * FROM ${FLOW_VERSION_TABLE}`, + ) let count = 0 for (const flowVersion of flowVersions) { const step = flowVersion.trigger const update = updateStep(step, false) if (update) { count++ - await queryRunner.query(`UPDATE ${FLOW_VERSION_TABLE} SET trigger = $1 WHERE id = $2`, [flowVersion.trigger, flowVersion.id]) + await queryRunner.query( + `UPDATE ${FLOW_VERSION_TABLE} SET trigger = $1 WHERE id = $2`, + [flowVersion.trigger, flowVersion.id], + ) } } - logger.info(`ChangeVariableSyntax1683898241599, down ${count} flow versions`) + logger.info( + `ChangeVariableSyntax1683898241599, down ${count} flow versions`, + ) } } @@ -91,10 +104,12 @@ function traverse(input: unknown, forward: boolean): unknown { } else if (typeof input === 'object') { const result: Record = {} - for (const [key, value] of Object.entries(input as Record)) { + for (const [key, value] of Object.entries( + input as Record, + )) { result[key] = traverse(value, forward) } return result } return input -} \ No newline at end of file +} diff --git a/packages/server/api/src/app/database/migration/postgres/1685537054805-piece-metadata.ts b/packages/server/api/src/app/database/migration/postgres/1685537054805-piece-metadata.ts new file mode 100644 index 0000000000..170d1a108c --- /dev/null +++ b/packages/server/api/src/app/database/migration/postgres/1685537054805-piece-metadata.ts @@ -0,0 +1,30 @@ +import { MigrationInterface, QueryRunner } from 'typeorm' +import { logger } from 'server-shared' + +export class PieceMetadata1685537054805 implements MigrationInterface { + name = 'PieceMetadata1685537054805' + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query( + 'CREATE COLLATION en_natural (LOCALE = \'en-US-u-kn-true\', PROVIDER = \'icu\')', + ) + await queryRunner.query( + 'CREATE TABLE "piece_metadata" ("id" character varying(21) NOT NULL, "created" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "updated" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "name" character varying NOT NULL, "displayName" character varying NOT NULL, "logoUrl" character varying NOT NULL, "description" character varying, "version" character varying COLLATE "en_natural" NOT NULL, "minimumSupportedRelease" character varying COLLATE "en_natural" NOT NULL, "maximumSupportedRelease" character varying COLLATE "en_natural" NOT NULL, "actions" jsonb NOT NULL, "triggers" jsonb NOT NULL, CONSTRAINT "PK_b045821e9caf2be9aba520d96da" PRIMARY KEY ("id"))', + ) + await queryRunner.query( + 'CREATE UNIQUE INDEX "idx_piece_metadata_name_version" ON "piece_metadata" ("name", "version") ', + ) + + logger.info('[PieceMetadata1685537054805] up') + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query('DROP COLLATION en_natural') + await queryRunner.query( + 'DROP INDEX "public"."idx_piece_metadata_name_version"', + ) + await queryRunner.query('DROP TABLE "piece_metadata"') + + logger.info('[PieceMetadata1685537054805] down') + } +} diff --git a/packages/server/api/src/app/database/migration/postgres/1686090319016-AddProjectIdToPieceMetadata.ts b/packages/server/api/src/app/database/migration/postgres/1686090319016-AddProjectIdToPieceMetadata.ts new file mode 100644 index 0000000000..cecc3da762 --- /dev/null +++ b/packages/server/api/src/app/database/migration/postgres/1686090319016-AddProjectIdToPieceMetadata.ts @@ -0,0 +1,39 @@ +import { MigrationInterface, QueryRunner } from 'typeorm' +import { logger } from 'server-shared' + +export class AddProjectIdToPieceMetadata1686090319016 +implements MigrationInterface { + name = 'AddProjectIdToPieceMetadata1686090319016' + + public async up(queryRunner: QueryRunner): Promise { + logger.info('[AddProjectIdToPieceMetadata1686090319016] up') + await queryRunner.query( + 'DROP INDEX "public"."idx_piece_metadata_name_version"', + ) + await queryRunner.query( + 'ALTER TABLE "piece_metadata" ADD "projectId" character varying', + ) + await queryRunner.query( + 'CREATE UNIQUE INDEX "idx_piece_metadata_name_project_id_version" ON "piece_metadata" ("name", "version", "projectId") ', + ) + await queryRunner.query( + 'ALTER TABLE "piece_metadata" ADD CONSTRAINT "fk_piece_metadata_project_id" FOREIGN KEY ("projectId") REFERENCES "project"("id") ON DELETE CASCADE ON UPDATE NO ACTION', + ) + logger.info('[AddProjectIdToPieceMetadata1686090319016] finished') + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query( + 'ALTER TABLE "piece_metadata" DROP CONSTRAINT "fk_piece_metadata_project_id"', + ) + await queryRunner.query( + 'DROP INDEX "public"."idx_piece_metadata_name_project_id_version"', + ) + await queryRunner.query( + 'ALTER TABLE "piece_metadata" DROP COLUMN "projectId"', + ) + await queryRunner.query( + 'CREATE UNIQUE INDEX "idx_piece_metadata_name_version" ON "piece_metadata" ("name", "version") ', + ) + } +} diff --git a/packages/backend/src/app/database/migration/postgres/1686138629812-unifyPieceName.ts b/packages/server/api/src/app/database/migration/postgres/1686138629812-unifyPieceName.ts similarity index 57% rename from packages/backend/src/app/database/migration/postgres/1686138629812-unifyPieceName.ts rename to packages/server/api/src/app/database/migration/postgres/1686138629812-unifyPieceName.ts index 7ae7bb8d03..1e15255ffc 100644 --- a/packages/backend/src/app/database/migration/postgres/1686138629812-unifyPieceName.ts +++ b/packages/server/api/src/app/database/migration/postgres/1686138629812-unifyPieceName.ts @@ -1,5 +1,5 @@ import { MigrationInterface, QueryRunner } from 'typeorm' -import { logger } from '../../../helper/logger' +import { logger } from 'server-shared' const FLOW_VERSION_TABLE = 'flow_version' const APP_CONNECTION_TABLE = 'app_connection' @@ -21,7 +21,6 @@ type Step = { } export class UnifyPieceName1686138629812 implements MigrationInterface { - name = 'UnifyPieceName1686138629812' public async up(queryRunner: QueryRunner): Promise { @@ -33,7 +32,18 @@ export class UnifyPieceName1686138629812 implements MigrationInterface { const pieceMetadataCount = await updatePieceMetadata(queryRunner, false) const triggerEventCount = await updateTriggerEvent(queryRunner, false) - logger.info('UnifyPieceName1686138629812, finished renaming ' + count + ' flows and connections count ' + connectionCount + ' appEventsRoutCount ' + appEventsRoutCount + ' pieceMetadataCount ' + pieceMetadataCount + ' triggerEventCount ' + triggerEventCount) + logger.info( + 'UnifyPieceName1686138629812, finished renaming ' + + count + + ' flows and connections count ' + + connectionCount + + ' appEventsRoutCount ' + + appEventsRoutCount + + ' pieceMetadataCount ' + + pieceMetadataCount + + ' triggerEventCount ' + + triggerEventCount, + ) } public async down(queryRunner: QueryRunner): Promise { @@ -47,16 +57,23 @@ export class UnifyPieceName1686138629812 implements MigrationInterface { logger.info( 'UnifyPieceName1686138629812, finished reverting renaming ' + - count + ' flows and connections count ' + - connectionCount + ' appEventsRoutCount ' + - appEventsRoutCount + ' pieceMetadataCount ' + - pieceMetadataCount + ' triggerEventCount ' + - triggerEventCount) + count + + ' flows and connections count ' + + connectionCount + + ' appEventsRoutCount ' + + appEventsRoutCount + + ' pieceMetadataCount ' + + pieceMetadataCount + + ' triggerEventCount ' + + triggerEventCount, + ) } - } -async function updateFlowVersions(queryRunner: QueryRunner, revert: boolean): Promise { +async function updateFlowVersions( + queryRunner: QueryRunner, + revert: boolean, +): Promise { const flowVersions = await queryRunner.query('SELECT * FROM flow_version') let count = 0 @@ -66,15 +83,23 @@ async function updateFlowVersions(queryRunner: QueryRunner, revert: boolean): Pr if (update) { count++ - await queryRunner.query(`UPDATE ${FLOW_VERSION_TABLE} SET trigger = $1 WHERE id = $2`, [flowVersion.trigger, flowVersion.id]) + await queryRunner.query( + `UPDATE ${FLOW_VERSION_TABLE} SET trigger = $1 WHERE id = $2`, + [flowVersion.trigger, flowVersion.id], + ) } } return count } -async function updateTriggerEvent(queryRunner: QueryRunner, revert: boolean): Promise { - const triggerEvents = await queryRunner.query(`SELECT * FROM ${TRIGGER_EVENT}`) +async function updateTriggerEvent( + queryRunner: QueryRunner, + revert: boolean, +): Promise { + const triggerEvents = await queryRunner.query( + `SELECT * FROM ${TRIGGER_EVENT}`, + ) let count = 0 for (const triggerEvent of triggerEvents) { if (triggerEvent.source) { @@ -82,43 +107,76 @@ async function updateTriggerEvent(queryRunner: QueryRunner, revert: boolean): Pr triggerEvent.source = `@activepieces/piece-${triggerEvent.source}` } else { - triggerEvent.source = triggerEvent.source.replace('@activepieces/piece-', '') + triggerEvent.source = triggerEvent.source.replace( + '@activepieces/piece-', + '', + ) } count++ - await queryRunner.query(`UPDATE ${TRIGGER_EVENT} SET source = $1 WHERE id = $2`, [triggerEvent.source, triggerEvent.id]) + await queryRunner.query( + `UPDATE ${TRIGGER_EVENT} SET source = $1 WHERE id = $2`, + [triggerEvent.source, triggerEvent.id], + ) } } return count } -async function updateAppConnections(queryRunner: QueryRunner, revert: boolean): Promise { - const appConnections = await queryRunner.query(`SELECT * FROM ${APP_CONNECTION_TABLE}`) +async function updateAppConnections( + queryRunner: QueryRunner, + revert: boolean, +): Promise { + const appConnections = await queryRunner.query( + `SELECT * FROM ${APP_CONNECTION_TABLE}`, + ) let count = 0 for (const appConnection of appConnections) { - appConnection.appName = getPackageNameForPiece(appConnection.appName, revert) + appConnection.appName = getPackageNameForPiece( + appConnection.appName, + revert, + ) count++ - await queryRunner.query(`UPDATE ${APP_CONNECTION_TABLE} SET "appName" = $1 WHERE id = $2`, [appConnection.appName, appConnection.id]) + await queryRunner.query( + `UPDATE ${APP_CONNECTION_TABLE} SET "appName" = $1 WHERE id = $2`, + [appConnection.appName, appConnection.id], + ) } return count } -async function updateAppEventRoutes(queryRunner: QueryRunner, revert: boolean): Promise { - const appEventsRoutes = await queryRunner.query(`SELECT * FROM ${APP_EVENT_ROUTING_TABLE}`) +async function updateAppEventRoutes( + queryRunner: QueryRunner, + revert: boolean, +): Promise { + const appEventsRoutes = await queryRunner.query( + `SELECT * FROM ${APP_EVENT_ROUTING_TABLE}`, + ) let count = 0 for (const appEventsRoute of appEventsRoutes) { - appEventsRoute.appName = getPackageNameForPiece(appEventsRoute.appName, revert) + appEventsRoute.appName = getPackageNameForPiece( + appEventsRoute.appName, + revert, + ) count++ - await queryRunner.query(`UPDATE ${APP_EVENT_ROUTING_TABLE} SET "appName" = $1 WHERE id = $2`, [appEventsRoute.appName, appEventsRoute.id]) + await queryRunner.query( + `UPDATE ${APP_EVENT_ROUTING_TABLE} SET "appName" = $1 WHERE id = $2`, + [appEventsRoute.appName, appEventsRoute.id], + ) } return count } -async function updatePieceMetadata(queryRunner: QueryRunner, revert: boolean): Promise { - const pieceMetadatas = await queryRunner.query('SELECT * FROM piece_metadata;') +async function updatePieceMetadata( + queryRunner: QueryRunner, + revert: boolean, +): Promise { + const pieceMetadatas = await queryRunner.query( + 'SELECT * FROM piece_metadata;', + ) let count = 0 for (const pieceMetadata of pieceMetadatas) { @@ -135,7 +193,10 @@ function updateStep(step: Step | undefined, revert: boolean): boolean { let update = false while (step) { if (step.type === PIECE_TYPE || step.type === PIECE_TRIGGER_TYPE) { - step.settings.pieceName = getPackageNameForPiece(step.settings.pieceName, revert)! + step.settings.pieceName = getPackageNameForPiece( + step.settings.pieceName, + revert, + )! update = true } if (step.firstLoopAction) { @@ -155,7 +216,10 @@ function updateStep(step: Step | undefined, revert: boolean): boolean { return update } -const getPackageNameForPiece = (pieceName: string | undefined, revert: boolean): string | undefined => { +const getPackageNameForPiece = ( + pieceName: string | undefined, + revert: boolean, +): string | undefined => { if (!pieceName) { return pieceName } diff --git a/packages/backend/src/app/database/migration/postgres/1687384796637-AddScheduleOptions.ts b/packages/server/api/src/app/database/migration/postgres/1687384796637-AddScheduleOptions.ts similarity index 79% rename from packages/backend/src/app/database/migration/postgres/1687384796637-AddScheduleOptions.ts rename to packages/server/api/src/app/database/migration/postgres/1687384796637-AddScheduleOptions.ts index 9af9dea648..23f5f1cad7 100644 --- a/packages/backend/src/app/database/migration/postgres/1687384796637-AddScheduleOptions.ts +++ b/packages/server/api/src/app/database/migration/postgres/1687384796637-AddScheduleOptions.ts @@ -1,5 +1,5 @@ import { MigrationInterface, QueryRunner } from 'typeorm' -import { logger } from '../../../helper/logger' +import { logger } from 'server-shared' export class AddScheduleOptions1687384796637 implements MigrationInterface { name = 'AddScheduleOptions1687384796637' @@ -11,8 +11,8 @@ export class AddScheduleOptions1687384796637 implements MigrationInterface { } public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query('ALTER TABLE "flow_instance" DROP COLUMN "schedule"') + await queryRunner.query( + 'ALTER TABLE "flow_instance" DROP COLUMN "schedule"', + ) } - } - diff --git a/packages/backend/src/app/database/migration/postgres/1688922241747-AddAuthToPiecesMetadata.ts b/packages/server/api/src/app/database/migration/postgres/1688922241747-AddAuthToPiecesMetadata.ts similarity index 80% rename from packages/backend/src/app/database/migration/postgres/1688922241747-AddAuthToPiecesMetadata.ts rename to packages/server/api/src/app/database/migration/postgres/1688922241747-AddAuthToPiecesMetadata.ts index 9176925e0d..49b1de6100 100644 --- a/packages/backend/src/app/database/migration/postgres/1688922241747-AddAuthToPiecesMetadata.ts +++ b/packages/server/api/src/app/database/migration/postgres/1688922241747-AddAuthToPiecesMetadata.ts @@ -1,18 +1,17 @@ import { MigrationInterface, QueryRunner } from 'typeorm' -import { logger } from '../../../helper/logger' +import { logger } from 'server-shared' -export class AddAuthToPiecesMetadata1688922241747 implements MigrationInterface { +export class AddAuthToPiecesMetadata1688922241747 +implements MigrationInterface { name = 'AddAuthToPiecesMetadata1688922241747' public async up(queryRunner: QueryRunner): Promise { logger.info('AddAuthToPiecesMetadata1688922241747 is Running') await queryRunner.query('ALTER TABLE "piece_metadata" ADD "auth" jsonb') logger.info('AddAuthToPiecesMetadata1688922241747 is Finished') - } public async down(queryRunner: QueryRunner): Promise { await queryRunner.query('ALTER TABLE "piece_metadata" DROP COLUMN "auth"') } - } diff --git a/packages/server/api/src/app/database/migration/postgres/1689292797727-AddUpdatedByInFlowVersion.ts b/packages/server/api/src/app/database/migration/postgres/1689292797727-AddUpdatedByInFlowVersion.ts new file mode 100644 index 0000000000..c3119bd11d --- /dev/null +++ b/packages/server/api/src/app/database/migration/postgres/1689292797727-AddUpdatedByInFlowVersion.ts @@ -0,0 +1,27 @@ +import { MigrationInterface, QueryRunner } from 'typeorm' +import { logger } from 'server-shared' + +export class AddUpdatedByInFlowVersion1689292797727 +implements MigrationInterface { + name = 'AddUpdatedByInFlowVersion1689292797727' + + public async up(queryRunner: QueryRunner): Promise { + logger.info('AddUpdatedByInFlowVersion1689292797727 up') + await queryRunner.query( + 'ALTER TABLE "flow_version" ADD "updatedBy" character varying', + ) + await queryRunner.query( + 'ALTER TABLE "flow_version" ADD CONSTRAINT "fk_updated_by_user_flow" FOREIGN KEY ("updatedBy") REFERENCES "user"("id") ON DELETE CASCADE ON UPDATE NO ACTION', + ) + logger.info('AddUpdatedByInFlowVersion1689292797727 finished') + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query( + 'ALTER TABLE "flow_version" DROP CONSTRAINT "fk_updated_by_user_flow"', + ) + await queryRunner.query( + 'ALTER TABLE "flow_version" DROP COLUMN "updatedBy"', + ) + } +} diff --git a/packages/backend/src/app/database/migration/postgres/1689351564290-AddTasksToRun.ts b/packages/server/api/src/app/database/migration/postgres/1689351564290-AddTasksToRun.ts similarity index 99% rename from packages/backend/src/app/database/migration/postgres/1689351564290-AddTasksToRun.ts rename to packages/server/api/src/app/database/migration/postgres/1689351564290-AddTasksToRun.ts index 8942411718..fc2bb207a0 100644 --- a/packages/backend/src/app/database/migration/postgres/1689351564290-AddTasksToRun.ts +++ b/packages/server/api/src/app/database/migration/postgres/1689351564290-AddTasksToRun.ts @@ -10,5 +10,4 @@ export class AddTasksToRun1689351564290 implements MigrationInterface { public async down(queryRunner: QueryRunner): Promise { await queryRunner.query('ALTER TABLE "flow_run" DROP COLUMN "tasks"') } - } diff --git a/packages/backend/src/app/database/migration/postgres/1691703023866-add-app-connection-type-to-top-level.ts b/packages/server/api/src/app/database/migration/postgres/1691703023866-add-app-connection-type-to-top-level.ts similarity index 64% rename from packages/backend/src/app/database/migration/postgres/1691703023866-add-app-connection-type-to-top-level.ts rename to packages/server/api/src/app/database/migration/postgres/1691703023866-add-app-connection-type-to-top-level.ts index 149dfbc0a7..a8c9efa868 100644 --- a/packages/backend/src/app/database/migration/postgres/1691703023866-add-app-connection-type-to-top-level.ts +++ b/packages/server/api/src/app/database/migration/postgres/1691703023866-add-app-connection-type-to-top-level.ts @@ -1,35 +1,43 @@ import { MigrationInterface, QueryRunner } from 'typeorm' -import { logger } from '../../../helper/logger' +import { logger } from 'server-shared' import * as crypto from 'crypto' -import { system } from '../../../helper/system/system' -import { SystemProp } from '../../../helper/system/system-prop' +import { SystemProp, system } from 'server-shared' type AppConnectionValue = { type: string } const algorithm = 'aes-256-cbc' -export class AddAppConnectionTypeToTopLevel1691703023866 implements MigrationInterface { +export class AddAppConnectionTypeToTopLevel1691703023866 +implements MigrationInterface { name = 'AddAppConnectionTypeToTopLevel1691703023866' public async up(queryRunner: QueryRunner): Promise { logger.info('AddAppConnectionTypeToTopLevel1691703023866 up') - await queryRunner.query('ALTER TABLE "app_connection" ADD "type" character varying') + await queryRunner.query( + 'ALTER TABLE "app_connection" ADD "type" character varying', + ) const connections = await queryRunner.query('SELECT * FROM app_connection') for (const currentConnection of connections) { try { - const connectionValue = decryptObject(currentConnection.value) - await queryRunner.query(`UPDATE "app_connection" SET "type" = '${connectionValue.type}' WHERE id = '${currentConnection.id}'`) + const connectionValue = decryptObject( + currentConnection.value, + ) + await queryRunner.query( + `UPDATE "app_connection" SET "type" = '${connectionValue.type}' WHERE id = '${currentConnection.id}'`, + ) } catch (e) { logger.error(e) } } - await queryRunner.query('ALTER TABLE "app_connection" ALTER COLUMN "type" SET NOT NULL') + await queryRunner.query( + 'ALTER TABLE "app_connection" ALTER COLUMN "type" SET NOT NULL', + ) logger.info('AddAppConnectionTypeToTopLevel1691703023866 finished') } @@ -41,14 +49,16 @@ export class AddAppConnectionTypeToTopLevel1691703023866 implements MigrationInt logger.info('AddAppConnectionTypeToTopLevel1691703023866 finished') } - } function decryptObject(encryptedObject: { iv: string, data: string }): T { const iv = Buffer.from(encryptedObject.iv, 'hex') - const key = Buffer.from(system.getOrThrow(SystemProp.ENCRYPTION_KEY), 'binary') + const key = Buffer.from( + system.getOrThrow(SystemProp.ENCRYPTION_KEY), + 'binary', + ) const decipher = crypto.createDecipheriv(algorithm, key, iv) let decrypted = decipher.update(encryptedObject.data, 'hex', 'utf8') decrypted += decipher.final('utf8') return JSON.parse(decrypted) -} \ No newline at end of file +} diff --git a/packages/backend/src/app/database/migration/postgres/1692106375081-AddTagsToRun.ts b/packages/server/api/src/app/database/migration/postgres/1692106375081-AddTagsToRun.ts similarity index 77% rename from packages/backend/src/app/database/migration/postgres/1692106375081-AddTagsToRun.ts rename to packages/server/api/src/app/database/migration/postgres/1692106375081-AddTagsToRun.ts index a24e8a499a..9455f4ef5e 100644 --- a/packages/backend/src/app/database/migration/postgres/1692106375081-AddTagsToRun.ts +++ b/packages/server/api/src/app/database/migration/postgres/1692106375081-AddTagsToRun.ts @@ -4,11 +4,12 @@ export class AddTagsToRun1692106375081 implements MigrationInterface { name = 'AddTagsToRun1692106375081' public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query('ALTER TABLE "flow_run" ADD "tags" character varying array') + await queryRunner.query( + 'ALTER TABLE "flow_run" ADD "tags" character varying array', + ) } public async down(queryRunner: QueryRunner): Promise { await queryRunner.query('ALTER TABLE "flow_run" DROP COLUMN "tags"') } - } diff --git a/packages/server/api/src/app/database/migration/postgres/1693004806926-AddFileToPostgres.ts b/packages/server/api/src/app/database/migration/postgres/1693004806926-AddFileToPostgres.ts new file mode 100644 index 0000000000..3d9dba7ffd --- /dev/null +++ b/packages/server/api/src/app/database/migration/postgres/1693004806926-AddFileToPostgres.ts @@ -0,0 +1,33 @@ +import { MigrationInterface, QueryRunner } from 'typeorm' + +export class AddFileToPostgres1693004806926 implements MigrationInterface { + name = 'AddFileToPostgres1693004806926' + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query( + 'CREATE TABLE "step_file" ("id" character varying(21) NOT NULL, "created" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "updated" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "flowId" character varying(21) NOT NULL, "projectId" character varying(21) NOT NULL, "name" character varying NOT NULL, "size" integer NOT NULL, "stepName" character varying NOT NULL, "data" bytea NOT NULL, CONSTRAINT "PK_04bb9022ff8c2190fea2036174e" PRIMARY KEY ("id"))', + ) + await queryRunner.query( + 'CREATE UNIQUE INDEX "step_file_project_id_flow_id_step_name_name" ON "step_file" ("projectId", "flowId", "stepName", "name") ', + ) + await queryRunner.query( + 'ALTER TABLE "step_file" ADD CONSTRAINT "fk_step_file_project_id" FOREIGN KEY ("projectId") REFERENCES "project"("id") ON DELETE CASCADE ON UPDATE NO ACTION', + ) + await queryRunner.query( + 'ALTER TABLE "step_file" ADD CONSTRAINT "fk_step_file_flow_id" FOREIGN KEY ("flowId") REFERENCES "flow"("id") ON DELETE CASCADE ON UPDATE NO ACTION', + ) + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query( + 'ALTER TABLE "step_file" DROP CONSTRAINT "fk_step_file_flow_id"', + ) + await queryRunner.query( + 'ALTER TABLE "step_file" DROP CONSTRAINT "fk_step_file_project_id"', + ) + await queryRunner.query( + 'DROP INDEX "public"."step_file_project_id_flow_id_step_name_name"', + ) + await queryRunner.query('DROP TABLE "step_file"') + } +} diff --git a/packages/server/api/src/app/database/migration/postgres/1693402930301-AddStatusToConnections.ts b/packages/server/api/src/app/database/migration/postgres/1693402930301-AddStatusToConnections.ts new file mode 100644 index 0000000000..f84ba74155 --- /dev/null +++ b/packages/server/api/src/app/database/migration/postgres/1693402930301-AddStatusToConnections.ts @@ -0,0 +1,34 @@ +import { MigrationInterface, QueryRunner } from 'typeorm' + +export class AddStatusToConnections1693402930301 implements MigrationInterface { + name = 'AddStatusToConnections1693402930301' + + public async up(queryRunner: QueryRunner): Promise { + // Add the new column without NOT NULL constraint first + await queryRunner.query( + 'ALTER TABLE "app_connection" ADD "status" character varying DEFAULT \'ACTIVE\'', + ) + + // Update existing rows to set the default value + await queryRunner.query( + 'UPDATE "app_connection" SET "status" = \'ACTIVE\'', + ) + + // Finally, alter the column to set NOT NULL constraint + await queryRunner.query( + 'ALTER TABLE "app_connection" ALTER COLUMN "status" SET NOT NULL', + ) + } + + public async down(queryRunner: QueryRunner): Promise { + // Remove NOT NULL constraint first + await queryRunner.query( + 'ALTER TABLE "app_connection" ALTER COLUMN "status" DROP NOT NULL', + ) + + // Drop the "status" column + await queryRunner.query( + 'ALTER TABLE "app_connection" DROP COLUMN "status"', + ) + } +} diff --git a/packages/backend/src/app/database/migration/postgres/1693850082449-AddUserMetaInformation.ts b/packages/server/api/src/app/database/migration/postgres/1693850082449-AddUserMetaInformation.ts similarity index 83% rename from packages/backend/src/app/database/migration/postgres/1693850082449-AddUserMetaInformation.ts rename to packages/server/api/src/app/database/migration/postgres/1693850082449-AddUserMetaInformation.ts index 8236f830be..fbfc2ff782 100644 --- a/packages/backend/src/app/database/migration/postgres/1693850082449-AddUserMetaInformation.ts +++ b/packages/server/api/src/app/database/migration/postgres/1693850082449-AddUserMetaInformation.ts @@ -4,7 +4,9 @@ export class AddUserMetaInformation1693850082449 implements MigrationInterface { name = 'AddUserMetaInformation1693850082449' public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query('ALTER TABLE "user" ADD "imageUrl" character varying') + await queryRunner.query( + 'ALTER TABLE "user" ADD "imageUrl" character varying', + ) await queryRunner.query('ALTER TABLE "user" ADD "title" character varying') } @@ -12,5 +14,4 @@ export class AddUserMetaInformation1693850082449 implements MigrationInterface { await queryRunner.query('ALTER TABLE "user" DROP COLUMN "title"') await queryRunner.query('ALTER TABLE "user" DROP COLUMN "imageUrl"') } - } diff --git a/packages/server/api/src/app/database/migration/postgres/1694367186954-fix-piece-metadata-order-bug.ts b/packages/server/api/src/app/database/migration/postgres/1694367186954-fix-piece-metadata-order-bug.ts new file mode 100644 index 0000000000..aaf00857da --- /dev/null +++ b/packages/server/api/src/app/database/migration/postgres/1694367186954-fix-piece-metadata-order-bug.ts @@ -0,0 +1,35 @@ +import { MigrationInterface, QueryRunner } from 'typeorm' +import { logger } from 'server-shared' + +export class FixPieceMetadataOrderBug1694367186954 +implements MigrationInterface { + name = 'FixPieceMetadataOrderBug1694367186954' + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query( + 'ALTER TABLE "piece_metadata" ALTER COLUMN "auth" TYPE json', + ) + await queryRunner.query( + 'ALTER TABLE "piece_metadata" ALTER COLUMN "actions" TYPE json', + ) + await queryRunner.query( + 'ALTER TABLE "piece_metadata" ALTER COLUMN "triggers" TYPE json', + ) + + logger.info('[FixPieceMetadataOrderBug1694367186954] up') + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query( + 'ALTER TABLE "piece_metadata" ALTER COLUMN "auth" SET DATA TYPE jsonb USING my_json::jsonb', + ) + await queryRunner.query( + 'ALTER TABLE "piece_metadata" ALTER COLUMN "actions" SET DATA TYPE jsonb USING my_json::jsonb', + ) + await queryRunner.query( + 'ALTER TABLE "piece_metadata" ALTER COLUMN "triggers" SET DATA TYPE jsonb USING my_json::jsonb', + ) + + logger.info('[FixPieceMetadataOrderBug1694367186954] down') + } +} diff --git a/packages/backend/src/app/database/migration/postgres/1694691554696-file-type-compression.ts b/packages/server/api/src/app/database/migration/postgres/1694691554696-file-type-compression.ts similarity index 65% rename from packages/backend/src/app/database/migration/postgres/1694691554696-file-type-compression.ts rename to packages/server/api/src/app/database/migration/postgres/1694691554696-file-type-compression.ts index ae238b7072..c68c0377b2 100644 --- a/packages/backend/src/app/database/migration/postgres/1694691554696-file-type-compression.ts +++ b/packages/server/api/src/app/database/migration/postgres/1694691554696-file-type-compression.ts @@ -1,12 +1,16 @@ import { MigrationInterface, QueryRunner } from 'typeorm' -import { logger } from '../../../helper/logger' +import { logger } from 'server-shared' export class FileTypeCompression1694691554696 implements MigrationInterface { name = 'FileTypeCompression1694691554696' public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query('ALTER TABLE "file" ADD "type" character varying NOT NULL DEFAULT \'UNKNOWN\'') - await queryRunner.query('ALTER TABLE "file" ADD "compression" character varying NOT NULL DEFAULT \'NONE\'') + await queryRunner.query( + 'ALTER TABLE "file" ADD "type" character varying NOT NULL DEFAULT \'UNKNOWN\'', + ) + await queryRunner.query( + 'ALTER TABLE "file" ADD "compression" character varying NOT NULL DEFAULT \'NONE\'', + ) logger.info('[FileTypeCompression1694691554696] up') } @@ -17,5 +21,4 @@ export class FileTypeCompression1694691554696 implements MigrationInterface { logger.info('[FileTypeCompression1694691554696] down') } - } diff --git a/packages/server/api/src/app/database/migration/postgres/1694902537040-Chatbot.ts b/packages/server/api/src/app/database/migration/postgres/1694902537040-Chatbot.ts new file mode 100644 index 0000000000..11d6bb64f5 --- /dev/null +++ b/packages/server/api/src/app/database/migration/postgres/1694902537040-Chatbot.ts @@ -0,0 +1,27 @@ +import { MigrationInterface, QueryRunner } from 'typeorm' + +export class Chatbot1694902537040 implements MigrationInterface { + name = 'Chatbot1694902537040' + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query( + 'CREATE TABLE "chatbot" ("id" character varying(21) NOT NULL, "created" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "updated" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "type" character varying NOT NULL, "displayName" character varying NOT NULL, "projectId" character varying NOT NULL, "connectionId" character varying, "dataSources" jsonb NOT NULL, "prompt" character varying, CONSTRAINT "PK_1ee1961e62c5cec278314f1d68e" PRIMARY KEY ("id"))', + ) + await queryRunner.query( + 'ALTER TABLE "chatbot" ADD CONSTRAINT "FK_d2f5f245c27541cd70f13f169eb" FOREIGN KEY ("projectId") REFERENCES "project"("id") ON DELETE NO ACTION ON UPDATE NO ACTION', + ) + await queryRunner.query( + 'ALTER TABLE "chatbot" ADD CONSTRAINT "FK_13f7ad52cefa43433864732c384" FOREIGN KEY ("connectionId") REFERENCES "app_connection"("id") ON DELETE NO ACTION ON UPDATE NO ACTION', + ) + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query( + 'ALTER TABLE "chatbot" DROP CONSTRAINT "FK_13f7ad52cefa43433864732c384"', + ) + await queryRunner.query( + 'ALTER TABLE "chatbot" DROP CONSTRAINT "FK_d2f5f245c27541cd70f13f169eb"', + ) + await queryRunner.query('DROP TABLE "chatbot"') + } +} diff --git a/packages/server/api/src/app/database/migration/postgres/1695719749099-AddVisibilityStatusToChatbot.ts b/packages/server/api/src/app/database/migration/postgres/1695719749099-AddVisibilityStatusToChatbot.ts new file mode 100644 index 0000000000..f6bd3c580f --- /dev/null +++ b/packages/server/api/src/app/database/migration/postgres/1695719749099-AddVisibilityStatusToChatbot.ts @@ -0,0 +1,18 @@ +import { MigrationInterface, QueryRunner } from 'typeorm' + +export class AddVisibilityStatusToChatbot1695719749099 +implements MigrationInterface { + name = 'AddVisibilityStatusToChatbot1695719749099' + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query( + 'ALTER TABLE "chatbot" ADD "visibilityStatus" character varying NOT NULL DEFAULT \'PRIVATE\'', + ) + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query( + 'ALTER TABLE "chatbot" DROP COLUMN "visibilityStatus"', + ) + } +} diff --git a/packages/server/api/src/app/database/migration/postgres/1695992551156-add-piece-type-and-package-type-to-piece-metadata.ts b/packages/server/api/src/app/database/migration/postgres/1695992551156-add-piece-type-and-package-type-to-piece-metadata.ts new file mode 100644 index 0000000000..05e23cfb6f --- /dev/null +++ b/packages/server/api/src/app/database/migration/postgres/1695992551156-add-piece-type-and-package-type-to-piece-metadata.ts @@ -0,0 +1,45 @@ +import { MigrationInterface, QueryRunner } from 'typeorm' +import { logger } from 'server-shared' + +export class AddPieceTypeAndPackageTypeToPieceMetadata1695992551156 +implements MigrationInterface { + name = 'AddPieceTypeAndPackageTypeToPieceMetadata1695992551156' + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query( + 'ALTER TABLE "piece_metadata" ADD "pieceType" character varying', + ) + await queryRunner.query( + 'UPDATE "piece_metadata" SET "pieceType" = \'OFFICIAL\' WHERE "projectId" IS NULL', + ) + await queryRunner.query( + 'UPDATE "piece_metadata" SET "pieceType" = \'CUSTOM\' WHERE "projectId" IS NOT NULL', + ) + await queryRunner.query( + 'ALTER TABLE "piece_metadata" ALTER COLUMN "pieceType" SET NOT NULL', + ) + + await queryRunner.query( + 'ALTER TABLE "piece_metadata" ADD "packageType" character varying', + ) + await queryRunner.query( + 'UPDATE "piece_metadata" SET "packageType" = \'REGISTRY\'', + ) + await queryRunner.query( + 'ALTER TABLE "piece_metadata" ALTER COLUMN "packageType" SET NOT NULL', + ) + + logger.info('AddPieceTypeAndPackageTypeToPieceMetadata1695992551156 up') + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query( + 'ALTER TABLE "piece_metadata" DROP COLUMN "packageType"', + ) + await queryRunner.query( + 'ALTER TABLE "piece_metadata" DROP COLUMN "pieceType"', + ) + + logger.info('AddPieceTypeAndPackageTypeToPieceMetadata1695992551156 down') + } +} diff --git a/packages/backend/src/app/database/migration/postgres/1696950789636-add-archive-id-to-piece-metadata.ts b/packages/server/api/src/app/database/migration/postgres/1696950789636-add-archive-id-to-piece-metadata.ts similarity index 90% rename from packages/backend/src/app/database/migration/postgres/1696950789636-add-archive-id-to-piece-metadata.ts rename to packages/server/api/src/app/database/migration/postgres/1696950789636-add-archive-id-to-piece-metadata.ts index ff3d29093b..66b0e78d2b 100644 --- a/packages/backend/src/app/database/migration/postgres/1696950789636-add-archive-id-to-piece-metadata.ts +++ b/packages/server/api/src/app/database/migration/postgres/1696950789636-add-archive-id-to-piece-metadata.ts @@ -1,7 +1,8 @@ import { MigrationInterface, QueryRunner } from 'typeorm' -import { logger } from '../../../helper/logger' +import { logger } from 'server-shared' -export class AddArchiveIdToPieceMetadata1696950789636 implements MigrationInterface { +export class AddArchiveIdToPieceMetadata1696950789636 +implements MigrationInterface { name = 'AddArchiveIdToPieceMetadata1696950789636' public async up(queryRunner: QueryRunner): Promise { @@ -34,5 +35,4 @@ export class AddArchiveIdToPieceMetadata1696950789636 implements MigrationInterf logger.info('AddArchiveIdToPieceMetadata1696950789636 down') } - } diff --git a/packages/backend/src/app/database/migration/postgres/1698065083750-add-platform-to-project.ts b/packages/server/api/src/app/database/migration/postgres/1698065083750-add-platform-to-project.ts similarity index 95% rename from packages/backend/src/app/database/migration/postgres/1698065083750-add-platform-to-project.ts rename to packages/server/api/src/app/database/migration/postgres/1698065083750-add-platform-to-project.ts index 3c699350b4..76f697c9cc 100644 --- a/packages/backend/src/app/database/migration/postgres/1698065083750-add-platform-to-project.ts +++ b/packages/server/api/src/app/database/migration/postgres/1698065083750-add-platform-to-project.ts @@ -1,5 +1,5 @@ import { MigrationInterface, QueryRunner } from 'typeorm' -import { logger } from '../../../helper/logger' +import { logger } from 'server-shared' export class AddPlatformToProject1698065083750 implements MigrationInterface { name = 'AddPlatformToProject1698065083750' @@ -27,5 +27,4 @@ export class AddPlatformToProject1698065083750 implements MigrationInterface { logger.info('AddPlatformToProject1698065083750 down') } - } diff --git a/packages/backend/src/app/database/migration/postgres/1698323987669-AddTerminationReason.ts b/packages/server/api/src/app/database/migration/postgres/1698323987669-AddTerminationReason.ts similarity index 99% rename from packages/backend/src/app/database/migration/postgres/1698323987669-AddTerminationReason.ts rename to packages/server/api/src/app/database/migration/postgres/1698323987669-AddTerminationReason.ts index 588c4a9059..bfc580e152 100644 --- a/packages/backend/src/app/database/migration/postgres/1698323987669-AddTerminationReason.ts +++ b/packages/server/api/src/app/database/migration/postgres/1698323987669-AddTerminationReason.ts @@ -26,7 +26,5 @@ export class AddTerminationReason1698323987669 implements MigrationInterface { await queryRunner.query(` ALTER TABLE "flow_run" DROP COLUMN "terminationReason" `) - } - } diff --git a/packages/backend/src/app/database/migration/postgres/1698602417745-add-signing-key.ts b/packages/server/api/src/app/database/migration/postgres/1698602417745-add-signing-key.ts similarity index 97% rename from packages/backend/src/app/database/migration/postgres/1698602417745-add-signing-key.ts rename to packages/server/api/src/app/database/migration/postgres/1698602417745-add-signing-key.ts index 7fa64e0e09..9fa38919b2 100644 --- a/packages/backend/src/app/database/migration/postgres/1698602417745-add-signing-key.ts +++ b/packages/server/api/src/app/database/migration/postgres/1698602417745-add-signing-key.ts @@ -1,5 +1,5 @@ import { MigrationInterface, QueryRunner } from 'typeorm' -import { logger } from '../../../helper/logger' +import { logger } from 'server-shared' export class AddSigningKey1698602417745 implements MigrationInterface { name = 'AddSigningKey1698602417745' @@ -42,5 +42,4 @@ export class AddSigningKey1698602417745 implements MigrationInterface { logger.info('AddSigningKey1698602417745 down') } - } diff --git a/packages/backend/src/app/database/migration/postgres/1698698190965-AddDisplayNameToSigningKey.ts b/packages/server/api/src/app/database/migration/postgres/1698698190965-AddDisplayNameToSigningKey.ts similarity index 85% rename from packages/backend/src/app/database/migration/postgres/1698698190965-AddDisplayNameToSigningKey.ts rename to packages/server/api/src/app/database/migration/postgres/1698698190965-AddDisplayNameToSigningKey.ts index 0d792ecee2..86982a3e76 100644 --- a/packages/backend/src/app/database/migration/postgres/1698698190965-AddDisplayNameToSigningKey.ts +++ b/packages/server/api/src/app/database/migration/postgres/1698698190965-AddDisplayNameToSigningKey.ts @@ -1,6 +1,7 @@ import { MigrationInterface, QueryRunner } from 'typeorm' -export class AddDisplayNameToSigningKey1698698190965 implements MigrationInterface { +export class AddDisplayNameToSigningKey1698698190965 +implements MigrationInterface { name = 'AddDisplayNameToSigningKey1698698190965' public async up(queryRunner: QueryRunner): Promise { @@ -15,5 +16,4 @@ export class AddDisplayNameToSigningKey1698698190965 implements MigrationInterfa ALTER TABLE "signing_key" DROP COLUMN "displayName" `) } - } diff --git a/packages/backend/src/app/database/migration/postgres/1698700720482-managed-authn-initial.ts b/packages/server/api/src/app/database/migration/postgres/1698700720482-managed-authn-initial.ts similarity index 96% rename from packages/backend/src/app/database/migration/postgres/1698700720482-managed-authn-initial.ts rename to packages/server/api/src/app/database/migration/postgres/1698700720482-managed-authn-initial.ts index 9b4d04133f..e7b429e1b8 100644 --- a/packages/backend/src/app/database/migration/postgres/1698700720482-managed-authn-initial.ts +++ b/packages/server/api/src/app/database/migration/postgres/1698700720482-managed-authn-initial.ts @@ -1,5 +1,5 @@ import { MigrationInterface, QueryRunner } from 'typeorm' -import { logger } from '../../../helper/logger' +import { logger } from 'server-shared' export class ManagedAuthnInitial1698700720482 implements MigrationInterface { name = 'ManagedAuthnInitial1698700720482' @@ -39,5 +39,4 @@ export class ManagedAuthnInitial1698700720482 implements MigrationInterface { logger.info('ManagedAuthnInitial1698700720482 down') } - } diff --git a/packages/backend/src/app/database/migration/postgres/1699221414907-AddOAuth2AppEntiity.ts b/packages/server/api/src/app/database/migration/postgres/1699221414907-AddOAuth2AppEntiity.ts similarity index 99% rename from packages/backend/src/app/database/migration/postgres/1699221414907-AddOAuth2AppEntiity.ts rename to packages/server/api/src/app/database/migration/postgres/1699221414907-AddOAuth2AppEntiity.ts index 5b8dbb1109..e5e22d1fe4 100644 --- a/packages/backend/src/app/database/migration/postgres/1699221414907-AddOAuth2AppEntiity.ts +++ b/packages/server/api/src/app/database/migration/postgres/1699221414907-AddOAuth2AppEntiity.ts @@ -36,5 +36,4 @@ export class AddOAuth2AppEntiity1699221414907 implements MigrationInterface { DROP TABLE "oauth_app" `) } - } diff --git a/packages/backend/src/app/database/migration/postgres/1699281870038-add-filtered-pieces-to-platform.ts b/packages/server/api/src/app/database/migration/postgres/1699281870038-add-filtered-pieces-to-platform.ts similarity index 92% rename from packages/backend/src/app/database/migration/postgres/1699281870038-add-filtered-pieces-to-platform.ts rename to packages/server/api/src/app/database/migration/postgres/1699281870038-add-filtered-pieces-to-platform.ts index 12cf7eb957..ee118f4063 100644 --- a/packages/backend/src/app/database/migration/postgres/1699281870038-add-filtered-pieces-to-platform.ts +++ b/packages/server/api/src/app/database/migration/postgres/1699281870038-add-filtered-pieces-to-platform.ts @@ -1,6 +1,7 @@ import { MigrationInterface, QueryRunner } from 'typeorm' -export class AddFilteredPiecesToPlatform1699281870038 implements MigrationInterface { +export class AddFilteredPiecesToPlatform1699281870038 +implements MigrationInterface { name = 'AddFilteredPiecesToPlatform1699281870038' public async up(queryRunner: QueryRunner): Promise { @@ -30,5 +31,4 @@ export class AddFilteredPiecesToPlatform1699281870038 implements MigrationInterf ALTER TABLE "platform" DROP COLUMN "filteredPieceNames" `) } - } diff --git a/packages/backend/src/app/database/migration/postgres/1699491705906-AddSmtpAndPrivacyUrlToPlatform.ts b/packages/server/api/src/app/database/migration/postgres/1699491705906-AddSmtpAndPrivacyUrlToPlatform.ts similarity index 96% rename from packages/backend/src/app/database/migration/postgres/1699491705906-AddSmtpAndPrivacyUrlToPlatform.ts rename to packages/server/api/src/app/database/migration/postgres/1699491705906-AddSmtpAndPrivacyUrlToPlatform.ts index f974768edd..225d1a8b5e 100644 --- a/packages/backend/src/app/database/migration/postgres/1699491705906-AddSmtpAndPrivacyUrlToPlatform.ts +++ b/packages/server/api/src/app/database/migration/postgres/1699491705906-AddSmtpAndPrivacyUrlToPlatform.ts @@ -1,6 +1,7 @@ import { MigrationInterface, QueryRunner } from 'typeorm' -export class AddSmtpAndPrivacyUrlToPlatform1699491705906 implements MigrationInterface { +export class AddSmtpAndPrivacyUrlToPlatform1699491705906 +implements MigrationInterface { name = 'AddSmtpAndPrivacyUrlToPlatform1699491705906' public async up(queryRunner: QueryRunner): Promise { @@ -45,7 +46,7 @@ export class AddSmtpAndPrivacyUrlToPlatform1699491705906 implements MigrationInt UPDATE "platform" SET "showPoweredBy" = false `) - + await queryRunner.query(` ALTER TABLE "platform" ALTER COLUMN "showPoweredBy" SET NOT NULL @@ -55,7 +56,6 @@ export class AddSmtpAndPrivacyUrlToPlatform1699491705906 implements MigrationInt ALTER TABLE "platform" ADD "cloudAuthEnabled" boolean NOT NULL DEFAULT true `) - } public async down(queryRunner: QueryRunner): Promise { @@ -90,5 +90,4 @@ export class AddSmtpAndPrivacyUrlToPlatform1699491705906 implements MigrationInt ALTER TABLE "platform" DROP COLUMN "smtpHost" `) } - } diff --git a/packages/backend/src/app/database/migration/postgres/1699901161457-add-platform-id-to-user.ts b/packages/server/api/src/app/database/migration/postgres/1699901161457-add-platform-id-to-user.ts similarity index 97% rename from packages/backend/src/app/database/migration/postgres/1699901161457-add-platform-id-to-user.ts rename to packages/server/api/src/app/database/migration/postgres/1699901161457-add-platform-id-to-user.ts index 4e8da7fdb8..bcf47776a9 100644 --- a/packages/backend/src/app/database/migration/postgres/1699901161457-add-platform-id-to-user.ts +++ b/packages/server/api/src/app/database/migration/postgres/1699901161457-add-platform-id-to-user.ts @@ -1,5 +1,5 @@ import { MigrationInterface, QueryRunner } from 'typeorm' -import { logger } from '../../../helper/logger' +import { logger } from 'server-shared' export class AddPlatformIdToUser1699901161457 implements MigrationInterface { name = 'AddPlatformIdToUser1699901161457' @@ -45,5 +45,4 @@ export class AddPlatformIdToUser1699901161457 implements MigrationInterface { logger.info('AddPlatformIdToUser1699901161457 down') } - } diff --git a/packages/backend/src/app/database/migration/postgres/1700132368636-RemoveUnusedFieldsinBilling.ts b/packages/server/api/src/app/database/migration/postgres/1700132368636-RemoveUnusedFieldsinBilling.ts similarity index 96% rename from packages/backend/src/app/database/migration/postgres/1700132368636-RemoveUnusedFieldsinBilling.ts rename to packages/server/api/src/app/database/migration/postgres/1700132368636-RemoveUnusedFieldsinBilling.ts index 46147043b3..6c5e860c86 100644 --- a/packages/backend/src/app/database/migration/postgres/1700132368636-RemoveUnusedFieldsinBilling.ts +++ b/packages/server/api/src/app/database/migration/postgres/1700132368636-RemoveUnusedFieldsinBilling.ts @@ -1,6 +1,7 @@ import { MigrationInterface, QueryRunner } from 'typeorm' -export class RemoveUnusedFieldsinBilling1700132368636 implements MigrationInterface { +export class RemoveUnusedFieldsinBilling1700132368636 +implements MigrationInterface { name = 'RemoveUnusedFieldsinBilling1700132368636' public async up(queryRunner: QueryRunner): Promise { @@ -75,5 +76,4 @@ export class RemoveUnusedFieldsinBilling1700132368636 implements MigrationInterf ADD "activeFlows" integer NOT NULL `) } - } diff --git a/packages/backend/src/app/database/migration/postgres/1700396157624-add-otp-entity.ts b/packages/server/api/src/app/database/migration/postgres/1700396157624-add-otp-entity.ts similarity index 96% rename from packages/backend/src/app/database/migration/postgres/1700396157624-add-otp-entity.ts rename to packages/server/api/src/app/database/migration/postgres/1700396157624-add-otp-entity.ts index 0e19f143d7..9b374c4ff9 100644 --- a/packages/backend/src/app/database/migration/postgres/1700396157624-add-otp-entity.ts +++ b/packages/server/api/src/app/database/migration/postgres/1700396157624-add-otp-entity.ts @@ -1,5 +1,5 @@ import { MigrationInterface, QueryRunner } from 'typeorm' -import { logger } from '../../../helper/logger' +import { logger } from 'server-shared' export class AddOtpEntity1700396157624 implements MigrationInterface { name = 'AddOtpEntity1700396157624' @@ -40,5 +40,4 @@ export class AddOtpEntity1700396157624 implements MigrationInterface { logger.info('AddOtpEntity1700396157624 down') } - } diff --git a/packages/backend/src/app/database/migration/postgres/1700406308445-AddPlatformDefaultLanguage.ts b/packages/server/api/src/app/database/migration/postgres/1700406308445-AddPlatformDefaultLanguage.ts similarity index 85% rename from packages/backend/src/app/database/migration/postgres/1700406308445-AddPlatformDefaultLanguage.ts rename to packages/server/api/src/app/database/migration/postgres/1700406308445-AddPlatformDefaultLanguage.ts index c5920e4569..ed81bb8a0b 100644 --- a/packages/backend/src/app/database/migration/postgres/1700406308445-AddPlatformDefaultLanguage.ts +++ b/packages/server/api/src/app/database/migration/postgres/1700406308445-AddPlatformDefaultLanguage.ts @@ -1,6 +1,7 @@ import { MigrationInterface, QueryRunner } from 'typeorm' -export class AddPlatformDefaultLanguage1700406308445 implements MigrationInterface { +export class AddPlatformDefaultLanguage1700406308445 +implements MigrationInterface { name = 'AddPlatformDefaultLanguage1700406308445' public async up(queryRunner: QueryRunner): Promise { @@ -15,5 +16,4 @@ export class AddPlatformDefaultLanguage1700406308445 implements MigrationInterfa ALTER TABLE "platform" DROP COLUMN "defaultLocale" `) } - } diff --git a/packages/backend/src/app/database/migration/postgres/1700522340280-AddPlatformIdToPieceMetadata.ts b/packages/server/api/src/app/database/migration/postgres/1700522340280-AddPlatformIdToPieceMetadata.ts similarity index 85% rename from packages/backend/src/app/database/migration/postgres/1700522340280-AddPlatformIdToPieceMetadata.ts rename to packages/server/api/src/app/database/migration/postgres/1700522340280-AddPlatformIdToPieceMetadata.ts index 6c82309333..a4d045e190 100644 --- a/packages/backend/src/app/database/migration/postgres/1700522340280-AddPlatformIdToPieceMetadata.ts +++ b/packages/server/api/src/app/database/migration/postgres/1700522340280-AddPlatformIdToPieceMetadata.ts @@ -1,6 +1,7 @@ import { MigrationInterface, QueryRunner } from 'typeorm' -export class AddPlatformIdToPieceMetadata1700522340280 implements MigrationInterface { +export class AddPlatformIdToPieceMetadata1700522340280 +implements MigrationInterface { name = 'AddPlatformIdToPieceMetadata1700522340280' public async up(queryRunner: QueryRunner): Promise { @@ -15,5 +16,4 @@ export class AddPlatformIdToPieceMetadata1700522340280 implements MigrationInter ALTER TABLE "piece_metadata" DROP COLUMN "platformId" `) } - } diff --git a/packages/backend/src/app/database/migration/postgres/1700751925992-MakeStripeCustomerIdNullable.ts b/packages/server/api/src/app/database/migration/postgres/1700751925992-MakeStripeCustomerIdNullable.ts similarity index 88% rename from packages/backend/src/app/database/migration/postgres/1700751925992-MakeStripeCustomerIdNullable.ts rename to packages/server/api/src/app/database/migration/postgres/1700751925992-MakeStripeCustomerIdNullable.ts index 95c217e375..53b6c4fa33 100644 --- a/packages/backend/src/app/database/migration/postgres/1700751925992-MakeStripeCustomerIdNullable.ts +++ b/packages/server/api/src/app/database/migration/postgres/1700751925992-MakeStripeCustomerIdNullable.ts @@ -1,7 +1,8 @@ import { MigrationInterface, QueryRunner } from 'typeorm' -import { logger } from '../../../helper/logger' +import { logger } from 'server-shared' -export class MakeStripeCustomerIdNullable1700751925992 implements MigrationInterface { +export class MakeStripeCustomerIdNullable1700751925992 +implements MigrationInterface { name = 'MakeStripeCustomerIdNullable1700751925992' public async up(queryRunner: QueryRunner): Promise { @@ -27,5 +28,4 @@ export class MakeStripeCustomerIdNullable1700751925992 implements MigrationInter CREATE UNIQUE INDEX "idx_plan_stripe_customer_id" ON "project_plan" ("stripeCustomerId") `) } - } diff --git a/packages/backend/src/app/database/migration/postgres/1701084418793-add-state-to-otp.ts b/packages/server/api/src/app/database/migration/postgres/1701084418793-add-state-to-otp.ts similarity index 92% rename from packages/backend/src/app/database/migration/postgres/1701084418793-add-state-to-otp.ts rename to packages/server/api/src/app/database/migration/postgres/1701084418793-add-state-to-otp.ts index 18ca8d20e6..4fc8eed5df 100644 --- a/packages/backend/src/app/database/migration/postgres/1701084418793-add-state-to-otp.ts +++ b/packages/server/api/src/app/database/migration/postgres/1701084418793-add-state-to-otp.ts @@ -1,5 +1,5 @@ import { MigrationInterface, QueryRunner } from 'typeorm' -import { logger } from '../../../helper/logger' +import { logger } from 'server-shared' export class AddStateToOtp1701084418793 implements MigrationInterface { name = 'AddStateToOtp1701084418793' @@ -20,5 +20,4 @@ export class AddStateToOtp1701084418793 implements MigrationInterface { logger.info('AddStateToOtp1701084418793 down') } - } diff --git a/packages/backend/src/app/database/migration/postgres/1701261357197-migrate-ee-users-to-oldest-platform.ts b/packages/server/api/src/app/database/migration/postgres/1701261357197-migrate-ee-users-to-oldest-platform.ts similarity index 90% rename from packages/backend/src/app/database/migration/postgres/1701261357197-migrate-ee-users-to-oldest-platform.ts rename to packages/server/api/src/app/database/migration/postgres/1701261357197-migrate-ee-users-to-oldest-platform.ts index 6904b33e29..a4dfaf3495 100644 --- a/packages/backend/src/app/database/migration/postgres/1701261357197-migrate-ee-users-to-oldest-platform.ts +++ b/packages/server/api/src/app/database/migration/postgres/1701261357197-migrate-ee-users-to-oldest-platform.ts @@ -1,7 +1,8 @@ import { MigrationInterface, QueryRunner } from 'typeorm' import { isNil } from '@activepieces/shared' -export class MigrateEeUsersToOldestPlatform1701261357197 implements MigrationInterface { +export class MigrateEeUsersToOldestPlatform1701261357197 +implements MigrationInterface { name = 'MigrateEeUsersToOldestPlatform1701261357197' public async up(queryRunner: QueryRunner): Promise { @@ -30,5 +31,4 @@ export class MigrateEeUsersToOldestPlatform1701261357197 implements MigrationInt WHERE "platformId" IS NOT NULL `) } - } diff --git a/packages/backend/src/app/database/migration/postgres/1701647565290-ModifyProjectMembersAndRemoveUserId.ts b/packages/server/api/src/app/database/migration/postgres/1701647565290-ModifyProjectMembersAndRemoveUserId.ts similarity index 96% rename from packages/backend/src/app/database/migration/postgres/1701647565290-ModifyProjectMembersAndRemoveUserId.ts rename to packages/server/api/src/app/database/migration/postgres/1701647565290-ModifyProjectMembersAndRemoveUserId.ts index 1360984442..cc98125e78 100644 --- a/packages/backend/src/app/database/migration/postgres/1701647565290-ModifyProjectMembersAndRemoveUserId.ts +++ b/packages/server/api/src/app/database/migration/postgres/1701647565290-ModifyProjectMembersAndRemoveUserId.ts @@ -1,6 +1,7 @@ import { MigrationInterface, QueryRunner } from 'typeorm' -export class ModifyProjectMembersAndRemoveUserId1701647565290 implements MigrationInterface { +export class ModifyProjectMembersAndRemoveUserId1701647565290 +implements MigrationInterface { name = 'ModifyProjectMembersAndRemoveUserId1701647565290' public async up(queryRunner: QueryRunner): Promise { @@ -36,8 +37,6 @@ export class ModifyProjectMembersAndRemoveUserId1701647565290 implements Migrati await queryRunner.query(` ALTER TABLE "project_member" DROP COLUMN "userId" `) - - } public async down(queryRunner: QueryRunner): Promise { @@ -62,5 +61,4 @@ export class ModifyProjectMembersAndRemoveUserId1701647565290 implements Migrati ADD CONSTRAINT "fk_project_member_user_id" FOREIGN KEY ("userId") REFERENCES "user"("id") ON DELETE CASCADE ON UPDATE NO ACTION `) } - } diff --git a/packages/backend/src/app/database/migration/postgres/1701716639135-AddApiKeys.ts b/packages/server/api/src/app/database/migration/postgres/1701716639135-AddApiKeys.ts similarity index 99% rename from packages/backend/src/app/database/migration/postgres/1701716639135-AddApiKeys.ts rename to packages/server/api/src/app/database/migration/postgres/1701716639135-AddApiKeys.ts index 71027199ee..1fa3b122c7 100644 --- a/packages/backend/src/app/database/migration/postgres/1701716639135-AddApiKeys.ts +++ b/packages/server/api/src/app/database/migration/postgres/1701716639135-AddApiKeys.ts @@ -30,5 +30,4 @@ export class AddApiKeys1701716639135 implements MigrationInterface { DROP TABLE "api_key" `) } - } diff --git a/packages/backend/src/app/database/migration/postgres/1701794452891-AddEmbeddingFeatureToPlatform.ts b/packages/server/api/src/app/database/migration/postgres/1701794452891-AddEmbeddingFeatureToPlatform.ts similarity index 87% rename from packages/backend/src/app/database/migration/postgres/1701794452891-AddEmbeddingFeatureToPlatform.ts rename to packages/server/api/src/app/database/migration/postgres/1701794452891-AddEmbeddingFeatureToPlatform.ts index 8f349d04e3..708bfca2d4 100644 --- a/packages/backend/src/app/database/migration/postgres/1701794452891-AddEmbeddingFeatureToPlatform.ts +++ b/packages/server/api/src/app/database/migration/postgres/1701794452891-AddEmbeddingFeatureToPlatform.ts @@ -1,6 +1,7 @@ import { MigrationInterface, QueryRunner } from 'typeorm' -export class AddEmbeddingFeatureToPlatform1701794452891 implements MigrationInterface { +export class AddEmbeddingFeatureToPlatform1701794452891 +implements MigrationInterface { name = 'AddEmbeddingFeatureToPlatform1701794452891' public async up(queryRunner: QueryRunner): Promise { @@ -20,5 +21,4 @@ export class AddEmbeddingFeatureToPlatform1701794452891 implements MigrationInte ALTER TABLE "platform" DROP COLUMN "embeddingEnabled" `) } - } diff --git a/packages/backend/src/app/database/migration/postgres/1701807681821-AddPlatformIdToFile.ts b/packages/server/api/src/app/database/migration/postgres/1701807681821-AddPlatformIdToFile.ts similarity index 99% rename from packages/backend/src/app/database/migration/postgres/1701807681821-AddPlatformIdToFile.ts rename to packages/server/api/src/app/database/migration/postgres/1701807681821-AddPlatformIdToFile.ts index 3f61631526..86833d481a 100644 --- a/packages/backend/src/app/database/migration/postgres/1701807681821-AddPlatformIdToFile.ts +++ b/packages/server/api/src/app/database/migration/postgres/1701807681821-AddPlatformIdToFile.ts @@ -15,5 +15,4 @@ export class AddPlatformIdToFile1701807681821 implements MigrationInterface { ALTER TABLE "file" DROP COLUMN "platformId" `) } - } diff --git a/packages/backend/src/app/database/migration/postgres/1702379794665-remove-flow-instance.ts b/packages/server/api/src/app/database/migration/postgres/1702379794665-remove-flow-instance.ts similarity index 98% rename from packages/backend/src/app/database/migration/postgres/1702379794665-remove-flow-instance.ts rename to packages/server/api/src/app/database/migration/postgres/1702379794665-remove-flow-instance.ts index 95031ca4a2..0f33f89b4d 100644 --- a/packages/backend/src/app/database/migration/postgres/1702379794665-remove-flow-instance.ts +++ b/packages/server/api/src/app/database/migration/postgres/1702379794665-remove-flow-instance.ts @@ -1,5 +1,5 @@ import { MigrationInterface, QueryRunner } from 'typeorm' -import { logger } from '../../../helper/logger' +import { logger } from 'server-shared' export class RemoveFlowInstance1702379794665 implements MigrationInterface { name = 'RemoveFlowInstance1702379794665' @@ -76,5 +76,4 @@ export class RemoveFlowInstance1702379794665 implements MigrationInterface { logger.info('RemoveFlowInstance1702379794665 down') } - } diff --git a/packages/backend/src/app/database/migration/postgres/1703411318826-AddPlatformIdToFlowTemplates.ts b/packages/server/api/src/app/database/migration/postgres/1703411318826-AddPlatformIdToFlowTemplates.ts similarity index 97% rename from packages/backend/src/app/database/migration/postgres/1703411318826-AddPlatformIdToFlowTemplates.ts rename to packages/server/api/src/app/database/migration/postgres/1703411318826-AddPlatformIdToFlowTemplates.ts index a87f7ce8d0..0adcba7011 100644 --- a/packages/backend/src/app/database/migration/postgres/1703411318826-AddPlatformIdToFlowTemplates.ts +++ b/packages/server/api/src/app/database/migration/postgres/1703411318826-AddPlatformIdToFlowTemplates.ts @@ -1,6 +1,7 @@ import { MigrationInterface, QueryRunner } from 'typeorm' -export class AddPlatformIdToFlowTemplates1703411318826 implements MigrationInterface { +export class AddPlatformIdToFlowTemplates1703411318826 +implements MigrationInterface { name = 'AddPlatformIdToFlowTemplates1703411318826' public async up(queryRunner: QueryRunner): Promise { @@ -79,5 +80,4 @@ export class AddPlatformIdToFlowTemplates1703411318826 implements MigrationInter ADD CONSTRAINT "fk_flow_template_user_id" FOREIGN KEY ("userId") REFERENCES "user"("id") ON DELETE CASCADE ON UPDATE NO ACTION `) } - } diff --git a/packages/backend/src/app/database/migration/postgres/1703711596105-RenameAppNameToPieceName.ts b/packages/server/api/src/app/database/migration/postgres/1703711596105-RenameAppNameToPieceName.ts similarity index 86% rename from packages/backend/src/app/database/migration/postgres/1703711596105-RenameAppNameToPieceName.ts rename to packages/server/api/src/app/database/migration/postgres/1703711596105-RenameAppNameToPieceName.ts index 525ace720e..fcbf4c72d3 100644 --- a/packages/backend/src/app/database/migration/postgres/1703711596105-RenameAppNameToPieceName.ts +++ b/packages/server/api/src/app/database/migration/postgres/1703711596105-RenameAppNameToPieceName.ts @@ -1,6 +1,7 @@ import { MigrationInterface, QueryRunner } from 'typeorm' -export class RenameAppNameToPieceName1703711596105 implements MigrationInterface { +export class RenameAppNameToPieceName1703711596105 +implements MigrationInterface { name = 'RenameAppNameToPieceName1703711596105' public async up(queryRunner: QueryRunner): Promise { @@ -16,5 +17,4 @@ export class RenameAppNameToPieceName1703711596105 implements MigrationInterface RENAME COLUMN "pieceName" TO "appName" `) } - } diff --git a/packages/backend/src/app/database/migration/postgres/1703769034497-AddVerifiedAndChangeStatus.ts b/packages/server/api/src/app/database/migration/postgres/1703769034497-AddVerifiedAndChangeStatus.ts similarity index 92% rename from packages/backend/src/app/database/migration/postgres/1703769034497-AddVerifiedAndChangeStatus.ts rename to packages/server/api/src/app/database/migration/postgres/1703769034497-AddVerifiedAndChangeStatus.ts index ab44a2c2d7..eb6585acef 100644 --- a/packages/backend/src/app/database/migration/postgres/1703769034497-AddVerifiedAndChangeStatus.ts +++ b/packages/server/api/src/app/database/migration/postgres/1703769034497-AddVerifiedAndChangeStatus.ts @@ -1,6 +1,7 @@ import { MigrationInterface, QueryRunner } from 'typeorm' -export class AddVerifiedAndChangeStatus1703769034497 implements MigrationInterface { +export class AddVerifiedAndChangeStatus1703769034497 +implements MigrationInterface { name = 'AddVerifiedAndChangeStatus1703769034497' public async up(queryRunner: QueryRunner): Promise { @@ -12,7 +13,7 @@ export class AddVerifiedAndChangeStatus1703769034497 implements MigrationInterfa UPDATE "user" SET "verified" = false `) - + await queryRunner.query(` ALTER TABLE "user" ALTER COLUMN "verified" SET NOT NULL @@ -23,12 +24,11 @@ export class AddVerifiedAndChangeStatus1703769034497 implements MigrationInterfa SET "verified" = true WHERE "status" = 'VERIFIED' `) - + await queryRunner.query(` UPDATE "user" SET "status" = 'ACTIVE' `) - } public async down(queryRunner: QueryRunner): Promise { @@ -54,5 +54,4 @@ export class AddVerifiedAndChangeStatus1703769034497 implements MigrationInterfa DROP COLUMN "verified" `) } - } diff --git a/packages/backend/src/app/database/migration/postgres/1704503804056-AddGitRepoMigrationPostgres.ts b/packages/server/api/src/app/database/migration/postgres/1704503804056-AddGitRepoMigrationPostgres.ts similarity index 94% rename from packages/backend/src/app/database/migration/postgres/1704503804056-AddGitRepoMigrationPostgres.ts rename to packages/server/api/src/app/database/migration/postgres/1704503804056-AddGitRepoMigrationPostgres.ts index 804c53568d..da61d67ee5 100644 --- a/packages/backend/src/app/database/migration/postgres/1704503804056-AddGitRepoMigrationPostgres.ts +++ b/packages/server/api/src/app/database/migration/postgres/1704503804056-AddGitRepoMigrationPostgres.ts @@ -1,6 +1,7 @@ import { MigrationInterface, QueryRunner } from 'typeorm' -export class AddGitRepoMigrationPostgres1704503804056 implements MigrationInterface { +export class AddGitRepoMigrationPostgres1704503804056 +implements MigrationInterface { name = 'AddGitRepoMigrationPostgres1704503804056' public async up(queryRunner: QueryRunner): Promise { @@ -37,5 +38,4 @@ export class AddGitRepoMigrationPostgres1704503804056 implements MigrationInterf DROP TABLE "git_repo" `) } - } diff --git a/packages/backend/src/app/database/migration/postgres/1704636362533-AddGitSyncEnabledToPlatform.ts b/packages/server/api/src/app/database/migration/postgres/1704636362533-AddGitSyncEnabledToPlatform.ts similarity index 89% rename from packages/backend/src/app/database/migration/postgres/1704636362533-AddGitSyncEnabledToPlatform.ts rename to packages/server/api/src/app/database/migration/postgres/1704636362533-AddGitSyncEnabledToPlatform.ts index 3c1af8a384..801c9b3f94 100644 --- a/packages/backend/src/app/database/migration/postgres/1704636362533-AddGitSyncEnabledToPlatform.ts +++ b/packages/server/api/src/app/database/migration/postgres/1704636362533-AddGitSyncEnabledToPlatform.ts @@ -1,6 +1,7 @@ import { MigrationInterface, QueryRunner } from 'typeorm' -export class AddGitSyncEnabledToPlatform1704636362533 implements MigrationInterface { +export class AddGitSyncEnabledToPlatform1704636362533 +implements MigrationInterface { name = 'AddGitSyncEnabledToPlatform1704636362533' public async up(queryRunner: QueryRunner): Promise { @@ -25,5 +26,4 @@ export class AddGitSyncEnabledToPlatform1704636362533 implements MigrationInterf ALTER TABLE "platform" DROP COLUMN "gitSyncEnabled" `) } - } diff --git a/packages/backend/src/app/database/migration/postgres/1704667304953-AddAuthOptionsToPlatform.ts b/packages/server/api/src/app/database/migration/postgres/1704667304953-AddAuthOptionsToPlatform.ts similarity index 80% rename from packages/backend/src/app/database/migration/postgres/1704667304953-AddAuthOptionsToPlatform.ts rename to packages/server/api/src/app/database/migration/postgres/1704667304953-AddAuthOptionsToPlatform.ts index a43dd15c9f..7168c48722 100644 --- a/packages/backend/src/app/database/migration/postgres/1704667304953-AddAuthOptionsToPlatform.ts +++ b/packages/server/api/src/app/database/migration/postgres/1704667304953-AddAuthOptionsToPlatform.ts @@ -1,11 +1,11 @@ import { MigrationInterface, QueryRunner } from 'typeorm' -export class AddAuthOptionsToPlatform1704667304953 implements MigrationInterface { +export class AddAuthOptionsToPlatform1704667304953 +implements MigrationInterface { name = 'AddAuthOptionsToPlatform1704667304953' public async up(queryRunner: QueryRunner): Promise { - - // allowedAuthDomains + // allowedAuthDomains await queryRunner.query(` ALTER TABLE "platform" ADD COLUMN "allowedAuthDomains" character varying[] @@ -19,7 +19,6 @@ export class AddAuthOptionsToPlatform1704667304953 implements MigrationInterface ALTER COLUMN "allowedAuthDomains" SET NOT NULL `) - // enforceAllowedAuthDomains await queryRunner.query(` ALTER TABLE "platform" @@ -49,10 +48,15 @@ export class AddAuthOptionsToPlatform1704667304953 implements MigrationInterface `) // federatedAuthProviders - await queryRunner.query('ALTER TABLE "platform" ADD COLUMN "federatedAuthProviders" jsonb') - await queryRunner.query('UPDATE "platform" SET "federatedAuthProviders" = \'{}\'') - await queryRunner.query('ALTER TABLE "platform" ALTER COLUMN "federatedAuthProviders" SET NOT NULL') - + await queryRunner.query( + 'ALTER TABLE "platform" ADD COLUMN "federatedAuthProviders" jsonb', + ) + await queryRunner.query( + 'UPDATE "platform" SET "federatedAuthProviders" = \'{}\'', + ) + await queryRunner.query( + 'ALTER TABLE "platform" ALTER COLUMN "federatedAuthProviders" SET NOT NULL', + ) } public async down(queryRunner: QueryRunner): Promise { @@ -69,5 +73,4 @@ export class AddAuthOptionsToPlatform1704667304953 implements MigrationInterface ALTER TABLE "platform" DROP COLUMN "allowedAuthDomains" `) } - } diff --git a/packages/backend/src/app/database/migration/postgres/1704797979825-AddEnableEmailAuthToPlatform.ts b/packages/server/api/src/app/database/migration/postgres/1704797979825-AddEnableEmailAuthToPlatform.ts similarity index 58% rename from packages/backend/src/app/database/migration/postgres/1704797979825-AddEnableEmailAuthToPlatform.ts rename to packages/server/api/src/app/database/migration/postgres/1704797979825-AddEnableEmailAuthToPlatform.ts index fec9f66f45..c328e6d9d3 100644 --- a/packages/backend/src/app/database/migration/postgres/1704797979825-AddEnableEmailAuthToPlatform.ts +++ b/packages/server/api/src/app/database/migration/postgres/1704797979825-AddEnableEmailAuthToPlatform.ts @@ -1,12 +1,17 @@ import { MigrationInterface, QueryRunner } from 'typeorm' -export class AddEnableEmailAuthToPlatform1704797979825 implements MigrationInterface { +export class AddEnableEmailAuthToPlatform1704797979825 +implements MigrationInterface { name = 'AddEnableEmailAuthToPlatform1704797979825' public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query('ALTER TABLE "platform" ADD "emailAuthEnabled" boolean') + await queryRunner.query( + 'ALTER TABLE "platform" ADD "emailAuthEnabled" boolean', + ) await queryRunner.query('UPDATE "platform" SET "emailAuthEnabled" = TRUE') - await queryRunner.query('ALTER TABLE "platform" ALTER COLUMN "emailAuthEnabled" SET NOT NULL') + await queryRunner.query( + 'ALTER TABLE "platform" ALTER COLUMN "emailAuthEnabled" SET NOT NULL', + ) } public async down(queryRunner: QueryRunner): Promise { @@ -14,5 +19,4 @@ export class AddEnableEmailAuthToPlatform1704797979825 implements MigrationInter ALTER TABLE "platform" DROP COLUMN "emailAuthEnabled" `) } - } diff --git a/packages/backend/src/app/database/migration/postgres/1705586178452-RemoveUniqueonAppNameAppCredentials.ts b/packages/server/api/src/app/database/migration/postgres/1705586178452-RemoveUniqueonAppNameAppCredentials.ts similarity index 85% rename from packages/backend/src/app/database/migration/postgres/1705586178452-RemoveUniqueonAppNameAppCredentials.ts rename to packages/server/api/src/app/database/migration/postgres/1705586178452-RemoveUniqueonAppNameAppCredentials.ts index cbc475fea4..95b8418c37 100644 --- a/packages/backend/src/app/database/migration/postgres/1705586178452-RemoveUniqueonAppNameAppCredentials.ts +++ b/packages/server/api/src/app/database/migration/postgres/1705586178452-RemoveUniqueonAppNameAppCredentials.ts @@ -1,6 +1,7 @@ import { MigrationInterface, QueryRunner } from 'typeorm' -export class RemoveUniqueonAppNameAppCredentials1705586178452 implements MigrationInterface { +export class RemoveUniqueonAppNameAppCredentials1705586178452 +implements MigrationInterface { name = 'RemoveUniqueonAppNameAppCredentials1705586178452' public async up(queryRunner: QueryRunner): Promise { @@ -14,5 +15,4 @@ export class RemoveUniqueonAppNameAppCredentials1705586178452 implements Migrati CREATE UNIQUE INDEX "idx_app_credentials_projectId_appName" ON "app_credential" ("appName", "projectId") `) } - } diff --git a/packages/backend/src/app/database/migration/postgres/1707231704973-AddCategoriesToPieceMetadataPostgres.ts b/packages/server/api/src/app/database/migration/postgres/1707231704973-AddCategoriesToPieceMetadataPostgres.ts similarity index 84% rename from packages/backend/src/app/database/migration/postgres/1707231704973-AddCategoriesToPieceMetadataPostgres.ts rename to packages/server/api/src/app/database/migration/postgres/1707231704973-AddCategoriesToPieceMetadataPostgres.ts index fbca8e549d..2a56df804c 100644 --- a/packages/backend/src/app/database/migration/postgres/1707231704973-AddCategoriesToPieceMetadataPostgres.ts +++ b/packages/server/api/src/app/database/migration/postgres/1707231704973-AddCategoriesToPieceMetadataPostgres.ts @@ -1,6 +1,7 @@ import { MigrationInterface, QueryRunner } from 'typeorm' -export class AddCategoriesToPieceMetadataPostgres1707231704973 implements MigrationInterface { +export class AddCategoriesToPieceMetadataPostgres1707231704973 +implements MigrationInterface { name = 'AddCategoriesToPieceMetadataPostgres1707231704973' public async up(queryRunner: QueryRunner): Promise { @@ -15,5 +16,4 @@ export class AddCategoriesToPieceMetadataPostgres1707231704973 implements Migrat ALTER TABLE "piece_metadata" DROP COLUMN "categories" `) } - } diff --git a/packages/backend/src/app/database/migration/postgres/1707614902283-AddAuditEvents.ts b/packages/server/api/src/app/database/migration/postgres/1707614902283-AddAuditEvents.ts similarity index 99% rename from packages/backend/src/app/database/migration/postgres/1707614902283-AddAuditEvents.ts rename to packages/server/api/src/app/database/migration/postgres/1707614902283-AddAuditEvents.ts index 4678d536a7..eb2e814119 100644 --- a/packages/backend/src/app/database/migration/postgres/1707614902283-AddAuditEvents.ts +++ b/packages/server/api/src/app/database/migration/postgres/1707614902283-AddAuditEvents.ts @@ -59,5 +59,4 @@ export class AddAuditEvents1707614902283 implements MigrationInterface { DROP TABLE "audit_event" `) } - } diff --git a/packages/server/api/src/app/database/migration/sqlite/1690195839899-InitialSql3Migration.ts b/packages/server/api/src/app/database/migration/sqlite/1690195839899-InitialSql3Migration.ts new file mode 100644 index 0000000000..21e7f1d319 --- /dev/null +++ b/packages/server/api/src/app/database/migration/sqlite/1690195839899-InitialSql3Migration.ts @@ -0,0 +1,477 @@ +import { MigrationInterface, QueryRunner } from 'typeorm' +import { logger } from 'server-shared' + +export class InitialSql3Migration1690195839899 implements MigrationInterface { + name = 'InitialSql3Migration1690195839899' + + public async up(queryRunner: QueryRunner): Promise { + logger.info(`Running migration ${this.name}`) + await queryRunner.query( + 'CREATE TABLE "trigger_event" ("id" varchar(21) PRIMARY KEY NOT NULL, "created" datetime NOT NULL DEFAULT (datetime(\'now\')), "updated" datetime NOT NULL DEFAULT (datetime(\'now\')), "flowId" varchar(21) NOT NULL, "projectId" varchar(21) NOT NULL, "sourceName" varchar NOT NULL, "payload" text)', + ) + await queryRunner.query( + 'CREATE INDEX "idx_trigger_event_flow_id" ON "trigger_event" ("flowId") ', + ) + await queryRunner.query( + 'CREATE TABLE "flow_instance" ("id" varchar(21) PRIMARY KEY NOT NULL, "created" datetime NOT NULL DEFAULT (datetime(\'now\')), "updated" datetime NOT NULL DEFAULT (datetime(\'now\')), "projectId" varchar(21) NOT NULL, "flowId" varchar(21) NOT NULL, "flowVersionId" varchar(21) NOT NULL, "status" varchar NOT NULL, "schedule" text, CONSTRAINT "REL_cb897f5e48cc3cba1418966326" UNIQUE ("flowId"), CONSTRAINT "REL_ec72f514c21734fb7a08797d75" UNIQUE ("flowVersionId"))', + ) + await queryRunner.query( + 'CREATE UNIQUE INDEX "idx_flow_instance_project_id_flow_id" ON "flow_instance" ("projectId", "flowId") ', + ) + await queryRunner.query( + 'CREATE TABLE "app_event_routing" ("id" varchar(21) PRIMARY KEY NOT NULL, "created" datetime NOT NULL DEFAULT (datetime(\'now\')), "updated" datetime NOT NULL DEFAULT (datetime(\'now\')), "appName" varchar NOT NULL, "projectId" varchar(21) NOT NULL, "flowId" varchar(21) NOT NULL, "identifierValue" varchar NOT NULL, "event" varchar NOT NULL)', + ) + await queryRunner.query( + 'CREATE INDEX "idx_app_event_routing_flow_id" ON "app_event_routing" ("flowId") ', + ) + await queryRunner.query( + 'CREATE UNIQUE INDEX "idx_app_event_project_id_appName_identifier_value_event" ON "app_event_routing" ("appName", "projectId", "identifierValue", "event") ', + ) + await queryRunner.query( + 'CREATE TABLE "file" ("id" varchar(21) PRIMARY KEY NOT NULL, "created" datetime NOT NULL DEFAULT (datetime(\'now\')), "updated" datetime NOT NULL DEFAULT (datetime(\'now\')), "projectId" varchar(21), "data" blob NOT NULL)', + ) + await queryRunner.query( + 'CREATE TABLE "flag" ("id" varchar(21) PRIMARY KEY NOT NULL, "created" datetime NOT NULL DEFAULT (datetime(\'now\')), "updated" datetime NOT NULL DEFAULT (datetime(\'now\')), "value" text NOT NULL)', + ) + await queryRunner.query( + 'CREATE TABLE "flow" ("id" varchar(21) PRIMARY KEY NOT NULL, "created" datetime NOT NULL DEFAULT (datetime(\'now\')), "updated" datetime NOT NULL DEFAULT (datetime(\'now\')), "projectId" varchar(21) NOT NULL, "folderId" varchar(21))', + ) + await queryRunner.query( + 'CREATE INDEX "idx_flow_project_id" ON "flow" ("projectId") ', + ) + await queryRunner.query( + 'CREATE INDEX "idx_flow_folder_id" ON "flow" ("folderId") ', + ) + await queryRunner.query( + 'CREATE TABLE "flow_version" ("id" varchar(21) PRIMARY KEY NOT NULL, "created" datetime NOT NULL DEFAULT (datetime(\'now\')), "updated" datetime NOT NULL DEFAULT (datetime(\'now\')), "flowId" varchar(21) NOT NULL, "displayName" varchar NOT NULL, "trigger" text, "updatedBy" varchar, "valid" boolean NOT NULL, "state" varchar NOT NULL)', + ) + await queryRunner.query( + 'CREATE INDEX "idx_flow_version_flow_id" ON "flow_version" ("flowId") ', + ) + await queryRunner.query( + 'CREATE TABLE "flow_run" ("id" varchar(21) PRIMARY KEY NOT NULL, "created" datetime NOT NULL DEFAULT (datetime(\'now\')), "updated" datetime NOT NULL DEFAULT (datetime(\'now\')), "projectId" varchar(21) NOT NULL, "flowId" varchar(21) NOT NULL, "flowVersionId" varchar(21) NOT NULL, "environment" varchar, "flowDisplayName" varchar NOT NULL, "logsFileId" varchar(21), "status" varchar NOT NULL, "tasks" integer, "startTime" datetime NOT NULL, "finishTime" datetime, "pauseMetadata" text)', + ) + await queryRunner.query( + 'CREATE INDEX "idx_run_project_id_environment_created_desc" ON "flow_run" ("projectId", "environment", "created") ', + ) + await queryRunner.query( + 'CREATE INDEX "idx_run_project_id_environment_status_created_desc" ON "flow_run" ("projectId", "environment", "status", "created") ', + ) + await queryRunner.query( + 'CREATE INDEX "idx_run_project_id_flow_id_environment_created_desc" ON "flow_run" ("projectId", "flowId", "environment", "created") ', + ) + await queryRunner.query( + 'CREATE INDEX "idx_run_project_id_flow_id_environment_status_created_desc" ON "flow_run" ("projectId", "flowId", "environment", "status", "created") ', + ) + await queryRunner.query( + 'CREATE TABLE "project" ("id" varchar(21) PRIMARY KEY NOT NULL, "created" datetime NOT NULL DEFAULT (datetime(\'now\')), "updated" datetime NOT NULL DEFAULT (datetime(\'now\')), "ownerId" varchar(21) NOT NULL, "displayName" varchar NOT NULL, "notifyStatus" varchar NOT NULL)', + ) + await queryRunner.query( + 'CREATE INDEX "idx_project_owner_id" ON "project" ("ownerId") ', + ) + await queryRunner.query( + 'CREATE TABLE "store-entry" ("id" varchar(21) PRIMARY KEY NOT NULL, "created" datetime NOT NULL DEFAULT (datetime(\'now\')), "updated" datetime NOT NULL DEFAULT (datetime(\'now\')), "key" varchar NOT NULL, "projectId" varchar(21) NOT NULL, "value" text)', + ) + await queryRunner.query( + 'CREATE TABLE "user" ("id" varchar(21) PRIMARY KEY NOT NULL, "created" datetime NOT NULL DEFAULT (datetime(\'now\')), "updated" datetime NOT NULL DEFAULT (datetime(\'now\')), "email" varchar NOT NULL, "firstName" varchar NOT NULL, "lastName" varchar NOT NULL, "password" varchar NOT NULL, "status" varchar NOT NULL, "trackEvents" boolean, "newsLetter" boolean, CONSTRAINT "UQ_e12875dfb3b1d92d7d7c5377e22" UNIQUE ("email"))', + ) + await queryRunner.query( + 'CREATE TABLE "app_connection" ("id" varchar(21) PRIMARY KEY NOT NULL, "created" datetime NOT NULL DEFAULT (datetime(\'now\')), "updated" datetime NOT NULL DEFAULT (datetime(\'now\')), "name" varchar NOT NULL, "appName" varchar NOT NULL, "projectId" varchar(21) NOT NULL, "value" text NOT NULL)', + ) + await queryRunner.query( + 'CREATE UNIQUE INDEX "idx_app_connection_project_id_and_name" ON "app_connection" ("projectId", "name") ', + ) + await queryRunner.query( + 'CREATE TABLE "webhook_simulation" ("id" varchar(21) PRIMARY KEY NOT NULL, "created" datetime NOT NULL DEFAULT (datetime(\'now\')), "updated" datetime NOT NULL DEFAULT (datetime(\'now\')), "flowId" varchar(21) NOT NULL, "projectId" varchar(21) NOT NULL)', + ) + await queryRunner.query( + 'CREATE UNIQUE INDEX "idx_webhook_simulation_flow_id" ON "webhook_simulation" ("flowId") ', + ) + await queryRunner.query( + 'CREATE TABLE "folder" ("id" varchar(21) PRIMARY KEY NOT NULL, "created" datetime NOT NULL DEFAULT (datetime(\'now\')), "updated" datetime NOT NULL DEFAULT (datetime(\'now\')), "displayName" varchar NOT NULL, "projectId" varchar(21) NOT NULL)', + ) + await queryRunner.query( + 'CREATE INDEX "idx_folder_project_id" ON "folder" ("projectId") ', + ) + await queryRunner.query( + 'CREATE TABLE "piece_metadata" ("id" varchar(21) PRIMARY KEY NOT NULL, "created" datetime NOT NULL DEFAULT (datetime(\'now\')), "updated" datetime NOT NULL DEFAULT (datetime(\'now\')), "name" varchar NOT NULL, "displayName" varchar NOT NULL, "logoUrl" varchar NOT NULL, "description" varchar, "projectId" varchar, "version" varchar NOT NULL, "minimumSupportedRelease" varchar NOT NULL, "maximumSupportedRelease" varchar NOT NULL, "auth" text, "actions" text NOT NULL, "triggers" text NOT NULL)', + ) + await queryRunner.query( + 'CREATE UNIQUE INDEX "idx_piece_metadata_name_project_id_version" ON "piece_metadata" ("name", "version", "projectId") ', + ) + await queryRunner.query('DROP INDEX "idx_trigger_event_flow_id"') + await queryRunner.query( + 'CREATE TABLE "temporary_trigger_event" ("id" varchar(21) PRIMARY KEY NOT NULL, "created" datetime NOT NULL DEFAULT (datetime(\'now\')), "updated" datetime NOT NULL DEFAULT (datetime(\'now\')), "flowId" varchar(21) NOT NULL, "projectId" varchar(21) NOT NULL, "sourceName" varchar NOT NULL, "payload" text, CONSTRAINT "fk_trigger_event_project_id" FOREIGN KEY ("projectId") REFERENCES "project" ("id") ON DELETE CASCADE ON UPDATE NO ACTION, CONSTRAINT "fk_trigger_event_flow_id" FOREIGN KEY ("flowId") REFERENCES "flow" ("id") ON DELETE CASCADE ON UPDATE NO ACTION)', + ) + await queryRunner.query( + 'INSERT INTO "temporary_trigger_event"("id", "created", "updated", "flowId", "projectId", "sourceName", "payload") SELECT "id", "created", "updated", "flowId", "projectId", "sourceName", "payload" FROM "trigger_event"', + ) + await queryRunner.query('DROP TABLE "trigger_event"') + await queryRunner.query( + 'ALTER TABLE "temporary_trigger_event" RENAME TO "trigger_event"', + ) + await queryRunner.query( + 'CREATE INDEX "idx_trigger_event_flow_id" ON "trigger_event" ("flowId") ', + ) + await queryRunner.query( + 'DROP INDEX "idx_flow_instance_project_id_flow_id"', + ) + await queryRunner.query( + 'CREATE TABLE "temporary_flow_instance" ("id" varchar(21) PRIMARY KEY NOT NULL, "created" datetime NOT NULL DEFAULT (datetime(\'now\')), "updated" datetime NOT NULL DEFAULT (datetime(\'now\')), "projectId" varchar(21) NOT NULL, "flowId" varchar(21) NOT NULL, "flowVersionId" varchar(21) NOT NULL, "status" varchar NOT NULL, "schedule" text, CONSTRAINT "REL_cb897f5e48cc3cba1418966326" UNIQUE ("flowId"), CONSTRAINT "REL_ec72f514c21734fb7a08797d75" UNIQUE ("flowVersionId"), CONSTRAINT "fk_flow_instance_flow" FOREIGN KEY ("flowId") REFERENCES "flow" ("id") ON DELETE CASCADE ON UPDATE NO ACTION, CONSTRAINT "fk_flow_instance_flow_version" FOREIGN KEY ("flowVersionId") REFERENCES "flow_version" ("id") ON DELETE CASCADE ON UPDATE NO ACTION)', + ) + await queryRunner.query( + 'INSERT INTO "temporary_flow_instance"("id", "created", "updated", "projectId", "flowId", "flowVersionId", "status", "schedule") SELECT "id", "created", "updated", "projectId", "flowId", "flowVersionId", "status", "schedule" FROM "flow_instance"', + ) + await queryRunner.query('DROP TABLE "flow_instance"') + await queryRunner.query( + 'ALTER TABLE "temporary_flow_instance" RENAME TO "flow_instance"', + ) + await queryRunner.query( + 'CREATE UNIQUE INDEX "idx_flow_instance_project_id_flow_id" ON "flow_instance" ("projectId", "flowId") ', + ) + await queryRunner.query( + 'CREATE TABLE "temporary_file" ("id" varchar(21) PRIMARY KEY NOT NULL, "created" datetime NOT NULL DEFAULT (datetime(\'now\')), "updated" datetime NOT NULL DEFAULT (datetime(\'now\')), "projectId" varchar(21), "data" blob NOT NULL, CONSTRAINT "fk_file_project_id" FOREIGN KEY ("projectId") REFERENCES "project" ("id") ON DELETE CASCADE ON UPDATE NO ACTION)', + ) + await queryRunner.query( + 'INSERT INTO "temporary_file"("id", "created", "updated", "projectId", "data") SELECT "id", "created", "updated", "projectId", "data" FROM "file"', + ) + await queryRunner.query('DROP TABLE "file"') + await queryRunner.query('ALTER TABLE "temporary_file" RENAME TO "file"') + await queryRunner.query('DROP INDEX "idx_flow_project_id"') + await queryRunner.query('DROP INDEX "idx_flow_folder_id"') + await queryRunner.query( + 'CREATE TABLE "temporary_flow" ("id" varchar(21) PRIMARY KEY NOT NULL, "created" datetime NOT NULL DEFAULT (datetime(\'now\')), "updated" datetime NOT NULL DEFAULT (datetime(\'now\')), "projectId" varchar(21) NOT NULL, "folderId" varchar(21), CONSTRAINT "fk_flow_folder_id" FOREIGN KEY ("folderId") REFERENCES "folder" ("id") ON DELETE SET NULL ON UPDATE NO ACTION, CONSTRAINT "fk_flow_project_id" FOREIGN KEY ("projectId") REFERENCES "project" ("id") ON DELETE CASCADE ON UPDATE NO ACTION)', + ) + await queryRunner.query( + 'INSERT INTO "temporary_flow"("id", "created", "updated", "projectId", "folderId") SELECT "id", "created", "updated", "projectId", "folderId" FROM "flow"', + ) + await queryRunner.query('DROP TABLE "flow"') + await queryRunner.query('ALTER TABLE "temporary_flow" RENAME TO "flow"') + await queryRunner.query( + 'CREATE INDEX "idx_flow_project_id" ON "flow" ("projectId") ', + ) + await queryRunner.query( + 'CREATE INDEX "idx_flow_folder_id" ON "flow" ("folderId") ', + ) + await queryRunner.query('DROP INDEX "idx_flow_version_flow_id"') + await queryRunner.query( + 'CREATE TABLE "temporary_flow_version" ("id" varchar(21) PRIMARY KEY NOT NULL, "created" datetime NOT NULL DEFAULT (datetime(\'now\')), "updated" datetime NOT NULL DEFAULT (datetime(\'now\')), "flowId" varchar(21) NOT NULL, "displayName" varchar NOT NULL, "trigger" text, "updatedBy" varchar, "valid" boolean NOT NULL, "state" varchar NOT NULL, CONSTRAINT "fk_updated_by_user_flow" FOREIGN KEY ("updatedBy") REFERENCES "user" ("id") ON DELETE CASCADE ON UPDATE NO ACTION, CONSTRAINT "fk_flow_version_flow" FOREIGN KEY ("flowId") REFERENCES "flow" ("id") ON DELETE CASCADE ON UPDATE NO ACTION)', + ) + await queryRunner.query( + 'INSERT INTO "temporary_flow_version"("id", "created", "updated", "flowId", "displayName", "trigger", "updatedBy", "valid", "state") SELECT "id", "created", "updated", "flowId", "displayName", "trigger", "updatedBy", "valid", "state" FROM "flow_version"', + ) + await queryRunner.query('DROP TABLE "flow_version"') + await queryRunner.query( + 'ALTER TABLE "temporary_flow_version" RENAME TO "flow_version"', + ) + await queryRunner.query( + 'CREATE INDEX "idx_flow_version_flow_id" ON "flow_version" ("flowId") ', + ) + await queryRunner.query( + 'DROP INDEX "idx_run_project_id_environment_created_desc"', + ) + await queryRunner.query( + 'DROP INDEX "idx_run_project_id_environment_status_created_desc"', + ) + await queryRunner.query( + 'DROP INDEX "idx_run_project_id_flow_id_environment_created_desc"', + ) + await queryRunner.query( + 'DROP INDEX "idx_run_project_id_flow_id_environment_status_created_desc"', + ) + await queryRunner.query( + 'CREATE TABLE "temporary_flow_run" ("id" varchar(21) PRIMARY KEY NOT NULL, "created" datetime NOT NULL DEFAULT (datetime(\'now\')), "updated" datetime NOT NULL DEFAULT (datetime(\'now\')), "projectId" varchar(21) NOT NULL, "flowId" varchar(21) NOT NULL, "flowVersionId" varchar(21) NOT NULL, "environment" varchar, "flowDisplayName" varchar NOT NULL, "logsFileId" varchar(21), "status" varchar NOT NULL, "tasks" integer, "startTime" datetime NOT NULL, "finishTime" datetime, "pauseMetadata" text, CONSTRAINT "fk_flow_run_project_id" FOREIGN KEY ("projectId") REFERENCES "project" ("id") ON DELETE CASCADE ON UPDATE NO ACTION, CONSTRAINT "fk_flow_run_flow_id" FOREIGN KEY ("flowId") REFERENCES "flow" ("id") ON DELETE CASCADE ON UPDATE NO ACTION)', + ) + await queryRunner.query( + 'INSERT INTO "temporary_flow_run"("id", "created", "updated", "projectId", "flowId", "flowVersionId", "environment", "flowDisplayName", "logsFileId", "status", "tasks", "startTime", "finishTime", "pauseMetadata") SELECT "id", "created", "updated", "projectId", "flowId", "flowVersionId", "environment", "flowDisplayName", "logsFileId", "status", "tasks", "startTime", "finishTime", "pauseMetadata" FROM "flow_run"', + ) + await queryRunner.query('DROP TABLE "flow_run"') + await queryRunner.query( + 'ALTER TABLE "temporary_flow_run" RENAME TO "flow_run"', + ) + await queryRunner.query( + 'CREATE INDEX "idx_run_project_id_environment_created_desc" ON "flow_run" ("projectId", "environment", "created") ', + ) + await queryRunner.query( + 'CREATE INDEX "idx_run_project_id_environment_status_created_desc" ON "flow_run" ("projectId", "environment", "status", "created") ', + ) + await queryRunner.query( + 'CREATE INDEX "idx_run_project_id_flow_id_environment_created_desc" ON "flow_run" ("projectId", "flowId", "environment", "created") ', + ) + await queryRunner.query( + 'CREATE INDEX "idx_run_project_id_flow_id_environment_status_created_desc" ON "flow_run" ("projectId", "flowId", "environment", "status", "created") ', + ) + await queryRunner.query('DROP INDEX "idx_project_owner_id"') + await queryRunner.query( + 'CREATE TABLE "temporary_project" ("id" varchar(21) PRIMARY KEY NOT NULL, "created" datetime NOT NULL DEFAULT (datetime(\'now\')), "updated" datetime NOT NULL DEFAULT (datetime(\'now\')), "ownerId" varchar(21) NOT NULL, "displayName" varchar NOT NULL, "notifyStatus" varchar NOT NULL, CONSTRAINT "fk_project_owner_id" FOREIGN KEY ("ownerId") REFERENCES "user" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION)', + ) + await queryRunner.query( + 'INSERT INTO "temporary_project"("id", "created", "updated", "ownerId", "displayName", "notifyStatus") SELECT "id", "created", "updated", "ownerId", "displayName", "notifyStatus" FROM "project"', + ) + await queryRunner.query('DROP TABLE "project"') + await queryRunner.query( + 'ALTER TABLE "temporary_project" RENAME TO "project"', + ) + await queryRunner.query( + 'CREATE INDEX "idx_project_owner_id" ON "project" ("ownerId") ', + ) + await queryRunner.query( + 'DROP INDEX "idx_app_connection_project_id_and_name"', + ) + await queryRunner.query( + 'CREATE TABLE "temporary_app_connection" ("id" varchar(21) PRIMARY KEY NOT NULL, "created" datetime NOT NULL DEFAULT (datetime(\'now\')), "updated" datetime NOT NULL DEFAULT (datetime(\'now\')), "name" varchar NOT NULL, "appName" varchar NOT NULL, "projectId" varchar(21) NOT NULL, "value" text NOT NULL, CONSTRAINT "fk_app_connection_app_project_id" FOREIGN KEY ("projectId") REFERENCES "project" ("id") ON DELETE CASCADE ON UPDATE NO ACTION)', + ) + await queryRunner.query( + 'INSERT INTO "temporary_app_connection"("id", "created", "updated", "name", "appName", "projectId", "value") SELECT "id", "created", "updated", "name", "appName", "projectId", "value" FROM "app_connection"', + ) + await queryRunner.query('DROP TABLE "app_connection"') + await queryRunner.query( + 'ALTER TABLE "temporary_app_connection" RENAME TO "app_connection"', + ) + await queryRunner.query( + 'CREATE UNIQUE INDEX "idx_app_connection_project_id_and_name" ON "app_connection" ("projectId", "name") ', + ) + await queryRunner.query('DROP INDEX "idx_folder_project_id"') + await queryRunner.query( + 'CREATE TABLE "temporary_folder" ("id" varchar(21) PRIMARY KEY NOT NULL, "created" datetime NOT NULL DEFAULT (datetime(\'now\')), "updated" datetime NOT NULL DEFAULT (datetime(\'now\')), "displayName" varchar NOT NULL, "projectId" varchar(21) NOT NULL, CONSTRAINT "fk_folder_project" FOREIGN KEY ("projectId") REFERENCES "project" ("id") ON DELETE CASCADE ON UPDATE NO ACTION)', + ) + await queryRunner.query( + 'INSERT INTO "temporary_folder"("id", "created", "updated", "displayName", "projectId") SELECT "id", "created", "updated", "displayName", "projectId" FROM "folder"', + ) + await queryRunner.query('DROP TABLE "folder"') + await queryRunner.query( + 'ALTER TABLE "temporary_folder" RENAME TO "folder"', + ) + await queryRunner.query( + 'CREATE INDEX "idx_folder_project_id" ON "folder" ("projectId") ', + ) + await queryRunner.query( + 'DROP INDEX "idx_piece_metadata_name_project_id_version"', + ) + await queryRunner.query( + 'CREATE TABLE "temporary_piece_metadata" ("id" varchar(21) PRIMARY KEY NOT NULL, "created" datetime NOT NULL DEFAULT (datetime(\'now\')), "updated" datetime NOT NULL DEFAULT (datetime(\'now\')), "name" varchar NOT NULL, "displayName" varchar NOT NULL, "logoUrl" varchar NOT NULL, "description" varchar, "projectId" varchar, "version" varchar NOT NULL, "minimumSupportedRelease" varchar NOT NULL, "maximumSupportedRelease" varchar NOT NULL, "auth" text, "actions" text NOT NULL, "triggers" text NOT NULL, CONSTRAINT "fk_piece_metadata_project_id" FOREIGN KEY ("projectId") REFERENCES "project" ("id") ON DELETE CASCADE ON UPDATE NO ACTION)', + ) + await queryRunner.query( + 'INSERT INTO "temporary_piece_metadata"("id", "created", "updated", "name", "displayName", "logoUrl", "description", "projectId", "version", "minimumSupportedRelease", "maximumSupportedRelease", "auth", "actions", "triggers") SELECT "id", "created", "updated", "name", "displayName", "logoUrl", "description", "projectId", "version", "minimumSupportedRelease", "maximumSupportedRelease", "auth", "actions", "triggers" FROM "piece_metadata"', + ) + await queryRunner.query('DROP TABLE "piece_metadata"') + await queryRunner.query( + 'ALTER TABLE "temporary_piece_metadata" RENAME TO "piece_metadata"', + ) + await queryRunner.query( + 'CREATE UNIQUE INDEX "idx_piece_metadata_name_project_id_version" ON "piece_metadata" ("name", "version", "projectId") ', + ) + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query( + 'DROP INDEX "idx_piece_metadata_name_project_id_version"', + ) + await queryRunner.query( + 'ALTER TABLE "piece_metadata" RENAME TO "temporary_piece_metadata"', + ) + await queryRunner.query( + 'CREATE TABLE "piece_metadata" ("id" varchar(21) PRIMARY KEY NOT NULL, "created" datetime NOT NULL DEFAULT (datetime(\'now\')), "updated" datetime NOT NULL DEFAULT (datetime(\'now\')), "name" varchar NOT NULL, "displayName" varchar NOT NULL, "logoUrl" varchar NOT NULL, "description" varchar, "projectId" varchar, "version" varchar NOT NULL, "minimumSupportedRelease" varchar NOT NULL, "maximumSupportedRelease" varchar NOT NULL, "auth" text, "actions" text NOT NULL, "triggers" text NOT NULL)', + ) + await queryRunner.query( + 'INSERT INTO "piece_metadata"("id", "created", "updated", "name", "displayName", "logoUrl", "description", "projectId", "version", "minimumSupportedRelease", "maximumSupportedRelease", "auth", "actions", "triggers") SELECT "id", "created", "updated", "name", "displayName", "logoUrl", "description", "projectId", "version", "minimumSupportedRelease", "maximumSupportedRelease", "auth", "actions", "triggers" FROM "temporary_piece_metadata"', + ) + await queryRunner.query('DROP TABLE "temporary_piece_metadata"') + await queryRunner.query( + 'CREATE UNIQUE INDEX "idx_piece_metadata_name_project_id_version" ON "piece_metadata" ("name", "version", "projectId") ', + ) + await queryRunner.query('DROP INDEX "idx_folder_project_id"') + await queryRunner.query( + 'ALTER TABLE "folder" RENAME TO "temporary_folder"', + ) + await queryRunner.query( + 'CREATE TABLE "folder" ("id" varchar(21) PRIMARY KEY NOT NULL, "created" datetime NOT NULL DEFAULT (datetime(\'now\')), "updated" datetime NOT NULL DEFAULT (datetime(\'now\')), "displayName" varchar NOT NULL, "projectId" varchar(21) NOT NULL)', + ) + await queryRunner.query( + 'INSERT INTO "folder"("id", "created", "updated", "displayName", "projectId") SELECT "id", "created", "updated", "displayName", "projectId" FROM "temporary_folder"', + ) + await queryRunner.query('DROP TABLE "temporary_folder"') + await queryRunner.query( + 'CREATE INDEX "idx_folder_project_id" ON "folder" ("projectId") ', + ) + await queryRunner.query( + 'DROP INDEX "idx_app_connection_project_id_and_name"', + ) + await queryRunner.query( + 'ALTER TABLE "app_connection" RENAME TO "temporary_app_connection"', + ) + await queryRunner.query( + 'CREATE TABLE "app_connection" ("id" varchar(21) PRIMARY KEY NOT NULL, "created" datetime NOT NULL DEFAULT (datetime(\'now\')), "updated" datetime NOT NULL DEFAULT (datetime(\'now\')), "name" varchar NOT NULL, "appName" varchar NOT NULL, "projectId" varchar(21) NOT NULL, "value" text NOT NULL)', + ) + await queryRunner.query( + 'INSERT INTO "app_connection"("id", "created", "updated", "name", "appName", "projectId", "value") SELECT "id", "created", "updated", "name", "appName", "projectId", "value" FROM "temporary_app_connection"', + ) + await queryRunner.query('DROP TABLE "temporary_app_connection"') + await queryRunner.query( + 'CREATE UNIQUE INDEX "idx_app_connection_project_id_and_name" ON "app_connection" ("projectId", "name") ', + ) + await queryRunner.query('DROP INDEX "idx_project_owner_id"') + await queryRunner.query( + 'ALTER TABLE "project" RENAME TO "temporary_project"', + ) + await queryRunner.query( + 'CREATE TABLE "project" ("id" varchar(21) PRIMARY KEY NOT NULL, "created" datetime NOT NULL DEFAULT (datetime(\'now\')), "updated" datetime NOT NULL DEFAULT (datetime(\'now\')), "ownerId" varchar(21) NOT NULL, "displayName" varchar NOT NULL, "notifyStatus" varchar NOT NULL)', + ) + await queryRunner.query( + 'INSERT INTO "project"("id", "created", "updated", "ownerId", "displayName", "notifyStatus") SELECT "id", "created", "updated", "ownerId", "displayName", "notifyStatus" FROM "temporary_project"', + ) + await queryRunner.query('DROP TABLE "temporary_project"') + await queryRunner.query( + 'CREATE INDEX "idx_project_owner_id" ON "project" ("ownerId") ', + ) + await queryRunner.query( + 'DROP INDEX "idx_run_project_id_flow_id_environment_status_created_desc"', + ) + await queryRunner.query( + 'DROP INDEX "idx_run_project_id_flow_id_environment_created_desc"', + ) + await queryRunner.query( + 'DROP INDEX "idx_run_project_id_environment_status_created_desc"', + ) + await queryRunner.query( + 'DROP INDEX "idx_run_project_id_environment_created_desc"', + ) + await queryRunner.query( + 'ALTER TABLE "flow_run" RENAME TO "temporary_flow_run"', + ) + await queryRunner.query( + 'CREATE TABLE "flow_run" ("id" varchar(21) PRIMARY KEY NOT NULL, "created" datetime NOT NULL DEFAULT (datetime(\'now\')), "updated" datetime NOT NULL DEFAULT (datetime(\'now\')), "projectId" varchar(21) NOT NULL, "flowId" varchar(21) NOT NULL, "flowVersionId" varchar(21) NOT NULL, "environment" varchar, "flowDisplayName" varchar NOT NULL, "logsFileId" varchar(21), "status" varchar NOT NULL, "tasks" integer, "startTime" datetime NOT NULL, "finishTime" datetime, "pauseMetadata" text)', + ) + await queryRunner.query( + 'INSERT INTO "flow_run"("id", "created", "updated", "projectId", "flowId", "flowVersionId", "environment", "flowDisplayName", "logsFileId", "status", "tasks", "startTime", "finishTime", "pauseMetadata") SELECT "id", "created", "updated", "projectId", "flowId", "flowVersionId", "environment", "flowDisplayName", "logsFileId", "status", "tasks", "startTime", "finishTime", "pauseMetadata" FROM "temporary_flow_run"', + ) + await queryRunner.query('DROP TABLE "temporary_flow_run"') + await queryRunner.query( + 'CREATE INDEX "idx_run_project_id_flow_id_environment_status_created_desc" ON "flow_run" ("projectId", "flowId", "environment", "status", "created") ', + ) + await queryRunner.query( + 'CREATE INDEX "idx_run_project_id_flow_id_environment_created_desc" ON "flow_run" ("projectId", "flowId", "environment", "created") ', + ) + await queryRunner.query( + 'CREATE INDEX "idx_run_project_id_environment_status_created_desc" ON "flow_run" ("projectId", "environment", "status", "created") ', + ) + await queryRunner.query( + 'CREATE INDEX "idx_run_project_id_environment_created_desc" ON "flow_run" ("projectId", "environment", "created") ', + ) + await queryRunner.query('DROP INDEX "idx_flow_version_flow_id"') + await queryRunner.query( + 'ALTER TABLE "flow_version" RENAME TO "temporary_flow_version"', + ) + await queryRunner.query( + 'CREATE TABLE "flow_version" ("id" varchar(21) PRIMARY KEY NOT NULL, "created" datetime NOT NULL DEFAULT (datetime(\'now\')), "updated" datetime NOT NULL DEFAULT (datetime(\'now\')), "flowId" varchar(21) NOT NULL, "displayName" varchar NOT NULL, "trigger" text, "updatedBy" varchar, "valid" boolean NOT NULL, "state" varchar NOT NULL)', + ) + await queryRunner.query( + 'INSERT INTO "flow_version"("id", "created", "updated", "flowId", "displayName", "trigger", "updatedBy", "valid", "state") SELECT "id", "created", "updated", "flowId", "displayName", "trigger", "updatedBy", "valid", "state" FROM "temporary_flow_version"', + ) + await queryRunner.query('DROP TABLE "temporary_flow_version"') + await queryRunner.query( + 'CREATE INDEX "idx_flow_version_flow_id" ON "flow_version" ("flowId") ', + ) + await queryRunner.query('DROP INDEX "idx_flow_folder_id"') + await queryRunner.query('DROP INDEX "idx_flow_project_id"') + await queryRunner.query('ALTER TABLE "flow" RENAME TO "temporary_flow"') + await queryRunner.query( + 'CREATE TABLE "flow" ("id" varchar(21) PRIMARY KEY NOT NULL, "created" datetime NOT NULL DEFAULT (datetime(\'now\')), "updated" datetime NOT NULL DEFAULT (datetime(\'now\')), "projectId" varchar(21) NOT NULL, "folderId" varchar(21))', + ) + await queryRunner.query( + 'INSERT INTO "flow"("id", "created", "updated", "projectId", "folderId") SELECT "id", "created", "updated", "projectId", "folderId" FROM "temporary_flow"', + ) + await queryRunner.query('DROP TABLE "temporary_flow"') + await queryRunner.query( + 'CREATE INDEX "idx_flow_folder_id" ON "flow" ("folderId") ', + ) + await queryRunner.query( + 'CREATE INDEX "idx_flow_project_id" ON "flow" ("projectId") ', + ) + await queryRunner.query('ALTER TABLE "file" RENAME TO "temporary_file"') + await queryRunner.query( + 'CREATE TABLE "file" ("id" varchar(21) PRIMARY KEY NOT NULL, "created" datetime NOT NULL DEFAULT (datetime(\'now\')), "updated" datetime NOT NULL DEFAULT (datetime(\'now\')), "projectId" varchar(21), "data" blob NOT NULL)', + ) + await queryRunner.query( + 'INSERT INTO "file"("id", "created", "updated", "projectId", "data") SELECT "id", "created", "updated", "projectId", "data" FROM "temporary_file"', + ) + await queryRunner.query('DROP TABLE "temporary_file"') + await queryRunner.query( + 'DROP INDEX "idx_flow_instance_project_id_flow_id"', + ) + await queryRunner.query( + 'ALTER TABLE "flow_instance" RENAME TO "temporary_flow_instance"', + ) + await queryRunner.query( + 'CREATE TABLE "flow_instance" ("id" varchar(21) PRIMARY KEY NOT NULL, "created" datetime NOT NULL DEFAULT (datetime(\'now\')), "updated" datetime NOT NULL DEFAULT (datetime(\'now\')), "projectId" varchar(21) NOT NULL, "flowId" varchar(21) NOT NULL, "flowVersionId" varchar(21) NOT NULL, "status" varchar NOT NULL, "schedule" text, CONSTRAINT "REL_cb897f5e48cc3cba1418966326" UNIQUE ("flowId"), CONSTRAINT "REL_ec72f514c21734fb7a08797d75" UNIQUE ("flowVersionId"))', + ) + await queryRunner.query( + 'INSERT INTO "flow_instance"("id", "created", "updated", "projectId", "flowId", "flowVersionId", "status", "schedule") SELECT "id", "created", "updated", "projectId", "flowId", "flowVersionId", "status", "schedule" FROM "temporary_flow_instance"', + ) + await queryRunner.query('DROP TABLE "temporary_flow_instance"') + await queryRunner.query( + 'CREATE UNIQUE INDEX "idx_flow_instance_project_id_flow_id" ON "flow_instance" ("projectId", "flowId") ', + ) + await queryRunner.query('DROP INDEX "idx_trigger_event_flow_id"') + await queryRunner.query( + 'ALTER TABLE "trigger_event" RENAME TO "temporary_trigger_event"', + ) + await queryRunner.query( + 'CREATE TABLE "trigger_event" ("id" varchar(21) PRIMARY KEY NOT NULL, "created" datetime NOT NULL DEFAULT (datetime(\'now\')), "updated" datetime NOT NULL DEFAULT (datetime(\'now\')), "flowId" varchar(21) NOT NULL, "projectId" varchar(21) NOT NULL, "sourceName" varchar NOT NULL, "payload" text)', + ) + await queryRunner.query( + 'INSERT INTO "trigger_event"("id", "created", "updated", "flowId", "projectId", "sourceName", "payload") SELECT "id", "created", "updated", "flowId", "projectId", "sourceName", "payload" FROM "temporary_trigger_event"', + ) + await queryRunner.query('DROP TABLE "temporary_trigger_event"') + await queryRunner.query( + 'CREATE INDEX "idx_trigger_event_flow_id" ON "trigger_event" ("flowId") ', + ) + await queryRunner.query( + 'DROP INDEX "idx_piece_metadata_name_project_id_version"', + ) + await queryRunner.query('DROP TABLE "piece_metadata"') + await queryRunner.query('DROP INDEX "idx_folder_project_id"') + await queryRunner.query('DROP TABLE "folder"') + await queryRunner.query('DROP INDEX "idx_webhook_simulation_flow_id"') + await queryRunner.query('DROP TABLE "webhook_simulation"') + await queryRunner.query( + 'DROP INDEX "idx_app_connection_project_id_and_name"', + ) + await queryRunner.query('DROP TABLE "app_connection"') + await queryRunner.query('DROP TABLE "user"') + await queryRunner.query('DROP TABLE "store-entry"') + await queryRunner.query('DROP INDEX "idx_project_owner_id"') + await queryRunner.query('DROP TABLE "project"') + await queryRunner.query( + 'DROP INDEX "idx_run_project_id_flow_id_environment_status_created_desc"', + ) + await queryRunner.query( + 'DROP INDEX "idx_run_project_id_flow_id_environment_created_desc"', + ) + await queryRunner.query( + 'DROP INDEX "idx_run_project_id_environment_status_created_desc"', + ) + await queryRunner.query( + 'DROP INDEX "idx_run_project_id_environment_created_desc"', + ) + await queryRunner.query('DROP TABLE "flow_run"') + await queryRunner.query('DROP INDEX "idx_flow_version_flow_id"') + await queryRunner.query('DROP TABLE "flow_version"') + await queryRunner.query('DROP INDEX "idx_flow_folder_id"') + await queryRunner.query('DROP INDEX "idx_flow_project_id"') + await queryRunner.query('DROP TABLE "flow"') + await queryRunner.query('DROP TABLE "flag"') + await queryRunner.query('DROP TABLE "file"') + await queryRunner.query( + 'DROP INDEX "idx_app_event_project_id_appName_identifier_value_event"', + ) + await queryRunner.query('DROP INDEX "idx_app_event_routing_flow_id"') + await queryRunner.query('DROP TABLE "app_event_routing"') + await queryRunner.query( + 'DROP INDEX "idx_flow_instance_project_id_flow_id"', + ) + await queryRunner.query('DROP TABLE "flow_instance"') + await queryRunner.query('DROP INDEX "idx_trigger_event_flow_id"') + await queryRunner.query('DROP TABLE "trigger_event"') + } +} diff --git a/packages/server/api/src/app/database/migration/sqlite/1691706020626-add-app-connection-type-to-top-level.ts b/packages/server/api/src/app/database/migration/sqlite/1691706020626-add-app-connection-type-to-top-level.ts new file mode 100644 index 0000000000..7a8359bb75 --- /dev/null +++ b/packages/server/api/src/app/database/migration/sqlite/1691706020626-add-app-connection-type-to-top-level.ts @@ -0,0 +1,85 @@ +import { MigrationInterface, QueryRunner } from 'typeorm' +import { decryptObject } from '../../../helper/encryption' +import { logger } from 'server-shared' + +type AppConnectionValue = { + type: string +} + +export class AddAppConnectionTypeToTopLevel1691706020626 +implements MigrationInterface { + name = 'AddAppConnectionTypeToTopLevel1691706020626' + + public async up(queryRunner: QueryRunner): Promise { + logger.info('AddAppConnectionTypeToTopLevel1691706020626 up') + + await queryRunner.query( + 'DROP INDEX "idx_app_connection_project_id_and_name"', + ) + await queryRunner.query( + 'CREATE TABLE "temporary_app_connection" ("id" varchar(21) PRIMARY KEY NOT NULL, "created" datetime NOT NULL DEFAULT (datetime(\'now\')), "updated" datetime NOT NULL DEFAULT (datetime(\'now\')), "name" varchar NOT NULL, "appName" varchar NOT NULL, "projectId" varchar(21) NOT NULL, "value" text NOT NULL, "type" varchar, CONSTRAINT "fk_app_connection_app_project_id" FOREIGN KEY ("projectId") REFERENCES "project" ("id") ON DELETE CASCADE ON UPDATE NO ACTION)', + ) + await queryRunner.query( + 'INSERT INTO "temporary_app_connection"("id", "created", "updated", "name", "appName", "projectId", "value") SELECT "id", "created", "updated", "name", "appName", "projectId", "value" FROM "app_connection"', + ) + await queryRunner.query('DROP TABLE "app_connection"') + await queryRunner.query( + 'ALTER TABLE "temporary_app_connection" RENAME TO "app_connection"', + ) + + const connections = await queryRunner.query('SELECT * FROM app_connection') + + for (const currentConnection of connections) { + try { + const connectionValue = decryptObject( + JSON.parse(currentConnection.value), + ) + await queryRunner.query( + `UPDATE "app_connection" SET "type" = '${connectionValue.type}' WHERE id = '${currentConnection.id}'`, + ) + } + catch (e) { + logger.error(e) + } + } + + await queryRunner.query( + 'CREATE TABLE "temporary_app_connection" ("id" varchar(21) PRIMARY KEY NOT NULL, "created" datetime NOT NULL DEFAULT (datetime(\'now\')), "updated" datetime NOT NULL DEFAULT (datetime(\'now\')), "name" varchar NOT NULL, "appName" varchar NOT NULL, "projectId" varchar(21) NOT NULL, "value" text NOT NULL, "type" varchar NOT NULL, CONSTRAINT "fk_app_connection_app_project_id" FOREIGN KEY ("projectId") REFERENCES "project" ("id") ON DELETE CASCADE ON UPDATE NO ACTION)', + ) + await queryRunner.query( + 'INSERT INTO "temporary_app_connection"("id", "created", "updated", "name", "appName", "projectId", "value", "type") SELECT "id", "created", "updated", "name", "appName", "projectId", "value", "type" FROM "app_connection"', + ) + await queryRunner.query('DROP TABLE "app_connection"') + await queryRunner.query( + 'ALTER TABLE "temporary_app_connection" RENAME TO "app_connection"', + ) + await queryRunner.query( + 'CREATE UNIQUE INDEX "idx_app_connection_project_id_and_name" ON "app_connection" ("projectId", "name") ', + ) + + logger.info('AddAppConnectionTypeToTopLevel1691706020626 finished') + } + + public async down(queryRunner: QueryRunner): Promise { + logger.info('AddAppConnectionTypeToTopLevel1691706020626 down') + + await queryRunner.query( + 'DROP INDEX "idx_app_connection_project_id_and_name"', + ) + await queryRunner.query( + 'ALTER TABLE "app_connection" RENAME TO "temporary_app_connection"', + ) + await queryRunner.query( + 'CREATE TABLE "app_connection" ("id" varchar(21) PRIMARY KEY NOT NULL, "created" datetime NOT NULL DEFAULT (datetime(\'now\')), "updated" datetime NOT NULL DEFAULT (datetime(\'now\')), "name" varchar NOT NULL, "appName" varchar NOT NULL, "projectId" varchar(21) NOT NULL, "value" text NOT NULL, CONSTRAINT "fk_app_connection_app_project_id" FOREIGN KEY ("projectId") REFERENCES "project" ("id") ON DELETE CASCADE ON UPDATE NO ACTION)', + ) + await queryRunner.query( + 'INSERT INTO "app_connection"("id", "created", "updated", "name", "appName", "projectId", "value") SELECT "id", "created", "updated", "name", "appName", "projectId", "value" FROM "temporary_app_connection"', + ) + await queryRunner.query('DROP TABLE "temporary_app_connection"') + await queryRunner.query( + 'CREATE UNIQUE INDEX "idx_app_connection_project_id_and_name" ON "app_connection" ("projectId", "name") ', + ) + + logger.info('AddAppConnectionTypeToTopLevel1691706020626 finished') + } +} diff --git a/packages/server/api/src/app/database/migration/sqlite/1692056190942-AddTagsToRunSqlite.ts b/packages/server/api/src/app/database/migration/sqlite/1692056190942-AddTagsToRunSqlite.ts new file mode 100644 index 0000000000..4995e2e8e3 --- /dev/null +++ b/packages/server/api/src/app/database/migration/sqlite/1692056190942-AddTagsToRunSqlite.ts @@ -0,0 +1,93 @@ +import { MigrationInterface, QueryRunner } from 'typeorm' + +export class AddTagsToRunSqlite1692056190942 implements MigrationInterface { + name = 'AddTagsToRunSqlite1692056190942' + + public async up(queryRunner: QueryRunner): Promise { + if (await migrationRan('AddTagsToRunSqlite31692056190942', queryRunner)) { + return + } + await queryRunner.query( + 'DROP INDEX "idx_run_project_id_flow_id_environment_status_created_desc"', + ) + await queryRunner.query( + 'DROP INDEX "idx_run_project_id_flow_id_environment_created_desc"', + ) + await queryRunner.query( + 'DROP INDEX "idx_run_project_id_environment_status_created_desc"', + ) + await queryRunner.query( + 'DROP INDEX "idx_run_project_id_environment_created_desc"', + ) + await queryRunner.query( + 'CREATE TABLE "temporary_flow_run" ("id" varchar(21) PRIMARY KEY NOT NULL, "created" datetime NOT NULL DEFAULT (datetime(\'now\')), "updated" datetime NOT NULL DEFAULT (datetime(\'now\')), "projectId" varchar(21) NOT NULL, "flowId" varchar(21) NOT NULL, "flowVersionId" varchar(21) NOT NULL, "environment" varchar, "flowDisplayName" varchar NOT NULL, "logsFileId" varchar(21), "status" varchar NOT NULL, "tasks" integer, "startTime" datetime NOT NULL, "finishTime" datetime, "pauseMetadata" text, "tags" text, CONSTRAINT "fk_flow_run_flow_id" FOREIGN KEY ("flowId") REFERENCES "flow" ("id") ON DELETE CASCADE ON UPDATE NO ACTION, CONSTRAINT "fk_flow_run_project_id" FOREIGN KEY ("projectId") REFERENCES "project" ("id") ON DELETE CASCADE ON UPDATE NO ACTION)', + ) + await queryRunner.query( + 'INSERT INTO "temporary_flow_run"("id", "created", "updated", "projectId", "flowId", "flowVersionId", "environment", "flowDisplayName", "logsFileId", "status", "tasks", "startTime", "finishTime", "pauseMetadata") SELECT "id", "created", "updated", "projectId", "flowId", "flowVersionId", "environment", "flowDisplayName", "logsFileId", "status", "tasks", "startTime", "finishTime", "pauseMetadata" FROM "flow_run"', + ) + await queryRunner.query('DROP TABLE "flow_run"') + await queryRunner.query( + 'ALTER TABLE "temporary_flow_run" RENAME TO "flow_run"', + ) + await queryRunner.query( + 'CREATE INDEX "idx_run_project_id_flow_id_environment_status_created_desc" ON "flow_run" ("projectId", "flowId", "environment", "status", "created") ', + ) + await queryRunner.query( + 'CREATE INDEX "idx_run_project_id_flow_id_environment_created_desc" ON "flow_run" ("projectId", "flowId", "environment", "created") ', + ) + await queryRunner.query( + 'CREATE INDEX "idx_run_project_id_environment_status_created_desc" ON "flow_run" ("projectId", "environment", "status", "created") ', + ) + await queryRunner.query( + 'CREATE INDEX "idx_run_project_id_environment_created_desc" ON "flow_run" ("projectId", "environment", "created") ', + ) + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query( + 'DROP INDEX "idx_run_project_id_environment_created_desc"', + ) + await queryRunner.query( + 'DROP INDEX "idx_run_project_id_environment_status_created_desc"', + ) + await queryRunner.query( + 'DROP INDEX "idx_run_project_id_flow_id_environment_created_desc"', + ) + await queryRunner.query( + 'DROP INDEX "idx_run_project_id_flow_id_environment_status_created_desc"', + ) + await queryRunner.query( + 'ALTER TABLE "flow_run" RENAME TO "temporary_flow_run"', + ) + await queryRunner.query( + 'CREATE TABLE "flow_run" ("id" varchar(21) PRIMARY KEY NOT NULL, "created" datetime NOT NULL DEFAULT (datetime(\'now\')), "updated" datetime NOT NULL DEFAULT (datetime(\'now\')), "projectId" varchar(21) NOT NULL, "flowId" varchar(21) NOT NULL, "flowVersionId" varchar(21) NOT NULL, "environment" varchar, "flowDisplayName" varchar NOT NULL, "logsFileId" varchar(21), "status" varchar NOT NULL, "tasks" integer, "startTime" datetime NOT NULL, "finishTime" datetime, "pauseMetadata" text, CONSTRAINT "fk_flow_run_flow_id" FOREIGN KEY ("flowId") REFERENCES "flow" ("id") ON DELETE CASCADE ON UPDATE NO ACTION, CONSTRAINT "fk_flow_run_project_id" FOREIGN KEY ("projectId") REFERENCES "project" ("id") ON DELETE CASCADE ON UPDATE NO ACTION)', + ) + await queryRunner.query( + 'INSERT INTO "flow_run"("id", "created", "updated", "projectId", "flowId", "flowVersionId", "environment", "flowDisplayName", "logsFileId", "status", "tasks", "startTime", "finishTime", "pauseMetadata") SELECT "id", "created", "updated", "projectId", "flowId", "flowVersionId", "environment", "flowDisplayName", "logsFileId", "status", "tasks", "startTime", "finishTime", "pauseMetadata" FROM "temporary_flow_run"', + ) + await queryRunner.query('DROP TABLE "temporary_flow_run"') + await queryRunner.query( + 'CREATE INDEX "idx_run_project_id_environment_created_desc" ON "flow_run" ("projectId", "environment", "created") ', + ) + await queryRunner.query( + 'CREATE INDEX "idx_run_project_id_environment_status_created_desc" ON "flow_run" ("projectId", "environment", "status", "created") ', + ) + await queryRunner.query( + 'CREATE INDEX "idx_run_project_id_flow_id_environment_created_desc" ON "flow_run" ("projectId", "flowId", "environment", "created") ', + ) + await queryRunner.query( + 'CREATE INDEX "idx_run_project_id_flow_id_environment_status_created_desc" ON "flow_run" ("projectId", "flowId", "environment", "status", "created") ', + ) + } +} + +async function migrationRan( + migration: string, + queryRunner: QueryRunner, +): Promise { + const result = await queryRunner.query( + 'SELECT * from migrations where name = ?', + [migration], + ) + return result.length > 0 +} diff --git a/packages/server/api/src/app/database/migration/sqlite/1692958076906-AddStepFileSqlite.ts b/packages/server/api/src/app/database/migration/sqlite/1692958076906-AddStepFileSqlite.ts new file mode 100644 index 0000000000..edf16d3f4b --- /dev/null +++ b/packages/server/api/src/app/database/migration/sqlite/1692958076906-AddStepFileSqlite.ts @@ -0,0 +1,67 @@ +import { MigrationInterface, QueryRunner } from 'typeorm' + +export class AddStepFileSqlite1692958076906 implements MigrationInterface { + name = 'AddStepFileSqlite1692958076906' + + public async up(queryRunner: QueryRunner): Promise { + if (await migrationRan('AddStepFileSqlite31692958076906', queryRunner)) { + return + } + await queryRunner.query( + 'CREATE TABLE "step_file" ("id" varchar(21) PRIMARY KEY NOT NULL, "created" datetime NOT NULL DEFAULT (datetime(\'now\')), "updated" datetime NOT NULL DEFAULT (datetime(\'now\')), "flowId" varchar(21) NOT NULL, "projectId" varchar(21) NOT NULL, "name" varchar NOT NULL, "size" integer NOT NULL, "stepName" varchar NOT NULL, "data" blob NOT NULL)', + ) + await queryRunner.query( + 'CREATE UNIQUE INDEX "step_file_project_id_flow_id_step_name_name" ON "step_file" ("projectId", "flowId", "stepName", "name") ', + ) + await queryRunner.query( + 'DROP INDEX "step_file_project_id_flow_id_step_name_name"', + ) + await queryRunner.query( + 'CREATE TABLE "temporary_step_file" ("id" varchar(21) PRIMARY KEY NOT NULL, "created" datetime NOT NULL DEFAULT (datetime(\'now\')), "updated" datetime NOT NULL DEFAULT (datetime(\'now\')), "flowId" varchar(21) NOT NULL, "projectId" varchar(21) NOT NULL, "name" varchar NOT NULL, "size" integer NOT NULL, "stepName" varchar NOT NULL, "data" blob NOT NULL, CONSTRAINT "fk_step_file_project_id" FOREIGN KEY ("projectId") REFERENCES "project" ("id") ON DELETE CASCADE ON UPDATE NO ACTION, CONSTRAINT "fk_step_file_flow_id" FOREIGN KEY ("flowId") REFERENCES "flow" ("id") ON DELETE CASCADE ON UPDATE NO ACTION)', + ) + await queryRunner.query( + 'INSERT INTO "temporary_step_file"("id", "created", "updated", "flowId", "projectId", "name", "size", "stepName", "data") SELECT "id", "created", "updated", "flowId", "projectId", "name", "size", "stepName", "data" FROM "step_file"', + ) + await queryRunner.query('DROP TABLE "step_file"') + await queryRunner.query( + 'ALTER TABLE "temporary_step_file" RENAME TO "step_file"', + ) + await queryRunner.query( + 'CREATE UNIQUE INDEX "step_file_project_id_flow_id_step_name_name" ON "step_file" ("projectId", "flowId", "stepName", "name") ', + ) + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query( + 'DROP INDEX "step_file_project_id_flow_id_step_name_name"', + ) + await queryRunner.query( + 'ALTER TABLE "step_file" RENAME TO "temporary_step_file"', + ) + await queryRunner.query( + 'CREATE TABLE "step_file" ("id" varchar(21) PRIMARY KEY NOT NULL, "created" datetime NOT NULL DEFAULT (datetime(\'now\')), "updated" datetime NOT NULL DEFAULT (datetime(\'now\')), "flowId" varchar(21) NOT NULL, "projectId" varchar(21) NOT NULL, "name" varchar NOT NULL, "size" integer NOT NULL, "stepName" varchar NOT NULL, "data" blob NOT NULL)', + ) + await queryRunner.query( + 'INSERT INTO "step_file"("id", "created", "updated", "flowId", "projectId", "name", "size", "stepName", "data") SELECT "id", "created", "updated", "flowId", "projectId", "name", "size", "stepName", "data" FROM "temporary_step_file"', + ) + await queryRunner.query('DROP TABLE "temporary_step_file"') + await queryRunner.query( + 'CREATE UNIQUE INDEX "step_file_project_id_flow_id_step_name_name" ON "step_file" ("projectId", "flowId", "stepName", "name") ', + ) + await queryRunner.query( + 'DROP INDEX "step_file_project_id_flow_id_step_name_name"', + ) + await queryRunner.query('DROP TABLE "step_file"') + } +} + +async function migrationRan( + migration: string, + queryRunner: QueryRunner, +): Promise { + const result = await queryRunner.query( + 'SELECT * from migrations where name = ?', + [migration], + ) + return result.length > 0 +} diff --git a/packages/server/api/src/app/database/migration/sqlite/1693402376520-AddStatusToConnectionsSqlite.ts b/packages/server/api/src/app/database/migration/sqlite/1693402376520-AddStatusToConnectionsSqlite.ts new file mode 100644 index 0000000000..9fa892b1f2 --- /dev/null +++ b/packages/server/api/src/app/database/migration/sqlite/1693402376520-AddStatusToConnectionsSqlite.ts @@ -0,0 +1,63 @@ +import { MigrationInterface, QueryRunner } from 'typeorm' + +export class AddStatusToConnectionsSqlite1693402376520 +implements MigrationInterface { + name = 'AddStatusToConnectionsSqlite1693402376520' + + public async up(queryRunner: QueryRunner): Promise { + if ( + await migrationRan( + 'AddStatusToConnectionsSqlite31693402376520', + queryRunner, + ) + ) { + return + } + await queryRunner.query( + 'DROP INDEX "idx_app_connection_project_id_and_name"', + ) + await queryRunner.query( + 'CREATE TABLE "temporary_app_connection" ("id" varchar(21) PRIMARY KEY NOT NULL, "created" datetime NOT NULL DEFAULT (datetime(\'now\')), "updated" datetime NOT NULL DEFAULT (datetime(\'now\')), "name" varchar NOT NULL, "appName" varchar NOT NULL, "projectId" varchar(21) NOT NULL, "value" text NOT NULL, "type" varchar NOT NULL, "status" varchar NOT NULL DEFAULT (\'ACTIVE\'), CONSTRAINT "fk_app_connection_app_project_id" FOREIGN KEY ("projectId") REFERENCES "project" ("id") ON DELETE CASCADE ON UPDATE NO ACTION)', + ) + await queryRunner.query( + 'INSERT INTO "temporary_app_connection"("id", "created", "updated", "name", "appName", "projectId", "value", "type") SELECT "id", "created", "updated", "name", "appName", "projectId", "value", "type" FROM "app_connection"', + ) + await queryRunner.query('DROP TABLE "app_connection"') + await queryRunner.query( + 'ALTER TABLE "temporary_app_connection" RENAME TO "app_connection"', + ) + await queryRunner.query( + 'CREATE UNIQUE INDEX "idx_app_connection_project_id_and_name" ON "app_connection" ("projectId", "name") ', + ) + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query( + 'DROP INDEX "idx_app_connection_project_id_and_name"', + ) + await queryRunner.query( + 'ALTER TABLE "app_connection" RENAME TO "temporary_app_connection"', + ) + await queryRunner.query( + 'CREATE TABLE "app_connection" ("id" varchar(21) PRIMARY KEY NOT NULL, "created" datetime NOT NULL DEFAULT (datetime(\'now\')), "updated" datetime NOT NULL DEFAULT (datetime(\'now\')), "name" varchar NOT NULL, "appName" varchar NOT NULL, "projectId" varchar(21) NOT NULL, "value" text NOT NULL, "type" varchar NOT NULL, CONSTRAINT "fk_app_connection_app_project_id" FOREIGN KEY ("projectId") REFERENCES "project" ("id") ON DELETE CASCADE ON UPDATE NO ACTION)', + ) + await queryRunner.query( + 'INSERT INTO "app_connection"("id", "created", "updated", "name", "appName", "projectId", "value", "type") SELECT "id", "created", "updated", "name", "appName", "projectId", "value", "type" FROM "temporary_app_connection"', + ) + await queryRunner.query('DROP TABLE "temporary_app_connection"') + await queryRunner.query( + 'CREATE UNIQUE INDEX "idx_app_connection_project_id_and_name" ON "app_connection" ("projectId", "name") ', + ) + } +} + +async function migrationRan( + migration: string, + queryRunner: QueryRunner, +): Promise { + const result = await queryRunner.query( + 'SELECT * from migrations where name = ?', + [migration], + ) + return result.length > 0 +} diff --git a/packages/server/api/src/app/database/migration/sqlite/1693774053027-AddImageUrlAndTitleToUser.ts b/packages/server/api/src/app/database/migration/sqlite/1693774053027-AddImageUrlAndTitleToUser.ts new file mode 100644 index 0000000000..52d1d92df2 --- /dev/null +++ b/packages/server/api/src/app/database/migration/sqlite/1693774053027-AddImageUrlAndTitleToUser.ts @@ -0,0 +1,28 @@ +import { MigrationInterface, QueryRunner } from 'typeorm' + +export class AddImageUrlAndTitleToUser1693774053027 +implements MigrationInterface { + name = 'AddImageUrlAndTitleToUser1693774053027' + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query( + 'CREATE TABLE "temporary_user" ("id" varchar(21) PRIMARY KEY NOT NULL, "created" datetime NOT NULL DEFAULT (datetime(\'now\')), "updated" datetime NOT NULL DEFAULT (datetime(\'now\')), "email" varchar NOT NULL, "firstName" varchar NOT NULL, "lastName" varchar NOT NULL, "password" varchar NOT NULL, "status" varchar NOT NULL, "trackEvents" boolean, "newsLetter" boolean, "imageUrl" varchar, "title" varchar, CONSTRAINT "UQ_e12875dfb3b1d92d7d7c5377e22" UNIQUE ("email"))', + ) + await queryRunner.query( + 'INSERT INTO "temporary_user"("id", "created", "updated", "email", "firstName", "lastName", "password", "status", "trackEvents", "newsLetter") SELECT "id", "created", "updated", "email", "firstName", "lastName", "password", "status", "trackEvents", "newsLetter" FROM "user"', + ) + await queryRunner.query('DROP TABLE "user"') + await queryRunner.query('ALTER TABLE "temporary_user" RENAME TO "user"') + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query('ALTER TABLE "user" RENAME TO "temporary_user"') + await queryRunner.query( + 'CREATE TABLE "user" ("id" varchar(21) PRIMARY KEY NOT NULL, "created" datetime NOT NULL DEFAULT (datetime(\'now\')), "updated" datetime NOT NULL DEFAULT (datetime(\'now\')), "email" varchar NOT NULL, "firstName" varchar NOT NULL, "lastName" varchar NOT NULL, "password" varchar NOT NULL, "status" varchar NOT NULL, "trackEvents" boolean, "newsLetter" boolean, CONSTRAINT "UQ_e12875dfb3b1d92d7d7c5377e22" UNIQUE ("email"))', + ) + await queryRunner.query( + 'INSERT INTO "user"("id", "created", "updated", "email", "firstName", "lastName", "password", "status", "trackEvents", "newsLetter") SELECT "id", "created", "updated", "email", "firstName", "lastName", "password", "status", "trackEvents", "newsLetter" FROM "temporary_user"', + ) + await queryRunner.query('DROP TABLE "temporary_user"') + } +} diff --git a/packages/server/api/src/app/database/migration/sqlite/1694695212159-file-type-compression.ts b/packages/server/api/src/app/database/migration/sqlite/1694695212159-file-type-compression.ts new file mode 100644 index 0000000000..ae97000da2 --- /dev/null +++ b/packages/server/api/src/app/database/migration/sqlite/1694695212159-file-type-compression.ts @@ -0,0 +1,32 @@ +import { MigrationInterface, QueryRunner } from 'typeorm' +import { logger } from 'server-shared' + +export class FileTypeCompression1694695212159 implements MigrationInterface { + name = 'FileTypeCompression1694695212159' + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query( + 'CREATE TABLE "temporary_file" ("id" varchar(21) PRIMARY KEY NOT NULL, "created" datetime NOT NULL DEFAULT (datetime(\'now\')), "updated" datetime NOT NULL DEFAULT (datetime(\'now\')), "projectId" varchar(21), "data" blob NOT NULL, "type" varchar NOT NULL DEFAULT (\'UNKNOWN\'), "compression" varchar NOT NULL DEFAULT (\'NONE\'), CONSTRAINT "fk_file_project_id" FOREIGN KEY ("projectId") REFERENCES "project" ("id") ON DELETE CASCADE ON UPDATE NO ACTION)', + ) + await queryRunner.query( + 'INSERT INTO "temporary_file"("id", "created", "updated", "projectId", "data") SELECT "id", "created", "updated", "projectId", "data" FROM "file"', + ) + await queryRunner.query('DROP TABLE "file"') + await queryRunner.query('ALTER TABLE "temporary_file" RENAME TO "file"') + + logger.info('[FileTypeCompression1694695212159] up') + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query('ALTER TABLE "file" RENAME TO "temporary_file"') + await queryRunner.query( + 'CREATE TABLE "file" ("id" varchar(21) PRIMARY KEY NOT NULL, "created" datetime NOT NULL DEFAULT (datetime(\'now\')), "updated" datetime NOT NULL DEFAULT (datetime(\'now\')), "projectId" varchar(21), "data" blob NOT NULL, CONSTRAINT "fk_file_project_id" FOREIGN KEY ("projectId") REFERENCES "project" ("id") ON DELETE CASCADE ON UPDATE NO ACTION)', + ) + await queryRunner.query( + 'INSERT INTO "file"("id", "created", "updated", "projectId", "data") SELECT "id", "created", "updated", "projectId", "data" FROM "temporary_file"', + ) + await queryRunner.query('DROP TABLE "temporary_file"') + + logger.info('[FileTypeCompression1694695212159] down') + } +} diff --git a/packages/server/api/src/app/database/migration/sqlite/1696016228398-add-piece-type-and-package-type-to-piece-metadata.ts b/packages/server/api/src/app/database/migration/sqlite/1696016228398-add-piece-type-and-package-type-to-piece-metadata.ts new file mode 100644 index 0000000000..91b31ccf31 --- /dev/null +++ b/packages/server/api/src/app/database/migration/sqlite/1696016228398-add-piece-type-and-package-type-to-piece-metadata.ts @@ -0,0 +1,70 @@ +import { MigrationInterface, QueryRunner } from 'typeorm' +import { logger } from 'server-shared' + +export class AddPieceTypeAndPackageTypeToPieceMetadata1696016228398 +implements MigrationInterface { + name = 'AddPieceTypeAndPackageTypeToPieceMetadata1696016228398' + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query( + 'CREATE TABLE "temporary_piece_metadata" ("id" varchar(21) PRIMARY KEY NOT NULL, "created" datetime NOT NULL DEFAULT (datetime(\'now\')), "updated" datetime NOT NULL DEFAULT (datetime(\'now\')), "name" varchar NOT NULL, "displayName" varchar NOT NULL, "logoUrl" varchar NOT NULL, "description" varchar, "projectId" varchar, "version" varchar NOT NULL, "minimumSupportedRelease" varchar NOT NULL, "maximumSupportedRelease" varchar NOT NULL, "auth" text, "actions" text NOT NULL, "triggers" text NOT NULL, "pieceType" varchar, "packageType" varchar, CONSTRAINT "fk_piece_metadata_project_id" FOREIGN KEY ("projectId") REFERENCES "project" ("id") ON DELETE CASCADE ON UPDATE NO ACTION)', + ) + await queryRunner.query( + 'INSERT INTO "temporary_piece_metadata"("id", "created", "updated", "name", "displayName", "logoUrl", "description", "projectId", "version", "minimumSupportedRelease", "maximumSupportedRelease", "auth", "actions", "triggers") SELECT "id", "created", "updated", "name", "displayName", "logoUrl", "description", "projectId", "version", "minimumSupportedRelease", "maximumSupportedRelease", "auth", "actions", "triggers" FROM "piece_metadata"', + ) + + await queryRunner.query( + 'DROP INDEX "idx_piece_metadata_name_project_id_version"', + ) + await queryRunner.query('DROP TABLE "piece_metadata"') + + await queryRunner.query( + 'UPDATE "temporary_piece_metadata" SET "pieceType" = \'OFFICIAL\' WHERE "projectId" IS NULL', + ) + await queryRunner.query( + 'UPDATE "temporary_piece_metadata" SET "pieceType" = \'CUSTOM\' WHERE "projectId" IS NOT NULL', + ) + await queryRunner.query( + 'UPDATE "temporary_piece_metadata" SET "packageType" = \'REGISTRY\'', + ) + + await queryRunner.query( + 'CREATE TABLE "temporary_piece_metadata_two" ("id" varchar(21) PRIMARY KEY NOT NULL, "created" datetime NOT NULL DEFAULT (datetime(\'now\')), "updated" datetime NOT NULL DEFAULT (datetime(\'now\')), "name" varchar NOT NULL, "displayName" varchar NOT NULL, "logoUrl" varchar NOT NULL, "description" varchar, "projectId" varchar, "version" varchar NOT NULL, "minimumSupportedRelease" varchar NOT NULL, "maximumSupportedRelease" varchar NOT NULL, "auth" text, "actions" text NOT NULL, "triggers" text NOT NULL, "pieceType" varchar NOT NULL, "packageType" varchar NOT NULL, CONSTRAINT "fk_piece_metadata_project_id" FOREIGN KEY ("projectId") REFERENCES "project" ("id") ON DELETE CASCADE ON UPDATE NO ACTION)', + ) + await queryRunner.query( + 'INSERT INTO "temporary_piece_metadata_two"("id", "created", "updated", "name", "displayName", "logoUrl", "description", "projectId", "version", "minimumSupportedRelease", "maximumSupportedRelease", "auth", "actions", "triggers", "pieceType", "packageType") SELECT "id", "created", "updated", "name", "displayName", "logoUrl", "description", "projectId", "version", "minimumSupportedRelease", "maximumSupportedRelease", "auth", "actions", "triggers", "pieceType", "packageType" FROM "temporary_piece_metadata"', + ) + + await queryRunner.query('DROP TABLE "temporary_piece_metadata"') + + await queryRunner.query( + 'ALTER TABLE "temporary_piece_metadata_two" RENAME TO "piece_metadata"', + ) + await queryRunner.query( + 'CREATE UNIQUE INDEX "idx_piece_metadata_name_project_id_version" ON "piece_metadata" ("name", "version", "projectId") ', + ) + + logger.info('AddPieceTypeAndPackageTypeToPieceMetadata1696016228398: up') + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query( + 'DROP INDEX "idx_piece_metadata_name_project_id_version"', + ) + await queryRunner.query( + 'ALTER TABLE "piece_metadata" RENAME TO "temporary_piece_metadata"', + ) + await queryRunner.query( + 'CREATE TABLE "piece_metadata" ("id" varchar(21) PRIMARY KEY NOT NULL, "created" datetime NOT NULL DEFAULT (datetime(\'now\')), "updated" datetime NOT NULL DEFAULT (datetime(\'now\')), "name" varchar NOT NULL, "displayName" varchar NOT NULL, "logoUrl" varchar NOT NULL, "description" varchar, "projectId" varchar, "version" varchar NOT NULL, "minimumSupportedRelease" varchar NOT NULL, "maximumSupportedRelease" varchar NOT NULL, "auth" text, "actions" text NOT NULL, "triggers" text NOT NULL, CONSTRAINT "fk_piece_metadata_project_id" FOREIGN KEY ("projectId") REFERENCES "project" ("id") ON DELETE CASCADE ON UPDATE NO ACTION)', + ) + await queryRunner.query( + 'INSERT INTO "piece_metadata"("id", "created", "updated", "name", "displayName", "logoUrl", "description", "projectId", "version", "minimumSupportedRelease", "maximumSupportedRelease", "auth", "actions", "triggers") SELECT "id", "created", "updated", "name", "displayName", "logoUrl", "description", "projectId", "version", "minimumSupportedRelease", "maximumSupportedRelease", "auth", "actions", "triggers" FROM "temporary_piece_metadata"', + ) + await queryRunner.query('DROP TABLE "temporary_piece_metadata"') + await queryRunner.query( + 'CREATE UNIQUE INDEX "idx_piece_metadata_name_project_id_version" ON "piece_metadata" ("name", "version", "projectId") ', + ) + + logger.info('AddPieceTypeAndPackageTypeToPieceMetadata1696016228398: down') + } +} diff --git a/packages/server/api/src/app/database/migration/sqlite/1696029443045-AddChatBotSqlite.ts b/packages/server/api/src/app/database/migration/sqlite/1696029443045-AddChatBotSqlite.ts new file mode 100644 index 0000000000..8f7c07d2ab --- /dev/null +++ b/packages/server/api/src/app/database/migration/sqlite/1696029443045-AddChatBotSqlite.ts @@ -0,0 +1,49 @@ +import { MigrationInterface, QueryRunner } from 'typeorm' + +export class AddChatBotSqlite1696029443045 implements MigrationInterface { + name = 'AddChatBotSqlite1696029443045' + + public async up(queryRunner: QueryRunner): Promise { + if (await migrationRan('AddChatBotSqlite31696029443045', queryRunner)) { + return + } + await queryRunner.query( + 'CREATE TABLE "chatbot" ("id" varchar(21) PRIMARY KEY NOT NULL, "created" datetime NOT NULL DEFAULT (datetime(\'now\')), "updated" datetime NOT NULL DEFAULT (datetime(\'now\')), "type" varchar NOT NULL, "displayName" varchar NOT NULL, "projectId" varchar NOT NULL, "connectionId" varchar, "visibilityStatus" varchar NOT NULL, "dataSources" text NOT NULL, "prompt" varchar)', + ) + await queryRunner.query( + 'CREATE TABLE "temporary_chatbot" ("id" varchar(21) PRIMARY KEY NOT NULL, "created" datetime NOT NULL DEFAULT (datetime(\'now\')), "updated" datetime NOT NULL DEFAULT (datetime(\'now\')), "type" varchar NOT NULL, "displayName" varchar NOT NULL, "projectId" varchar NOT NULL, "connectionId" varchar, "visibilityStatus" varchar NOT NULL, "dataSources" text NOT NULL, "prompt" varchar, CONSTRAINT "FK_d2f5f245c27541cd70f13f169eb" FOREIGN KEY ("projectId") REFERENCES "project" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION, CONSTRAINT "FK_13f7ad52cefa43433864732c384" FOREIGN KEY ("connectionId") REFERENCES "app_connection" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION)', + ) + await queryRunner.query( + 'INSERT INTO "temporary_chatbot"("id", "created", "updated", "type", "displayName", "projectId", "connectionId", "visibilityStatus", "dataSources", "prompt") SELECT "id", "created", "updated", "type", "displayName", "projectId", "connectionId", "visibilityStatus", "dataSources", "prompt" FROM "chatbot"', + ) + await queryRunner.query('DROP TABLE "chatbot"') + await queryRunner.query( + 'ALTER TABLE "temporary_chatbot" RENAME TO "chatbot"', + ) + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query( + 'ALTER TABLE "chatbot" RENAME TO "temporary_chatbot"', + ) + await queryRunner.query( + 'CREATE TABLE "chatbot" ("id" varchar(21) PRIMARY KEY NOT NULL, "created" datetime NOT NULL DEFAULT (datetime(\'now\')), "updated" datetime NOT NULL DEFAULT (datetime(\'now\')), "type" varchar NOT NULL, "displayName" varchar NOT NULL, "projectId" varchar NOT NULL, "connectionId" varchar, "visibilityStatus" varchar NOT NULL, "dataSources" text NOT NULL, "prompt" varchar)', + ) + await queryRunner.query( + 'INSERT INTO "chatbot"("id", "created", "updated", "type", "displayName", "projectId", "connectionId", "visibilityStatus", "dataSources", "prompt") SELECT "id", "created", "updated", "type", "displayName", "projectId", "connectionId", "visibilityStatus", "dataSources", "prompt" FROM "temporary_chatbot"', + ) + await queryRunner.query('DROP TABLE "temporary_chatbot"') + await queryRunner.query('DROP TABLE "chatbot"') + } +} + +async function migrationRan( + migration: string, + queryRunner: QueryRunner, +): Promise { + const result = await queryRunner.query( + 'SELECT * from migrations where name = ?', + [migration], + ) + return result.length > 0 +} diff --git a/packages/backend/src/app/database/migration/sqlite/1696956123632-add-archive-id-to-piece-metadata.ts b/packages/server/api/src/app/database/migration/sqlite/1696956123632-add-archive-id-to-piece-metadata.ts similarity index 98% rename from packages/backend/src/app/database/migration/sqlite/1696956123632-add-archive-id-to-piece-metadata.ts rename to packages/server/api/src/app/database/migration/sqlite/1696956123632-add-archive-id-to-piece-metadata.ts index 2fb7f92428..5b5101971c 100644 --- a/packages/backend/src/app/database/migration/sqlite/1696956123632-add-archive-id-to-piece-metadata.ts +++ b/packages/server/api/src/app/database/migration/sqlite/1696956123632-add-archive-id-to-piece-metadata.ts @@ -1,7 +1,8 @@ import { MigrationInterface, QueryRunner } from 'typeorm' -import { logger } from '../../../helper/logger' +import { logger } from 'server-shared' -export class AddArchiveIdToPieceMetadata1696956123632 implements MigrationInterface { +export class AddArchiveIdToPieceMetadata1696956123632 +implements MigrationInterface { name = 'AddArchiveIdToPieceMetadata1696956123632' public async up(queryRunner: QueryRunner): Promise { @@ -308,5 +309,4 @@ export class AddArchiveIdToPieceMetadata1696956123632 implements MigrationInterf logger.info('AddArchiveIdToPieceMetadata1696956123632: down') } - } diff --git a/packages/backend/src/app/database/migration/sqlite/1698078715730-add-platform-to-project.ts b/packages/server/api/src/app/database/migration/sqlite/1698078715730-add-platform-to-project.ts similarity index 98% rename from packages/backend/src/app/database/migration/sqlite/1698078715730-add-platform-to-project.ts rename to packages/server/api/src/app/database/migration/sqlite/1698078715730-add-platform-to-project.ts index 01adea5483..c9415b0e89 100644 --- a/packages/backend/src/app/database/migration/sqlite/1698078715730-add-platform-to-project.ts +++ b/packages/server/api/src/app/database/migration/sqlite/1698078715730-add-platform-to-project.ts @@ -1,5 +1,5 @@ import { MigrationInterface, QueryRunner } from 'typeorm' -import { logger } from '../../../helper/logger' +import { logger } from 'server-shared' export class AddPlatformToProject1698078715730 implements MigrationInterface { name = 'AddPlatformToProject1698078715730' @@ -97,5 +97,4 @@ export class AddPlatformToProject1698078715730 implements MigrationInterface { logger.info('AddPlatformToProject1698078715730 down') } - } diff --git a/packages/backend/src/app/database/migration/sqlite/1698323327318-AddTerminationReason.ts b/packages/server/api/src/app/database/migration/sqlite/1698323327318-AddTerminationReason.ts similarity index 94% rename from packages/backend/src/app/database/migration/sqlite/1698323327318-AddTerminationReason.ts rename to packages/server/api/src/app/database/migration/sqlite/1698323327318-AddTerminationReason.ts index 99a70f532f..d47eac366b 100644 --- a/packages/backend/src/app/database/migration/sqlite/1698323327318-AddTerminationReason.ts +++ b/packages/server/api/src/app/database/migration/sqlite/1698323327318-AddTerminationReason.ts @@ -1,10 +1,16 @@ import { MigrationInterface, QueryRunner } from 'typeorm' -export class AddTerminationReasonSqlite1698323327318 implements MigrationInterface { +export class AddTerminationReasonSqlite1698323327318 +implements MigrationInterface { name = 'AddTerminationReasonSqlite1698323327318' public async up(queryRunner: QueryRunner): Promise { - if (await migrationRan('AddTerminationReasonSqlite31698323327318', queryRunner)) { + if ( + await migrationRan( + 'AddTerminationReasonSqlite31698323327318', + queryRunner, + ) + ) { return } await queryRunner.query(` @@ -210,11 +216,15 @@ export class AddTerminationReasonSqlite1698323327318 implements MigrationInterfa CREATE INDEX "idx_run_project_id_environment_created_desc" ON "flow_run" ("projectId", "environment", "created") `) } - } - -async function migrationRan(migration: string, queryRunner: QueryRunner): Promise { - const result = await queryRunner.query('SELECT * from migrations where name = ?', [migration]) +async function migrationRan( + migration: string, + queryRunner: QueryRunner, +): Promise { + const result = await queryRunner.query( + 'SELECT * from migrations where name = ?', + [migration], + ) return result.length > 0 -} \ No newline at end of file +} diff --git a/packages/backend/src/app/database/migration/sqlite/1698857968495-AddExternalIdSqlite.ts b/packages/server/api/src/app/database/migration/sqlite/1698857968495-AddExternalIdSqlite.ts similarity index 96% rename from packages/backend/src/app/database/migration/sqlite/1698857968495-AddExternalIdSqlite.ts rename to packages/server/api/src/app/database/migration/sqlite/1698857968495-AddExternalIdSqlite.ts index 7f254bccc1..11596c7046 100644 --- a/packages/backend/src/app/database/migration/sqlite/1698857968495-AddExternalIdSqlite.ts +++ b/packages/server/api/src/app/database/migration/sqlite/1698857968495-AddExternalIdSqlite.ts @@ -1,5 +1,5 @@ import { MigrationInterface, QueryRunner } from 'typeorm' -import { logger } from '../../../helper/logger' +import { logger } from 'server-shared' export class AddExternalIdSqlite1698857968495 implements MigrationInterface { name = 'AddExternalIdSqlite1698857968495' @@ -228,10 +228,15 @@ export class AddExternalIdSqlite1698857968495 implements MigrationInterface { CREATE INDEX "idx_project_owner_id" ON "project" ("ownerId") `) } - } -async function migrationRan(migration: string, queryRunner: QueryRunner): Promise { - const result = await queryRunner.query('SELECT * from migrations where name = ?', [migration]) +async function migrationRan( + migration: string, + queryRunner: QueryRunner, +): Promise { + const result = await queryRunner.query( + 'SELECT * from migrations where name = ?', + [migration], + ) return result.length > 0 -} \ No newline at end of file +} diff --git a/packages/backend/src/app/database/migration/sqlite/1700147448410-AddPlatformIdToUserSqlite.ts b/packages/server/api/src/app/database/migration/sqlite/1700147448410-AddPlatformIdToUserSqlite.ts similarity index 99% rename from packages/backend/src/app/database/migration/sqlite/1700147448410-AddPlatformIdToUserSqlite.ts rename to packages/server/api/src/app/database/migration/sqlite/1700147448410-AddPlatformIdToUserSqlite.ts index f84ca85e9d..3b7d710813 100644 --- a/packages/backend/src/app/database/migration/sqlite/1700147448410-AddPlatformIdToUserSqlite.ts +++ b/packages/server/api/src/app/database/migration/sqlite/1700147448410-AddPlatformIdToUserSqlite.ts @@ -1,6 +1,7 @@ import { MigrationInterface, QueryRunner } from 'typeorm' -export class AddPlatformIdToUserSqlite1700147448410 implements MigrationInterface { +export class AddPlatformIdToUserSqlite1700147448410 +implements MigrationInterface { name = 'AddPlatformIdToUserSqlite1700147448410' public async up(queryRunner: QueryRunner): Promise { @@ -257,5 +258,4 @@ export class AddPlatformIdToUserSqlite1700147448410 implements MigrationInterfac CREATE UNIQUE INDEX "idx_user_external_id" ON "user" ("externalId") `) } - } diff --git a/packages/backend/src/app/database/migration/sqlite/1700524446967-AddPlatformIdToPieceMetadataSqlite.ts b/packages/server/api/src/app/database/migration/sqlite/1700524446967-AddPlatformIdToPieceMetadataSqlite.ts similarity index 99% rename from packages/backend/src/app/database/migration/sqlite/1700524446967-AddPlatformIdToPieceMetadataSqlite.ts rename to packages/server/api/src/app/database/migration/sqlite/1700524446967-AddPlatformIdToPieceMetadataSqlite.ts index 0f46034f67..cb61b344c7 100644 --- a/packages/backend/src/app/database/migration/sqlite/1700524446967-AddPlatformIdToPieceMetadataSqlite.ts +++ b/packages/server/api/src/app/database/migration/sqlite/1700524446967-AddPlatformIdToPieceMetadataSqlite.ts @@ -1,6 +1,7 @@ import { MigrationInterface, QueryRunner } from 'typeorm' -export class AddPlatformIdToPieceMetadataSqlite1700524446967 implements MigrationInterface { +export class AddPlatformIdToPieceMetadataSqlite1700524446967 +implements MigrationInterface { name = 'AddPlatformIdToPieceMetadataSqlite1700524446967' public async up(queryRunner: QueryRunner): Promise { @@ -445,5 +446,4 @@ export class AddPlatformIdToPieceMetadataSqlite1700524446967 implements Migratio CREATE UNIQUE INDEX "idx_user_platform_id_external_id" ON "user" ("platformId", "externalId") `) } - } diff --git a/packages/backend/src/app/database/migration/sqlite/1701808264444-AddPlatformIdToFileSqlite.ts b/packages/server/api/src/app/database/migration/sqlite/1701808264444-AddPlatformIdToFileSqlite.ts similarity index 99% rename from packages/backend/src/app/database/migration/sqlite/1701808264444-AddPlatformIdToFileSqlite.ts rename to packages/server/api/src/app/database/migration/sqlite/1701808264444-AddPlatformIdToFileSqlite.ts index 73270052bb..02d683ee5d 100644 --- a/packages/backend/src/app/database/migration/sqlite/1701808264444-AddPlatformIdToFileSqlite.ts +++ b/packages/server/api/src/app/database/migration/sqlite/1701808264444-AddPlatformIdToFileSqlite.ts @@ -1,6 +1,7 @@ import { MigrationInterface, QueryRunner } from 'typeorm' -export class AddPlatformIdToFileSqlite1701808264444 implements MigrationInterface { +export class AddPlatformIdToFileSqlite1701808264444 +implements MigrationInterface { name = 'AddPlatformIdToFileSqlite1701808264444' public async up(queryRunner: QueryRunner): Promise { @@ -397,5 +398,4 @@ export class AddPlatformIdToFileSqlite1701808264444 implements MigrationInterfac WHERE "platformId" IS NULL `) } - } diff --git a/packages/backend/src/app/database/migration/sqlite/1702412280963-remove-flow-instance-sqlite.ts b/packages/server/api/src/app/database/migration/sqlite/1702412280963-remove-flow-instance-sqlite.ts similarity index 97% rename from packages/backend/src/app/database/migration/sqlite/1702412280963-remove-flow-instance-sqlite.ts rename to packages/server/api/src/app/database/migration/sqlite/1702412280963-remove-flow-instance-sqlite.ts index 0021392eec..0120eea0c2 100644 --- a/packages/backend/src/app/database/migration/sqlite/1702412280963-remove-flow-instance-sqlite.ts +++ b/packages/server/api/src/app/database/migration/sqlite/1702412280963-remove-flow-instance-sqlite.ts @@ -1,7 +1,8 @@ import { MigrationInterface, QueryRunner } from 'typeorm' -import { logger } from '../../../helper/logger' +import { logger } from 'server-shared' -export class RemoveFlowInstanceSqlite1702412280963 implements MigrationInterface { +export class RemoveFlowInstanceSqlite1702412280963 +implements MigrationInterface { name = 'RemoveFlowInstanceSqlite1702412280963' public async up(queryRunner: QueryRunner): Promise { @@ -137,5 +138,4 @@ export class RemoveFlowInstanceSqlite1702412280963 implements MigrationInterface logger.info('RemoveFlowInstanceSqlite1702412280963 down') } - } diff --git a/packages/backend/src/app/database/migration/sqlite/1703713027818-UpdateStatusInUserSqlite.ts b/packages/server/api/src/app/database/migration/sqlite/1703713027818-UpdateStatusInUserSqlite.ts similarity index 99% rename from packages/backend/src/app/database/migration/sqlite/1703713027818-UpdateStatusInUserSqlite.ts rename to packages/server/api/src/app/database/migration/sqlite/1703713027818-UpdateStatusInUserSqlite.ts index 3e11f08137..46802da25f 100644 --- a/packages/backend/src/app/database/migration/sqlite/1703713027818-UpdateStatusInUserSqlite.ts +++ b/packages/server/api/src/app/database/migration/sqlite/1703713027818-UpdateStatusInUserSqlite.ts @@ -1,7 +1,8 @@ import { MigrationInterface, QueryRunner } from 'typeorm' -import { logger } from '../../../helper/logger' +import { logger } from 'server-shared' -export class UpdateStatusInUserSqlite1703713027818 implements MigrationInterface { +export class UpdateStatusInUserSqlite1703713027818 +implements MigrationInterface { name = 'UpdateStatusInUserSqlite1703713027818' public async up(queryRunner: QueryRunner): Promise { @@ -436,5 +437,4 @@ export class UpdateStatusInUserSqlite1703713027818 implements MigrationInterface CREATE UNIQUE INDEX "idx_user_platform_id_email" ON "user" ("platformId", "email") `) } - } diff --git a/packages/backend/src/app/database/migration/sqlite/1703713475755-RenameAppNameToPieceNameSqlite.ts b/packages/server/api/src/app/database/migration/sqlite/1703713475755-RenameAppNameToPieceNameSqlite.ts similarity index 99% rename from packages/backend/src/app/database/migration/sqlite/1703713475755-RenameAppNameToPieceNameSqlite.ts rename to packages/server/api/src/app/database/migration/sqlite/1703713475755-RenameAppNameToPieceNameSqlite.ts index 445ab188a8..a1771e9859 100644 --- a/packages/backend/src/app/database/migration/sqlite/1703713475755-RenameAppNameToPieceNameSqlite.ts +++ b/packages/server/api/src/app/database/migration/sqlite/1703713475755-RenameAppNameToPieceNameSqlite.ts @@ -1,7 +1,8 @@ import { MigrationInterface, QueryRunner } from 'typeorm' -import { logger } from '../../../helper/logger' +import { logger } from 'server-shared' -export class RenameAppNameToPieceNameSqlite1703713475755 implements MigrationInterface { +export class RenameAppNameToPieceNameSqlite1703713475755 +implements MigrationInterface { name = 'RenameAppNameToPieceNameSqlite1703713475755' public async up(queryRunner: QueryRunner): Promise { @@ -536,5 +537,4 @@ export class RenameAppNameToPieceNameSqlite1703713475755 implements MigrationInt CREATE UNIQUE INDEX "idx_user_platform_id_email" ON "user" ("platformId", "email") `) } - } diff --git a/packages/backend/src/app/database/migration/sqlite/1703768553820-AddVerifiedAndChangeStatusSqlite.ts b/packages/server/api/src/app/database/migration/sqlite/1703768553820-AddVerifiedAndChangeStatusSqlite.ts similarity index 99% rename from packages/backend/src/app/database/migration/sqlite/1703768553820-AddVerifiedAndChangeStatusSqlite.ts rename to packages/server/api/src/app/database/migration/sqlite/1703768553820-AddVerifiedAndChangeStatusSqlite.ts index c237b95241..317e2e5d32 100644 --- a/packages/backend/src/app/database/migration/sqlite/1703768553820-AddVerifiedAndChangeStatusSqlite.ts +++ b/packages/server/api/src/app/database/migration/sqlite/1703768553820-AddVerifiedAndChangeStatusSqlite.ts @@ -1,6 +1,7 @@ import { MigrationInterface, QueryRunner } from 'typeorm' -export class AddVerifiedAndChangeStatusSqlite1703768553820 implements MigrationInterface { +export class AddVerifiedAndChangeStatusSqlite1703768553820 +implements MigrationInterface { name = 'AddVerifiedAndChangeStatusSqlite1703768553820' public async up(queryRunner: QueryRunner): Promise { @@ -225,7 +226,6 @@ export class AddVerifiedAndChangeStatusSqlite1703768553820 implements MigrationI await queryRunner.query(` CREATE UNIQUE INDEX "idx_user_platform_id_email" ON "user" ("platformId", "email") `) - } public async down(queryRunner: QueryRunner): Promise { @@ -449,5 +449,4 @@ export class AddVerifiedAndChangeStatusSqlite1703768553820 implements MigrationI CREATE UNIQUE INDEX "idx_user_platform_id_email" ON "user" ("platformId", "email") `) } - } diff --git a/packages/backend/src/app/database/migration/sqlite/1707229986819-AddCategoriesToPieceMetadata.ts b/packages/server/api/src/app/database/migration/sqlite/1707229986819-AddCategoriesToPieceMetadata.ts similarity index 99% rename from packages/backend/src/app/database/migration/sqlite/1707229986819-AddCategoriesToPieceMetadata.ts rename to packages/server/api/src/app/database/migration/sqlite/1707229986819-AddCategoriesToPieceMetadata.ts index 602db2c32e..ceb4333fb2 100644 --- a/packages/backend/src/app/database/migration/sqlite/1707229986819-AddCategoriesToPieceMetadata.ts +++ b/packages/server/api/src/app/database/migration/sqlite/1707229986819-AddCategoriesToPieceMetadata.ts @@ -1,6 +1,7 @@ import { MigrationInterface, QueryRunner } from 'typeorm' -export class AddCategoriesToPieceMetadata1707229986819 implements MigrationInterface { +export class AddCategoriesToPieceMetadata1707229986819 +implements MigrationInterface { name = 'AddCategoriesToPieceMetadata1707229986819' public async up(queryRunner: QueryRunner): Promise { @@ -491,5 +492,4 @@ export class AddCategoriesToPieceMetadata1707229986819 implements MigrationInter CREATE UNIQUE INDEX "idx_user_platform_id_email" ON "user" ("platformId", "email") `) } - } diff --git a/packages/backend/src/app/database/postgres-connection.ts b/packages/server/api/src/app/database/postgres-connection.ts similarity index 99% rename from packages/backend/src/app/database/postgres-connection.ts rename to packages/server/api/src/app/database/postgres-connection.ts index e0701f5100..2028b070d0 100644 --- a/packages/backend/src/app/database/postgres-connection.ts +++ b/packages/server/api/src/app/database/postgres-connection.ts @@ -1,6 +1,5 @@ import { DataSource, MigrationInterface } from 'typeorm' -import { system } from '../helper/system/system' -import { SystemProp } from '../helper/system/system-prop' +import { system, SystemProp } from 'server-shared' import { TlsOptions } from 'node:tls' import { FlowAndFileProjectId1674788714498 } from './migration/postgres/1674788714498-FlowAndFileProjectId' import { initializeSchema1676238396411 } from './migration/postgres/1676238396411-initialize-schema' diff --git a/packages/backend/src/app/database/redis-connection.ts b/packages/server/api/src/app/database/redis-connection.ts old mode 100755 new mode 100644 similarity index 86% rename from packages/backend/src/app/database/redis-connection.ts rename to packages/server/api/src/app/database/redis-connection.ts index c8f6475d7c..a6ec4c975d --- a/packages/backend/src/app/database/redis-connection.ts +++ b/packages/server/api/src/app/database/redis-connection.ts @@ -1,6 +1,5 @@ import Redis, { RedisOptions } from 'ioredis' -import { system } from '../helper/system/system' -import { SystemProp } from '../helper/system/system-prop' +import { system, SystemProp } from 'server-shared' const url = system.get(SystemProp.REDIS_URL) const username = system.get(SystemProp.REDIS_USER) @@ -37,8 +36,8 @@ export const createRedisClient = (params?: CreateRedisClientParams): Redis => { type CreateRedisClientParams = { /** - * connection timeout in milliseconds - */ + * connection timeout in milliseconds + */ connectTimeout?: number maxRetriesPerRequest?: number } diff --git a/packages/backend/src/app/database/seeds/dev-seeds.ts b/packages/server/api/src/app/database/seeds/dev-seeds.ts similarity index 89% rename from packages/backend/src/app/database/seeds/dev-seeds.ts rename to packages/server/api/src/app/database/seeds/dev-seeds.ts index cd0e9a967b..4ad46789a8 100644 --- a/packages/backend/src/app/database/seeds/dev-seeds.ts +++ b/packages/server/api/src/app/database/seeds/dev-seeds.ts @@ -1,8 +1,7 @@ import { ApEnvironment } from '@activepieces/shared' import { authenticationService } from '../../authentication/authentication-service' -import { logger } from '../../helper/logger' -import { system } from '../../helper/system/system' -import { SystemProp } from '../../helper/system/system-prop' +import { logger } from 'server-shared' +import { SystemProp, system } from 'server-shared' import { userService } from '../../user/user-service' import { Provider } from '../../authentication/authentication-service/hooks/authentication-service-hooks' @@ -32,7 +31,6 @@ const seedDevUser = async (): Promise => { } export const seedDevData = async (): Promise => { - const env = system.get(SystemProp.ENVIRONMENT) if (env !== ApEnvironment.DEVELOPMENT) { diff --git a/packages/backend/src/app/database/sqlite-connection.ts b/packages/server/api/src/app/database/sqlite-connection.ts similarity index 98% rename from packages/backend/src/app/database/sqlite-connection.ts rename to packages/server/api/src/app/database/sqlite-connection.ts index dfe47c2a74..580ee6d544 100644 --- a/packages/backend/src/app/database/sqlite-connection.ts +++ b/packages/server/api/src/app/database/sqlite-connection.ts @@ -11,8 +11,7 @@ import { ApEdition, ApEnvironment } from '@activepieces/shared' import { getEdition } from '../helper/secret-helper' import { AddPieceTypeAndPackageTypeToPieceMetadata1696016228398 } from './migration/sqlite/1696016228398-add-piece-type-and-package-type-to-piece-metadata' import { AddArchiveIdToPieceMetadata1696956123632 } from './migration/sqlite/1696956123632-add-archive-id-to-piece-metadata' -import { system } from '../helper/system/system' -import { SystemProp } from '../helper/system/system-prop' +import { system, SystemProp } from 'server-shared' import { StoreCodeInsideFlow1697969398200 } from './migration/common/1697969398200-store-code-inside-flow' import { AddPlatformToProject1698078715730 } from './migration/sqlite/1698078715730-add-platform-to-project' import { AddExternalIdSqlite1698857968495 } from './migration/sqlite/1698857968495-AddExternalIdSqlite' diff --git a/packages/backend/src/app/ee/api-keys/api-key-entity.ts b/packages/server/api/src/app/ee/api-keys/api-key-entity.ts similarity index 90% rename from packages/backend/src/app/ee/api-keys/api-key-entity.ts rename to packages/server/api/src/app/ee/api-keys/api-key-entity.ts index 2a0caedf4b..d460bcca74 100644 --- a/packages/backend/src/app/ee/api-keys/api-key-entity.ts +++ b/packages/server/api/src/app/ee/api-keys/api-key-entity.ts @@ -1,6 +1,9 @@ import { Platform, ApiKey } from '@activepieces/ee-shared' import { EntitySchema } from 'typeorm' -import { ApIdSchema, BaseColumnSchemaPart } from '../../database/database-common' +import { + ApIdSchema, + BaseColumnSchemaPart, +} from '../../database/database-common' type ApiKeySchema = ApiKey & { platform: Platform @@ -27,8 +30,7 @@ export const ApiKeyEntity = new EntitySchema({ nullable: false, }, }, - indices: [ - ], + indices: [], relations: { platform: { type: 'many-to-one', diff --git a/packages/backend/src/app/ee/api-keys/api-key-module.ts b/packages/server/api/src/app/ee/api-keys/api-key-module.ts similarity index 91% rename from packages/backend/src/app/ee/api-keys/api-key-module.ts rename to packages/server/api/src/app/ee/api-keys/api-key-module.ts index ba0985c9ab..acd0795be7 100644 --- a/packages/backend/src/app/ee/api-keys/api-key-module.ts +++ b/packages/server/api/src/app/ee/api-keys/api-key-module.ts @@ -1,8 +1,14 @@ -import { FastifyPluginAsyncTypebox, Type } from '@fastify/type-provider-typebox' +import { + FastifyPluginAsyncTypebox, + Type, +} from '@fastify/type-provider-typebox' import { platformMustBeOwnedByCurrentUser } from '../authentication/ee-authorization' import { ApId, SeekPage, assertNotNullOrUndefined } from '@activepieces/shared' import { apiKeyService } from './api-key-service' -import { ApiKeyResponseWithoutValue, CreateApiKeyRequest } from '@activepieces/ee-shared' +import { + ApiKeyResponseWithoutValue, + CreateApiKeyRequest, +} from '@activepieces/ee-shared' import { StatusCodes } from 'http-status-codes' import { ApiKeyResponseWithValue } from '@activepieces/ee-shared' @@ -11,7 +17,6 @@ export const apiKeyModule: FastifyPluginAsyncTypebox = async (app) => { await app.register(apiKeyController, { prefix: '/v1/api-keys' }) } - export const apiKeyController: FastifyPluginAsyncTypebox = async (app) => { app.post('/', CreateRequest, async (req, res) => { const platformId = req.principal.platform?.id @@ -44,7 +49,6 @@ export const apiKeyController: FastifyPluginAsyncTypebox = async (app) => { }) } - const ListRequest = { schema: { response: { diff --git a/packages/backend/src/app/ee/api-keys/api-key-service.ts b/packages/server/api/src/app/ee/api-keys/api-key-service.ts similarity index 85% rename from packages/backend/src/app/ee/api-keys/api-key-service.ts rename to packages/server/api/src/app/ee/api-keys/api-key-service.ts index feeee35a4c..400c51d184 100644 --- a/packages/backend/src/app/ee/api-keys/api-key-service.ts +++ b/packages/server/api/src/app/ee/api-keys/api-key-service.ts @@ -1,5 +1,17 @@ -import { PlatformId, ApiKeyResponseWithValue, ApiKey } from '@activepieces/ee-shared' -import { ActivepiecesError, ErrorCode, SeekPage, apId, assertNotNullOrUndefined, isNil, secureApId } from '@activepieces/shared' +import { + PlatformId, + ApiKeyResponseWithValue, + ApiKey, +} from '@activepieces/ee-shared' +import { + ActivepiecesError, + ErrorCode, + SeekPage, + apId, + assertNotNullOrUndefined, + isNil, + secureApId, +} from '@activepieces/shared' import { databaseConnection } from '../../database/database-connection' import { ApiKeyEntity } from './api-key-entity' import { hashSHA256 } from '../../helper/crypto' @@ -8,7 +20,10 @@ const API_KEY_TOKEN_LENGTH = 64 const repo = databaseConnection.getRepository(ApiKeyEntity) export const apiKeyService = { - async add({ platformId, displayName }: AddParams): Promise { + async add({ + platformId, + displayName, + }: AddParams): Promise { const generatedApiKey = generateApiKey() const savedApiKey = await repo.save({ id: apId(), @@ -59,7 +74,6 @@ export const apiKeyService = { }, } - export function generateApiKey() { const secretValue = secureApId(API_KEY_TOKEN_LENGTH - 3) const secretKey = `sk-${secretValue}` @@ -70,7 +84,6 @@ export function generateApiKey() { } } - type AddParams = { platformId: PlatformId displayName: string diff --git a/packages/backend/src/app/ee/app-connections/cloud-app-connection-service.ts b/packages/server/api/src/app/ee/app-connections/cloud-app-connection-service.ts similarity index 94% rename from packages/backend/src/app/ee/app-connections/cloud-app-connection-service.ts rename to packages/server/api/src/app/ee/app-connections/cloud-app-connection-service.ts index 14f3d8499e..8c06e5d839 100644 --- a/packages/backend/src/app/ee/app-connections/cloud-app-connection-service.ts +++ b/packages/server/api/src/app/ee/app-connections/cloud-app-connection-service.ts @@ -1,4 +1,4 @@ -import { logger } from '../../helper/logger' +import { logger } from 'server-shared' import { acquireLock } from '../../helper/lock' import { AppConnectionHooks } from '../../app-connection/app-connection-service/app-connection-hooks' import { connectionsLimits } from '../billing/limits/connections-limits' diff --git a/packages/backend/src/app/ee/app-connections/platform-oauth2-service.ts b/packages/server/api/src/app/ee/app-connections/platform-oauth2-service.ts similarity index 68% rename from packages/backend/src/app/ee/app-connections/platform-oauth2-service.ts rename to packages/server/api/src/app/ee/app-connections/platform-oauth2-service.ts index 4feecc8668..f3a9430af8 100644 --- a/packages/backend/src/app/ee/app-connections/platform-oauth2-service.ts +++ b/packages/server/api/src/app/ee/app-connections/platform-oauth2-service.ts @@ -1,28 +1,42 @@ -import { AppConnectionType, PlatformOAuth2ConnectionValue, assertNotNullOrUndefined, isNil } from '@activepieces/shared' +import { + AppConnectionType, + PlatformOAuth2ConnectionValue, + assertNotNullOrUndefined, + isNil, +} from '@activepieces/shared' import { PropertyType } from '@activepieces/pieces-framework' import { pieceMetadataService } from '../../pieces/piece-metadata-service' import { oauthAppService } from '../oauth-apps/oauth-app.service' -import { ClaimOAuth2Request, OAuth2Service, RefreshOAuth2Request } from '../../app-connection/app-connection-service/oauth2/oauth2-service' +import { + ClaimOAuth2Request, + OAuth2Service, + RefreshOAuth2Request, +} from '../../app-connection/app-connection-service/oauth2/oauth2-service' import { credentialsOauth2Service } from '../../app-connection/app-connection-service/oauth2/services/credentials-oauth2-service' import { projectService } from '../../project/project-service' import { OAuthAppWithSecret } from '../oauth-apps/oauth-app.entity' -export const platformOAuth2Service: OAuth2Service = { - claim, - refresh, -} +export const platformOAuth2Service: OAuth2Service = + { + claim, + refresh, + } -async function refresh({ pieceName, projectId, connectionValue }: RefreshOAuth2Request): Promise { +async function refresh({ + pieceName, + projectId, + connectionValue, +}: RefreshOAuth2Request): Promise { const oauth2App = await getApp({ pieceName, clientId: connectionValue.client_id, projectId, }) - const newValue = await credentialsOauth2Service.refresh({ + const newValue = await credentialsOauth2Service.refresh({ pieceName, projectId, connectionValue: { - ...connectionValue, + ...connectionValue, type: AppConnectionType.OAUTH2, client_secret: oauth2App.clientSecret, }, @@ -44,18 +58,23 @@ async function refresh({ pieceName, projectId, connectionValue }: RefreshOAuth2R } } - -async function claim( - { request, projectId, pieceName }: ClaimOAuth2Request, -): Promise { - +async function claim({ + request, + projectId, + pieceName, +}: ClaimOAuth2Request): Promise { const { auth } = await pieceMetadataService.getOrThrow({ name: pieceName, version: undefined, projectId, }) if (isNil(auth) || auth.type !== PropertyType.OAUTH2) { - throw new Error('Cannot claim auth for non oauth2 property ' + auth?.type + ' ' + pieceName) + throw new Error( + 'Cannot claim auth for non oauth2 property ' + + auth?.type + + ' ' + + pieceName, + ) } const oauth2App = await getApp({ pieceName, @@ -78,7 +97,15 @@ async function claim( } } -async function getApp({ pieceName, clientId, projectId }: { clientId: string, pieceName: string, projectId: string }): Promise { +async function getApp({ + pieceName, + clientId, + projectId, +}: { + clientId: string + pieceName: string + projectId: string +}): Promise { const project = await projectService.getOne(projectId) const platformId = project?.platformId assertNotNullOrUndefined(platformId, 'Platform id is not defined') @@ -87,5 +114,4 @@ async function getApp({ pieceName, clientId, projectId }: { clientId: string, pi clientId, platformId, }) - } diff --git a/packages/backend/src/app/ee/app-credentials/app-credentials.entity.ts b/packages/server/api/src/app/ee/app-credentials/app-credentials.entity.ts similarity index 86% rename from packages/backend/src/app/ee/app-credentials/app-credentials.entity.ts rename to packages/server/api/src/app/ee/app-credentials/app-credentials.entity.ts index dcb27c5f42..f4cfcc1b35 100644 --- a/packages/backend/src/app/ee/app-credentials/app-credentials.entity.ts +++ b/packages/server/api/src/app/ee/app-credentials/app-credentials.entity.ts @@ -1,7 +1,11 @@ import { EntitySchema } from 'typeorm' import { AppCredential } from '@activepieces/ee-shared' import { Project } from '@activepieces/shared' -import { ApIdSchema, BaseColumnSchemaPart, JSONB_COLUMN_TYPE } from '../../database/database-common' +import { + ApIdSchema, + BaseColumnSchemaPart, + JSONB_COLUMN_TYPE, +} from '../../database/database-common' export type AppCredentialSchema = { project: Project[] diff --git a/packages/backend/src/app/ee/app-credentials/app-credentials.module.ts b/packages/server/api/src/app/ee/app-credentials/app-credentials.module.ts similarity index 60% rename from packages/backend/src/app/ee/app-credentials/app-credentials.module.ts rename to packages/server/api/src/app/ee/app-credentials/app-credentials.module.ts index 46b29d4f62..63bd38e77f 100644 --- a/packages/backend/src/app/ee/app-credentials/app-credentials.module.ts +++ b/packages/server/api/src/app/ee/app-credentials/app-credentials.module.ts @@ -2,31 +2,48 @@ import { FastifyRequest } from 'fastify' import { StatusCodes } from 'http-status-codes' import { ALL_PRINICPAL_TYPES, SeekPage } from '@activepieces/shared' import { appCredentialService } from './app-credentials.service' -import { ListAppCredentialsRequest, UpsertAppCredentialRequest, AppCredential, AppCredentialId, AppCredentialType } from '@activepieces/ee-shared' +import { + ListAppCredentialsRequest, + UpsertAppCredentialRequest, + AppCredential, + AppCredentialId, + AppCredentialType, +} from '@activepieces/ee-shared' import { FastifyPluginAsyncTypebox } from '@fastify/type-provider-typebox' export const appCredentialModule: FastifyPluginAsyncTypebox = async (app) => { - await app.register(appCredentialController, { prefix: '/v1/app-credentials' }) + await app.register(appCredentialController, { + prefix: '/v1/app-credentials', + }) } const DEFAULT_LIMIT_SIZE = 10 const appCredentialController: FastifyPluginAsyncTypebox = async (fastify) => { - - fastify.get('/', { - config: { - allowedPrincipals: ALL_PRINICPAL_TYPES, + fastify.get( + '/', + { + config: { + allowedPrincipals: ALL_PRINICPAL_TYPES, + }, + schema: { + querystring: ListAppCredentialsRequest, + }, }, - schema: { - querystring: ListAppCredentialsRequest, + async ( + request: FastifyRequest<{ + Querystring: ListAppCredentialsRequest + }>, + ) => { + const page = await appCredentialService.list( + request.query.projectId, + request.query.appName, + request.query.cursor ?? null, + request.query.limit ?? DEFAULT_LIMIT_SIZE, + ) + return censorClientSecret(page) }, - }, async (request: FastifyRequest< - { - Querystring: ListAppCredentialsRequest - }>) => { - const page = await appCredentialService.list(request.query.projectId, request.query.appName, request.query.cursor ?? null, request.query.limit ?? DEFAULT_LIMIT_SIZE) - return censorClientSecret(page) - }) + ) fastify.post( '/', @@ -65,11 +82,12 @@ const appCredentialController: FastifyPluginAsyncTypebox = async (fastify) => { return reply.status(StatusCodes.OK).send() }, ) - } -function censorClientSecret(page: SeekPage): SeekPage { - page.data = page.data.map(f => { +function censorClientSecret( + page: SeekPage, +): SeekPage { + page.data = page.data.map((f) => { if (f.settings.type === AppCredentialType.OAUTH2) { f.settings.clientSecret = undefined } diff --git a/packages/backend/src/app/ee/app-credentials/app-credentials.service.ts b/packages/server/api/src/app/ee/app-credentials/app-credentials.service.ts similarity index 63% rename from packages/backend/src/app/ee/app-credentials/app-credentials.service.ts rename to packages/server/api/src/app/ee/app-credentials/app-credentials.service.ts index bb57464faf..a5fa98538d 100644 --- a/packages/backend/src/app/ee/app-credentials/app-credentials.service.ts +++ b/packages/server/api/src/app/ee/app-credentials/app-credentials.service.ts @@ -1,15 +1,24 @@ import { apId, Cursor, ProjectId, SeekPage } from '@activepieces/shared' import { AppCredentialEntity } from './app-credentials.entity' -import { AppCredential, AppCredentialId, UpsertAppCredentialRequest } from '@activepieces/ee-shared' +import { + AppCredential, + AppCredentialId, + UpsertAppCredentialRequest, +} from '@activepieces/ee-shared' import { databaseConnection } from '../../database/database-connection' import { paginationHelper } from '../../helper/pagination/pagination-utils' import { buildPaginator } from '../../helper/pagination/build-paginator' - -export const appCredentialRepo = databaseConnection.getRepository(AppCredentialEntity) +export const appCredentialRepo = + databaseConnection.getRepository(AppCredentialEntity) export const appCredentialService = { - async list(projectId: ProjectId, appName: string | undefined, cursorRequest: Cursor | null, limit: number): Promise> { + async list( + projectId: ProjectId, + appName: string | undefined, + cursorRequest: Cursor | null, + limit: number, + ): Promise> { const decodedCursor = paginationHelper.decodeCursor(cursorRequest ?? null) const paginator = buildPaginator({ entity: AppCredentialEntity, @@ -20,7 +29,9 @@ export const appCredentialService = { beforeCursor: decodedCursor.previousCursor, }, }) - let queryBuilder = appCredentialRepo.createQueryBuilder('app_credential').where({ projectId }) + let queryBuilder = appCredentialRepo + .createQueryBuilder('app_credential') + .where({ projectId }) if (appName !== undefined) { queryBuilder = queryBuilder.where({ appName }) } @@ -30,13 +41,22 @@ export const appCredentialService = { async getOneOrThrow(id: AppCredentialId): Promise { return appCredentialRepo.findOneByOrFail({ id }) }, - async upsert({ projectId, request }: { projectId: ProjectId, request: UpsertAppCredentialRequest }): Promise { + async upsert({ + projectId, + request, + }: { + projectId: ProjectId + request: UpsertAppCredentialRequest + }): Promise { const newId = request.id ?? apId() - await appCredentialRepo.upsert({ - id: newId, - projectId, - ...request, - }, ['id']) + await appCredentialRepo.upsert( + { + id: newId, + projectId, + ...request, + }, + ['id'], + ) return appCredentialRepo.findOneBy({ projectId, appName: request.appName }) }, async delete({ id, projectId }: DeleteParams): Promise { diff --git a/packages/backend/src/app/ee/appsumo/appsumo.entity.ts b/packages/server/api/src/app/ee/appsumo/appsumo.entity.ts similarity index 90% rename from packages/backend/src/app/ee/appsumo/appsumo.entity.ts rename to packages/server/api/src/app/ee/appsumo/appsumo.entity.ts index 1fae231039..bb8e028d82 100644 --- a/packages/backend/src/app/ee/appsumo/appsumo.entity.ts +++ b/packages/server/api/src/app/ee/appsumo/appsumo.entity.ts @@ -20,8 +20,6 @@ export const AppSumoEntity = new EntitySchema({ type: String, }, }, - indices: [ - ], - relations: { - }, -}) \ No newline at end of file + indices: [], + relations: {}, +}) diff --git a/packages/backend/src/app/ee/appsumo/appsumo.module.ts b/packages/server/api/src/app/ee/appsumo/appsumo.module.ts similarity index 88% rename from packages/backend/src/app/ee/appsumo/appsumo.module.ts rename to packages/server/api/src/app/ee/appsumo/appsumo.module.ts index e8caf525de..9fd746013a 100644 --- a/packages/backend/src/app/ee/appsumo/appsumo.module.ts +++ b/packages/server/api/src/app/ee/appsumo/appsumo.module.ts @@ -5,8 +5,7 @@ import { projectService } from '../../project/project-service' import { StatusCodes } from 'http-status-codes' import { isNil } from 'lodash' import { appsumoService } from './appsumo.service' -import { system } from '../../helper/system/system' -import { SystemProp } from '../../helper/system/system-prop' +import { SystemProp, system } from 'server-shared' import { FastifyPluginAsyncTypebox } from '@fastify/type-provider-typebox' import { plansService } from '../billing/project-plan/project-plan.service' import { defaultPlanInformation } from '../billing/project-plan/pricing-plans' @@ -40,7 +39,9 @@ const AuthorizationHeaders = Type.Object({ }) type AuthorizationHeaders = Static -const appsumoController: FastifyPluginAsyncTypebox = async (fastify: FastifyInstance) => { +const appsumoController: FastifyPluginAsyncTypebox = async ( + fastify: FastifyInstance, +) => { fastify.post( '/token', { @@ -59,7 +60,7 @@ const appsumoController: FastifyPluginAsyncTypebox = async (fastify: FastifyInst ) => { if ( request.body.username === exchangeCredentialUsername && - request.body.password === exchangeCredentialPassword + request.body.password === exchangeCredentialPassword ) { return reply.status(StatusCodes.OK).send({ access: token, @@ -95,14 +96,15 @@ const appsumoController: FastifyPluginAsyncTypebox = async (fastify: FastifyInst else { const { plan_id, action, uuid } = request.body const appSumoLicense = await appsumoService.getById(uuid) - const activation_email = appSumoLicense?.activation_email ?? request.body.activation_email + const activation_email = + appSumoLicense?.activation_email ?? request.body.activation_email const appSumoPlan = appsumoService.getPlanInformation(plan_id) const user = await userService.getByPlatformAndEmail({ platformId: system.getOrThrow(SystemProp.CLOUD_PLATFORM_ID), email: activation_email, }) if (!isNil(user)) { - const project = (await projectService.getUserProjectOrThrow(user.id)) + const project = await projectService.getUserProjectOrThrow(user.id) if (action === 'refund') { await plansService.update({ projectId: project.id, @@ -136,8 +138,8 @@ const appsumoController: FastifyPluginAsyncTypebox = async (fastify: FastifyInst case 'activate': return reply.status(StatusCodes.CREATED).send({ redirect_url: - 'https://cloud.activepieces.com/sign-up?email=' + - encodeURIComponent(activation_email), + 'https://cloud.activepieces.com/sign-up?email=' + + encodeURIComponent(activation_email), message: 'success', }) default: diff --git a/packages/backend/src/app/ee/appsumo/appsumo.service.ts b/packages/server/api/src/app/ee/appsumo/appsumo.service.ts similarity index 92% rename from packages/backend/src/app/ee/appsumo/appsumo.service.ts rename to packages/server/api/src/app/ee/appsumo/appsumo.service.ts index 281335eba0..2d4b13b860 100644 --- a/packages/backend/src/app/ee/appsumo/appsumo.service.ts +++ b/packages/server/api/src/app/ee/appsumo/appsumo.service.ts @@ -2,39 +2,38 @@ import { databaseConnection } from '../../database/database-connection' import { FlowPlanLimits } from '../billing/project-plan/pricing-plans' import { AppSumoEntity, AppSumoPlan } from './appsumo.entity' - const appsumoRepo = databaseConnection.getRepository(AppSumoEntity) const appSumoPlans: Record = { - 'activepieces_tier1': { + activepieces_tier1: { nickname: 'appsumo_activepieces_tier1', tasks: 10000, minimumPollingInterval: 10, connections: 100, teamMembers: 1, }, - 'activepieces_tier2': { + activepieces_tier2: { nickname: 'appsumo_activepieces_tier2', tasks: 50000, minimumPollingInterval: 5, connections: 100, teamMembers: 1, }, - 'activepieces_tier3': { + activepieces_tier3: { nickname: 'appsumo_activepieces_tier3', tasks: 200000, minimumPollingInterval: 1, connections: 100, teamMembers: 5, }, - 'activepieces_tier4': { + activepieces_tier4: { nickname: 'appsumo_activepieces_tier4', tasks: 500000, minimumPollingInterval: 1, connections: 100, teamMembers: 5, }, - 'activepieces_tier5': { + activepieces_tier5: { nickname: 'appsumo_activepieces_tier5', tasks: 1000000, minimumPollingInterval: 1, @@ -65,4 +64,4 @@ export const appsumoService = { upsert(plan: AppSumoPlan) { return appsumoRepo.upsert(plan, ['uuid']) }, -} \ No newline at end of file +} diff --git a/packages/backend/src/app/ee/audit-logs/audit-event-entity.ts b/packages/server/api/src/app/ee/audit-logs/audit-event-entity.ts similarity index 99% rename from packages/backend/src/app/ee/audit-logs/audit-event-entity.ts rename to packages/server/api/src/app/ee/audit-logs/audit-event-entity.ts index 2e22fdbcc5..28507bdbef 100644 --- a/packages/backend/src/app/ee/audit-logs/audit-event-entity.ts +++ b/packages/server/api/src/app/ee/audit-logs/audit-event-entity.ts @@ -57,4 +57,4 @@ export const AuditEventEntity = new EntitySchema({ }, }, }, -}) \ No newline at end of file +}) diff --git a/packages/backend/src/app/ee/audit-logs/audit-event-module.ts b/packages/server/api/src/app/ee/audit-logs/audit-event-module.ts similarity index 63% rename from packages/backend/src/app/ee/audit-logs/audit-event-module.ts rename to packages/server/api/src/app/ee/audit-logs/audit-event-module.ts index aea327a11a..4cfd363790 100644 --- a/packages/backend/src/app/ee/audit-logs/audit-event-module.ts +++ b/packages/server/api/src/app/ee/audit-logs/audit-event-module.ts @@ -1,6 +1,10 @@ import { FastifyPluginAsyncTypebox } from '@fastify/type-provider-typebox' import { platformMustBeOwnedByCurrentUser } from '../authentication/ee-authorization' -import { ActivepiecesError, ErrorCode, assertNotNullOrUndefined } from '@activepieces/shared' +import { + ActivepiecesError, + ErrorCode, + assertNotNullOrUndefined, +} from '@activepieces/shared' import { auditLogService } from './audit-event-service' import { ListAuditEventsRequest } from '@activepieces/ee-shared' import { platformService } from '../platform/platform.service' @@ -11,22 +15,24 @@ export const auditEventModule: FastifyPluginAsyncTypebox = async (app) => { } const auditEventController: FastifyPluginAsyncTypebox = async (app) => { - - app.get('/', { - schema: { - querystring: ListAuditEventsRequest, + app.get( + '/', + { + schema: { + querystring: ListAuditEventsRequest, + }, }, - }, async (request) => { - const platformId = request.principal.platform?.id - assertNotNullOrUndefined(platformId, 'platformId') - await assertAuditLogEnabled(platformId) - return auditLogService.list({ - platformId, - cursorRequest: request.query.cursor ?? null, - limit: request.query.limit ?? 20, - }) - }) - + async (request) => { + const platformId = request.principal.platform?.id + assertNotNullOrUndefined(platformId, 'platformId') + await assertAuditLogEnabled(platformId) + return auditLogService.list({ + platformId, + cursorRequest: request.query.cursor ?? null, + limit: request.query.limit ?? 20, + }) + }, + ) } async function assertAuditLogEnabled(platformId: string): Promise { diff --git a/packages/backend/src/app/ee/audit-logs/audit-event-service.ts b/packages/server/api/src/app/ee/audit-logs/audit-event-service.ts similarity index 74% rename from packages/backend/src/app/ee/audit-logs/audit-event-service.ts rename to packages/server/api/src/app/ee/audit-logs/audit-event-service.ts index 6b34ea2b36..fdc83f716d 100644 --- a/packages/backend/src/app/ee/audit-logs/audit-event-service.ts +++ b/packages/server/api/src/app/ee/audit-logs/audit-event-service.ts @@ -1,29 +1,54 @@ import { databaseConnection } from '../../database/database-connection' import { AuditEventEntity } from './audit-event-entity' -import { Cursor, PrincipalType, SeekPage, apId, assertNotNullOrUndefined, isNil } from '@activepieces/shared' +import { + Cursor, + PrincipalType, + SeekPage, + apId, + assertNotNullOrUndefined, + isNil, +} from '@activepieces/shared' import { PlatformId } from '@activepieces/ee-shared' import { buildPaginator } from '../../helper/pagination/build-paginator' import { paginationHelper } from '../../helper/pagination/pagination-utils' -import { ApplicationEventHooks, CreateAuditEventParam } from '../../helper/audit-events' -import { ApplicationEvent, ApplicationEventName } from '@activepieces/ee-shared' +import { + ApplicationEventHooks, + CreateAuditEventParam, +} from '../../helper/application-events' +import { + ApplicationEvent, + ApplicationEventName, +} from '@activepieces/ee-shared' import { userService } from '../../user/user-service' import { projectService } from '../../project/project-service' -import { rejectedPromiseHandler } from '../../helper/promise-handler' import { FastifyRequest } from 'fastify' import { extractClientRealIp } from '../../helper/network-utils' +import { rejectedPromiseHandler } from 'server-shared' const auditLogRepo = databaseConnection.getRepository(AuditEventEntity) type AuditLogService = { send: ApplicationEventHooks['send'] - list: (params: { platformId: PlatformId, cursorRequest: Cursor | null, limit: number }) => Promise> + list: (params: { + platformId: PlatformId + cursorRequest: Cursor | null + limit: number + }) => Promise> } export const auditLogService: AuditLogService = { send(request, rawEvent) { rejectedPromiseHandler(saveEvent(request, rawEvent)) }, - async list({ platformId, cursorRequest, limit }: { platformId: PlatformId, cursorRequest: Cursor | null, limit: number }): Promise> { + async list({ + platformId, + cursorRequest, + limit, + }: { + platformId: PlatformId + cursorRequest: Cursor | null + limit: number + }): Promise> { const decodedCursor = paginationHelper.decodeCursor(cursorRequest) const paginator = buildPaginator({ entity: AuditEventEntity, @@ -34,14 +59,25 @@ export const auditLogService: AuditLogService = { beforeCursor: decodedCursor.previousCursor, }, }) - const paginationResponse = await paginator.paginate(auditLogRepo.createQueryBuilder('audit_event').where({ platformId })) - return paginationHelper.createPage(paginationResponse.data, paginationResponse.cursor) + const paginationResponse = await paginator.paginate( + auditLogRepo.createQueryBuilder('audit_event').where({ platformId }), + ) + return paginationHelper.createPage( + paginationResponse.data, + paginationResponse.cursor, + ) }, } - -const saveEvent = async (request: FastifyRequest, rawEvent: CreateAuditEventParam) => { - if (![PrincipalType.USER, PrincipalType.UNKNOWN].includes(request.principal.type)) { +const saveEvent = async ( + request: FastifyRequest, + rawEvent: CreateAuditEventParam, +) => { + if ( + ![PrincipalType.USER, PrincipalType.UNKNOWN].includes( + request.principal.type, + ) + ) { return } const userInformation = await userService.getMetaInfo({ @@ -79,7 +115,6 @@ const saveEvent = async (request: FastifyRequest, rawEvent: CreateAuditEventPara } case ApplicationEventName.CREATED_FLOW: case ApplicationEventName.DELETED_FLOW: { - eventToSave = { ...baseProps, action: rawEvent.action, @@ -92,7 +127,6 @@ const saveEvent = async (request: FastifyRequest, rawEvent: CreateAuditEventPara } case ApplicationEventName.UPSERTED_CONNECTION: case ApplicationEventName.DELETED_CONNECTION: { - eventToSave = { ...baseProps, action: rawEvent.action, @@ -106,7 +140,6 @@ const saveEvent = async (request: FastifyRequest, rawEvent: CreateAuditEventPara case ApplicationEventName.CREATED_FOLDER: case ApplicationEventName.UPDATED_FOLDER: case ApplicationEventName.DELETED_FOLDER: { - eventToSave = { ...baseProps, action: rawEvent.action, diff --git a/packages/backend/src/app/ee/authentication/authentication-service/hooks/authentication-helper.ts b/packages/server/api/src/app/ee/authentication/authentication-service/hooks/authentication-helper.ts similarity index 68% rename from packages/backend/src/app/ee/authentication/authentication-service/hooks/authentication-helper.ts rename to packages/server/api/src/app/ee/authentication/authentication-service/hooks/authentication-helper.ts index 34d277f5b3..94e021f1bc 100644 --- a/packages/backend/src/app/ee/authentication/authentication-service/hooks/authentication-helper.ts +++ b/packages/server/api/src/app/ee/authentication/authentication-service/hooks/authentication-helper.ts @@ -1,5 +1,18 @@ -import { Platform, PlatformId, ProjectMemberStatus } from '@activepieces/ee-shared' -import { PrincipalType, Project, isNil, User, ActivepiecesError, ErrorCode, ApEdition, PlatformRole } from '@activepieces/shared' +import { + Platform, + PlatformId, + ProjectMemberStatus, +} from '@activepieces/ee-shared' +import { + PrincipalType, + Project, + isNil, + User, + ActivepiecesError, + ErrorCode, + ApEdition, + PlatformRole, +} from '@activepieces/shared' import { platformService } from '../../../platform/platform.service' import { accessTokenManager } from '../../../../authentication/lib/access-token-manager' import { projectMemberService } from '../../../project-members/project-member.service' @@ -27,7 +40,6 @@ async function getProjectForUserOrThrow(user: User): Promise { return invitedProject } - const getProjectMemberOrThrow = async (user: User): Promise => { const platformProjects = await projectMemberService.listByUser(user) @@ -38,23 +50,33 @@ const getProjectMemberOrThrow = async (user: User): Promise => { return projectService.getOneOrThrow(platformProjects[0].projectId) } -const populateTokenWithPlatformInfo = async ({ user, project }: PopulateTokenWithPlatformInfoParams): Promise => { +const populateTokenWithPlatformInfo = async ({ + user, + project, +}: PopulateTokenWithPlatformInfoParams): Promise => { const platform = await getPlatform(user.platformId) const updatedToken = await accessTokenManager.generateToken({ id: user.id, type: PrincipalType.USER, projectId: project.id, projectType: project.type, - platform: isNil(platform) ? undefined : { - id: platform.id, - role: platform.ownerId === user.id ? PlatformRole.OWNER : PlatformRole.MEMBER, - }, + platform: isNil(platform) + ? undefined + : { + id: platform.id, + role: + platform.ownerId === user.id + ? PlatformRole.OWNER + : PlatformRole.MEMBER, + }, }) return updatedToken } -const getPlatform = async (platformId: PlatformId | null): Promise => { +const getPlatform = async ( + platformId: PlatformId | null, +): Promise => { if (isNil(platformId)) { return null } @@ -74,7 +96,9 @@ async function autoVerifyUserIfEligible(user: User): Promise { return } const projects = await projectMemberService.listByUser(user) - const activeInAnyProject = !isNil(projects.find(f => f.status === ProjectMemberStatus.ACTIVE)) + const activeInAnyProject = !isNil( + projects.find((f) => f.status === ProjectMemberStatus.ACTIVE), + ) if (activeInAnyProject) { await userService.verify({ id: user.id, @@ -83,7 +107,9 @@ async function autoVerifyUserIfEligible(user: User): Promise { } } -async function getProjectAndTokenOrThrow(user: User): Promise<{ project: Project, token: string }> { +async function getProjectAndTokenOrThrow( + user: User, +): Promise<{ project: Project, token: string }> { const project = await getProjectForUserOrThrow(user) return { project, @@ -91,7 +117,13 @@ async function getProjectAndTokenOrThrow(user: User): Promise<{ project: Project } } -async function isInvitedToProject({ email, platformId }: { email: string, platformId: string }): Promise { +async function isInvitedToProject({ + email, + platformId, +}: { + email: string + platformId: string +}): Promise { const platformProjects = await projectMemberService.listByUser({ email, platformId, @@ -99,7 +131,13 @@ async function isInvitedToProject({ email, platformId }: { email: string, platfo return platformProjects.length > 0 } -async function assertUserIsInvitedToAnyProject({ email, platformId }: { email: string, platformId: string }): Promise { +async function assertUserIsInvitedToAnyProject({ + email, + platformId, +}: { + email: string + platformId: string +}): Promise { const isInvited = await isInvitedToProject({ email, platformId }) if (!isInvited) { throw new ActivepiecesError({ @@ -109,7 +147,13 @@ async function assertUserIsInvitedToAnyProject({ email, platformId }: { email: s } } -async function assertEmailAuthIsEnabled({ platformId, provider }: { platformId: string | null, provider: Provider }): Promise { +async function assertEmailAuthIsEnabled({ + platformId, + provider, +}: { + platformId: string | null + provider: Provider +}): Promise { if (isNil(platformId)) { return } @@ -128,7 +172,13 @@ async function assertEmailAuthIsEnabled({ platformId, provider }: { platformId: } } -async function assertDomainIsAllowed({ email, platformId }: { email: string, platformId: string | null }): Promise { +async function assertDomainIsAllowed({ + email, + platformId, +}: { + email: string + platformId: string | null +}): Promise { if (isNil(platformId)) { return } @@ -137,7 +187,9 @@ async function assertDomainIsAllowed({ email, platformId }: { email: string, pla return } const emailDomain = email.split('@')[1] - const isAllowedDomaiin = !platform.enforceAllowedAuthDomains || platform.allowedAuthDomains.includes(emailDomain) + const isAllowedDomaiin = + !platform.enforceAllowedAuthDomains || + platform.allowedAuthDomains.includes(emailDomain) if (!isAllowedDomaiin) { throw new ActivepiecesError({ @@ -149,9 +201,16 @@ async function assertDomainIsAllowed({ email, platformId }: { email: string, pla } } -async function assertUserIsInvitedAndDomainIsAllowed({ email, platformId }: { email: string, platformId: string | null }): Promise { +async function assertUserIsInvitedAndDomainIsAllowed({ + email, + platformId, +}: { + email: string + platformId: string | null +}): Promise { await assertDomainIsAllowed({ email, platformId }) - const customerPlatformEnabled = !isNil(platformId) && !flagService.isCloudPlatform(platformId) + const customerPlatformEnabled = + !isNil(platformId) && !flagService.isCloudPlatform(platformId) if (customerPlatformEnabled) { await assertUserIsInvitedToAnyProject({ email, platformId }) } @@ -164,5 +223,3 @@ export const authenticationHelper = { assertDomainIsAllowed, assertEmailAuthIsEnabled, } - - diff --git a/packages/backend/src/app/ee/authentication/authentication-service/hooks/cloud-authentication-service-hooks.ts b/packages/server/api/src/app/ee/authentication/authentication-service/hooks/cloud-authentication-service-hooks.ts similarity index 72% rename from packages/backend/src/app/ee/authentication/authentication-service/hooks/cloud-authentication-service-hooks.ts rename to packages/server/api/src/app/ee/authentication/authentication-service/hooks/cloud-authentication-service-hooks.ts index 6b28cffc09..3533fa796b 100644 --- a/packages/backend/src/app/ee/authentication/authentication-service/hooks/cloud-authentication-service-hooks.ts +++ b/packages/server/api/src/app/ee/authentication/authentication-service/hooks/cloud-authentication-service-hooks.ts @@ -1,6 +1,4 @@ -import { - AuthenticationServiceHooks, -} from '../../../../authentication/authentication-service/hooks/authentication-service-hooks' +import { AuthenticationServiceHooks } from '../../../../authentication/authentication-service/hooks/authentication-service-hooks' import { OtpType } from '@activepieces/ee-shared' import { otpService } from '../../../otp/otp-service' import { referralService } from '../../../referrals/referral.service' @@ -12,16 +10,27 @@ import { flagService } from '../../../../../app/flags/flag.service' export const cloudAuthenticationServiceHooks: AuthenticationServiceHooks = { async preSignIn({ email, platformId, provider }) { - await authenticationHelper.assertEmailAuthIsEnabled({ platformId, provider }) + await authenticationHelper.assertEmailAuthIsEnabled({ + platformId, + provider, + }) await authenticationHelper.assertDomainIsAllowed({ email, platformId }) }, async preSignUp({ email, platformId, provider }) { - await authenticationHelper.assertEmailAuthIsEnabled({ platformId, provider }) - await authenticationHelper.assertUserIsInvitedAndDomainIsAllowed({ email, platformId }) + await authenticationHelper.assertEmailAuthIsEnabled({ + platformId, + provider, + }) + await authenticationHelper.assertUserIsInvitedAndDomainIsAllowed({ + email, + platformId, + }) }, async postSignUp({ user, referringUserId }) { - - if (!isNil(user.platformId) && flagService.isCloudPlatform(user.platformId)) { + if ( + !isNil(user.platformId) && + flagService.isCloudPlatform(user.platformId) + ) { await projectService.create({ displayName: `${user.firstName}'s Project`, ownerId: user.id, @@ -39,7 +48,8 @@ export const cloudAuthenticationServiceHooks: AuthenticationServiceHooks = { await authenticationHelper.autoVerifyUserIfEligible(user) const updatedUser = await userService.getOneOrFail({ id: user.id }) - const { project, token } = await authenticationHelper.getProjectAndTokenOrThrow(user) + const { project, token } = + await authenticationHelper.getProjectAndTokenOrThrow(user) if (!updatedUser.verified) { await otpService.createAndSend({ @@ -56,7 +66,8 @@ export const cloudAuthenticationServiceHooks: AuthenticationServiceHooks = { }, async postSignIn({ user }) { - const { project, token } = await authenticationHelper.getProjectAndTokenOrThrow(user) + const { project, token } = + await authenticationHelper.getProjectAndTokenOrThrow(user) return { user, project, @@ -64,4 +75,3 @@ export const cloudAuthenticationServiceHooks: AuthenticationServiceHooks = { } }, } - diff --git a/packages/server/api/src/app/ee/authentication/authentication-service/hooks/enterprise-authentication-service-hooks.ts b/packages/server/api/src/app/ee/authentication/authentication-service/hooks/enterprise-authentication-service-hooks.ts new file mode 100644 index 0000000000..382fb54335 --- /dev/null +++ b/packages/server/api/src/app/ee/authentication/authentication-service/hooks/enterprise-authentication-service-hooks.ts @@ -0,0 +1,90 @@ +import { AuthenticationServiceHooks } from '../../../../authentication/authentication-service/hooks/authentication-service-hooks' +import { flagService } from '../../../../flags/flag.service' +import { ApFlagId, ProjectType } from '@activepieces/shared' +import { platformService } from '../../../platform/platform.service' +import { userService } from '../../../../user/user-service' +import { authenticationHelper } from './authentication-helper' +import { projectService } from '../../../../project/project-service' +import { enforceLimits } from '../../../helper/license-validator' + +const DEFAULT_PLATFORM_NAME = 'platform' + +export const enterpriseAuthenticationServiceHooks: AuthenticationServiceHooks = + { + async preSignIn({ email, platformId, provider }) { + await authenticationHelper.assertEmailAuthIsEnabled({ + platformId, + provider, + }) + await authenticationHelper.assertDomainIsAllowed({ email, platformId }) + }, + async preSignUp({ email, platformId, provider }) { + await authenticationHelper.assertEmailAuthIsEnabled({ + platformId, + provider, + }) + await authenticationHelper.assertUserIsInvitedAndDomainIsAllowed({ + email, + platformId, + }) + }, + async postSignUp({ user }) { + const platformCreated = await flagService.getOne( + ApFlagId.PLATFORM_CREATED, + ) + if (platformCreated?.value) { + const { project, token } = + await authenticationHelper.getProjectAndTokenOrThrow(user) + return { + user, + project, + token, + } + } + + const project = await projectService.create({ + displayName: `${user.firstName}'s Project`, + ownerId: user.id, + platformId: undefined, + type: ProjectType.STANDALONE, + }) + + const platform = await platformService.add({ + ownerId: user.id, + projectId: project.id, + name: DEFAULT_PLATFORM_NAME, + }) + + await userService.updatePlatformId({ + id: user.id, + platformId: platform.id, + }) + + await enforceLimits() + + await flagService.save({ + id: ApFlagId.PLATFORM_CREATED, + value: true, + }) + + await authenticationHelper.autoVerifyUserIfEligible(user) + const updatedUser = await userService.getOneOrFail({ id: user.id }) + const { project: updatedProject, token } = + await authenticationHelper.getProjectAndTokenOrThrow(updatedUser) + return { + user: updatedUser, + project: updatedProject, + token, + } + }, + + async postSignIn({ user }) { + const { project, token } = + await authenticationHelper.getProjectAndTokenOrThrow(user) + return { + user, + project, + token, + } + }, + } diff --git a/packages/server/api/src/app/ee/authentication/ee-authorization.ts b/packages/server/api/src/app/ee/authentication/ee-authorization.ts new file mode 100644 index 0000000000..2f1c6a8e86 --- /dev/null +++ b/packages/server/api/src/app/ee/authentication/ee-authorization.ts @@ -0,0 +1,27 @@ +import { + ActivepiecesError, + ErrorCode, + PlatformRole, + isNil, +} from '@activepieces/shared' +import { onRequestAsyncHookHandler } from 'fastify' + +const USER_NOT_ALLOWED_TO_PERFORM_OPERATION_ERROR = new ActivepiecesError({ + code: ErrorCode.AUTHORIZATION, + params: {}, +}) + +export const platformMustBeOwnedByCurrentUser: onRequestAsyncHookHandler = + async (request, _res) => { + const platformId = request.principal.platform?.id + + if (isNil(platformId)) { + throw USER_NOT_ALLOWED_TO_PERFORM_OPERATION_ERROR + } + + const canEditPlatform = + request.principal.platform?.role === PlatformRole.OWNER + if (!canEditPlatform) { + throw USER_NOT_ALLOWED_TO_PERFORM_OPERATION_ERROR + } + } diff --git a/packages/backend/src/app/ee/authentication/enterprise-local-authn/enterprise-local-authn-controller.ts b/packages/server/api/src/app/ee/authentication/enterprise-local-authn/enterprise-local-authn-controller.ts similarity index 87% rename from packages/backend/src/app/ee/authentication/enterprise-local-authn/enterprise-local-authn-controller.ts rename to packages/server/api/src/app/ee/authentication/enterprise-local-authn/enterprise-local-authn-controller.ts index 93525650be..e678fcf9b3 100644 --- a/packages/backend/src/app/ee/authentication/enterprise-local-authn/enterprise-local-authn-controller.ts +++ b/packages/server/api/src/app/ee/authentication/enterprise-local-authn/enterprise-local-authn-controller.ts @@ -1,11 +1,16 @@ import { FastifyPluginAsyncTypebox } from '@fastify/type-provider-typebox' import { enterpriseLocalAuthnService } from './enterprise-local-authn-service' -import { ResetPasswordRequestBody, VerifyEmailRequestBody } from '@activepieces/ee-shared' +import { + ResetPasswordRequestBody, + VerifyEmailRequestBody, +} from '@activepieces/ee-shared' import { ALL_PRINICPAL_TYPES } from '@activepieces/shared' -import { eventsHooks } from '../../../helper/audit-events' +import { eventsHooks } from '../../../helper/application-events' import { ApplicationEventName } from '@activepieces/ee-shared' -export const enterpriseLocalAuthnController: FastifyPluginAsyncTypebox = async (app) => { +export const enterpriseLocalAuthnController: FastifyPluginAsyncTypebox = async ( + app, +) => { app.post('/verify-email', VerifyEmailRequest, async (req) => { await enterpriseLocalAuthnService.verifyEmail(req.body) eventsHooks.get().send(req, { diff --git a/packages/backend/src/app/ee/authentication/enterprise-local-authn/enterprise-local-authn-module.ts b/packages/server/api/src/app/ee/authentication/enterprise-local-authn/enterprise-local-authn-module.ts similarity index 63% rename from packages/backend/src/app/ee/authentication/enterprise-local-authn/enterprise-local-authn-module.ts rename to packages/server/api/src/app/ee/authentication/enterprise-local-authn/enterprise-local-authn-module.ts index 5bfbb6c6ae..971d205198 100644 --- a/packages/backend/src/app/ee/authentication/enterprise-local-authn/enterprise-local-authn-module.ts +++ b/packages/server/api/src/app/ee/authentication/enterprise-local-authn/enterprise-local-authn-module.ts @@ -1,8 +1,10 @@ import { FastifyPluginAsyncTypebox } from '@fastify/type-provider-typebox' import { enterpriseLocalAuthnController } from './enterprise-local-authn-controller' - -export const enterpriseLocalAuthnModule: FastifyPluginAsyncTypebox = async (app) => { - await app.register(enterpriseLocalAuthnController, { prefix: '/v1/authn/local' }) +export const enterpriseLocalAuthnModule: FastifyPluginAsyncTypebox = async ( + app, +) => { + await app.register(enterpriseLocalAuthnController, { + prefix: '/v1/authn/local', + }) } - diff --git a/packages/backend/src/app/ee/authentication/enterprise-local-authn/enterprise-local-authn-service.ts b/packages/server/api/src/app/ee/authentication/enterprise-local-authn/enterprise-local-authn-service.ts similarity index 75% rename from packages/backend/src/app/ee/authentication/enterprise-local-authn/enterprise-local-authn-service.ts rename to packages/server/api/src/app/ee/authentication/enterprise-local-authn/enterprise-local-authn-service.ts index ff2ac51829..1ace90fe63 100644 --- a/packages/backend/src/app/ee/authentication/enterprise-local-authn/enterprise-local-authn-service.ts +++ b/packages/server/api/src/app/ee/authentication/enterprise-local-authn/enterprise-local-authn-service.ts @@ -1,5 +1,9 @@ import { UserId, ActivepiecesError, ErrorCode } from '@activepieces/shared' -import { OtpType, ResetPasswordRequestBody, VerifyEmailRequestBody } from '@activepieces/ee-shared' +import { + OtpType, + ResetPasswordRequestBody, + VerifyEmailRequestBody, +} from '@activepieces/ee-shared' import { userService } from '../../../user/user-service' import { otpService } from '../../otp/otp-service' @@ -14,7 +18,11 @@ export const enterpriseLocalAuthnService = { await userService.verify({ id: userId }) }, - async resetPassword({ userId, otp, newPassword }: ResetPasswordRequestBody): Promise { + async resetPassword({ + userId, + otp, + newPassword, + }: ResetPasswordRequestBody): Promise { await confirmOtp({ userId, otp, @@ -28,7 +36,11 @@ export const enterpriseLocalAuthnService = { }, } -const confirmOtp = async ({ userId, otp, otpType }: ConfirmOtpParams): Promise => { +const confirmOtp = async ({ + userId, + otp, + otpType, +}: ConfirmOtpParams): Promise => { const isOtpValid = await otpService.confirm({ userId, type: otpType, @@ -43,7 +55,6 @@ const confirmOtp = async ({ userId, otp, otpType }: ConfirmOtpParams): Promise Promise - authenticate: (hostname: string, platform: Platform, authorizationCode: string) => Promise + authenticate: ( + hostname: string, + platform: Platform, + authorizationCode: string + ) => Promise } - export const providers: Record = { [ThirdPartyAuthnProviderEnum.GOOGLE]: googleAuthnProvider, [ThirdPartyAuthnProviderEnum.GITHUB]: gitHubAuthnProvider, diff --git a/packages/backend/src/app/ee/authentication/federated-authn/authn-provider/github-authn-provider.ts b/packages/server/api/src/app/ee/authentication/federated-authn/authn-provider/github-authn-provider.ts similarity index 70% rename from packages/backend/src/app/ee/authentication/federated-authn/authn-provider/github-authn-provider.ts rename to packages/server/api/src/app/ee/authentication/federated-authn/authn-provider/github-authn-provider.ts index 0e058fe666..3999c04dfd 100644 --- a/packages/backend/src/app/ee/authentication/federated-authn/authn-provider/github-authn-provider.ts +++ b/packages/server/api/src/app/ee/authentication/federated-authn/authn-provider/github-authn-provider.ts @@ -1,14 +1,24 @@ -import { ActivepiecesError, AuthenticationResponse, ErrorCode, assertNotNullOrUndefined, isNil } from '@activepieces/shared' +import { + ActivepiecesError, + AuthenticationResponse, + ErrorCode, + assertNotNullOrUndefined, + isNil, +} from '@activepieces/shared' import { AuthnProvider } from './authn-provider' import { authenticationService } from '../../../../authentication/authentication-service' import { flagService } from '../../../../flags/flag.service' import { Platform } from '@activepieces/ee-shared' - - -function getClientIdAndSecret(platform: Platform): { clientId: string, clientSecret: string } { +function getClientIdAndSecret(platform: Platform): { + clientId: string + clientSecret: string +} { const clientInformation = platform.federatedAuthProviders.github - assertNotNullOrUndefined(clientInformation, 'Github information is not configured for this platform') + assertNotNullOrUndefined( + clientInformation, + 'Github information is not configured for this platform', + ) return { clientId: clientInformation.clientId, clientSecret: clientInformation.clientSecret, @@ -20,21 +30,40 @@ export const gitHubAuthnProvider: AuthnProvider = { const { clientId } = getClientIdAndSecret(platform) const loginUrl = new URL('https://github.com/login/oauth/authorize') loginUrl.searchParams.set('client_id', clientId) - loginUrl.searchParams.set('redirect_uri', flagService.getThirdPartyRedirectUrl(platform.id, hostname)) + loginUrl.searchParams.set( + 'redirect_uri', + flagService.getThirdPartyRedirectUrl(platform.id, hostname), + ) loginUrl.searchParams.set('scope', 'user:email') return loginUrl.href }, - async authenticate(hostname, platform, authorizationCode): Promise { + async authenticate( + hostname, + platform, + authorizationCode, + ): Promise { const { clientId, clientSecret } = getClientIdAndSecret(platform) - const githubAccessToken = await getGitHubAccessToken(platform, hostname, clientId, clientSecret, authorizationCode) + const githubAccessToken = await getGitHubAccessToken( + platform, + hostname, + clientId, + clientSecret, + authorizationCode, + ) const gitHubUserInfo = await getGitHubUserInfo(githubAccessToken) return authenticateUser(platform.id, gitHubUserInfo) }, } -const getGitHubAccessToken = async (platform: Platform, hostname: string, clientId: string, clientSecret: string, authorizationCode: string): Promise => { +const getGitHubAccessToken = async ( + platform: Platform, + hostname: string, + clientId: string, + clientSecret: string, + authorizationCode: string, +): Promise => { const response = await fetch('https://github.com/login/oauth/access_token', { method: 'POST', headers: { @@ -68,7 +97,9 @@ const getGitHubAccessToken = async (platform: Platform, hostname: string, client return accessToken } -const getGitHubUserInfo = async (gitHubAccessToken: string): Promise => { +const getGitHubUserInfo = async ( + gitHubAccessToken: string, +): Promise => { const response = await fetch('https://api.github.com/user', { headers: { Accept: 'application/vnd.github+json', @@ -90,7 +121,9 @@ const getGitHubUserInfo = async (gitHubAccessToken: string): Promise => { +const getGitHubUserEmail = async ( + gitHubAccessToken: string, +): Promise => { const response = await fetch('https://api.github.com/user/emails', { headers: { Accept: 'application/vnd.github+json', @@ -107,13 +140,16 @@ const getGitHubUserEmail = async (gitHubAccessToken: string): Promise => } const emails: { primary: boolean, email: string }[] = await response.json() - const email = emails.find(email => email.primary)?.email + const email = emails.find((email) => email.primary)?.email if (!email) { throw new Error('Can\'t find email for the github account') } return email } -const authenticateUser = async (platformId: string | null, gitHubUserInfo: GitHubUserInfo): Promise => { +const authenticateUser = async ( + platformId: string | null, + gitHubUserInfo: GitHubUserInfo, +): Promise => { return authenticationService.federatedAuthn({ email: gitHubUserInfo.email, verified: true, diff --git a/packages/backend/src/app/ee/authentication/federated-authn/authn-provider/google-authn-provider.ts b/packages/server/api/src/app/ee/authentication/federated-authn/authn-provider/google-authn-provider.ts similarity index 72% rename from packages/backend/src/app/ee/authentication/federated-authn/authn-provider/google-authn-provider.ts rename to packages/server/api/src/app/ee/authentication/federated-authn/authn-provider/google-authn-provider.ts index 363701d89f..b96d530f2a 100644 --- a/packages/backend/src/app/ee/authentication/federated-authn/authn-provider/google-authn-provider.ts +++ b/packages/server/api/src/app/ee/authentication/federated-authn/authn-provider/google-authn-provider.ts @@ -1,5 +1,8 @@ import jwksClient from 'jwks-rsa' -import { AuthenticationResponse, assertNotNullOrUndefined } from '@activepieces/shared' +import { + AuthenticationResponse, + assertNotNullOrUndefined, +} from '@activepieces/shared' import { AuthnProvider } from './authn-provider' import { authenticationService } from '../../../../authentication/authentication-service' import { jwtUtils, JwtSignAlgorithm } from '../../../../helper/jwt-utils' @@ -14,9 +17,15 @@ const keyLoader = jwksClient({ jwksUri: JWKS_URI, }) -function getClientIdAndSecret(platform: Platform): { clientId: string, clientSecret: string } { +function getClientIdAndSecret(platform: Platform): { + clientId: string + clientSecret: string +} { const clientInformation = platform.federatedAuthProviders.google - assertNotNullOrUndefined(clientInformation, 'Google information is not configured for this platform') + assertNotNullOrUndefined( + clientInformation, + 'Google information is not configured for this platform', + ) return { clientId: clientInformation.clientId, clientSecret: clientInformation.clientSecret, @@ -28,22 +37,41 @@ export const googleAuthnProvider: AuthnProvider = { const { clientId } = getClientIdAndSecret(platform) const loginUrl = new URL('https://accounts.google.com/o/oauth2/v2/auth') loginUrl.searchParams.set('client_id', clientId) - loginUrl.searchParams.set('redirect_uri', flagService.getThirdPartyRedirectUrl(platform.id, hostname)) + loginUrl.searchParams.set( + 'redirect_uri', + flagService.getThirdPartyRedirectUrl(platform.id, hostname), + ) loginUrl.searchParams.set('scope', 'email profile') loginUrl.searchParams.set('response_type', 'code') return loginUrl.href }, - async authenticate(hostname, platform, authorizationCode): Promise { + async authenticate( + hostname, + platform, + authorizationCode, + ): Promise { const { clientId, clientSecret } = getClientIdAndSecret(platform) - const idToken = await exchangeCodeForIdToken(platform.id, hostname, clientId, clientSecret, authorizationCode) + const idToken = await exchangeCodeForIdToken( + platform.id, + hostname, + clientId, + clientSecret, + authorizationCode, + ) const idTokenPayload = await verifyIdToken(clientId, idToken) return generateAuthenticationResponse(platform.id, idTokenPayload) }, } -const exchangeCodeForIdToken = async (platformId: string, hostName: string, clientId: string, clientSecret: string, code: string): Promise => { +const exchangeCodeForIdToken = async ( + platformId: string, + hostName: string, + clientId: string, + clientSecret: string, + code: string, +): Promise => { const response = await fetch('https://oauth2.googleapis.com/token', { method: 'POST', headers: { @@ -62,7 +90,10 @@ const exchangeCodeForIdToken = async (platformId: string, hostName: string, clie return idToken } -const verifyIdToken = async (clientId: string, idToken: string): Promise => { +const verifyIdToken = async ( + clientId: string, + idToken: string, +): Promise => { const { header } = jwtUtils.decode({ jwt: idToken }) const signingKey = await keyLoader.getSigningKey(header.kid) const publicKey = signingKey.getPublicKey() @@ -83,7 +114,10 @@ const verifyIdToken = async (clientId: string, idToken: string): Promise => { +const generateAuthenticationResponse = async ( + platformId: string | null, + idTokenPayload: IdTokenPayload, +): Promise => { return authenticationService.federatedAuthn({ email: idTokenPayload.email, verified: true, diff --git a/packages/backend/src/app/ee/authentication/federated-authn/federated-authn-controller.ts b/packages/server/api/src/app/ee/authentication/federated-authn/federated-authn-controller.ts similarity index 81% rename from packages/backend/src/app/ee/authentication/federated-authn/federated-authn-controller.ts rename to packages/server/api/src/app/ee/authentication/federated-authn/federated-authn-controller.ts index 65569b67e0..3b7fd2f4e7 100644 --- a/packages/backend/src/app/ee/authentication/federated-authn/federated-authn-controller.ts +++ b/packages/server/api/src/app/ee/authentication/federated-authn/federated-authn-controller.ts @@ -1,10 +1,21 @@ -import { FastifyPluginAsyncTypebox, Type } from '@fastify/type-provider-typebox' +import { + FastifyPluginAsyncTypebox, + Type, +} from '@fastify/type-provider-typebox' import { federatedAuthnService } from './federated-authn-service' -import { ClaimTokenRequest, ThirdPartyAuthnProviderEnum } from '@activepieces/ee-shared' -import { ALL_PRINICPAL_TYPES, assertNotNullOrUndefined } from '@activepieces/shared' +import { + ClaimTokenRequest, + ThirdPartyAuthnProviderEnum, +} from '@activepieces/ee-shared' +import { + ALL_PRINICPAL_TYPES, + assertNotNullOrUndefined, +} from '@activepieces/shared' import { resolvePlatformIdForRequest } from '../../platform/lib/platform-utils' -export const federatedAuthnController: FastifyPluginAsyncTypebox = async (app) => { +export const federatedAuthnController: FastifyPluginAsyncTypebox = async ( + app, +) => { app.get('/login', LoginRequestSchema, async (req) => { const platformId = await resolvePlatformIdForRequest(req) assertNotNullOrUndefined(platformId, 'Platform id is not defined') diff --git a/packages/backend/src/app/ee/authentication/federated-authn/federated-authn-module.ts b/packages/server/api/src/app/ee/authentication/federated-authn/federated-authn-module.ts similarity index 70% rename from packages/backend/src/app/ee/authentication/federated-authn/federated-authn-module.ts rename to packages/server/api/src/app/ee/authentication/federated-authn/federated-authn-module.ts index 43ebae8994..f2660ca2e0 100644 --- a/packages/backend/src/app/ee/authentication/federated-authn/federated-authn-module.ts +++ b/packages/server/api/src/app/ee/authentication/federated-authn/federated-authn-module.ts @@ -2,5 +2,7 @@ import { FastifyPluginAsyncTypebox } from '@fastify/type-provider-typebox' import { federatedAuthnController } from './federated-authn-controller' export const federatedAuthModule: FastifyPluginAsyncTypebox = async (app) => { - await app.register(federatedAuthnController, { prefix: '/v1/authn/federated' }) + await app.register(federatedAuthnController, { + prefix: '/v1/authn/federated', + }) } diff --git a/packages/backend/src/app/ee/authentication/federated-authn/federated-authn-service.ts b/packages/server/api/src/app/ee/authentication/federated-authn/federated-authn-service.ts similarity index 70% rename from packages/backend/src/app/ee/authentication/federated-authn/federated-authn-service.ts rename to packages/server/api/src/app/ee/authentication/federated-authn/federated-authn-service.ts index 231f4b210b..606317e4d1 100644 --- a/packages/backend/src/app/ee/authentication/federated-authn/federated-authn-service.ts +++ b/packages/server/api/src/app/ee/authentication/federated-authn/federated-authn-service.ts @@ -1,11 +1,17 @@ import { AuthenticationResponse } from '@activepieces/shared' -import { FederatedAuthnLoginResponse, ThirdPartyAuthnProviderEnum } from '@activepieces/ee-shared' +import { + FederatedAuthnLoginResponse, + ThirdPartyAuthnProviderEnum, +} from '@activepieces/ee-shared' import { providers } from './authn-provider/authn-provider' import { platformService } from '../../platform/platform.service' - export const federatedAuthnService = { - async login({ providerName, platformId, hostname }: LoginParams): Promise { + async login({ + providerName, + platformId, + hostname, + }: LoginParams): Promise { const provider = providers[providerName] const platform = await platformService.getOneOrThrow(platformId) const loginUrl = await provider.getLoginUrl(hostname, platform) @@ -15,7 +21,12 @@ export const federatedAuthnService = { } }, - async claim({ hostname, platformId, providerName, code }: ClaimParams): Promise { + async claim({ + hostname, + platformId, + providerName, + code, + }: ClaimParams): Promise { const provider = providers[providerName] const platform = await platformService.getOneOrThrow(platformId) return provider.authenticate(hostname, platform, code) @@ -28,7 +39,6 @@ type LoginParams = { providerName: ThirdPartyAuthnProviderEnum } - type ClaimParams = { platformId: string hostname: string diff --git a/packages/backend/src/app/ee/authentication/rbac-auth-middleware.ts b/packages/server/api/src/app/ee/authentication/rbac-auth-middleware.ts similarity index 78% rename from packages/backend/src/app/ee/authentication/rbac-auth-middleware.ts rename to packages/server/api/src/app/ee/authentication/rbac-auth-middleware.ts index a8ada4f994..c418371482 100644 --- a/packages/backend/src/app/ee/authentication/rbac-auth-middleware.ts +++ b/packages/server/api/src/app/ee/authentication/rbac-auth-middleware.ts @@ -1,7 +1,17 @@ import { FastifyRequest } from 'fastify' -import { ActivepiecesError, ApEdition, ErrorCode, PrincipalType, isNil } from '@activepieces/shared' +import { + ActivepiecesError, + ApEdition, + ErrorCode, + PrincipalType, + isNil, +} from '@activepieces/shared' import { projectMemberService } from '../../ee/project-members/project-member.service' -import { ProjectMemberPermission, ProjectMemberRole, ProjectMemberRoleToPermissions } from '@activepieces/ee-shared' +import { + ProjectMemberPermission, + ProjectMemberRole, + ProjectMemberRoleToPermissions, +} from '@activepieces/ee-shared' import { getEdition } from '../../helper/secret-helper' import { extractResourceName } from '../../authentication/authorization' @@ -32,18 +42,20 @@ const ProjectMemberPermissionResourceAndAction = { }, } -const managedResources = [ - 'flows', - 'connections', - 'project-members', -] +const managedResources = ['flows', 'connections', 'project-members'] -export const rbacAuthMiddleware = async (req: FastifyRequest): Promise => { +export const rbacAuthMiddleware = async ( + req: FastifyRequest, +): Promise => { const edition = getEdition() if (edition === ApEdition.COMMUNITY) { return } - if (req.url.startsWith('/redirect') || req.url.startsWith('/ui') || req.url.startsWith('/v1/project-members/accept')) { + if ( + req.url.startsWith('/redirect') || + req.url.startsWith('/ui') || + req.url.startsWith('/v1/project-members/accept') + ) { return } const action = req.method @@ -93,10 +105,15 @@ async function hasPermission({ role, resource, action, -}: { role: ProjectMemberRole, resource: string, action: string }): Promise { +}: { + role: ProjectMemberRole + resource: string + action: string +}): Promise { const permissions = ProjectMemberRoleToPermissions[role] const permission = permissions.find((permission: ProjectMemberPermission) => { - const { resource: permissionResource, action: permissionAction } = ProjectMemberPermissionResourceAndAction[permission] + const { resource: permissionResource, action: permissionAction } = + ProjectMemberPermissionResourceAndAction[permission] return permissionResource === resource && permissionAction.includes(action) }) return !!permission diff --git a/packages/backend/src/app/ee/billing/billing/billing.module.ts b/packages/server/api/src/app/ee/billing/billing/billing.module.ts similarity index 51% rename from packages/backend/src/app/ee/billing/billing/billing.module.ts rename to packages/server/api/src/app/ee/billing/billing/billing.module.ts index 4402c51002..990e8fe1e1 100644 --- a/packages/backend/src/app/ee/billing/billing/billing.module.ts +++ b/packages/server/api/src/app/ee/billing/billing/billing.module.ts @@ -6,29 +6,34 @@ import { billingService } from './billing.service' import { UpgradeRequest } from '@activepieces/ee-shared' import Stripe from 'stripe' import { plansService } from '../project-plan/project-plan.service' -import { captureException, logger } from '../../../helper/logger' +import { exceptionHandler, logger } from 'server-shared' import { projectUsageService } from '../project-usage/project-usage-service' import { defaultPlanInformation } from '../project-plan/pricing-plans' -import { ALL_PRINICPAL_TYPES, assertNotNullOrUndefined, isNil } from '@activepieces/shared' +import { + ALL_PRINICPAL_TYPES, + assertNotNullOrUndefined, + isNil, +} from '@activepieces/shared' export const billingModule: FastifyPluginAsyncTypebox = async (app) => { await app.register(billingController, { prefix: '/v1/billing' }) } const billingController: FastifyPluginAsyncTypebox = async (fastify) => { - fastify.get( - '/', - async ( - request, - ) => { - return { - defaultPlan: defaultPlanInformation, - usage: await projectUsageService.getUsageByProjectId(request.principal.projectId), - plan: await plansService.getOrCreateDefaultPlan({ projectId: request.principal.projectId }), - customerPortalUrl: await stripeHelper.createPortalSessionUrl({ projectId: request.principal.projectId }), - } - }, - ) + fastify.get('/', async (request) => { + return { + defaultPlan: defaultPlanInformation, + usage: await projectUsageService.getUsageByProjectId( + request.principal.projectId, + ), + plan: await plansService.getOrCreateDefaultPlan({ + projectId: request.principal.projectId, + }), + customerPortalUrl: await stripeHelper.createPortalSessionUrl({ + projectId: request.principal.projectId, + }), + } + }) fastify.post( '/upgrade', @@ -37,10 +42,11 @@ const billingController: FastifyPluginAsyncTypebox = async (fastify) => { body: UpgradeRequest, }, }, - async ( - request, - ) => { - return billingService.upgrade({ projectId: request.principal.projectId, request: request.body }) + async (request) => { + return billingService.upgrade({ + projectId: request.principal.projectId, + request: request.body, + }) }, ) @@ -52,32 +58,45 @@ const billingController: FastifyPluginAsyncTypebox = async (fastify) => { rawBody: true, }, }, - async ( - request: FastifyRequest>, - reply, - ) => { + async (request: FastifyRequest>, reply) => { const payloadString = request.rawBody const sig = request.headers['stripe-signature'] as string try { - await handleWebhook({ payload: payloadString as string, signature: sig }) + await handleWebhook({ + payload: payloadString as string, + signature: sig, + }) return await reply.status(StatusCodes.OK).send() } catch (err) { logger.error(err) logger.warn('⚠️ Webhook signature verification failed.') - logger.warn('⚠️ Check the env file and enter the correct webhook secret.') - captureException(err) - return reply.status(StatusCodes.BAD_REQUEST).send('Invalid webhook signature') + logger.warn( + '⚠️ Check the env file and enter the correct webhook secret.', + ) + exceptionHandler.handle(err) + return reply + .status(StatusCodes.BAD_REQUEST) + .send('Invalid webhook signature') } }, ) } - -async function handleWebhook({ payload, signature }: { payload: string, signature: string }): Promise { +async function handleWebhook({ + payload, + signature, +}: { + payload: string + signature: string +}): Promise { const stripe = stripeHelper.getStripe() assertNotNullOrUndefined(stripe, 'Stripe is not configured') - const webhook = stripe.webhooks.constructEvent(payload, signature, stripeWebhookSecret) + const webhook = stripe.webhooks.constructEvent( + payload, + signature, + stripeWebhookSecret, + ) const subscription = webhook.data.object as Stripe.Subscription if (isSubscriptionPlatformOrCustom(subscription)) { return @@ -89,7 +108,10 @@ async function handleWebhook({ payload, signature }: { payload: string, signatur case 'customer.subscription.deleted': case 'customer.subscription.updated': case 'customer.subscription.created': { - await billingService.update({ subscription, projectId: projectPlan.projectId }) + await billingService.update({ + subscription, + projectId: projectPlan.projectId, + }) break } default: @@ -97,9 +119,14 @@ async function handleWebhook({ payload, signature }: { payload: string, signatur } } -function isSubscriptionPlatformOrCustom(subscription: Stripe.Subscription): boolean { - const customProduct = subscription.items.data.find(item => { - return item.price.metadata.productType === 'CUSTOM' || item.price.metadata.productType === 'PLATFORM' +function isSubscriptionPlatformOrCustom( + subscription: Stripe.Subscription, +): boolean { + const customProduct = subscription.items.data.find((item) => { + return ( + item.price.metadata.productType === 'CUSTOM' || + item.price.metadata.productType === 'PLATFORM' + ) }) return !isNil(customProduct) -} \ No newline at end of file +} diff --git a/packages/backend/src/app/ee/billing/billing/billing.service.ts b/packages/server/api/src/app/ee/billing/billing/billing.service.ts similarity index 55% rename from packages/backend/src/app/ee/billing/billing/billing.service.ts rename to packages/server/api/src/app/ee/billing/billing/billing.service.ts index 4471258235..eb2f842314 100644 --- a/packages/backend/src/app/ee/billing/billing/billing.service.ts +++ b/packages/server/api/src/app/ee/billing/billing/billing.service.ts @@ -2,24 +2,42 @@ import Stripe from 'stripe' import { isNil } from '@activepieces/shared' import { UpgradeRequest } from '@activepieces/ee-shared' import { plansService } from '../project-plan/project-plan.service' -import { FlowPlanLimits, defaultPlanInformation } from '../project-plan/pricing-plans' +import { + FlowPlanLimits, + defaultPlanInformation, +} from '../project-plan/pricing-plans' import { stripeHelper } from './stripe-helper' export const billingService = { - async update({ subscription, projectId }: { subscription: Stripe.Subscription | null, projectId: string }): Promise { + async update({ + subscription, + projectId, + }: { + subscription: Stripe.Subscription | null + projectId: string + }): Promise { const planLimits = findPlanOrReturnFree({ subscription }) await plansService.update({ projectId, planLimits, subscription, - }) + }) }, - async upgrade({ projectId, request }: { projectId: string, request: UpgradeRequest }): Promise<{ - paymentLink: string | null - }> { + async upgrade({ + projectId, + request, + }: { + projectId: string + request: UpgradeRequest + }): Promise<{ + paymentLink: string | null + }> { const plan = await plansService.getOrCreateDefaultPlan({ projectId }) if (!isNil(plan.stripeSubscriptionId)) { - return stripeHelper.upgrade({ request, subscriptionId: plan.stripeSubscriptionId }) + return stripeHelper.upgrade({ + request, + subscriptionId: plan.stripeSubscriptionId, + }) } else { return stripeHelper.createPaymentLink({ @@ -30,9 +48,13 @@ export const billingService = { }, } -function findPlanOrReturnFree({ subscription }: { subscription: Stripe.Subscription | null }): FlowPlanLimits { +function findPlanOrReturnFree({ + subscription, +}: { + subscription: Stripe.Subscription | null +}): FlowPlanLimits { if (subscription?.status === 'active') { return stripeHelper.parseStripeSubscription(subscription) } return defaultPlanInformation -} \ No newline at end of file +} diff --git a/packages/backend/src/app/ee/billing/billing/stripe-helper.ts b/packages/server/api/src/app/ee/billing/billing/stripe-helper.ts similarity index 85% rename from packages/backend/src/app/ee/billing/billing/stripe-helper.ts rename to packages/server/api/src/app/ee/billing/billing/stripe-helper.ts index 50bf69e55a..8a236a5d06 100644 --- a/packages/backend/src/app/ee/billing/billing/stripe-helper.ts +++ b/packages/server/api/src/app/ee/billing/billing/stripe-helper.ts @@ -1,14 +1,25 @@ import Stripe from 'stripe' -import { system } from '../../../helper/system/system' -import { SystemProp } from '../../../helper/system/system-prop' -import { ApEdition, ProjectId, UserMeta, assertNotNullOrUndefined } from '@activepieces/shared' -import { captureException } from '../../../helper/logger' -import { PlanName, UpgradeRequest, platformTasksPriceId, platformUserPriceId, proUserPriceId } from '@activepieces/ee-shared' +import { SystemProp, system, exceptionHandler } from 'server-shared' +import { + ApEdition, + ProjectId, + UserMeta, + assertNotNullOrUndefined, +} from '@activepieces/shared' +import { + PlanName, + UpgradeRequest, + platformTasksPriceId, + platformUserPriceId, + proUserPriceId, +} from '@activepieces/ee-shared' import { FlowPlanLimits } from '../project-plan/pricing-plans' import { plansService } from '../project-plan/project-plan.service' import { getEdition } from '../../../helper/secret-helper' -export const stripeWebhookSecret = system.get(SystemProp.STRIPE_WEBHOOK_SECRET)! +export const stripeWebhookSecret = system.get( + SystemProp.STRIPE_WEBHOOK_SECRET, +)! function getStripe(): Stripe | undefined { const edition = getEdition() @@ -27,7 +38,10 @@ enum StripeProductType { PLATFORM_USER = 'PLATFORM_USER', } -async function getOrCreateCustomer(user: UserMeta, projectId: ProjectId): Promise { +async function getOrCreateCustomer( + user: UserMeta, + projectId: ProjectId, +): Promise { const edition = getEdition() const stripe = getStripe() if (edition !== ApEdition.CLOUD) { @@ -35,7 +49,7 @@ async function getOrCreateCustomer(user: UserMeta, projectId: ProjectId): Promis } assertNotNullOrUndefined(stripe, 'Stripe is not configured') try { - // Retrieve the customer by their email + // Retrieve the customer by their email const existingCustomers = await stripe.customers.list({ email: user.email, limit: 1, @@ -56,7 +70,7 @@ async function getOrCreateCustomer(user: UserMeta, projectId: ProjectId): Promis return newCustomer.id } catch (error) { - captureException(error) + exceptionHandler.handle(error) throw error } } @@ -70,10 +84,12 @@ function parseStripeSubscription(sub: Stripe.Subscription): FlowPlanLimits { teamMembers: 0, } for (const plan of sub.items.data) { - const productType = plan.price.metadata.productType ?? StripeProductType.PRO + const productType = + plan.price.metadata.productType ?? StripeProductType.PRO switch (productType) { case StripeProductType.PRO: { - const { tasks, minimumPollingInterval, connections, teamMembers } = plan.price.metadata + const { tasks, minimumPollingInterval, connections, teamMembers } = + plan.price.metadata flowPlanLimits.nickname = plan.plan.nickname! flowPlanLimits.tasks += Number(tasks) ?? 0 flowPlanLimits.minimumPollingInterval = Number(minimumPollingInterval) @@ -99,12 +115,19 @@ function parseStripeSubscription(sub: Stripe.Subscription): FlowPlanLimits { async function upgrade({ request, subscriptionId, -}: { request: UpgradeRequest, subscriptionId: string }): Promise<{ paymentLink: null }> { +}: { + request: UpgradeRequest + subscriptionId: string +}): Promise<{ paymentLink: null }> { const stripe = getStripe() assertNotNullOrUndefined(stripe, 'Stripe is not configured') - const stripeSubscription = await stripe.subscriptions.retrieve(subscriptionId) - const products = getPlanProducts(request).map(item => { - const existingItem = stripeSubscription.items.data.find(f => f.price.id === item.price) + const stripeSubscription = await stripe.subscriptions.retrieve( + subscriptionId, + ) + const products = getPlanProducts(request).map((item) => { + const existingItem = stripeSubscription.items.data.find( + (f) => f.price.id === item.price, + ) if (!existingItem) { return item } @@ -160,7 +183,7 @@ async function createPaymentLink({ } } catch (error) { - captureException(error) + exceptionHandler.handle(error) throw new Error('Failed to create payment link') } } @@ -211,4 +234,4 @@ export const stripeHelper = { upgrade, getStripe, getOrCreateCustomer, -} \ No newline at end of file +} diff --git a/packages/backend/src/app/ee/billing/limits/connections-limits.ts b/packages/server/api/src/app/ee/billing/limits/connections-limits.ts similarity index 72% rename from packages/backend/src/app/ee/billing/limits/connections-limits.ts rename to packages/server/api/src/app/ee/billing/limits/connections-limits.ts index 8015534a2d..6ade6b11ef 100644 --- a/packages/backend/src/app/ee/billing/limits/connections-limits.ts +++ b/packages/server/api/src/app/ee/billing/limits/connections-limits.ts @@ -2,9 +2,16 @@ import { ActivepiecesError, ErrorCode, ProjectId } from '@activepieces/shared' import { appConnectionService } from '../../../app-connection/app-connection-service/app-connection-service' import { plansService } from '../project-plan/project-plan.service' -async function limitConnections({ projectId }: { projectId: ProjectId }): Promise { - const { connections: connectionQuota } = await plansService.getOrCreateDefaultPlan({ projectId }) - const connectionCount = await appConnectionService.countByProject({ projectId }) +async function limitConnections({ + projectId, +}: { + projectId: ProjectId +}): Promise { + const { connections: connectionQuota } = + await plansService.getOrCreateDefaultPlan({ projectId }) + const connectionCount = await appConnectionService.countByProject({ + projectId, + }) if (connectionCount === connectionQuota) { throw new ActivepiecesError({ @@ -19,4 +26,4 @@ async function limitConnections({ projectId }: { projectId: ProjectId }): Promis export const connectionsLimits = { limitConnections, -} \ No newline at end of file +} diff --git a/packages/backend/src/app/ee/billing/limits/members-limit.ts b/packages/server/api/src/app/ee/billing/limits/members-limit.ts similarity index 76% rename from packages/backend/src/app/ee/billing/limits/members-limit.ts rename to packages/server/api/src/app/ee/billing/limits/members-limit.ts index ce612e1670..0b75908d98 100644 --- a/packages/backend/src/app/ee/billing/limits/members-limit.ts +++ b/packages/server/api/src/app/ee/billing/limits/members-limit.ts @@ -1,11 +1,15 @@ -import { ActivepiecesError, ApEdition, ErrorCode, ProjectId } from '@activepieces/shared' +import { + ActivepiecesError, + ApEdition, + ErrorCode, + ProjectId, +} from '@activepieces/shared' import { getEdition } from '../../../helper/secret-helper' import { plansService } from '../project-plan/project-plan.service' import { ProjectMemberEntity } from '../../project-members/project-member.entity' import { databaseConnection } from '../../../database/database-connection' -const projectMemberRepo = - databaseConnection.getRepository(ProjectMemberEntity) +const projectMemberRepo = databaseConnection.getRepository(ProjectMemberEntity) export const projectMembersLimit = { async limit({ projectId }: { projectId: ProjectId }): Promise { @@ -16,9 +20,10 @@ export const projectMembersLimit = { const projectPlan = await plansService.getOrCreateDefaultPlan({ projectId, }) - const numberOfMembers = await projectMemberRepo.countBy({ - projectId, - }) + 1 + const numberOfMembers = + (await projectMemberRepo.countBy({ + projectId, + })) + 1 if (numberOfMembers > projectPlan.teamMembers) { throw new ActivepiecesError({ @@ -30,4 +35,4 @@ export const projectMembersLimit = { }) } }, -} \ No newline at end of file +} diff --git a/packages/backend/src/app/ee/billing/limits/tasks-limit.ts b/packages/server/api/src/app/ee/billing/limits/tasks-limit.ts similarity index 84% rename from packages/backend/src/app/ee/billing/limits/tasks-limit.ts rename to packages/server/api/src/app/ee/billing/limits/tasks-limit.ts index 4ed1130206..8ba97fa475 100644 --- a/packages/backend/src/app/ee/billing/limits/tasks-limit.ts +++ b/packages/server/api/src/app/ee/billing/limits/tasks-limit.ts @@ -1,4 +1,10 @@ -import { ActivepiecesError, ApEdition, ErrorCode, ProjectId, isNil } from '@activepieces/shared' +import { + ActivepiecesError, + ApEdition, + ErrorCode, + ProjectId, + isNil, +} from '@activepieces/shared' import { ProjectPlan, ProjectUsage } from '@activepieces/ee-shared' import { apDayjs } from '../../../helper/dayjs-helper' @@ -6,13 +12,15 @@ import { flowRunService } from '../../../flows/flow-run/flow-run-service' import { getEdition } from '../../../helper/secret-helper' import { plansService } from '../project-plan/project-plan.service' import { projectUsageService } from '../project-usage/project-usage-service' -import { captureException } from '../../../helper/logger' - +import { exceptionHandler } from 'server-shared' async function limitTasksPerDay({ projectId, tasksPerDay, -}: { projectId: ProjectId, tasksPerDay: number }): Promise { +}: { + projectId: ProjectId + tasksPerDay: number +}): Promise { const flowRunsInLastTwentyFourHours = await getTaskUserInUTCDay({ projectId, }) @@ -30,7 +38,10 @@ async function limitTasksPerDay({ async function limitTasksPerMonth({ projectPlan, projectUsage, -}: { projectPlan: ProjectPlan, projectUsage: ProjectUsage }): Promise { +}: { + projectPlan: ProjectPlan + projectUsage: ProjectUsage +}): Promise { if (projectUsage.consumedTasks > projectPlan.tasks) { throw new ActivepiecesError({ code: ErrorCode.QUOTA_EXCEEDED, @@ -42,7 +53,6 @@ async function limitTasksPerMonth({ } } - async function getTaskUserInUTCDay({ projectId, }: { @@ -75,7 +85,9 @@ async function limit({ projectId }: { projectId: ProjectId }): Promise { tasksPerDay: projectPlan.tasksPerDay, }) } - const projectUsage = await projectUsageService.getUsageByProjectId(projectId) + const projectUsage = await projectUsageService.getUsageByProjectId( + projectId, + ) await limitTasksPerMonth({ projectUsage, projectPlan, @@ -84,13 +96,13 @@ async function limit({ projectId }: { projectId: ProjectId }): Promise { catch (e) { if ( e instanceof ActivepiecesError && - e.error.code === ErrorCode.QUOTA_EXCEEDED + e.error.code === ErrorCode.QUOTA_EXCEEDED ) { throw e } else { // Ignore quota errors for sake of user experience and log them instead - captureException(e) + exceptionHandler.handle(e) } } } @@ -98,4 +110,4 @@ async function limit({ projectId }: { projectId: ProjectId }): Promise { export const tasksLimit = { limit, getTaskUserInUTCDay, -} \ No newline at end of file +} diff --git a/packages/backend/src/app/ee/billing/project-plan/pricing-plans.ts b/packages/server/api/src/app/ee/billing/project-plan/pricing-plans.ts similarity index 78% rename from packages/backend/src/app/ee/billing/project-plan/pricing-plans.ts rename to packages/server/api/src/app/ee/billing/project-plan/pricing-plans.ts index 153a7743fa..966535b763 100644 --- a/packages/backend/src/app/ee/billing/project-plan/pricing-plans.ts +++ b/packages/server/api/src/app/ee/billing/project-plan/pricing-plans.ts @@ -1,6 +1,5 @@ import { Static, Type } from '@sinclair/typebox' -import { system } from '../../../helper/system/system' -import { SystemProp } from '../../../helper/system/system-prop' +import { SystemProp, system } from 'server-shared' export const FlowPlanLimits = Type.Object({ nickname: Type.String(), @@ -15,4 +14,3 @@ export type FlowPlanLimits = Static export const defaultPlanInformation: FlowPlanLimits = JSON.parse( system.get(SystemProp.BILLING_SETTINGS) ?? '{}', ) - diff --git a/packages/backend/src/app/ee/billing/project-plan/project-plan.entity.ts b/packages/server/api/src/app/ee/billing/project-plan/project-plan.entity.ts similarity index 92% rename from packages/backend/src/app/ee/billing/project-plan/project-plan.entity.ts rename to packages/server/api/src/app/ee/billing/project-plan/project-plan.entity.ts index 0dbda99284..46b22ca922 100644 --- a/packages/backend/src/app/ee/billing/project-plan/project-plan.entity.ts +++ b/packages/server/api/src/app/ee/billing/project-plan/project-plan.entity.ts @@ -1,7 +1,11 @@ import { EntitySchema } from 'typeorm' import { Project } from '@activepieces/shared' import { ProjectPlan } from '@activepieces/ee-shared' -import { ApIdSchema, BaseColumnSchemaPart, TIMESTAMP_COLUMN_TYPE } from '../../../database/database-common' +import { + ApIdSchema, + BaseColumnSchemaPart, + TIMESTAMP_COLUMN_TYPE, +} from '../../../database/database-common' export type ProjectPlanSchema = { project: Project diff --git a/packages/backend/src/app/ee/billing/project-plan/project-plan.service.ts b/packages/server/api/src/app/ee/billing/project-plan/project-plan.service.ts similarity index 56% rename from packages/backend/src/app/ee/billing/project-plan/project-plan.service.ts rename to packages/server/api/src/app/ee/billing/project-plan/project-plan.service.ts index 42930babd3..8fc5491bb5 100644 --- a/packages/backend/src/app/ee/billing/project-plan/project-plan.service.ts +++ b/packages/server/api/src/app/ee/billing/project-plan/project-plan.service.ts @@ -1,4 +1,10 @@ -import { ApEdition, ProjectId, apId, isNil, spreadIfDefined } from '@activepieces/shared' +import { + ApEdition, + ProjectId, + apId, + isNil, + spreadIfDefined, +} from '@activepieces/shared' import { DEFAULT_PLATFORM_PLAN, ProjectPlan } from '@activepieces/ee-shared' import { databaseConnection } from '../../../database/database-connection' import { projectService } from '../../../project/project-service' @@ -12,20 +18,38 @@ import { appsumoService } from '../../appsumo/appsumo.service' import { getEdition } from '../../../helper/secret-helper' import { flagService } from '../../../flags/flag.service' -const projectPlanRepo = databaseConnection.getRepository(ProjectPlanEntity) +const projectPlanRepo = + databaseConnection.getRepository(ProjectPlanEntity) export const plansService = { - async getByCustomerId({ stripeCustomerId }: { stripeCustomerId: string }): Promise { + async getByCustomerId({ + stripeCustomerId, + }: { + stripeCustomerId: string + }): Promise { return projectPlanRepo.findOneByOrFail({ stripeCustomerId }) }, - async removeDailyTasksAndUpdateTasks({ projectId, tasks }: { projectId: ProjectId, tasks: number }): Promise { - await projectPlanRepo.update({ projectId }, { - tasks, - tasksPerDay: null, - }) + async removeDailyTasksAndUpdateTasks({ + projectId, + tasks, + }: { + projectId: ProjectId + tasks: number + }): Promise { + await projectPlanRepo.update( + { projectId }, + { + tasks, + tasksPerDay: null, + }, + ) }, - async getOrCreateDefaultPlan({ projectId }: { projectId: ProjectId }): Promise { + async getOrCreateDefaultPlan({ + projectId, + }: { + projectId: ProjectId + }): Promise { const plan = await projectPlanRepo.findOneBy({ projectId }) if (isNil(plan)) { return createInitialPlan({ projectId }) @@ -33,7 +57,11 @@ export const plansService = { return plan }, - async update({ planLimits, subscription, projectId }: { + async update({ + planLimits, + subscription, + projectId, + }: { planLimits: Partial subscription: null | Stripe.Subscription projectId: string @@ -42,7 +70,13 @@ export const plansService = { projectId, }) const stripeSubscriptionId = subscription?.id ?? null - const { nickname, connections, tasks, minimumPollingInterval, teamMembers } = planLimits + const { + nickname, + connections, + tasks, + minimumPollingInterval, + teamMembers, + } = planLimits await projectPlanRepo.update(projectPlan.id, { ...spreadIfDefined('flowPlanName', nickname), ...spreadIfDefined('connections', connections), @@ -56,8 +90,15 @@ export const plansService = { }, } -async function createInitialPlan({ projectId }: { projectId: ProjectId }): Promise { - const projectPlanLock = await acquireLock({ key: `project_plan_${projectId}`, timeout: 30 * 1000 }) +async function createInitialPlan({ + projectId, +}: { + projectId: ProjectId +}): Promise { + const projectPlanLock = await acquireLock({ + key: `project_plan_${projectId}`, + timeout: 30 * 1000, + }) try { const currentPlan = await projectPlanRepo.findOneBy({ projectId }) if (!isNil(currentPlan)) { @@ -65,20 +106,29 @@ async function createInitialPlan({ projectId }: { projectId: ProjectId }): Promi } const project = await projectService.getOneOrThrow(projectId) const user = (await userService.getMetaInfo({ id: project.ownerId }))! - const stripeCustomerId = await stripeHelper.getOrCreateCustomer(user, project.id) - const defaultPlanFlow = await getDefaultFlowPlan({ platformId: project.platformId ?? null, email: user.email }) - await projectPlanRepo.upsert({ - id: apId(), - projectId, - flowPlanName: defaultPlanFlow.nickname, - tasks: defaultPlanFlow.tasks, - connections: defaultPlanFlow.connections, - minimumPollingInterval: defaultPlanFlow.minimumPollingInterval, - teamMembers: defaultPlanFlow.teamMembers, - stripeCustomerId, - stripeSubscriptionId: null, - subscriptionStartDatetime: project.created, - }, ['projectId']) + const stripeCustomerId = await stripeHelper.getOrCreateCustomer( + user, + project.id, + ) + const defaultPlanFlow = await getDefaultFlowPlan({ + platformId: project.platformId ?? null, + email: user.email, + }) + await projectPlanRepo.upsert( + { + id: apId(), + projectId, + flowPlanName: defaultPlanFlow.nickname, + tasks: defaultPlanFlow.tasks, + connections: defaultPlanFlow.connections, + minimumPollingInterval: defaultPlanFlow.minimumPollingInterval, + teamMembers: defaultPlanFlow.teamMembers, + stripeCustomerId, + stripeSubscriptionId: null, + subscriptionStartDatetime: project.created, + }, + ['projectId'], + ) return await projectPlanRepo.findOneByOrFail({ projectId }) } finally { @@ -86,7 +136,13 @@ async function createInitialPlan({ projectId }: { projectId: ProjectId }): Promi } } -async function getDefaultFlowPlan({ platformId, email }: { platformId: string | null, email: string }): Promise { +async function getDefaultFlowPlan({ + platformId, + email, +}: { + platformId: string | null + email: string +}): Promise { const edition = getEdition() if (edition === ApEdition.CLOUD) { const appsumoPlan = await appsumoService.getByEmail(email) diff --git a/packages/backend/src/app/ee/billing/project-usage/project-usage-alerts.ts b/packages/server/api/src/app/ee/billing/project-usage/project-usage-alerts.ts similarity index 59% rename from packages/backend/src/app/ee/billing/project-usage/project-usage-alerts.ts rename to packages/server/api/src/app/ee/billing/project-usage/project-usage-alerts.ts index 001de28a07..ef1ca2a5e9 100644 --- a/packages/backend/src/app/ee/billing/project-usage/project-usage-alerts.ts +++ b/packages/server/api/src/app/ee/billing/project-usage/project-usage-alerts.ts @@ -1,17 +1,14 @@ -import { - ProjectUsage, -} from '@activepieces/ee-shared' +import { ProjectUsage } from '@activepieces/ee-shared' import { isNil } from 'lodash' import { telemetry } from '../../../helper/telemetry.utils' import { TelemetryEventName, UserMeta } from '@activepieces/shared' import { projectService } from '../../../project/project-service' import { userService } from '../../../user/user-service' -import { logger } from '../../../helper/logger' +import { logger } from 'server-shared' import { apDayjs } from '../../../helper/dayjs-helper' import { plansService } from '../project-plan/project-plan.service' import { emailService } from '../../helper/email/email-service' - const alertingEmails: { threshold: number templateId: 'quota-50' | 'quota-90' | 'quota-100' @@ -38,11 +35,15 @@ function calculateThreshold(consumedTask: number, planTasks: number): number { return Math.floor((consumedTask / planTasks) * 100) } -async function sendEmail(user: UserMeta, thresholdEmail: { - threshold: number - templateId: 'quota-50' | 'quota-90' | 'quota-100' - sendForDailyLimit: boolean -}, projectUsage: ProjectUsage): Promise { +async function sendEmail( + user: UserMeta, + thresholdEmail: { + threshold: number + templateId: 'quota-50' | 'quota-90' | 'quota-100' + sendForDailyLimit: boolean + }, + projectUsage: ProjectUsage, +): Promise { const project = await projectService.getOne(projectUsage.projectId) if (!project) { throw new Error(`Project with ID ${projectUsage.projectId} not found`) @@ -51,20 +52,28 @@ async function sendEmail(user: UserMeta, thresholdEmail: { const resetDate = apDayjs(projectUsage.nextResetDatetime) const formattedDate = resetDate.utc().format('MM/DD/YYYY hh:mm:ss A') - telemetry.trackProject(project.id, { - name: TelemetryEventName.QUOTA_ALERT, - payload: { - percentageUsed: thresholdEmail.threshold, - }, - }).catch((e) => logger.error(e, '[usageService#handleAlerts] telemetry.trackProject')) + telemetry + .trackProject(project.id, { + name: TelemetryEventName.QUOTA_ALERT, + payload: { + percentageUsed: thresholdEmail.threshold, + }, + }) + .catch((e) => + logger.error(e, '[usageService#handleAlerts] telemetry.trackProject'), + ) - emailService.sendQuotaAlert({ - templateId: thresholdEmail.templateId, - email: user.email, - projectId: project.id, - firstName: user.firstName, - resetDate: formattedDate, - }).catch((e) => logger.error(e, '[usageService#handleAlerts] emailService.send')) + emailService + .sendQuotaAlert({ + templateId: thresholdEmail.templateId, + email: user.email, + projectId: project.id, + firstName: user.firstName, + resetDate: formattedDate, + }) + .catch((e) => + logger.error(e, '[usageService#handleAlerts] emailService.send'), + ) } // Function to handle alerts @@ -78,22 +87,32 @@ async function handleAlerts({ const projectPlan = await plansService.getOrCreateDefaultPlan({ projectId: projectUsage.projectId, }) - const consumedTask = !isNil(projectPlan.tasksPerDay) ? - projectUsage.consumedTasksToday : - projectUsage.consumedTasks + const consumedTask = !isNil(projectPlan.tasksPerDay) + ? projectUsage.consumedTasksToday + : projectUsage.consumedTasks - const planTasks = projectPlan.tasksPerDay ? projectPlan.tasksPerDay : projectPlan.tasks + const planTasks = projectPlan.tasksPerDay + ? projectPlan.tasksPerDay + : projectPlan.tasks for (const emailTemplate of alertingEmails) { const threshold = calculateThreshold(consumedTask, planTasks) - const newThreshold = calculateThreshold(consumedTask + numberOfTasks, planTasks) + const newThreshold = calculateThreshold( + consumedTask + numberOfTasks, + planTasks, + ) - if (threshold < emailTemplate.threshold && newThreshold >= emailTemplate.threshold) { + if ( + threshold < emailTemplate.threshold && + newThreshold >= emailTemplate.threshold + ) { if (!emailTemplate.sendForDailyLimit && projectPlan.tasksPerDay) { continue } - const project = await projectService.getOneOrThrow(projectUsage.projectId) + const project = await projectService.getOneOrThrow( + projectUsage.projectId, + ) const user = (await userService.getMetaInfo({ id: project.ownerId }))! logger.info({ email: user.email, @@ -110,4 +129,4 @@ async function handleAlerts({ export const usageAlerts = { handleAlerts, -} \ No newline at end of file +} diff --git a/packages/backend/src/app/ee/billing/project-usage/project-usage-service.ts b/packages/server/api/src/app/ee/billing/project-usage/project-usage-service.ts similarity index 76% rename from packages/backend/src/app/ee/billing/project-usage/project-usage-service.ts rename to packages/server/api/src/app/ee/billing/project-usage/project-usage-service.ts index d6d37678a6..5310c64c28 100644 --- a/packages/backend/src/app/ee/billing/project-usage/project-usage-service.ts +++ b/packages/server/api/src/app/ee/billing/project-usage/project-usage-service.ts @@ -1,10 +1,7 @@ -import { - ProjectId, - apId, -} from '@activepieces/shared' -import { ProjectUsage } from '@activepieces/ee-shared' +import { ProjectId, apId } from '@activepieces/shared' +import { ProjectUsage } from '@activepieces/ee-shared' import { isNil } from 'lodash' -import { logger } from '../../../helper/logger' +import { logger } from 'server-shared' import { ProjectUsageEntity, ProjectUsageSchema } from './project-usage.entity' import { databaseConnection } from '../../../database/database-connection' import { projectMemberService } from '../../project-members/project-member.service' @@ -21,11 +18,17 @@ export const projectUsageService = { projectId: ProjectId tasks: number }): Promise { - const projectUsage = await projectUsageService.getUsageByProjectId(request.projectId) - usageAlerts.handleAlerts({ - projectUsage, - numberOfTasks: request.tasks, - }).catch((e) => logger.error(e, '[usageService#addTasksConsumed] handleAlerts')) + const projectUsage = await projectUsageService.getUsageByProjectId( + request.projectId, + ) + usageAlerts + .handleAlerts({ + projectUsage, + numberOfTasks: request.tasks, + }) + .catch((e) => + logger.error(e, '[usageService#addTasksConsumed] handleAlerts'), + ) await projectUsageRepo.increment( { id: projectUsage.id }, 'consumedTasks', @@ -33,7 +36,6 @@ export const projectUsageService = { ) }, - async getUsageByProjectId(projectId: string): Promise { let projectUsage = await projectUsageRepo.findOne({ where: { @@ -47,7 +49,7 @@ export const projectUsageService = { const nextReset = nextResetDatetime(plan.subscriptionStartDatetime) if ( isNil(projectUsage) || - isNotSame(nextReset, projectUsage.nextResetDatetime) + isNotSame(nextReset, projectUsage.nextResetDatetime) ) { projectUsage = await createNewUsage(projectId, nextReset) } @@ -55,7 +57,9 @@ export const projectUsageService = { }, } -async function enrichProjectUsage(schema: ProjectUsageSchema): Promise { +async function enrichProjectUsage( + schema: ProjectUsageSchema, +): Promise { const projectId = schema.projectId return { consumedTasksToday: await tasksLimit.getTaskUserInUTCDay({ projectId }), @@ -67,7 +71,10 @@ async function enrichProjectUsage(schema: ProjectUsageSchema): Promise { +async function createNewUsage( + projectId: string, + nextReset: string, +): Promise { return projectUsageRepo.save({ id: apId(), projectId, @@ -87,7 +94,6 @@ function nextResetDatetime(datetime: string): string { const date = apDayjs(datetime) const currentDate = apDayjs() const nextResetInMs = - thirtyDaysInMs - (currentDate.diff(date, 'millisecond') % thirtyDaysInMs) + thirtyDaysInMs - (currentDate.diff(date, 'millisecond') % thirtyDaysInMs) return currentDate.add(nextResetInMs, 'millisecond').toISOString() } - diff --git a/packages/backend/src/app/ee/billing/project-usage/project-usage.entity.ts b/packages/server/api/src/app/ee/billing/project-usage/project-usage.entity.ts similarity index 81% rename from packages/backend/src/app/ee/billing/project-usage/project-usage.entity.ts rename to packages/server/api/src/app/ee/billing/project-usage/project-usage.entity.ts index ca1ce0a8e1..6ad6445cc8 100644 --- a/packages/backend/src/app/ee/billing/project-usage/project-usage.entity.ts +++ b/packages/server/api/src/app/ee/billing/project-usage/project-usage.entity.ts @@ -1,9 +1,16 @@ import { EntitySchema } from 'typeorm' import { Project } from '@activepieces/shared' import { ProjectUsage } from '@activepieces/ee-shared' -import { ApIdSchema, BaseColumnSchemaPart, TIMESTAMP_COLUMN_TYPE } from '../../../database/database-common' +import { + ApIdSchema, + BaseColumnSchemaPart, + TIMESTAMP_COLUMN_TYPE, +} from '../../../database/database-common' -export type ProjectUsageDatabaseEntity = Omit +export type ProjectUsageDatabaseEntity = Omit< +ProjectUsage, +'consumedTasksToday' | 'activeFlows' | 'connections' | 'teamMembers' +> export type ProjectUsageSchema = { project: Project diff --git a/packages/backend/src/app/ee/connection-keys/connection-key.entity.ts b/packages/server/api/src/app/ee/connection-keys/connection-key.entity.ts similarity index 87% rename from packages/backend/src/app/ee/connection-keys/connection-key.entity.ts rename to packages/server/api/src/app/ee/connection-keys/connection-key.entity.ts index 18d9f4b63d..88f6ccd030 100644 --- a/packages/backend/src/app/ee/connection-keys/connection-key.entity.ts +++ b/packages/server/api/src/app/ee/connection-keys/connection-key.entity.ts @@ -1,7 +1,11 @@ import { EntitySchema } from 'typeorm' import { ConnectionKey } from '@activepieces/ee-shared' import { Project } from '@activepieces/shared' -import { ApIdSchema, BaseColumnSchemaPart, JSONB_COLUMN_TYPE } from '../../database/database-common' +import { + ApIdSchema, + BaseColumnSchemaPart, + JSONB_COLUMN_TYPE, +} from '../../database/database-common' export type ConnectionKeySchema = { project: Project diff --git a/packages/backend/src/app/ee/connection-keys/connection-key.module.ts b/packages/server/api/src/app/ee/connection-keys/connection-key.module.ts similarity index 74% rename from packages/backend/src/app/ee/connection-keys/connection-key.module.ts rename to packages/server/api/src/app/ee/connection-keys/connection-key.module.ts index ad31874ab3..eaf335c076 100644 --- a/packages/backend/src/app/ee/connection-keys/connection-key.module.ts +++ b/packages/server/api/src/app/ee/connection-keys/connection-key.module.ts @@ -1,5 +1,11 @@ import { FastifyRequest } from 'fastify' -import { ConnectionKeyId, GetOrDeleteConnectionFromTokenRequest, ListConnectionKeysRequest, UpsertConnectionFromToken, UpsertSigningKeyConnection } from '@activepieces/ee-shared' +import { + ConnectionKeyId, + GetOrDeleteConnectionFromTokenRequest, + ListConnectionKeysRequest, + UpsertConnectionFromToken, + UpsertSigningKeyConnection, +} from '@activepieces/ee-shared' import { connectionKeyService } from './connection-key.service' import { StatusCodes } from 'http-status-codes' import { FastifyPluginAsyncTypebox } from '@fastify/type-provider-typebox' @@ -7,13 +13,14 @@ import { appConnectionService } from '../../app-connection/app-connection-servic import { ALL_PRINICPAL_TYPES } from '@activepieces/shared' export const connectionKeyModule: FastifyPluginAsyncTypebox = async (app) => { - await app.register(connectionKeyController, { prefix: '/v1/connection-keys' }) + await app.register(connectionKeyController, { + prefix: '/v1/connection-keys', + }) } const DEFAULT_LIMIT_SIZE = 10 const connectionKeyController: FastifyPluginAsyncTypebox = async (fastify) => { - fastify.delete( '/app-connections', { @@ -29,9 +36,14 @@ const connectionKeyController: FastifyPluginAsyncTypebox = async (fastify) => { Querystring: GetOrDeleteConnectionFromTokenRequest }>, ) => { - const appConnection = await connectionKeyService.getConnection(request.query) + const appConnection = await connectionKeyService.getConnection( + request.query, + ) if (appConnection !== null) { - await appConnectionService.delete({ projectId: request.query.projectId, id: appConnection.id }) + await appConnectionService.delete({ + projectId: request.query.projectId, + id: appConnection.id, + }) } }, ) @@ -55,7 +67,6 @@ const connectionKeyController: FastifyPluginAsyncTypebox = async (fastify) => { }, ) - fastify.post( '/app-connections', { @@ -75,17 +86,25 @@ const connectionKeyController: FastifyPluginAsyncTypebox = async (fastify) => { }, ) - fastify.get('/', { - schema: { - querystring: ListConnectionKeysRequest, + fastify.get( + '/', + { + schema: { + querystring: ListConnectionKeysRequest, + }, }, - }, async (request: FastifyRequest< - { - Querystring: ListConnectionKeysRequest - }>) => { - return connectionKeyService.list(request.principal.projectId, request.query.cursor ?? null, request.query.limit ?? DEFAULT_LIMIT_SIZE) - }) - + async ( + request: FastifyRequest<{ + Querystring: ListConnectionKeysRequest + }>, + ) => { + return connectionKeyService.list( + request.principal.projectId, + request.query.cursor ?? null, + request.query.limit ?? DEFAULT_LIMIT_SIZE, + ) + }, + ) fastify.post( '/', @@ -106,7 +125,6 @@ const connectionKeyController: FastifyPluginAsyncTypebox = async (fastify) => { }, ) - fastify.delete( '/:connectionkeyId', async ( diff --git a/packages/backend/src/app/ee/connection-keys/connection-key.service.ts b/packages/server/api/src/app/ee/connection-keys/connection-key.service.ts similarity index 98% rename from packages/backend/src/app/ee/connection-keys/connection-key.service.ts rename to packages/server/api/src/app/ee/connection-keys/connection-key.service.ts index ad5e52bab0..19c0da00df 100644 --- a/packages/backend/src/app/ee/connection-keys/connection-key.service.ts +++ b/packages/server/api/src/app/ee/connection-keys/connection-key.service.ts @@ -44,7 +44,10 @@ export const connectionKeyService = { }, }) } - return appConnectionService.getOne({ projectId, name: `${finalAppName}_${connectionName}` }) + return appConnectionService.getOne({ + projectId, + name: `${finalAppName}_${connectionName}`, + }) }, async createConnection( request: UpsertConnectionFromToken, diff --git a/packages/backend/src/app/ee/custom-domains/custom-domain.entity.ts b/packages/server/api/src/app/ee/custom-domains/custom-domain.entity.ts similarity index 83% rename from packages/backend/src/app/ee/custom-domains/custom-domain.entity.ts rename to packages/server/api/src/app/ee/custom-domains/custom-domain.entity.ts index c472734160..10d0b45471 100644 --- a/packages/backend/src/app/ee/custom-domains/custom-domain.entity.ts +++ b/packages/server/api/src/app/ee/custom-domains/custom-domain.entity.ts @@ -1,6 +1,13 @@ -import { CustomDomain, CustomDomainStatus, Platform } from '@activepieces/ee-shared' +import { + CustomDomain, + CustomDomainStatus, + Platform, +} from '@activepieces/ee-shared' import { EntitySchema } from 'typeorm' -import { ApIdSchema, BaseColumnSchemaPart } from '../../database/database-common' +import { + ApIdSchema, + BaseColumnSchemaPart, +} from '../../database/database-common' type CustomDomainSchema = CustomDomain & { platform?: Platform @@ -41,4 +48,4 @@ export const CustomDomainEntity = new EntitySchema({ }, }, }, -}) \ No newline at end of file +}) diff --git a/packages/backend/src/app/ee/custom-domains/custom-domain.module.ts b/packages/server/api/src/app/ee/custom-domains/custom-domain.module.ts similarity index 63% rename from packages/backend/src/app/ee/custom-domains/custom-domain.module.ts rename to packages/server/api/src/app/ee/custom-domains/custom-domain.module.ts index 35019b635c..869a1a4fa9 100644 --- a/packages/backend/src/app/ee/custom-domains/custom-domain.module.ts +++ b/packages/server/api/src/app/ee/custom-domains/custom-domain.module.ts @@ -1,12 +1,18 @@ -import { AddDomainRequest, ListCustomDomainsRequest } from '@activepieces/ee-shared' -import { FastifyPluginAsyncTypebox, Static, Type } from '@fastify/type-provider-typebox' +import { + AddDomainRequest, + ListCustomDomainsRequest, +} from '@activepieces/ee-shared' +import { + FastifyPluginAsyncTypebox, + Static, + Type, +} from '@fastify/type-provider-typebox' import { customDomainService } from './custom-domain.service' import { HttpStatusCode } from 'axios' import { platformMustBeOwnedByCurrentUser } from '../authentication/ee-authorization' import { assertNotNullOrUndefined } from '@activepieces/shared' import { StatusCodes } from 'http-status-codes' - const GetOneRequest = Type.Object({ id: Type.String(), }) @@ -18,7 +24,6 @@ export const customDomainModule: FastifyPluginAsyncTypebox = async (app) => { } const customDomainController: FastifyPluginAsyncTypebox = async (app) => { - app.post( '/', { @@ -26,10 +31,7 @@ const customDomainController: FastifyPluginAsyncTypebox = async (app) => { body: AddDomainRequest, }, }, - async ( - request, - reply, - ) => { + async (request, reply) => { const platformId = request.principal.platform?.id assertNotNullOrUndefined(platformId, 'platformId') @@ -38,11 +40,9 @@ const customDomainController: FastifyPluginAsyncTypebox = async (app) => { }) if (domain) { - return reply - .status(HttpStatusCode.Conflict) - .send({ - message: `Domain ${request.body.domain} already exists`, - }) + return reply.status(HttpStatusCode.Conflict).send({ + message: `Domain ${request.body.domain} already exists`, + }) } const customDomain = await customDomainService.create({ @@ -50,25 +50,27 @@ const customDomainController: FastifyPluginAsyncTypebox = async (app) => { platformId, }) - return reply - .status(StatusCodes.CREATED) - .send(customDomain) + return reply.status(StatusCodes.CREATED).send(customDomain) }, ) - app.get('/', { - schema: { - querystring: ListCustomDomainsRequest, + app.get( + '/', + { + schema: { + querystring: ListCustomDomainsRequest, + }, }, - }, async (request) => { - const platformId = request.principal.platform?.id - assertNotNullOrUndefined(platformId, 'platformId') + async (request) => { + const platformId = request.principal.platform?.id + assertNotNullOrUndefined(platformId, 'platformId') - return customDomainService.list({ - platformId, - request: request.query, - }) - }) + return customDomainService.list({ + platformId, + request: request.query, + }) + }, + ) app.delete( '/:id', @@ -77,9 +79,7 @@ const customDomainController: FastifyPluginAsyncTypebox = async (app) => { params: GetOneRequest, }, }, - async ( - request, - ) => { + async (request) => { const platformId = request.principal.platform?.id assertNotNullOrUndefined(platformId, 'platformId') return customDomainService.delete({ @@ -89,4 +89,3 @@ const customDomainController: FastifyPluginAsyncTypebox = async (app) => { }, ) } - diff --git a/packages/backend/src/app/ee/custom-domains/custom-domain.service.ts b/packages/server/api/src/app/ee/custom-domains/custom-domain.service.ts similarity index 69% rename from packages/backend/src/app/ee/custom-domains/custom-domain.service.ts rename to packages/server/api/src/app/ee/custom-domains/custom-domain.service.ts index 6d9be4b75d..769e262eab 100644 --- a/packages/backend/src/app/ee/custom-domains/custom-domain.service.ts +++ b/packages/server/api/src/app/ee/custom-domains/custom-domain.service.ts @@ -1,11 +1,16 @@ -import { CustomDomain, CustomDomainStatus, ListCustomDomainsRequest } from '@activepieces/ee-shared' +import { + CustomDomain, + CustomDomainStatus, + ListCustomDomainsRequest, +} from '@activepieces/ee-shared' import { databaseConnection } from '../../database/database-connection' import { CustomDomainEntity } from './custom-domain.entity' import { paginationHelper } from '../../helper/pagination/pagination-utils' import { buildPaginator } from '../../helper/pagination/build-paginator' import { SeekPage, apId } from '@activepieces/shared' -const customDomainRepo = databaseConnection.getRepository(CustomDomainEntity) +const customDomainRepo = + databaseConnection.getRepository(CustomDomainEntity) export const customDomainService = { async delete(request: { id: string, platformId: string }): Promise { @@ -14,17 +19,24 @@ export const customDomainService = { platformId: request.platformId, }) }, - async getOneByDomain(request: { domain: string }): Promise { + async getOneByDomain(request: { + domain: string + }): Promise { return customDomainRepo.findOneBy({ domain: request.domain, }) }, - async getOneByPlatform(request: { platformId: string }): Promise { + async getOneByPlatform(request: { + platformId: string + }): Promise { return customDomainRepo.findOneBy({ platformId: request.platformId, }) }, - async create(request: { domain: string, platformId: string }): Promise { + async create(request: { + domain: string + platformId: string + }): Promise { const customDomain = customDomainRepo.create({ id: apId(), domain: request.domain, @@ -33,7 +45,13 @@ export const customDomainService = { }) return customDomainRepo.save(customDomain) }, - async list({ request, platformId }: { platformId: string, request: ListCustomDomainsRequest }): Promise> { + async list({ + request, + platformId, + }: { + platformId: string + request: ListCustomDomainsRequest + }): Promise> { const decodedCursor = paginationHelper.decodeCursor(request.cursor ?? null) const paginator = buildPaginator({ entity: CustomDomainEntity, @@ -50,10 +68,6 @@ export const customDomainService = { platformId, }) const { data, cursor } = await paginator.paginate(queryBuilder) - return paginationHelper.createPage( - data, - cursor, - ) + return paginationHelper.createPage(data, cursor) }, } - diff --git a/packages/server/api/src/app/ee/database/migrations/postgres/1685053959806-MakeStripeSubscriptionNullable.ts b/packages/server/api/src/app/ee/database/migrations/postgres/1685053959806-MakeStripeSubscriptionNullable.ts new file mode 100644 index 0000000000..ca8f0a02b6 --- /dev/null +++ b/packages/server/api/src/app/ee/database/migrations/postgres/1685053959806-MakeStripeSubscriptionNullable.ts @@ -0,0 +1,18 @@ +import { MigrationInterface, QueryRunner } from 'typeorm' + +export class MakeStripeSubscriptionNullable1685053959806 +implements MigrationInterface { + name = 'MakeStripeSubscriptionNullable1685053959806' + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query( + 'ALTER TABLE "project_plan" ALTER COLUMN "stripeSubscriptionId" DROP NOT NULL', + ) + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query( + 'ALTER TABLE "project_plan" ADD "name" character varying NOT NULL', + ) + } +} diff --git a/packages/server/api/src/app/ee/database/migrations/postgres/1685538145476-addTemplates.ts b/packages/server/api/src/app/ee/database/migrations/postgres/1685538145476-addTemplates.ts new file mode 100644 index 0000000000..ae1dc2ad8c --- /dev/null +++ b/packages/server/api/src/app/ee/database/migrations/postgres/1685538145476-addTemplates.ts @@ -0,0 +1,23 @@ +import { MigrationInterface, QueryRunner } from 'typeorm' + +export class AddTemplates1685538145476 implements MigrationInterface { + name = 'AddTemplates1685538145476' + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query( + 'CREATE TABLE "flow_template" ("id" character varying(21) NOT NULL, "created" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "updated" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "name" character varying NOT NULL, "description" character varying NOT NULL, "template" jsonb NOT NULL, "tags" character varying array NOT NULL, "pieces" character varying array NOT NULL, CONSTRAINT "PK_fcacbf8776a0a3337eb8eca7478" PRIMARY KEY ("id"))', + ) + await queryRunner.query( + 'CREATE INDEX "idx_flow_template_tags" ON "flow_template" ("tags") ', + ) + await queryRunner.query( + 'CREATE INDEX "idx_flow_template_pieces" ON "flow_template" ("pieces") ', + ) + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query('DROP INDEX "public"."idx_flow_template_pieces"') + await queryRunner.query('DROP INDEX "public"."idx_flow_template_tags"') + await queryRunner.query('DROP TABLE "flow_template"') + } +} diff --git a/packages/server/api/src/app/ee/database/migrations/postgres/1685991260335-ChangeToJsonToPeserveKeys.ts b/packages/server/api/src/app/ee/database/migrations/postgres/1685991260335-ChangeToJsonToPeserveKeys.ts new file mode 100644 index 0000000000..1e277a58bb --- /dev/null +++ b/packages/server/api/src/app/ee/database/migrations/postgres/1685991260335-ChangeToJsonToPeserveKeys.ts @@ -0,0 +1,36 @@ +import { MigrationInterface, QueryRunner } from 'typeorm' + +export class ChangeToJsonToKeepKeysOrder1685991260335 +implements MigrationInterface { + name = 'ChangeToJsonToKeepKeysOrder1685991260335' + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query( + 'ALTER TABLE "piece_metadata" DROP COLUMN "actions"', + ) + await queryRunner.query( + 'ALTER TABLE "piece_metadata" ADD "actions" json NOT NULL', + ) + await queryRunner.query( + 'ALTER TABLE "piece_metadata" DROP COLUMN "triggers"', + ) + await queryRunner.query( + 'ALTER TABLE "piece_metadata" ADD "triggers" json NOT NULL', + ) + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query( + 'ALTER TABLE "piece_metadata" DROP COLUMN "triggers"', + ) + await queryRunner.query( + 'ALTER TABLE "piece_metadata" ADD "triggers" jsonb NOT NULL', + ) + await queryRunner.query( + 'ALTER TABLE "piece_metadata" DROP COLUMN "actions"', + ) + await queryRunner.query( + 'ALTER TABLE "piece_metadata" ADD "actions" jsonb NOT NULL', + ) + } +} diff --git a/packages/server/api/src/app/ee/database/migrations/postgres/1686133672743-AddPinnedAndBlogUrlToTemplates.ts b/packages/server/api/src/app/ee/database/migrations/postgres/1686133672743-AddPinnedAndBlogUrlToTemplates.ts new file mode 100644 index 0000000000..62c34764b1 --- /dev/null +++ b/packages/server/api/src/app/ee/database/migrations/postgres/1686133672743-AddPinnedAndBlogUrlToTemplates.ts @@ -0,0 +1,22 @@ +import { MigrationInterface, QueryRunner } from 'typeorm' + +export class AddPinnedAndBlogUrlToTemplates1686133672743 +implements MigrationInterface { + name = 'AddPinnedAndBlogUrlToTemplates1686133672743' + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query( + 'ALTER TABLE "flow_template" ADD "pinned" boolean NOT NULL', + ) + await queryRunner.query( + 'ALTER TABLE "flow_template" ADD "blogUrl" character varying NOT NULL', + ) + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query( + 'ALTER TABLE "flow_template" DROP COLUMN "blogUrl"', + ) + await queryRunner.query('ALTER TABLE "flow_template" DROP COLUMN "pinned"') + } +} diff --git a/packages/server/api/src/app/ee/database/migrations/postgres/1686154285890-add_pinned_order.ts b/packages/server/api/src/app/ee/database/migrations/postgres/1686154285890-add_pinned_order.ts new file mode 100644 index 0000000000..c30ea15adc --- /dev/null +++ b/packages/server/api/src/app/ee/database/migrations/postgres/1686154285890-add_pinned_order.ts @@ -0,0 +1,27 @@ +import { MigrationInterface, QueryRunner } from 'typeorm' + +export class AddPinnedOrder1686154285890 implements MigrationInterface { + name = 'AddPinnedOrder1686154285890' + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query('ALTER TABLE "flow_template" DROP COLUMN "pinned"') + await queryRunner.query( + 'ALTER TABLE "flow_template" ADD "pinnedOrder" integer', + ) + await queryRunner.query( + 'ALTER TABLE "flow_template" ALTER COLUMN "blogUrl" DROP NOT NULL', + ) + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query( + 'ALTER TABLE "flow_template" ALTER COLUMN "blogUrl" SET NOT NULL', + ) + await queryRunner.query( + 'ALTER TABLE "flow_template" DROP COLUMN "pinnedOrder"', + ) + await queryRunner.query( + 'ALTER TABLE "flow_template" ADD "pinned" boolean NOT NULL', + ) + } +} diff --git a/packages/server/api/src/app/ee/database/migrations/postgres/1688083336934-AddProjectIdToTemplate.ts b/packages/server/api/src/app/ee/database/migrations/postgres/1688083336934-AddProjectIdToTemplate.ts new file mode 100644 index 0000000000..1fc6088317 --- /dev/null +++ b/packages/server/api/src/app/ee/database/migrations/postgres/1688083336934-AddProjectIdToTemplate.ts @@ -0,0 +1,26 @@ +import { MigrationInterface, QueryRunner } from 'typeorm' +import { logger } from 'server-shared' + +export class AddProjectIdToTemplate1688083336934 implements MigrationInterface { + name = 'AddProjectIdToTemplate1688083336934' + + public async up(queryRunner: QueryRunner): Promise { + logger.info('Running migration AddProjectIdToTemplate1688083336934') + await queryRunner.query( + 'ALTER TABLE "flow_template" ADD "projectId" character varying', + ) + await queryRunner.query( + 'ALTER TABLE "flow_template" ADD CONSTRAINT "fk_flow_template_project_id" FOREIGN KEY ("projectId") REFERENCES "project"("id") ON DELETE CASCADE ON UPDATE NO ACTION', + ) + logger.info('Finished migration AddProjectIdToTemplate1688083336934') + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query( + 'ALTER TABLE "flow_template" DROP CONSTRAINT "fk_flow_template_project_id"', + ) + await queryRunner.query( + 'ALTER TABLE "flow_template" DROP COLUMN "projectId"', + ) + } +} diff --git a/packages/server/api/src/app/ee/database/migrations/postgres/1688739844617-AddBillingParameters.ts b/packages/server/api/src/app/ee/database/migrations/postgres/1688739844617-AddBillingParameters.ts new file mode 100644 index 0000000000..6791fe84b2 --- /dev/null +++ b/packages/server/api/src/app/ee/database/migrations/postgres/1688739844617-AddBillingParameters.ts @@ -0,0 +1,53 @@ +import { MigrationInterface, QueryRunner } from 'typeorm' + +export class AddBillingParameters1688739844617 implements MigrationInterface { + name = 'AddBillingParameters1688739844617' + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query( + 'ALTER TABLE "project_plan" ADD "minimumPollingInterval" integer NOT NULL DEFAULT 5', + ) + await queryRunner.query( + 'ALTER TABLE "project_plan" ADD "activeFlows" integer NOT NULL DEFAULT 100', + ) + await queryRunner.query( + 'ALTER TABLE "project_plan" ADD "connections" integer NOT NULL DEFAULT 100', + ) + await queryRunner.query( + 'ALTER TABLE "project_plan" ADD "teamMembers" integer NOT NULL DEFAULT 1', + ) + await queryRunner.query( + 'ALTER TABLE "project_usage" ADD "activeFlows" integer NOT NULL DEFAULT 0', + ) + await queryRunner.query( + 'ALTER TABLE "project_usage" ADD "connections" integer NOT NULL DEFAULT 0', + ) + await queryRunner.query( + 'ALTER TABLE "project_usage" ADD "teamMembers" integer NOT NULL DEFAULT 0', + ) + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query( + 'ALTER TABLE "project_usage" DROP COLUMN "teamMembers"', + ) + await queryRunner.query( + 'ALTER TABLE "project_usage" DROP COLUMN "connections"', + ) + await queryRunner.query( + 'ALTER TABLE "project_usage" DROP COLUMN "activeFlows"', + ) + await queryRunner.query( + 'ALTER TABLE "project_plan" DROP COLUMN "teamMembers"', + ) + await queryRunner.query( + 'ALTER TABLE "project_plan" DROP COLUMN "connections"', + ) + await queryRunner.query( + 'ALTER TABLE "project_plan" DROP COLUMN "activeFlows"', + ) + await queryRunner.query( + 'ALTER TABLE "project_plan" DROP COLUMN "minimumPollingInterval"', + ) + } +} diff --git a/packages/backend/src/app/ee/database/migrations/postgres/1688943462327-AddAppSumo.ts b/packages/server/api/src/app/ee/database/migrations/postgres/1688943462327-AddAppSumo.ts similarity index 57% rename from packages/backend/src/app/ee/database/migrations/postgres/1688943462327-AddAppSumo.ts rename to packages/server/api/src/app/ee/database/migrations/postgres/1688943462327-AddAppSumo.ts index 92f2422b1c..ef6771f316 100644 --- a/packages/backend/src/app/ee/database/migrations/postgres/1688943462327-AddAppSumo.ts +++ b/packages/server/api/src/app/ee/database/migrations/postgres/1688943462327-AddAppSumo.ts @@ -4,11 +4,12 @@ export class AddAppSumo1688943462327 implements MigrationInterface { name = 'AddAppSumo1688943462327' public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query('CREATE TABLE "appsumo" ("uuid" character varying NOT NULL, "plan_id" character varying NOT NULL, "activation_email" character varying NOT NULL, CONSTRAINT "PK_3589df5be2973351814f727ae86" PRIMARY KEY ("uuid"))') + await queryRunner.query( + 'CREATE TABLE "appsumo" ("uuid" character varying NOT NULL, "plan_id" character varying NOT NULL, "activation_email" character varying NOT NULL, CONSTRAINT "PK_3589df5be2973351814f727ae86" PRIMARY KEY ("uuid"))', + ) } public async down(queryRunner: QueryRunner): Promise { await queryRunner.query('DROP TABLE "appsumo"') } - } diff --git a/packages/server/api/src/app/ee/database/migrations/postgres/1689177797092-AddProjectMembers.ts b/packages/server/api/src/app/ee/database/migrations/postgres/1689177797092-AddProjectMembers.ts new file mode 100644 index 0000000000..0e762237cf --- /dev/null +++ b/packages/server/api/src/app/ee/database/migrations/postgres/1689177797092-AddProjectMembers.ts @@ -0,0 +1,21 @@ +import { MigrationInterface, QueryRunner } from 'typeorm' + +export class AddProjectMembers1689177797092 implements MigrationInterface { + name = 'AddProjectMembers1689177797092' + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query( + 'CREATE TABLE "project_member" ("id" character varying(21) NOT NULL, "created" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "updated" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "userId" character varying(21) NOT NULL, "projectId" character varying(21) NOT NULL, "role" character varying NOT NULL, "status" character varying NOT NULL, CONSTRAINT "PK_64dba8e9dcf96ce383cfd19d6fb" PRIMARY KEY ("id"))', + ) + await queryRunner.query( + 'CREATE UNIQUE INDEX "idx_project_member_project_id_user_id" ON "project_member" ("projectId", "userId") ', + ) + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query( + 'DROP INDEX "public"."idx_project_member_project_id_user_id"', + ) + await queryRunner.query('DROP TABLE "project_member"') + } +} diff --git a/packages/server/api/src/app/ee/database/migrations/postgres/1689336533370-AddTasksPerDays.ts b/packages/server/api/src/app/ee/database/migrations/postgres/1689336533370-AddTasksPerDays.ts new file mode 100644 index 0000000000..ec606468c3 --- /dev/null +++ b/packages/server/api/src/app/ee/database/migrations/postgres/1689336533370-AddTasksPerDays.ts @@ -0,0 +1,59 @@ +import { MigrationInterface, QueryRunner } from 'typeorm' + +export class AddTasksPerDays1689336533370 implements MigrationInterface { + name = 'AddTasksPerDays1689336533370' + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query( + 'ALTER TABLE "project_plan" ADD "tasksPerDay" integer', + ) + await queryRunner.query( + 'ALTER TABLE "project_plan" ALTER COLUMN "minimumPollingInterval" DROP DEFAULT', + ) + await queryRunner.query( + 'ALTER TABLE "project_plan" ALTER COLUMN "activeFlows" DROP DEFAULT', + ) + await queryRunner.query( + 'ALTER TABLE "project_plan" ALTER COLUMN "connections" DROP DEFAULT', + ) + await queryRunner.query( + 'ALTER TABLE "project_plan" ALTER COLUMN "teamMembers" DROP DEFAULT', + ) + await queryRunner.query( + 'ALTER TABLE "project_usage" ALTER COLUMN "activeFlows" DROP DEFAULT', + ) + await queryRunner.query( + 'ALTER TABLE "project_usage" ALTER COLUMN "connections" DROP DEFAULT', + ) + await queryRunner.query( + 'ALTER TABLE "project_usage" ALTER COLUMN "teamMembers" DROP DEFAULT', + ) + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query( + 'ALTER TABLE "project_usage" ALTER COLUMN "teamMembers" SET DEFAULT \'0\'', + ) + await queryRunner.query( + 'ALTER TABLE "project_usage" ALTER COLUMN "connections" SET DEFAULT \'0\'', + ) + await queryRunner.query( + 'ALTER TABLE "project_usage" ALTER COLUMN "activeFlows" SET DEFAULT \'0\'', + ) + await queryRunner.query( + 'ALTER TABLE "project_plan" ALTER COLUMN "teamMembers" SET DEFAULT \'1\'', + ) + await queryRunner.query( + 'ALTER TABLE "project_plan" ALTER COLUMN "connections" SET DEFAULT \'100\'', + ) + await queryRunner.query( + 'ALTER TABLE "project_plan" ALTER COLUMN "activeFlows" SET DEFAULT \'100\'', + ) + await queryRunner.query( + 'ALTER TABLE "project_plan" ALTER COLUMN "minimumPollingInterval" SET DEFAULT \'5\'', + ) + await queryRunner.query( + 'ALTER TABLE "project_plan" DROP COLUMN "tasksPerDay"', + ) + } +} diff --git a/packages/server/api/src/app/ee/database/migrations/postgres/1689806173642-RemoveCalculatedMetrics.ts b/packages/server/api/src/app/ee/database/migrations/postgres/1689806173642-RemoveCalculatedMetrics.ts new file mode 100644 index 0000000000..ef29637711 --- /dev/null +++ b/packages/server/api/src/app/ee/database/migrations/postgres/1689806173642-RemoveCalculatedMetrics.ts @@ -0,0 +1,30 @@ +import { MigrationInterface, QueryRunner } from 'typeorm' + +export class RemoveCalculatedMetrics1689806173642 +implements MigrationInterface { + name = 'RemoveCalculatedMetrics1689806173642' + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query( + 'ALTER TABLE "project_usage" DROP COLUMN "activeFlows"', + ) + await queryRunner.query( + 'ALTER TABLE "project_usage" DROP COLUMN "connections"', + ) + await queryRunner.query( + 'ALTER TABLE "project_usage" DROP COLUMN "teamMembers"', + ) + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query( + 'ALTER TABLE "project_usage" ADD "teamMembers" integer NOT NULL', + ) + await queryRunner.query( + 'ALTER TABLE "project_usage" ADD "connections" integer NOT NULL', + ) + await queryRunner.query( + 'ALTER TABLE "project_usage" ADD "activeFlows" integer NOT NULL', + ) + } +} diff --git a/packages/server/api/src/app/ee/database/migrations/postgres/1690459469381-AddReferral.ts b/packages/server/api/src/app/ee/database/migrations/postgres/1690459469381-AddReferral.ts new file mode 100644 index 0000000000..a19f750b1f --- /dev/null +++ b/packages/server/api/src/app/ee/database/migrations/postgres/1690459469381-AddReferral.ts @@ -0,0 +1,33 @@ +import { MigrationInterface, QueryRunner } from 'typeorm' + +export class AddReferral1690459469381 implements MigrationInterface { + name = 'AddReferral1690459469381' + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query( + 'CREATE TABLE "referal" ("id" character varying(21) NOT NULL, "created" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "updated" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "referredUserId" character varying(21) NOT NULL, "referringUserId" character varying(21) NOT NULL, CONSTRAINT "PK_567787298ed6c13527df7887096" PRIMARY KEY ("id"))', + ) + await queryRunner.query( + 'CREATE UNIQUE INDEX "idx_referral_referring_user_id" ON "referal" ("referredUserId", "referringUserId") ', + ) + await queryRunner.query( + 'ALTER TABLE "referal" ADD CONSTRAINT "fk_referral_referred_user_id" FOREIGN KEY ("referredUserId") REFERENCES "user"("id") ON DELETE CASCADE ON UPDATE NO ACTION', + ) + await queryRunner.query( + 'ALTER TABLE "referal" ADD CONSTRAINT "fk_referral_referring_user_id" FOREIGN KEY ("referringUserId") REFERENCES "user"("id") ON DELETE CASCADE ON UPDATE NO ACTION', + ) + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query( + 'ALTER TABLE "referal" DROP CONSTRAINT "fk_referral_referring_user_id"', + ) + await queryRunner.query( + 'ALTER TABLE "referal" DROP CONSTRAINT "fk_referral_referred_user_id"', + ) + await queryRunner.query( + 'DROP INDEX "public"."idx_referral_referring_user_id"', + ) + await queryRunner.query('DROP TABLE "referal"') + } +} diff --git a/packages/server/api/src/app/ee/database/migrations/postgres/1694379223109-flow-template-add-user-id-and-image-url.ts b/packages/server/api/src/app/ee/database/migrations/postgres/1694379223109-flow-template-add-user-id-and-image-url.ts new file mode 100644 index 0000000000..1fdb71c828 --- /dev/null +++ b/packages/server/api/src/app/ee/database/migrations/postgres/1694379223109-flow-template-add-user-id-and-image-url.ts @@ -0,0 +1,57 @@ +import { MigrationInterface, QueryRunner } from 'typeorm' +import { logger } from 'server-shared' + +export class FlowTemplateAddUserIdAndImageUrl1694379223109 +implements MigrationInterface { + name = 'FlowTemplateAddUserIdAndImageUrl1694379223109' + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query( + 'ALTER TABLE "flow_template" DROP COLUMN "pinnedOrder"', + ) + await queryRunner.query( + 'ALTER TABLE "flow_template" ADD "userId" character varying', + ) + await queryRunner.query( + 'ALTER TABLE "flow_template" ADD "imageUrl" character varying', + ) + await queryRunner.query( + 'ALTER TABLE "flow_template" DROP CONSTRAINT "fk_flow_template_project_id"', + ) + await queryRunner.query( + 'ALTER TABLE "flow_template" ALTER COLUMN "projectId" SET NOT NULL', + ) + await queryRunner.query( + 'ALTER TABLE "flow_template" ADD CONSTRAINT "fk_flow_template_project_id" FOREIGN KEY ("projectId") REFERENCES "project"("id") ON DELETE CASCADE ON UPDATE NO ACTION', + ) + await queryRunner.query( + 'ALTER TABLE "flow_template" ADD CONSTRAINT "fk_flow_template_user_id" FOREIGN KEY ("userId") REFERENCES "user"("id") ON DELETE CASCADE ON UPDATE NO ACTION', + ) + + logger.info('FlowTemplateAddUserIdAndImageUrl1694379223109 up') + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query( + 'ALTER TABLE "flow_template" DROP CONSTRAINT "fk_flow_template_user_id"', + ) + await queryRunner.query( + 'ALTER TABLE "flow_template" DROP CONSTRAINT "fk_flow_template_project_id"', + ) + await queryRunner.query( + 'ALTER TABLE "flow_template" ALTER COLUMN "projectId" DROP NOT NULL', + ) + await queryRunner.query( + 'ALTER TABLE "flow_template" ADD CONSTRAINT "fk_flow_template_project_id" FOREIGN KEY ("projectId") REFERENCES "project"("id") ON DELETE CASCADE ON UPDATE NO ACTION', + ) + await queryRunner.query( + 'ALTER TABLE "flow_template" DROP COLUMN "imageUrl"', + ) + await queryRunner.query('ALTER TABLE "flow_template" DROP COLUMN "userId"') + await queryRunner.query( + 'ALTER TABLE "flow_template" ADD "pinnedOrder" integer', + ) + + logger.info('FlowTemplateAddUserIdAndImageUrl1694379223109 down') + } +} diff --git a/packages/server/api/src/app/ee/database/migrations/postgres/1694381968985-project-member-relations.ts b/packages/server/api/src/app/ee/database/migrations/postgres/1694381968985-project-member-relations.ts new file mode 100644 index 0000000000..2ad90a0537 --- /dev/null +++ b/packages/server/api/src/app/ee/database/migrations/postgres/1694381968985-project-member-relations.ts @@ -0,0 +1,28 @@ +import { MigrationInterface, QueryRunner } from 'typeorm' +import { logger } from 'server-shared' + +export class ProjectMemberRelations1694381968985 implements MigrationInterface { + name = 'ProjectMemberRelations1694381968985' + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query( + 'ALTER TABLE "project_member" ADD CONSTRAINT "fk_project_member_user_id" FOREIGN KEY ("userId") REFERENCES "user"("id") ON DELETE CASCADE ON UPDATE NO ACTION', + ) + await queryRunner.query( + 'ALTER TABLE "project_member" ADD CONSTRAINT "fk_project_member_project_id" FOREIGN KEY ("projectId") REFERENCES "project"("id") ON DELETE CASCADE ON UPDATE NO ACTION', + ) + + logger.info('ProjectMemberRelations1694381968985 up') + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query( + 'ALTER TABLE "project_member" DROP CONSTRAINT "fk_project_member_project_id"', + ) + await queryRunner.query( + 'ALTER TABLE "project_member" DROP CONSTRAINT "fk_project_member_user_id"', + ) + + logger.info('ProjectMemberRelations1694381968985 down') + } +} diff --git a/packages/server/api/src/app/ee/database/migrations/postgres/1694604120205-AddFeaturedDescriptionAndFlagToTemplates.ts b/packages/server/api/src/app/ee/database/migrations/postgres/1694604120205-AddFeaturedDescriptionAndFlagToTemplates.ts new file mode 100644 index 0000000000..32a0f9639d --- /dev/null +++ b/packages/server/api/src/app/ee/database/migrations/postgres/1694604120205-AddFeaturedDescriptionAndFlagToTemplates.ts @@ -0,0 +1,24 @@ +import { MigrationInterface, QueryRunner } from 'typeorm' + +export class AddFeaturedDescriptionAndFlagToTemplates1694604120205 +implements MigrationInterface { + name = 'AddFeaturedDescriptionAndFlagToTemplates1694604120205' + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query( + 'ALTER TABLE "flow_template" ADD "isFeatured" boolean', + ) + await queryRunner.query( + 'ALTER TABLE "flow_template" ADD "featuredDescription" character varying', + ) + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query( + 'ALTER TABLE "flow_template" DROP COLUMN "featuredDescription"', + ) + await queryRunner.query( + 'ALTER TABLE "flow_template" DROP COLUMN "isFeatured"', + ) + } +} diff --git a/packages/server/api/src/app/ee/database/migrations/postgres/1694902537045-ModifyBilling.ts b/packages/server/api/src/app/ee/database/migrations/postgres/1694902537045-ModifyBilling.ts new file mode 100644 index 0000000000..a616462d5f --- /dev/null +++ b/packages/server/api/src/app/ee/database/migrations/postgres/1694902537045-ModifyBilling.ts @@ -0,0 +1,46 @@ +import { MigrationInterface, QueryRunner } from 'typeorm' + +export class ModifyBilling1694902537045 implements MigrationInterface { + name = 'ModifyBilling1694902537045' + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query( + 'ALTER TABLE "project_plan" RENAME COLUMN "name" TO "flowPlanName"', + ) + await queryRunner.query( + 'ALTER TABLE "project_plan" ADD "botPlanName" character varying NOT NULL DEFAULT \'free\'', + ) + await queryRunner.query( + 'ALTER TABLE "project_plan" ADD "bots" integer NOT NULL DEFAULT 1', + ) + await queryRunner.query( + 'ALTER TABLE "project_plan" ADD "datasourcesSize" integer NOT NULL DEFAULT 10485760', + ) + await queryRunner.query( + 'ALTER TABLE "project_usage" ADD "datasourcesSize" integer NOT NULL DEFAULT \'0\'', + ) + await queryRunner.query( + 'ALTER TABLE "project_usage" ADD "bots" integer NOT NULL DEFAULT \'0\'', + ) + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query('ALTER TABLE "project_usage" DROP COLUMN "bots"') + await queryRunner.query( + 'ALTER TABLE "project_usage" DROP COLUMN "datasourcesSize"', + ) + await queryRunner.query( + 'ALTER TABLE "project_plan" DROP COLUMN "datasourcesSize"', + ) + await queryRunner.query('ALTER TABLE "project_plan" DROP COLUMN "bots"') + await queryRunner.query( + 'ALTER TABLE "project_plan" DROP COLUMN "botPlanName"', + ) + await queryRunner.query( + 'ALTER TABLE "project_plan" DROP COLUMN "flowPlanName"', + ) + await queryRunner.query( + 'ALTER TABLE "project_plan" ADD "name" character varying NOT NULL', + ) + } +} diff --git a/packages/server/api/src/app/ee/database/migrations/postgres/1695916063833-AddDatasourcesLimit.ts b/packages/server/api/src/app/ee/database/migrations/postgres/1695916063833-AddDatasourcesLimit.ts new file mode 100644 index 0000000000..438b505d08 --- /dev/null +++ b/packages/server/api/src/app/ee/database/migrations/postgres/1695916063833-AddDatasourcesLimit.ts @@ -0,0 +1,19 @@ +import { MigrationInterface, QueryRunner } from 'typeorm' + +export class AddDatasourcesLimit1695916063833 implements MigrationInterface { + name = 'AddDatasourcesLimit1695916063833' + + public async up(queryRunner: QueryRunner): Promise { + // Add the "datasources" column with a default value of 1 + await queryRunner.query( + 'ALTER TABLE "project_plan" ADD "datasources" integer NOT NULL DEFAULT 1', + ) + } + + public async down(queryRunner: QueryRunner): Promise { + // Remove the "datasources" column + await queryRunner.query( + 'ALTER TABLE "project_plan" DROP COLUMN "datasources"', + ) + } +} diff --git a/packages/backend/src/app/ee/database/migrations/postgres/1697717995884-add-platform.ts b/packages/server/api/src/app/ee/database/migrations/postgres/1697717995884-add-platform.ts similarity index 96% rename from packages/backend/src/app/ee/database/migrations/postgres/1697717995884-add-platform.ts rename to packages/server/api/src/app/ee/database/migrations/postgres/1697717995884-add-platform.ts index 1545c2d440..04f1b02628 100644 --- a/packages/backend/src/app/ee/database/migrations/postgres/1697717995884-add-platform.ts +++ b/packages/server/api/src/app/ee/database/migrations/postgres/1697717995884-add-platform.ts @@ -1,4 +1,4 @@ -import { logger } from '../../../../helper/logger' +import { logger } from 'server-shared' import { MigrationInterface, QueryRunner } from 'typeorm' export class AddPlatform1697717995884 implements MigrationInterface { @@ -38,5 +38,4 @@ export class AddPlatform1697717995884 implements MigrationInterface { logger.info('AddPlatform1697717995884 down') } - } diff --git a/packages/backend/src/app/ee/database/migrations/postgres/1698077078271-AddCustomDomain.ts b/packages/server/api/src/app/ee/database/migrations/postgres/1698077078271-AddCustomDomain.ts similarity index 99% rename from packages/backend/src/app/ee/database/migrations/postgres/1698077078271-AddCustomDomain.ts rename to packages/server/api/src/app/ee/database/migrations/postgres/1698077078271-AddCustomDomain.ts index 291cb155eb..a550d9846f 100644 --- a/packages/backend/src/app/ee/database/migrations/postgres/1698077078271-AddCustomDomain.ts +++ b/packages/server/api/src/app/ee/database/migrations/postgres/1698077078271-AddCustomDomain.ts @@ -35,5 +35,4 @@ export class AddCustomDomain1698077078271 implements MigrationInterface { DROP TABLE "custom_domain" `) } - } diff --git a/packages/backend/src/app/ee/flags/enterprise-flags.hooks.ts b/packages/server/api/src/app/ee/flags/enterprise-flags.hooks.ts similarity index 82% rename from packages/backend/src/app/ee/flags/enterprise-flags.hooks.ts rename to packages/server/api/src/app/ee/flags/enterprise-flags.hooks.ts index 227f44a097..a3035705b9 100644 --- a/packages/backend/src/app/ee/flags/enterprise-flags.hooks.ts +++ b/packages/server/api/src/app/ee/flags/enterprise-flags.hooks.ts @@ -16,14 +16,20 @@ export const enterpriseFlagsHooks: FlagsServiceHooks = { } const platform = await platformService.getOneOrThrow(platformId) modifiedFlags[ApFlagId.THIRD_PARTY_AUTH_PROVIDERS_TO_SHOW_MAP] = { - [ThirdPartyAuthnProviderEnum.GOOGLE]: !isNil(platform.federatedAuthProviders.google), - [ThirdPartyAuthnProviderEnum.GITHUB]: !isNil(platform.federatedAuthProviders.github), + [ThirdPartyAuthnProviderEnum.GOOGLE]: !isNil( + platform.federatedAuthProviders.google, + ), + [ThirdPartyAuthnProviderEnum.GITHUB]: !isNil( + platform.federatedAuthProviders.github, + ), } modifiedFlags[ApFlagId.EMAIL_AUTH_ENABLED] = platform.emailAuthEnabled const isCustomerPlatform = !flagService.isCloudPlatform(platformId) if (isCustomerPlatform) { modifiedFlags[ApFlagId.SHOW_PLATFORM_DEMO] = false - modifiedFlags[ApFlagId.THEME] = await apperanceHelper.getTheme({ platformId }) + modifiedFlags[ApFlagId.THEME] = await apperanceHelper.getTheme({ + platformId, + }) modifiedFlags[ApFlagId.SHOW_COMMUNITY] = false modifiedFlags[ApFlagId.SHOW_DOCS] = false modifiedFlags[ApFlagId.SHOW_BILLING] = false @@ -35,8 +41,11 @@ export const enterpriseFlagsHooks: FlagsServiceHooks = { modifiedFlags[ApFlagId.CLOUD_AUTH_ENABLED] = platform.cloudAuthEnabled modifiedFlags[ApFlagId.SHOW_GIT_SYNC] = platform.gitSyncEnabled modifiedFlags[ApFlagId.FRONTEND_URL] = `https://${hostname}` - modifiedFlags[ApFlagId.WEBHOOK_URL_PREFIX] = `https://${hostname}/api/v1/webhooks` - modifiedFlags[ApFlagId.THIRD_PARTY_AUTH_PROVIDER_REDIRECT_URL] = flagService.getThirdPartyRedirectUrl(platform.id, hostname) + modifiedFlags[ + ApFlagId.WEBHOOK_URL_PREFIX + ] = `https://${hostname}/api/v1/webhooks` + modifiedFlags[ApFlagId.THIRD_PARTY_AUTH_PROVIDER_REDIRECT_URL] = + flagService.getThirdPartyRedirectUrl(platform.id, hostname) modifiedFlags[ApFlagId.PRIVACY_POLICY_URL] = platform.privacyPolicyUrl modifiedFlags[ApFlagId.TERMS_OF_SERVICE_URL] = platform.termsOfServiceUrl modifiedFlags[ApFlagId.OWN_AUTH2_ENABLED] = false diff --git a/packages/backend/src/app/ee/flow-run/cloud-flow-run-hooks.ts b/packages/server/api/src/app/ee/flow-run/cloud-flow-run-hooks.ts similarity index 84% rename from packages/backend/src/app/ee/flow-run/cloud-flow-run-hooks.ts rename to packages/server/api/src/app/ee/flow-run/cloud-flow-run-hooks.ts index 783c3d53aa..281dd43c8f 100644 --- a/packages/backend/src/app/ee/flow-run/cloud-flow-run-hooks.ts +++ b/packages/server/api/src/app/ee/flow-run/cloud-flow-run-hooks.ts @@ -10,7 +10,13 @@ export const platformRunHooks: FlowRunHooks = { projectId, }) }, - async onFinish({ projectId, tasks }: { projectId: string, tasks: number }): Promise { + async onFinish({ + projectId, + tasks, + }: { + projectId: string + tasks: number + }): Promise { const edition = getEdition() if ([ApEdition.CLOUD, ApEdition.ENTERPRISE].includes(edition)) { await projectUsageService.addTasksConsumed({ @@ -19,4 +25,4 @@ export const platformRunHooks: FlowRunHooks = { }) } }, -} \ No newline at end of file +} diff --git a/packages/backend/src/app/ee/flow-template/flow-template.entity.ts b/packages/server/api/src/app/ee/flow-template/flow-template.entity.ts similarity index 95% rename from packages/backend/src/app/ee/flow-template/flow-template.entity.ts rename to packages/server/api/src/app/ee/flow-template/flow-template.entity.ts index 5adc69d2de..9e400d15ea 100644 --- a/packages/backend/src/app/ee/flow-template/flow-template.entity.ts +++ b/packages/server/api/src/app/ee/flow-template/flow-template.entity.ts @@ -1,5 +1,8 @@ import { EntitySchema } from 'typeorm' -import { BaseColumnSchemaPart, JSONB_COLUMN_TYPE } from '../../database/database-common' +import { + BaseColumnSchemaPart, + JSONB_COLUMN_TYPE, +} from '../../database/database-common' import { FlowTemplate, Project, User } from '@activepieces/shared' import { Platform } from '@activepieces/ee-shared' diff --git a/packages/backend/src/app/ee/flow-template/flow-template.service.ts b/packages/server/api/src/app/ee/flow-template/flow-template.service.ts similarity index 55% rename from packages/backend/src/app/ee/flow-template/flow-template.service.ts rename to packages/server/api/src/app/ee/flow-template/flow-template.service.ts index fefb58bba3..7ecced76e0 100644 --- a/packages/backend/src/app/ee/flow-template/flow-template.service.ts +++ b/packages/server/api/src/app/ee/flow-template/flow-template.service.ts @@ -1,37 +1,66 @@ import { ArrayContains, ArrayOverlap, Equal, ILike } from 'typeorm' import { databaseConnection } from '../../database/database-connection' -import { ActivepiecesError, ListFlowTemplatesRequest, ErrorCode, FlowTemplate, SeekPage, isNil, apId, FlowVersionTemplate, flowHelper, TemplateType } from '@activepieces/shared' +import { + ActivepiecesError, + ListFlowTemplatesRequest, + ErrorCode, + FlowTemplate, + SeekPage, + isNil, + apId, + FlowVersionTemplate, + flowHelper, + TemplateType, +} from '@activepieces/shared' import { FlowTemplateEntity } from './flow-template.entity' import { CreateFlowTemplateRequest } from '@activepieces/ee-shared' import { paginationHelper } from '../../helper/pagination/pagination-utils' -const templateRepo = databaseConnection.getRepository(FlowTemplateEntity) +const templateRepo = + databaseConnection.getRepository(FlowTemplateEntity) export const flowTemplateService = { - upsert: async (platformId: string | undefined, projectId: string | undefined, { description, type, template, blogUrl, tags, id }: CreateFlowTemplateRequest): Promise => { + upsert: async ( + platformId: string | undefined, + projectId: string | undefined, + { + description, + type, + template, + blogUrl, + tags, + id, + }: CreateFlowTemplateRequest, + ): Promise => { const flowTemplate: FlowVersionTemplate = template const newTags = tags ?? [] const newId = id ?? apId() - await templateRepo.upsert({ - id: newId, - // eslint-disable-next-line @typescript-eslint/no-explicit-any - template: flowTemplate as any, - name: flowTemplate.displayName, - description: description ?? '', - pieces: flowHelper.getUsedPieces(flowTemplate.trigger), - blogUrl, - type, - tags: newTags, - created: new Date().toISOString(), - updated: new Date().toISOString(), - platformId, - projectId, - }, ['id']) + await templateRepo.upsert( + { + id: newId, + // eslint-disable-next-line @typescript-eslint/no-explicit-any + template: flowTemplate as any, + name: flowTemplate.displayName, + description: description ?? '', + pieces: flowHelper.getUsedPieces(flowTemplate.trigger), + blogUrl, + type, + tags: newTags, + created: new Date().toISOString(), + updated: new Date().toISOString(), + platformId, + projectId, + }, + ['id'], + ) return templateRepo.findOneByOrFail({ id: newId, }) }, - list: async (platformId: string, { pieces, tags, search }: ListFlowTemplatesRequest): Promise> => { + list: async ( + platformId: string, + { pieces, tags, search }: ListFlowTemplatesRequest, + ): Promise> => { const commonFilters: Record = {} if (pieces) { commonFilters.pieces = ArrayOverlap(pieces) @@ -45,7 +74,8 @@ export const flowTemplateService = { } commonFilters.platformId = Equal(platformId) commonFilters.type = Equal(TemplateType.PLATFORM) - const templates = await templateRepo.createQueryBuilder('flow_template') + const templates = await templateRepo + .createQueryBuilder('flow_template') .where(commonFilters) .getMany() return paginationHelper.createPage(templates, null) @@ -70,4 +100,3 @@ export const flowTemplateService = { }) }, } - diff --git a/packages/server/api/src/app/ee/flow-template/platform-flow-template.module.ts b/packages/server/api/src/app/ee/flow-template/platform-flow-template.module.ts new file mode 100644 index 0000000000..9324738015 --- /dev/null +++ b/packages/server/api/src/app/ee/flow-template/platform-flow-template.module.ts @@ -0,0 +1,159 @@ +import { flowTemplateService } from './flow-template.service' +import { + ListFlowTemplatesRequest, + ALL_PRINICPAL_TYPES, + PrincipalType, + TemplateType, + ActivepiecesError, + ErrorCode, + assertNotNullOrUndefined, + Principal, +} from '@activepieces/shared' +import { Static, Type } from '@sinclair/typebox' +import { FastifyPluginAsyncTypebox } from '@fastify/type-provider-typebox' +import { CreateFlowTemplateRequest } from '@activepieces/ee-shared' +import { platformService } from '../platform/platform.service' +import { StatusCodes } from 'http-status-codes' +import { SystemProp, system } from 'server-shared' + +export const platformFlowTemplateModule: FastifyPluginAsyncTypebox = async ( + app, +) => { + await app.register(flowTemplateController, { prefix: '/v1/flow-templates' }) +} + +const GetIdParams = Type.Object({ + id: Type.String(), +}) +type GetIdParams = Static + +const flowTemplateController: FastifyPluginAsyncTypebox = async (fastify) => { + fastify.get( + '/:id', + { + config: { + allowedPrincipals: ALL_PRINICPAL_TYPES, + }, + schema: { + params: GetIdParams, + }, + }, + async (request) => { + return flowTemplateService.getOrThrow(request.params.id) + }, + ) + + fastify.get( + '/', + { + config: { + allowedPrincipals: ALL_PRINICPAL_TYPES, + }, + schema: { + querystring: ListFlowTemplatesRequest, + }, + }, + async (request) => { + const platformId = + request.principal.platform?.id ?? + system.getOrThrow(SystemProp.CLOUD_PLATFORM_ID) + return flowTemplateService.list(platformId, request.query) + }, + ) + + fastify.post( + '/', + { + config: { + allowedPrincipals: [PrincipalType.USER], + }, + schema: { + body: CreateFlowTemplateRequest, + }, + }, + async (request) => { + const { type } = request.body + if (type === TemplateType.PLATFORM) { + await assertUserIsPlatformOwner({ + platformId: request.principal.platform?.id, + userId: request.principal.id, + }) + } + return flowTemplateService.upsert( + request.principal.platform?.id, + request.principal.projectId, + request.body, + ) + }, + ) + fastify.delete( + '/:id', + { + config: { + allowedPrincipals: [PrincipalType.USER], + }, + schema: { + params: GetIdParams, + }, + }, + async (request, reply) => { + await assertUserCanDeleteTemplate({ + templateId: request.params.id, + userId: request.principal.id, + principal: request.principal, + }) + await flowTemplateService.delete({ + id: request.params.id, + }) + return reply.status(StatusCodes.NO_CONTENT).send() + }, + ) +} + +async function assertUserCanDeleteTemplate({ + templateId, + userId, + principal, +}: { + templateId: string + userId: string + principal: Principal +}): Promise { + const template = await flowTemplateService.getOrThrow(templateId) + switch (template.type) { + case TemplateType.PLATFORM: + await assertUserIsPlatformOwner({ + platformId: template.platformId, + userId, + }) + break + case TemplateType.PROJECT: + if (template.projectId !== principal.projectId) { + throw new ActivepiecesError({ + code: ErrorCode.AUTHORIZATION, + params: {}, + }) + } + break + } +} + +async function assertUserIsPlatformOwner({ + platformId, + userId, +}: { + platformId?: string + userId: string +}): Promise { + assertNotNullOrUndefined(platformId, 'platformId') + const userOwner = await platformService.checkUserIsOwner({ + platformId, + userId, + }) + if (!userOwner) { + throw new ActivepiecesError({ + code: ErrorCode.AUTHORIZATION, + params: {}, + }) + } +} diff --git a/packages/server/api/src/app/ee/flow-worker/cloud-flow-worker-hooks.ts b/packages/server/api/src/app/ee/flow-worker/cloud-flow-worker-hooks.ts new file mode 100644 index 0000000000..30f2f0dbfa --- /dev/null +++ b/packages/server/api/src/app/ee/flow-worker/cloud-flow-worker-hooks.ts @@ -0,0 +1,48 @@ +import { + ActivepiecesError, + ApEdition, + ErrorCode, + ExecutionOutputStatus, +} from '@activepieces/shared' +import { getEdition } from '../../helper/secret-helper' +import { flowRunService } from '../../flows/flow-run/flow-run-service' +import { FlowWorkerHooks } from '../../workers/flow-worker/flow-worker-hooks' +import { tasksLimit } from '../billing/limits/tasks-limit' +import { exceptionHandler } from 'server-shared' + +export const platformWorkerHooks: FlowWorkerHooks = { + async preExecute({ + projectId, + runId, + }: { + projectId: string + runId: string + }): Promise { + const edition = getEdition() + if ([ApEdition.CLOUD, ApEdition.ENTERPRISE].includes(edition)) { + try { + await tasksLimit.limit({ + projectId, + }) + } + catch (e: unknown) { + if ( + e instanceof ActivepiecesError && + (e as ActivepiecesError).error.code === ErrorCode.QUOTA_EXCEEDED + ) { + await flowRunService.finish({ + flowRunId: runId, + status: ExecutionOutputStatus.QUOTA_EXCEEDED, + tasks: 0, + logsFileId: null, + tags: [], + }) + return + } + else { + exceptionHandler.handle(e) + } + } + } + }, +} diff --git a/packages/backend/src/app/ee/git-repos/git-repo.controller.ts b/packages/server/api/src/app/ee/git-repos/git-repo.controller.ts similarity index 81% rename from packages/backend/src/app/ee/git-repos/git-repo.controller.ts rename to packages/server/api/src/app/ee/git-repos/git-repo.controller.ts index 2f16d6e6fb..9d070a0942 100644 --- a/packages/backend/src/app/ee/git-repos/git-repo.controller.ts +++ b/packages/server/api/src/app/ee/git-repos/git-repo.controller.ts @@ -1,14 +1,25 @@ -import { FastifyPluginCallbackTypebox, Type } from '@fastify/type-provider-typebox' +import { + FastifyPluginCallbackTypebox, + Type, +} from '@fastify/type-provider-typebox' import { gitRepoService } from './git-repo.service' import { PrincipalType, SeekPage } from '@activepieces/shared' -import { ConfigureRepoRequest, GitRepoWithoutSenestiveData, PushGitRepoRequest } from '@activepieces/ee-shared' +import { + ConfigureRepoRequest, + GitRepoWithoutSenestiveData, + PushGitRepoRequest, +} from '@activepieces/ee-shared' import { StatusCodes } from 'http-status-codes' - -export const gitRepoController: FastifyPluginCallbackTypebox = (app, _options, done): void => { - +export const gitRepoController: FastifyPluginCallbackTypebox = ( + app, + _options, + done, +): void => { app.post('/', ConfigureRepoRequestSchema, async (request, reply) => { - await reply.status(StatusCodes.CREATED).send(await gitRepoService.upsert(request.body)) + await reply + .status(StatusCodes.CREATED) + .send(await gitRepoService.upsert(request.body)) }) app.get('/', ListRepoRequestSchema, async (request) => { @@ -60,7 +71,8 @@ const PullRepoRequestSchema = { allowedPrincipals: [PrincipalType.SERVICE, PrincipalType.USER], }, schema: { - description: 'Pull all changes from the git repository and overwrite any conflicting changes in the project.', + description: + 'Pull all changes from the git repository and overwrite any conflicting changes in the project.', params: Type.Object({ id: Type.String(), }), @@ -76,7 +88,8 @@ const PushRepoRequestSchema = { allowedPrincipals: [PrincipalType.USER], }, schema: { - description: 'Push all changes from the project and overwrite any conflicting changes in the git repository.', + description: + 'Push all changes from the project and overwrite any conflicting changes in the git repository.', body: PushGitRepoRequest, params: Type.Object({ id: Type.String(), @@ -112,4 +125,4 @@ const ListRepoRequestSchema = { [StatusCodes.OK]: SeekPage(GitRepoWithoutSenestiveData), }, }, -} \ No newline at end of file +} diff --git a/packages/backend/src/app/ee/git-repos/git-repo.entity.ts b/packages/server/api/src/app/ee/git-repos/git-repo.entity.ts similarity index 92% rename from packages/backend/src/app/ee/git-repos/git-repo.entity.ts rename to packages/server/api/src/app/ee/git-repos/git-repo.entity.ts index a3dbfdea30..5199c3c11f 100644 --- a/packages/backend/src/app/ee/git-repos/git-repo.entity.ts +++ b/packages/server/api/src/app/ee/git-repos/git-repo.entity.ts @@ -1,9 +1,11 @@ import { EntitySchema } from 'typeorm' import { GitRepo } from '@activepieces/ee-shared' -import { ApIdSchema, BaseColumnSchemaPart } from '../../database/database-common' +import { + ApIdSchema, + BaseColumnSchemaPart, +} from '../../database/database-common' import { Project } from '@activepieces/shared' - type GitRepoSchema = GitRepo & { project: Project } diff --git a/packages/backend/src/app/ee/git-repos/git-repo.module.ts b/packages/server/api/src/app/ee/git-repos/git-repo.module.ts similarity index 99% rename from packages/backend/src/app/ee/git-repos/git-repo.module.ts rename to packages/server/api/src/app/ee/git-repos/git-repo.module.ts index c182c508fd..1ad012cd5c 100644 --- a/packages/backend/src/app/ee/git-repos/git-repo.module.ts +++ b/packages/server/api/src/app/ee/git-repos/git-repo.module.ts @@ -4,4 +4,3 @@ import { gitRepoController } from './git-repo.controller' export const gitRepoModule: FastifyPluginAsync = async (app) => { await app.register(gitRepoController, { prefix: '/v1/git-repos' }) } - diff --git a/packages/backend/src/app/ee/git-repos/git-repo.service.ts b/packages/server/api/src/app/ee/git-repos/git-repo.service.ts similarity index 57% rename from packages/backend/src/app/ee/git-repos/git-repo.service.ts rename to packages/server/api/src/app/ee/git-repos/git-repo.service.ts index 03a492429d..b5999f9e96 100644 --- a/packages/backend/src/app/ee/git-repos/git-repo.service.ts +++ b/packages/server/api/src/app/ee/git-repos/git-repo.service.ts @@ -3,8 +3,19 @@ import fs from 'fs/promises' import path from 'path' import { databaseConnection } from '../../database/database-connection' import { GitRepoEntity } from './git-repo.entity' -import { ConfigureRepoRequest, GitRepo, PushGitRepoRequest, PushSyncMode } from '@activepieces/ee-shared' -import { ActivepiecesError, apId, ErrorCode, isNil, SeekPage } from '@activepieces/shared' +import { + ConfigureRepoRequest, + GitRepo, + PushGitRepoRequest, + PushSyncMode, +} from '@activepieces/ee-shared' +import { + ActivepiecesError, + apId, + ErrorCode, + isNil, + SeekPage, +} from '@activepieces/shared' import { paginationHelper } from '../../helper/pagination/pagination-utils' import { FlowSyncOperation, gitSyncHelper } from './git-sync-helper' import { flowService } from '../../flows/flow/flow.service' @@ -13,16 +24,24 @@ import { userService } from '../../user/user-service' const repo = databaseConnection.getRepository(GitRepoEntity) export const gitRepoService = { - async upsert({ projectId, sshPrivateKey, branch, remoteUrl }: ConfigureRepoRequest): Promise { + async upsert({ + projectId, + sshPrivateKey, + branch, + remoteUrl, + }: ConfigureRepoRequest): Promise { const existingRepo = await repo.findOneBy({ projectId }) const id = existingRepo?.id ?? apId() - await repo.upsert({ - id, - projectId, - sshPrivateKey, - branch, - remoteUrl, - }, ['projectId']) + await repo.upsert( + { + id, + projectId, + sshPrivateKey, + branch, + remoteUrl, + }, + ['projectId'], + ) return repo.findOneByOrFail({ id }) }, async getOrThrow({ id }: { id: string }): Promise { @@ -42,37 +61,73 @@ export const gitRepoService = { const repos = await repo.findBy({ projectId }) return paginationHelper.createPage(repos, null) }, - async push({ id, userId, request }: { id: string, userId: string, request: PushGitRepoRequest }): Promise { + async push({ + id, + userId, + request, + }: { + id: string + userId: string + request: PushGitRepoRequest + }): Promise { const gitRepo = await gitRepoService.getOrThrow({ id }) const { flowFolderPath, git } = await createGitRepoAndReturnPaths(gitRepo) - const { email, firstName, lastName } = await userService.getOneOrFail({ id: userId }) + const { email, firstName, lastName } = await userService.getOneOrFail({ + id: userId, + }) await git.addConfig('user.email', email) await git.addConfig('user.name', `${firstName} ${lastName}`) let operations: FlowSyncOperation[] = [] switch (request.mode) { case PushSyncMode.FLOW: { - operations = [{ - type: 'upsert_flow_into_git', - flow: await flowService.getOnePopulatedOrThrow({ id: request.flowId, projectId: gitRepo.projectId, versionId: undefined, removeSecrets: false }), - }] + operations = [ + { + type: 'upsert_flow_into_git', + flow: await flowService.getOnePopulatedOrThrow({ + id: request.flowId, + projectId: gitRepo.projectId, + versionId: undefined, + removeSecrets: false, + }), + }, + ] break } case PushSyncMode.PROJECT: { - operations = await planPushOperations(gitRepo.projectId, flowFolderPath) + operations = await planPushOperations( + gitRepo.projectId, + flowFolderPath, + ) break } } - await gitSyncHelper.applyFlowOperations({ projectId: gitRepo.projectId, flowFolderPath, operations }) + await gitSyncHelper.applyFlowOperations({ + projectId: gitRepo.projectId, + flowFolderPath, + operations, + }) await commitAndPush(git, gitRepo, request.commitMessage) - }, async pull({ id }: PullGitRepoRequest): Promise { const gitRepo = await gitRepoService.getOrThrow({ id }) const { flowFolderPath } = await createGitRepoAndReturnPaths(gitRepo) - const operations: FlowSyncOperation[] = await planPullOperations(gitRepo.projectId, flowFolderPath) - await gitSyncHelper.applyFlowOperations({ projectId: gitRepo.projectId, flowFolderPath, operations }) + const operations: FlowSyncOperation[] = await planPullOperations( + gitRepo.projectId, + flowFolderPath, + ) + await gitSyncHelper.applyFlowOperations({ + projectId: gitRepo.projectId, + flowFolderPath, + operations, + }) }, - async delete({ id, projectId }: { id: string, projectId: string }): Promise { + async delete({ + id, + projectId, + }: { + id: string + projectId: string + }): Promise { const gitRepo = await repo.findOneBy({ id, projectId }) if (isNil(gitRepo)) { throw new ActivepiecesError({ @@ -87,16 +142,21 @@ export const gitRepoService = { }, } -async function planPullOperations(projectId: string, flowPath: string): Promise { +async function planPullOperations( + projectId: string, + flowPath: string, +): Promise { const projectFlows = await gitSyncHelper.fetchFlowsForProject(projectId) const gitFlows = await gitSyncHelper.parseFlowsFromDirectory(flowPath) - const deleteOperations: FlowSyncOperation[] = projectFlows.filter(f => gitFlows.findIndex(pf => pf.id === f.id) === -1).map(flow => { - return { - type: 'delete_flow_from_project', - flowId: flow.id, - } - }) - const upsertOperations: FlowSyncOperation[] = gitFlows.map(flow => { + const deleteOperations: FlowSyncOperation[] = projectFlows + .filter((f) => gitFlows.findIndex((pf) => pf.id === f.id) === -1) + .map((flow) => { + return { + type: 'delete_flow_from_project', + flowId: flow.id, + } + }) + const upsertOperations: FlowSyncOperation[] = gitFlows.map((flow) => { return { type: 'upsert_flow_into_project', flow, @@ -105,17 +165,21 @@ async function planPullOperations(projectId: string, flowPath: string): Promise< return [...deleteOperations, ...upsertOperations] } - -async function planPushOperations(projectId: string, flowPath: string): Promise { +async function planPushOperations( + projectId: string, + flowPath: string, +): Promise { const projectFlows = await gitSyncHelper.fetchFlowsForProject(projectId) const gitFlows = await gitSyncHelper.parseFlowsFromDirectory(flowPath) - const deleteOperations: FlowSyncOperation[] = gitFlows.filter(f => projectFlows.findIndex(pf => pf.id === f.id) === -1).map(flow => { - return { - type: 'delete_flow_from_git', - flowId: flow.id, - } - }) - const upsertOperations: FlowSyncOperation[] = projectFlows.map(flow => { + const deleteOperations: FlowSyncOperation[] = gitFlows + .filter((f) => projectFlows.findIndex((pf) => pf.id === f.id) === -1) + .map((flow) => { + return { + type: 'delete_flow_from_git', + flowId: flow.id, + } + }) + const upsertOperations: FlowSyncOperation[] = projectFlows.map((flow) => { return { type: 'upsert_flow_into_git', flow, @@ -124,15 +188,22 @@ async function planPushOperations(projectId: string, flowPath: string): Promise< return [...deleteOperations, ...upsertOperations] } -async function createGitRepoAndReturnPaths(gitRepo: GitRepo): Promise<{ flowFolderPath: string, git: SimpleGit }> { +async function createGitRepoAndReturnPaths( + gitRepo: GitRepo, +): Promise<{ flowFolderPath: string, git: SimpleGit }> { const tmpFolder = path.join('/', 'tmp', 'repo', gitRepo.projectId) try { await fs.rmdir(tmpFolder, { recursive: true }) } catch (e) { - // ignore + // ignore } - const flowFolderPath = path.join(tmpFolder, 'projects', gitRepo.projectId, 'flows') + const flowFolderPath = path.join( + tmpFolder, + 'projects', + gitRepo.projectId, + 'flows', + ) await fs.mkdir(flowFolderPath, { recursive: true }) const git = await initGitRepo(gitRepo, tmpFolder) return { @@ -141,7 +212,6 @@ async function createGitRepoAndReturnPaths(gitRepo: GitRepo): Promise<{ flowFold } } - async function createOrGetSshKeyPath(gitRepo: GitRepo): Promise { const keyPath = path.resolve(path.join('tmp', 'keys', gitRepo.id)) await fs.mkdir(path.dirname(keyPath), { recursive: true }) @@ -150,7 +220,10 @@ async function createOrGetSshKeyPath(gitRepo: GitRepo): Promise { return keyPath } -async function initGitRepo(gitRepo: GitRepo, baseDir: string): Promise { +async function initGitRepo( + gitRepo: GitRepo, + baseDir: string, +): Promise { const keyPath = await createOrGetSshKeyPath(gitRepo) const git = simpleGit({ baseDir, @@ -163,14 +236,16 @@ async function initGitRepo(gitRepo: GitRepo, baseDir: string): Promise { +async function commitAndPush( + git: SimpleGit, + gitRepo: GitRepo, + commitMessage: string, +): Promise { await git.add('.') await git.commit(commitMessage) await git.push('origin', gitRepo.branch) } - - type PullGitRepoRequest = { id: string } diff --git a/packages/backend/src/app/ee/git-repos/git-sync-helper.ts b/packages/server/api/src/app/ee/git-repos/git-sync-helper.ts similarity index 64% rename from packages/backend/src/app/ee/git-repos/git-sync-helper.ts rename to packages/server/api/src/app/ee/git-repos/git-sync-helper.ts index 36bbb24d0a..015d595ac7 100644 --- a/packages/backend/src/app/ee/git-repos/git-sync-helper.ts +++ b/packages/server/api/src/app/ee/git-repos/git-sync-helper.ts @@ -25,51 +25,67 @@ type UpsertFlowOperation = { flow: PopulatedFlow } -export type FlowSyncOperation = DeleteFlowFromGitOperation | UpsertFlowIntoProjectOperation | DeleteFlowFromProjectOperation | UpsertFlowOperation +export type FlowSyncOperation = + | DeleteFlowFromGitOperation + | UpsertFlowIntoProjectOperation + | DeleteFlowFromProjectOperation + | UpsertFlowOperation -async function fetchFlowsForProject(projectId: string): Promise { +async function fetchFlowsForProject( + projectId: string, +): Promise { const flows = await flowRepo().findBy({ projectId, }) - return Promise.all(flows.map(f => { - return flowService.getOnePopulatedOrThrow({ - id: f.id, - projectId, - removeSecrets: false, - }) - })) + return Promise.all( + flows.map((f) => { + return flowService.getOnePopulatedOrThrow({ + id: f.id, + projectId, + removeSecrets: false, + }) + }), + ) } -async function parseFlowsFromDirectory(flowPath: string): Promise { +async function parseFlowsFromDirectory( + flowPath: string, +): Promise { const flowFiles = await fs.readdir(flowPath) const parsedFlows = [] for (const file of flowFiles) { - const flow: PopulatedFlow = JSON.parse(await fs.readFile(path.join(flowPath, file), 'utf-8')) + const flow: PopulatedFlow = JSON.parse( + await fs.readFile(path.join(flowPath, file), 'utf-8'), + ) parsedFlows.push(flow) } return parsedFlows } -async function applyFlowOperations({ projectId, flowFolderPath, operations }: { projectId: string, flowFolderPath: string, operations: FlowSyncOperation[] }): Promise { +async function applyFlowOperations({ + projectId, + flowFolderPath, + operations, +}: { + projectId: string + flowFolderPath: string + operations: FlowSyncOperation[] +}): Promise { for (const operation of operations) { switch (operation.type) { - case 'upsert_flow_into_git': - { + case 'upsert_flow_into_git': { await upsertFlowToGit(operation.flow, flowFolderPath) break } - case 'delete_flow_from_git': - { + case 'delete_flow_from_git': { await deleteFlowFromGit(operation.flowId, flowFolderPath) break } - case 'upsert_flow_into_project': - { + case 'upsert_flow_into_project': { await upsertFlowToProject(operation.flow, projectId) break } - case 'delete_flow_from_project': - { + case 'delete_flow_from_project': { await deleteFlowFromProject(operation.flowId, projectId) break } @@ -77,7 +93,10 @@ async function applyFlowOperations({ projectId, flowFolderPath, operations }: { } } -async function upsertFlowToProject(flow: PopulatedFlow, projectId: string): Promise { +async function upsertFlowToProject( + flow: PopulatedFlow, + projectId: string, +): Promise { const existingFlow = await flowService.getOne({ id: flow.id, projectId }) let flowId = flow.id if (!existingFlow) { @@ -105,20 +124,28 @@ async function upsertFlowToProject(flow: PopulatedFlow, projectId: string): Prom }, }, }) - } -async function upsertFlowToGit(flow: Flow, flowFolderPath: string): Promise { +async function upsertFlowToGit( + flow: Flow, + flowFolderPath: string, +): Promise { const flowJsonPath = path.join(flowFolderPath, `${flow.id}.json`) await fs.writeFile(flowJsonPath, JSON.stringify(flow, null, 2)) } -async function deleteFlowFromGit(flowId: string, flowFolderPath: string): Promise { +async function deleteFlowFromGit( + flowId: string, + flowFolderPath: string, +): Promise { const flowJsonPath = path.join(flowFolderPath, `${flowId}.json`) await fs.unlink(flowJsonPath) } -async function deleteFlowFromProject(flowId: string, projectId: string): Promise { +async function deleteFlowFromProject( + flowId: string, + projectId: string, +): Promise { await flowService.delete({ id: flowId, projectId }) } diff --git a/packages/backend/src/app/ee/helper/apperance-helper.ts b/packages/server/api/src/app/ee/helper/apperance-helper.ts similarity index 100% rename from packages/backend/src/app/ee/helper/apperance-helper.ts rename to packages/server/api/src/app/ee/helper/apperance-helper.ts diff --git a/packages/backend/src/app/ee/helper/email/email-service.ts b/packages/server/api/src/app/ee/helper/email/email-service.ts similarity index 76% rename from packages/backend/src/app/ee/helper/email/email-service.ts rename to packages/server/api/src/app/ee/helper/email/email-service.ts index 3b7ab41756..4a98702a49 100644 --- a/packages/backend/src/app/ee/helper/email/email-service.ts +++ b/packages/server/api/src/app/ee/helper/email/email-service.ts @@ -1,5 +1,10 @@ import { getEdition } from '../../../helper/secret-helper' -import { ApEdition, User, assertNotNullOrUndefined, isNil } from '@activepieces/shared' +import { + ApEdition, + User, + assertNotNullOrUndefined, + isNil, +} from '@activepieces/shared' import fs from 'node:fs/promises' import Mustache from 'mustache' import nodemailer from 'nodemailer' @@ -7,20 +12,29 @@ import nodemailer from 'nodemailer' import { platformService } from '../../platform/platform.service' import { defaultTheme } from '../../../flags/theme' import { projectService } from '../../../project/project-service' -import { system } from '../../../helper/system/system' -import { SystemProp } from '../../../helper/system/system-prop' +import { SystemProp, system } from 'server-shared' import { OtpType, Platform } from '@activepieces/ee-shared' -import { logger } from '../../../helper/logger' +import { logger } from 'server-shared' import { platformDomainHelper } from '../platform-domain-helper' import { jwtUtils } from '../../../helper/jwt-utils' import { ProjectMemberToken } from '../../project-members/project-member.service' const EDITION = getEdition() -const EDITION_IS_NOT_PAID = ![ApEdition.CLOUD, ApEdition.ENTERPRISE].includes(EDITION) +const EDITION_IS_NOT_PAID = ![ApEdition.CLOUD, ApEdition.ENTERPRISE].includes( + EDITION, +) const EDITION_IS_NOT_CLOUD = EDITION !== ApEdition.CLOUD export const emailService = { - async sendInvitation({ email, invitationId, projectId }: { email: string, invitationId: string, projectId: string }): Promise { + async sendInvitation({ + email, + invitationId, + projectId, + }: { + email: string + invitationId: string + projectId: string + }): Promise { if (EDITION_IS_NOT_PAID) { return } @@ -51,7 +65,19 @@ export const emailService = { }) }, - async sendQuotaAlert({ email, projectId, resetDate, firstName, templateId }: { email: string, projectId: string, resetDate: string, firstName: string, templateId: 'quota-50' | 'quota-90' | 'quota-100' }): Promise { + async sendQuotaAlert({ + email, + projectId, + resetDate, + firstName, + templateId, + }: { + email: string + projectId: string + resetDate: string + firstName: string + templateId: 'quota-50' | 'quota-90' | 'quota-100' + }): Promise { if (EDITION_IS_NOT_CLOUD) { return } @@ -76,7 +102,12 @@ export const emailService = { }, }) }, - async sendOtpEmail({ platformId, user, otp, type }: SendOtpEmailParams): Promise { + async sendOtpEmail({ + platformId, + user, + otp, + type, + }: SendOtpEmailParams): Promise { const edition = getEdition() if (![ApEdition.CLOUD, ApEdition.ENTERPRISE].includes(edition)) { return @@ -84,7 +115,13 @@ export const emailService = { if (user.verified && type === OtpType.EMAIL_VERIFICATION) { return } - logger.info('Sending OTP email', { email: user.email, otp, userId: user.id, firstName: user.email, type }) + logger.info('Sending OTP email', { + email: user.email, + otp, + userId: user.id, + firstName: user.email, + type, + }) const frontendPath = { [OtpType.EMAIL_VERIFICATION]: 'verify-email', [OtpType.PASSWORD_RESET]: 'reset-password', @@ -119,17 +156,25 @@ export const emailService = { }, } - - - -async function sendEmail({ platformId, email, template }: { template: EmailTemplate, email: string, platformId: string | undefined }): Promise { - const platform = isNil(platformId) ? null : await platformService.getOne(platformId) +async function sendEmail({ + platformId, + email, + template, +}: { + template: EmailTemplate + email: string + platformId: string | undefined +}): Promise { + const platform = isNil(platformId) + ? null + : await platformService.getOne(platformId) const transporter = nodemailer.createTransport({ host: platform?.smtpHost ?? system.getOrThrow(SystemProp.SMTP_HOST), port: platform?.smtpPort ?? system.getNumber(SystemProp.SMTP_PORT)!, auth: { user: platform?.smtpUser ?? system.getOrThrow(SystemProp.SMTP_USERNAME), - pass: platform?.smtpPassword ?? system.getOrThrow(SystemProp.SMTP_PASSWORD), + pass: + platform?.smtpPassword ?? system.getOrThrow(SystemProp.SMTP_PASSWORD), }, secure: platform?.smtpUseSSL ?? system.getBoolean(SystemProp.SMTP_USE_SSL), }) @@ -143,7 +188,8 @@ async function sendEmail({ platformId, email, template }: { template: EmailTempl } const senderName = platform?.name ?? system.get(SystemProp.SMTP_SENDER_NAME) - const senderEmail = platform?.smtpSenderEmail ?? system.get(SystemProp.SMTP_SENDER_EMAIL) + const senderEmail = + platform?.smtpSenderEmail ?? system.get(SystemProp.SMTP_SENDER_EMAIL) await transporter.sendMail({ from: `${senderName} <${senderEmail}>`, to: email, @@ -155,7 +201,10 @@ async function sendEmail({ platformId, email, template }: { template: EmailTempl async function renderTemplate({ platform, request, -}: { request: EmailTemplate, platform: Platform | null }): Promise { +}: { + request: EmailTemplate + platform: Platform | null +}): Promise { const templateHtml = await readTemplateFile(request.templateName) return Mustache.render(templateHtml, { ...request.data, @@ -166,7 +215,10 @@ async function renderTemplate({ } async function readTemplateFile(templateName: string): Promise { - return fs.readFile(`./packages/backend/src/assets/emails/${templateName}.html`, 'utf-8') + return fs.readFile( + `./packages/server/api/src/assets/emails/${templateName}.html`, + 'utf-8', + ) } type InvitationEmailTemplate = { @@ -200,11 +252,10 @@ type ResetPasswordTemplate = { } } type EmailTemplate = - | InvitationEmailTemplate - | QuotaEmailTemplate - | VerifyEmailTemplate - | ResetPasswordTemplate - + | InvitationEmailTemplate + | QuotaEmailTemplate + | VerifyEmailTemplate + | ResetPasswordTemplate type SendOtpEmailParams = { type: OtpType @@ -212,4 +263,3 @@ type SendOtpEmailParams = { otp: string user: User } - diff --git a/packages/backend/src/app/ee/helper/license-validator/index.ts b/packages/server/api/src/app/ee/helper/license-validator/index.ts similarity index 84% rename from packages/backend/src/app/ee/helper/license-validator/index.ts rename to packages/server/api/src/app/ee/helper/license-validator/index.ts index 6cd4736aab..8ebeaf861b 100644 --- a/packages/backend/src/app/ee/helper/license-validator/index.ts +++ b/packages/server/api/src/app/ee/helper/license-validator/index.ts @@ -3,10 +3,9 @@ import { LiceneseStatus, LicenseValidator } from './license-validator' import { noOpLicenseValidator } from './no-op-license-validator' import { networkLicenseValidator } from './network-license-validator' import { ApEdition } from '@activepieces/shared' -import { system } from '../../../helper/system/system' -import { SystemProp } from '../../../helper/system/system-prop' +import { SystemProp, system } from 'server-shared' import { platformService } from '../../platform/platform.service' -import { logger } from '../../../helper/logger' +import { logger } from 'server-shared' const variant: Record = { [ApEnvironment.PRODUCTION]: networkLicenseValidator, @@ -25,7 +24,7 @@ export async function enforceLimits(): Promise { } const license = await licenseValidator.validate() switch (license.status) { - case LiceneseStatus.VALID:{ + case LiceneseStatus.VALID: { const oldestPlatform = await platformService.getOldestPlatform() if (!oldestPlatform) { break @@ -42,11 +41,13 @@ export async function enforceLimits(): Promise { break } case LiceneseStatus.INVALID: { - logger.error('[ERROR]: License key is not valid. Please contact sales@activepieces.com') + logger.error( + '[ERROR]: License key is not valid. Please contact sales@activepieces.com', + ) process.exit(1) break } - case LiceneseStatus.UNKNOWN:{ + case LiceneseStatus.UNKNOWN: { // We don't want to block the application from starting if the license is unknown // TODO find a better way to handle this break diff --git a/packages/backend/src/app/ee/helper/license-validator/license-validator.ts b/packages/server/api/src/app/ee/helper/license-validator/license-validator.ts similarity index 72% rename from packages/backend/src/app/ee/helper/license-validator/license-validator.ts rename to packages/server/api/src/app/ee/helper/license-validator/license-validator.ts index de70002c65..f916273554 100644 --- a/packages/backend/src/app/ee/helper/license-validator/license-validator.ts +++ b/packages/server/api/src/app/ee/helper/license-validator/license-validator.ts @@ -1,4 +1,3 @@ - export enum LiceneseStatus { VALID = 'VALID', INVALID = 'INVALID', @@ -13,11 +12,14 @@ export type SuccessLicenseResponse = { gitSyncEnabled?: boolean auditLogEnabled?: boolean } -export type LicenseResponse = SuccessLicenseResponse | { - status: LiceneseStatus.INVALID -} | { - status: LiceneseStatus.UNKNOWN -} +export type LicenseResponse = + | SuccessLicenseResponse + | { + status: LiceneseStatus.INVALID + } + | { + status: LiceneseStatus.UNKNOWN + } export type LicenseValidator = { validate: () => Promise diff --git a/packages/backend/src/app/ee/helper/license-validator/network-license-validator.ts b/packages/server/api/src/app/ee/helper/license-validator/network-license-validator.ts similarity index 78% rename from packages/backend/src/app/ee/helper/license-validator/network-license-validator.ts rename to packages/server/api/src/app/ee/helper/license-validator/network-license-validator.ts index 1a99886d43..eea4b101de 100644 --- a/packages/backend/src/app/ee/helper/license-validator/network-license-validator.ts +++ b/packages/server/api/src/app/ee/helper/license-validator/network-license-validator.ts @@ -1,15 +1,18 @@ import axios from 'axios' -import { logger } from '../../../helper/logger' +import { logger } from 'server-shared' import { LiceneseStatus, LicenseValidator } from './license-validator' -import { system } from '../../../helper/system/system' -import { SystemProp } from '../../../helper/system/system-prop' - +import { SystemProp, system } from 'server-shared' export const networkLicenseValidator: LicenseValidator = { async validate() { const license = obtainLicense() try { - const res = await axios.post('https://secrets.activepieces.com/verify', { licenseKey: license }) - logger.debug({ name: 'NetworkLicenseValidator#validate', response: res.data }) + const res = await axios.post('https://secrets.activepieces.com/verify', { + licenseKey: license, + }) + logger.debug({ + name: 'NetworkLicenseValidator#validate', + response: res.data, + }) if (res.status !== 200) { return { status: LiceneseStatus.INVALID, diff --git a/packages/backend/src/app/ee/helper/license-validator/no-op-license-validator.ts b/packages/server/api/src/app/ee/helper/license-validator/no-op-license-validator.ts similarity index 100% rename from packages/backend/src/app/ee/helper/license-validator/no-op-license-validator.ts rename to packages/server/api/src/app/ee/helper/license-validator/no-op-license-validator.ts diff --git a/packages/backend/src/app/ee/helper/platform-domain-helper.ts b/packages/server/api/src/app/ee/helper/platform-domain-helper.ts similarity index 64% rename from packages/backend/src/app/ee/helper/platform-domain-helper.ts rename to packages/server/api/src/app/ee/helper/platform-domain-helper.ts index 9813c494a3..0281b57ebb 100644 --- a/packages/backend/src/app/ee/helper/platform-domain-helper.ts +++ b/packages/server/api/src/app/ee/helper/platform-domain-helper.ts @@ -1,24 +1,43 @@ -import { SystemProp } from '../../helper/system/system-prop' -import { system } from '../../helper/system/system' +import { SystemProp, system } from 'server-shared' import { customDomainService } from '../custom-domains/custom-domain.service' import { ApEnvironment } from '@activepieces/shared' export const platformDomainHelper = { - async constructUrlFrom({ platformId, path }: { platformId: string | undefined | null, path: string }): Promise { + async constructUrlFrom({ + platformId, + path, + }: { + platformId: string | undefined | null + path: string + }): Promise { const domain = await getFrontendDomain(platformId) return `${domain}${path}` }, - async constructFrontendUrlFromRequest({ domain, path }: { domain: string, path: string }): Promise { + async constructFrontendUrlFromRequest({ + domain, + path, + }: { + domain: string + path: string + }): Promise { const domainWithProtocol = await getFrontendDomainFromHostname(domain) return `${domainWithProtocol}${path}` }, - async constructApiUrlFromRequest({ domain, path }: { domain: string, path: string }): Promise { + async constructApiUrlFromRequest({ + domain, + path, + }: { + domain: string + path: string + }): Promise { const domainWithProtocol = await getApiDomainFromHostname(domain) return `${domainWithProtocol}${path}` }, } -async function getFrontendDomainFromHostname(hostname: string): Promise { +async function getFrontendDomainFromHostname( + hostname: string, +): Promise { let domain = system.get(SystemProp.FRONTEND_URL) const customDomain = await customDomainService.getOneByDomain({ domain: hostname, @@ -30,11 +49,13 @@ async function getFrontendDomainFromHostname(hostname: string): Promise } async function getApiDomainFromHostname(hostname: string): Promise { - const frontendUrl = await getFrontendDomainFromHostname(hostname) + const frontendUrl = await getFrontendDomainFromHostname(hostname) const environment = system.getOrThrow(SystemProp.ENVIRONMENT) return frontendUrl + (environment === ApEnvironment.PRODUCTION ? 'api/' : '') } -async function getFrontendDomain(platformId: string | undefined | null): Promise { +async function getFrontendDomain( + platformId: string | undefined | null, +): Promise { let domain = system.getOrThrow(SystemProp.FRONTEND_URL) if (platformId) { const customDomain = await customDomainService.getOneByPlatform({ @@ -46,4 +67,3 @@ async function getFrontendDomain(platformId: string | undefined | null): Promise } return domain + (domain.endsWith('/') ? '' : '/') } - diff --git a/packages/backend/src/app/ee/managed-authn/lib/external-token-extractor.ts b/packages/server/api/src/app/ee/managed-authn/lib/external-token-extractor.ts similarity index 90% rename from packages/backend/src/app/ee/managed-authn/lib/external-token-extractor.ts rename to packages/server/api/src/app/ee/managed-authn/lib/external-token-extractor.ts index a2cbfe8086..1d2b106890 100644 --- a/packages/backend/src/app/ee/managed-authn/lib/external-token-extractor.ts +++ b/packages/server/api/src/app/ee/managed-authn/lib/external-token-extractor.ts @@ -1,7 +1,7 @@ import { ActivepiecesError, ErrorCode, isNil } from '@activepieces/shared' import { JwtSignAlgorithm, jwtUtils } from '../../../helper/jwt-utils' import { signingKeyService } from '../../signing-key/signing-key-service' -import { logger } from '../../../helper/logger' +import { logger } from 'server-shared' import { SigningKey, SigningKeyId } from '@activepieces/ee-shared' const ALGORITHM = JwtSignAlgorithm.RS256 @@ -39,14 +39,17 @@ export const externalTokenExtractor = { throw new ActivepiecesError({ code: ErrorCode.INVALID_BEARER_TOKEN, params: { - message: error instanceof Error ? error.message : 'error decoding token', + message: + error instanceof Error ? error.message : 'error decoding token', }, }) } }, } -const getSigningKey = async ({ signingKeyId }: GetSigningKeyParams): Promise => { +const getSigningKey = async ({ + signingKeyId, +}: GetSigningKeyParams): Promise => { const signingKey = await signingKeyService.get({ id: signingKeyId, }) diff --git a/packages/backend/src/app/ee/managed-authn/managed-authn-controller.ts b/packages/server/api/src/app/ee/managed-authn/managed-authn-controller.ts similarity index 50% rename from packages/backend/src/app/ee/managed-authn/managed-authn-controller.ts rename to packages/server/api/src/app/ee/managed-authn/managed-authn-controller.ts index 04f3ff420d..97997c4a97 100644 --- a/packages/backend/src/app/ee/managed-authn/managed-authn-controller.ts +++ b/packages/server/api/src/app/ee/managed-authn/managed-authn-controller.ts @@ -1,16 +1,25 @@ -import { ALL_PRINICPAL_TYPES, AuthenticationResponse } from '@activepieces/shared' +import { + ALL_PRINICPAL_TYPES, + AuthenticationResponse, +} from '@activepieces/shared' import { FastifyPluginAsyncTypebox } from '@fastify/type-provider-typebox' import { managedAuthnService } from './managed-authn-service' import { ManagedAuthnRequestBody } from '@activepieces/ee-shared' -export const managedAuthnController: FastifyPluginAsyncTypebox = async (app) => { - app.post('/external-token', ManagedAuthnRequest, async (req): Promise => { - const { externalAccessToken } = req.body +export const managedAuthnController: FastifyPluginAsyncTypebox = async ( + app, +) => { + app.post( + '/external-token', + ManagedAuthnRequest, + async (req): Promise => { + const { externalAccessToken } = req.body - return managedAuthnService.externalToken({ - externalAccessToken, - }) - }) + return managedAuthnService.externalToken({ + externalAccessToken, + }) + }, + ) } const ManagedAuthnRequest = { diff --git a/packages/backend/src/app/ee/managed-authn/managed-authn-module.ts b/packages/server/api/src/app/ee/managed-authn/managed-authn-module.ts similarity index 100% rename from packages/backend/src/app/ee/managed-authn/managed-authn-module.ts rename to packages/server/api/src/app/ee/managed-authn/managed-authn-module.ts diff --git a/packages/backend/src/app/ee/managed-authn/managed-authn-service.ts b/packages/server/api/src/app/ee/managed-authn/managed-authn-service.ts similarity index 80% rename from packages/backend/src/app/ee/managed-authn/managed-authn-service.ts rename to packages/server/api/src/app/ee/managed-authn/managed-authn-service.ts index cac89f5965..843e8f01cf 100644 --- a/packages/backend/src/app/ee/managed-authn/managed-authn-service.ts +++ b/packages/server/api/src/app/ee/managed-authn/managed-authn-service.ts @@ -1,8 +1,21 @@ import { randomBytes as randomBytesCallback } from 'node:crypto' import { promisify } from 'node:util' -import { AuthenticationResponse, PlatformRole, PrincipalType, Project, ProjectId, ProjectType, User } from '@activepieces/shared' +import { + AuthenticationResponse, + PlatformRole, + PrincipalType, + Project, + ProjectId, + ProjectType, + User, +} from '@activepieces/shared' import { userService } from '../../user/user-service' -import { DEFAULT_PLATFORM_PLAN, PlatformId, ProjectMemberRole, ProjectMemberStatus } from '@activepieces/ee-shared' +import { + DEFAULT_PLATFORM_PLAN, + PlatformId, + ProjectMemberRole, + ProjectMemberStatus, +} from '@activepieces/ee-shared' import { platformService } from '../platform/platform.service' import { projectService } from '../../project/project-service' import { projectMemberService } from '../project-members/project-member.service' @@ -11,8 +24,12 @@ import { externalTokenExtractor } from './lib/external-token-extractor' import { plansService } from '../billing/project-plan/project-plan.service' export const managedAuthnService = { - async externalToken({ externalAccessToken }: AuthenticateParams): Promise { - const externalPrincipal = await externalTokenExtractor.extract(externalAccessToken) + async externalToken({ + externalAccessToken, + }: AuthenticateParams): Promise { + const externalPrincipal = await externalTokenExtractor.extract( + externalAccessToken, + ) const user = await getOrCreateUser(externalPrincipal) const token = await accessTokenManager.generateToken({ @@ -33,8 +50,17 @@ export const managedAuthnService = { }, } -const getOrCreateUser = async (params: GetOrCreateUserParams): Promise => { - const { platformId, externalUserId, externalProjectId, externalEmail, externalFirstName, externalLastName } = params +const getOrCreateUser = async ( + params: GetOrCreateUserParams, +): Promise => { + const { + platformId, + externalUserId, + externalProjectId, + externalEmail, + externalFirstName, + externalLastName, + } = params const existingUser = await userService.getByPlatformAndExternalId({ platformId, externalId: externalUserId, @@ -79,7 +105,10 @@ const getOrCreateUser = async (params: GetOrCreateUserParams): Promise => { +const getOrCreateProject = async ({ + platformId, + externalProjectId, +}: GetOrCreateProjectParams): Promise => { const existingProject = await projectService.getByPlatformIdAndExternalId({ platformId, externalId: externalProjectId, @@ -98,7 +127,7 @@ const getOrCreateProject = async ({ platformId, externalProjectId }: GetOrCreate type: ProjectType.PLATFORM_MANAGED, externalId: externalProjectId, }) - + await plansService.update({ projectId: project.id, subscription: null, diff --git a/packages/backend/src/app/ee/oauth-apps/oauth-app.entity.ts b/packages/server/api/src/app/ee/oauth-apps/oauth-app.entity.ts similarity index 85% rename from packages/backend/src/app/ee/oauth-apps/oauth-app.entity.ts rename to packages/server/api/src/app/ee/oauth-apps/oauth-app.entity.ts index 56d5aecf9b..ba95b70879 100644 --- a/packages/backend/src/app/ee/oauth-apps/oauth-app.entity.ts +++ b/packages/server/api/src/app/ee/oauth-apps/oauth-app.entity.ts @@ -1,6 +1,10 @@ import { EntitySchema } from 'typeorm' import { OAuthApp, Platform } from '@activepieces/ee-shared' -import { ApIdSchema, BaseColumnSchemaPart, JSONB_COLUMN_TYPE } from '../../database/database-common' +import { + ApIdSchema, + BaseColumnSchemaPart, + JSONB_COLUMN_TYPE, +} from '../../database/database-common' import { EncryptedObject } from '../../helper/encryption' type OAuthAppSchema = { @@ -9,7 +13,9 @@ type OAuthAppSchema = { } & OAuthApp export type OAuthAppWithSecret = OAuthApp & { clientSecret: string } -export type OAuthAppWithEncryptedSecret = OAuthApp & { clientSecret: EncryptedObject } +export type OAuthAppWithEncryptedSecret = OAuthApp & { + clientSecret: EncryptedObject +} export const OAuthAppEntity = new EntitySchema({ name: 'oauth_app', diff --git a/packages/server/api/src/app/ee/oauth-apps/oauth-app.module.ts b/packages/server/api/src/app/ee/oauth-apps/oauth-app.module.ts new file mode 100644 index 0000000000..c5d2d9abf2 --- /dev/null +++ b/packages/server/api/src/app/ee/oauth-apps/oauth-app.module.ts @@ -0,0 +1,92 @@ +import { + FastifyPluginAsyncTypebox, + Static, + Type, +} from '@fastify/type-provider-typebox' +import { oauthAppService } from './oauth-app.service' +import { + ListOAuth2AppRequest, + OAuthApp, + UpsertOAuth2AppRequest, +} from '@activepieces/ee-shared' +import { SeekPage, assertNotNullOrUndefined } from '@activepieces/shared' +import { platformMustBeOwnedByCurrentUser } from '../authentication/ee-authorization' +import { StatusCodes } from 'http-status-codes' + +export const oauthAppModule: FastifyPluginAsyncTypebox = async (app) => { + await app.register(readOauthAppModule) + await app.register(writeOauthAppModule) +} + +const readOauthAppModule: FastifyPluginAsyncTypebox = async (app) => { + await app.register(readOauthAppController, { prefix: '/v1/oauth-apps' }) +} + +const readOauthAppController: FastifyPluginAsyncTypebox = async (app) => { + app.get( + '/', + { + schema: { + querystring: ListOAuth2AppRequest, + response: { + [StatusCodes.OK]: SeekPage(OAuthApp), + }, + }, + }, + async (request) => { + const platformId = request.principal.platform?.id + assertNotNullOrUndefined(platformId, 'platformId') + return oauthAppService.list({ + platformId, + request: request.query, + }) + }, + ) +} + +const writeOauthAppModule: FastifyPluginAsyncTypebox = async (app) => { + app.addHook('preHandler', platformMustBeOwnedByCurrentUser) + await app.register(oauthAppController, { prefix: '/v1/oauth-apps' }) +} + +const oauthAppController: FastifyPluginAsyncTypebox = async (app) => { + app.post( + '/', + { + schema: { + body: UpsertOAuth2AppRequest, + }, + }, + async (request) => { + const platformId = request.principal.platform?.id + assertNotNullOrUndefined(platformId, 'platformId') + return oauthAppService.upsert({ + platformId, + request: request.body, + }) + }, + ) + + app.delete( + '/:id', + { + schema: { + params: GetIdParams, + }, + }, + async (request) => { + const platformId = request.principal.platform?.id + assertNotNullOrUndefined(platformId, 'platformId') + return oauthAppService.delete({ + platformId, + id: request.params.id, + }) + }, + ) +} + +const GetIdParams = Type.Object({ + id: Type.String(), +}) + +type GetIdParams = Static diff --git a/packages/server/api/src/app/ee/oauth-apps/oauth-app.service.ts b/packages/server/api/src/app/ee/oauth-apps/oauth-app.service.ts new file mode 100644 index 0000000000..bdd91339a7 --- /dev/null +++ b/packages/server/api/src/app/ee/oauth-apps/oauth-app.service.ts @@ -0,0 +1,104 @@ +import { + ListOAuth2AppRequest, + OAuthApp, + UpsertOAuth2AppRequest, +} from '@activepieces/ee-shared' +import { OAuthAppEntity, OAuthAppWithSecret } from './oauth-app.entity' +import { databaseConnection } from '../../database/database-connection' +import { paginationHelper } from '../../helper/pagination/pagination-utils' +import { buildPaginator } from '../../helper/pagination/build-paginator' +import { + ActivepiecesError, + ErrorCode, + SeekPage, + apId, + deleteProps, + isNil, +} from '@activepieces/shared' +import { decryptString, encryptString } from '../../helper/encryption' + +const oauthRepo = databaseConnection.getRepository(OAuthAppEntity) + +export const oauthAppService = { + async upsert({ + platformId, + request, + }: { + platformId: string + request: UpsertOAuth2AppRequest + }): Promise { + await oauthRepo.upsert( + { + platformId, + ...request, + clientSecret: encryptString(request.clientSecret), + id: apId(), + }, + ['platformId', 'pieceName'], + ) + const connection = await oauthRepo.findOneByOrFail({ + platformId, + pieceName: request.pieceName, + }) + return deleteProps(connection, ['clientSecret']) + }, + async getWithSecret({ + platformId, + pieceName, + clientId, + }: { + platformId: string + pieceName: string + clientId?: string + }): Promise { + const oauthApp = await oauthRepo.findOneByOrFail({ + platformId, + pieceName, + clientId, + }) + return { + ...oauthApp, + clientSecret: decryptString(oauthApp.clientSecret), + } + }, + async list({ + request, + platformId, + }: { + platformId: string + request: ListOAuth2AppRequest + }): Promise> { + const decodedCursor = paginationHelper.decodeCursor(request.cursor ?? null) + const paginator = buildPaginator({ + entity: OAuthAppEntity, + query: { + limit: request.limit ?? 10, + order: 'ASC', + afterCursor: decodedCursor.nextCursor, + beforeCursor: decodedCursor.previousCursor, + }, + }) + const { data, cursor } = await paginator.paginate( + oauthRepo.createQueryBuilder('oauth_app').where({ platformId }), + ) + return paginationHelper.createPage(data, cursor) + }, + async delete({ + platformId, + id, + }: { + platformId: string + id: string + }): Promise { + const oauthApp = await oauthRepo.findOneBy({ platformId, id }) + if (isNil(oauthApp)) { + throw new ActivepiecesError({ + code: ErrorCode.ENTITY_NOT_FOUND, + params: { + message: `OAuth with id ${id} not found`, + }, + }) + } + await oauthRepo.delete({ platformId, id }) + }, +} diff --git a/packages/backend/src/app/ee/otp/lib/otp-generator.ts b/packages/server/api/src/app/ee/otp/lib/otp-generator.ts similarity index 100% rename from packages/backend/src/app/ee/otp/lib/otp-generator.ts rename to packages/server/api/src/app/ee/otp/lib/otp-generator.ts diff --git a/packages/backend/src/app/ee/otp/otp-controller.ts b/packages/server/api/src/app/ee/otp/otp-controller.ts similarity index 99% rename from packages/backend/src/app/ee/otp/otp-controller.ts rename to packages/server/api/src/app/ee/otp/otp-controller.ts index 7eec258478..10fbd2df1b 100644 --- a/packages/backend/src/app/ee/otp/otp-controller.ts +++ b/packages/server/api/src/app/ee/otp/otp-controller.ts @@ -5,7 +5,6 @@ import { resolvePlatformIdForRequest } from '../platform/lib/platform-utils' import { StatusCodes } from 'http-status-codes' import { ALL_PRINICPAL_TYPES } from '@activepieces/shared' - export const otpController: FastifyPluginAsyncTypebox = async (app) => { app.post('/', CreateOtpRequest, async (req, res) => { const platformId = await resolvePlatformIdForRequest(req) diff --git a/packages/backend/src/app/ee/otp/otp-entity.ts b/packages/server/api/src/app/ee/otp/otp-entity.ts similarity index 92% rename from packages/backend/src/app/ee/otp/otp-entity.ts rename to packages/server/api/src/app/ee/otp/otp-entity.ts index b6ed51afef..9393a9fe39 100644 --- a/packages/backend/src/app/ee/otp/otp-entity.ts +++ b/packages/server/api/src/app/ee/otp/otp-entity.ts @@ -1,6 +1,9 @@ import { EntitySchema } from 'typeorm' import { OtpModel, OtpState, OtpType } from '@activepieces/ee-shared' -import { ApIdSchema, BaseColumnSchemaPart } from '../../database/database-common' +import { + ApIdSchema, + BaseColumnSchemaPart, +} from '../../database/database-common' import { User } from '@activepieces/shared' export type OtpSchema = OtpModel & { diff --git a/packages/backend/src/app/ee/otp/otp-module.ts b/packages/server/api/src/app/ee/otp/otp-module.ts similarity index 100% rename from packages/backend/src/app/ee/otp/otp-module.ts rename to packages/server/api/src/app/ee/otp/otp-module.ts diff --git a/packages/backend/src/app/ee/otp/otp-service.ts b/packages/server/api/src/app/ee/otp/otp-service.ts similarity index 81% rename from packages/backend/src/app/ee/otp/otp-service.ts rename to packages/server/api/src/app/ee/otp/otp-service.ts index 655cc76919..7c68e611c9 100644 --- a/packages/backend/src/app/ee/otp/otp-service.ts +++ b/packages/server/api/src/app/ee/otp/otp-service.ts @@ -1,5 +1,10 @@ -import { OtpModel, OtpState, OtpType, PlatformId } from '@activepieces/ee-shared' -import { User, UserId, apId } from '@activepieces/shared' +import { + OtpModel, + OtpState, + OtpType, + PlatformId, +} from '@activepieces/ee-shared' +import { User, UserId, apId } from '@activepieces/shared' import { databaseConnection } from '../../database/database-connection' import { OtpEntity } from './otp-entity' import dayjs from 'dayjs' @@ -12,13 +17,16 @@ const THIRTY_MINUTES = 30 * 60 * 1000 const repo = databaseConnection.getRepository(OtpEntity) export const otpService = { - async createAndSend({ platformId, email, type }: CreateParams): Promise { + async createAndSend({ + platformId, + email, + type, + }: CreateParams): Promise { const user = await getUser({ platformId, email, }) if (user) { - const newOtp: Omit = { id: apId(), updated: dayjs().toISOString(), @@ -34,10 +42,7 @@ export const otpService = { otp: newOtp.value, type: newOtp.type, }) - - } - }, async confirm({ userId, type, value }: ConfirmParams): Promise { @@ -47,7 +52,8 @@ export const otpService = { }) const now = dayjs() const otpIsPending = otp.state === OtpState.PENDING - const otpIsNotExpired = now.diff(otp.updated, 'milliseconds') < THIRTY_MINUTES + const otpIsNotExpired = + now.diff(otp.updated, 'milliseconds') < THIRTY_MINUTES const otpMatches = otp.value === value const verdict = otpIsNotExpired && otpMatches && otpIsPending if (verdict) { @@ -60,7 +66,10 @@ export const otpService = { }, } -const getUser = async ({ platformId, email }: GetUserOrThrowParams): Promise => { +const getUser = async ({ + platformId, + email, +}: GetUserOrThrowParams): Promise => { const user = await userService.getByPlatformAndEmail({ platformId, email, diff --git a/packages/backend/src/app/ee/pieces/admin-piece-module.ts b/packages/server/api/src/app/ee/pieces/admin-piece-module.ts similarity index 59% rename from packages/backend/src/app/ee/pieces/admin-piece-module.ts rename to packages/server/api/src/app/ee/pieces/admin-piece-module.ts index 4361e7496f..6d57e9aade 100644 --- a/packages/backend/src/app/ee/pieces/admin-piece-module.ts +++ b/packages/server/api/src/app/ee/pieces/admin-piece-module.ts @@ -6,19 +6,26 @@ import { PackageType, PieceType } from '@activepieces/shared' import { PieceMetadataModel } from '../../pieces/piece-metadata-entity' import { pieceMetadataService } from '../../pieces/piece-metadata-service' - export const adminPieceModule: FastifyPluginAsyncTypebox = async (app) => { await app.register(adminPieceController, { prefix: '/v1/admin/pieces' }) } -const adminPieceController: FastifyPluginCallbackTypebox = (app, _opts, done) => { - app.post('/', CreatePieceRequest, async (req): Promise => { - return pieceMetadataService.create({ - pieceMetadata: req.body as PieceMetadata, - packageType: PackageType.REGISTRY, - pieceType: PieceType.OFFICIAL, - }) - }) +const adminPieceController: FastifyPluginCallbackTypebox = ( + app, + _opts, + done, +) => { + app.post( + '/', + CreatePieceRequest, + async (req): Promise => { + return pieceMetadataService.create({ + pieceMetadata: req.body as PieceMetadata, + packageType: PackageType.REGISTRY, + pieceType: PieceType.OFFICIAL, + }) + }, + ) done() -} \ No newline at end of file +} diff --git a/packages/backend/src/app/ee/pieces/admin-piece-requests.ee.ts b/packages/server/api/src/app/ee/pieces/admin-piece-requests.ee.ts similarity index 84% rename from packages/backend/src/app/ee/pieces/admin-piece-requests.ee.ts rename to packages/server/api/src/app/ee/pieces/admin-piece-requests.ee.ts index ae8d6a4dd8..a03d4771b1 100644 --- a/packages/backend/src/app/ee/pieces/admin-piece-requests.ee.ts +++ b/packages/server/api/src/app/ee/pieces/admin-piece-requests.ee.ts @@ -1,5 +1,13 @@ -import { TriggerStrategy, WebhookHandshakeConfiguration } from '@activepieces/pieces-framework' -import { ExactVersionType, PieceCategory, PrincipalType, TriggerTestStrategy } from '@activepieces/shared' +import { + TriggerStrategy, + WebhookHandshakeConfiguration, +} from '@activepieces/pieces-framework' +import { + ExactVersionType, + PieceCategory, + PrincipalType, + TriggerTestStrategy, +} from '@activepieces/shared' import { Type } from '@fastify/type-provider-typebox' const Action = Type.Object({ diff --git a/packages/backend/src/app/ee/pieces/enterprise-piece-metadata-service-hooks.ts b/packages/server/api/src/app/ee/pieces/enterprise-piece-metadata-service-hooks.ts similarity index 59% rename from packages/backend/src/app/ee/pieces/enterprise-piece-metadata-service-hooks.ts rename to packages/server/api/src/app/ee/pieces/enterprise-piece-metadata-service-hooks.ts index ce8dff7a8e..ea0a4bf32d 100644 --- a/packages/backend/src/app/ee/pieces/enterprise-piece-metadata-service-hooks.ts +++ b/packages/server/api/src/app/ee/pieces/enterprise-piece-metadata-service-hooks.ts @@ -1,27 +1,33 @@ import { FilteredPieceBehavior } from '@activepieces/ee-shared' import { isNil } from '@activepieces/shared' import { PieceMetadataSchema } from '../../pieces/piece-metadata-entity' -import { PieceMetadataServiceHooks, defaultPieceHooks } from '../../pieces/piece-metadata-service/hooks' +import { + PieceMetadataServiceHooks, + defaultPieceHooks, +} from '../../pieces/piece-metadata-service/hooks' import { platformService } from '../platform/platform.service' export const enterprisePieceMetadataServiceHooks: PieceMetadataServiceHooks = { async filterPieces(params) { const { platformId, includeHidden, pieces } = params if (isNil(platformId) || includeHidden) { - return defaultPieceHooks.filterPieces({ ...params, pieces }) + return defaultPieceHooks.filterPieces({ ...params, pieces }) } const platform = await platformService.getOneOrThrow(platformId) - const filterPredicate: Record boolean> = { - [FilteredPieceBehavior.ALLOWED]: p => platform.filteredPieceNames.includes(p.name), - [FilteredPieceBehavior.BLOCKED]: p => !platform.filteredPieceNames.includes(p.name), + const filterPredicate: Record< + FilteredPieceBehavior, + (p: PieceMetadataSchema) => boolean + > = { + [FilteredPieceBehavior.ALLOWED]: (p) => + platform.filteredPieceNames.includes(p.name), + [FilteredPieceBehavior.BLOCKED]: (p) => + !platform.filteredPieceNames.includes(p.name), } const predicate = filterPredicate[platform.filteredPieceBehavior] - const resultPieces = pieces - .slice() - .filter(predicate) + const resultPieces = pieces.slice().filter(predicate) return defaultPieceHooks.filterPieces({ ...params, pieces: resultPieces }) }, } diff --git a/packages/backend/src/app/ee/pieces/piece-service/platform-piece-service-hooks.ts b/packages/server/api/src/app/ee/pieces/piece-service/platform-piece-service-hooks.ts similarity index 68% rename from packages/backend/src/app/ee/pieces/piece-service/platform-piece-service-hooks.ts rename to packages/server/api/src/app/ee/pieces/piece-service/platform-piece-service-hooks.ts index 492ad0d20b..9c89ac7eea 100644 --- a/packages/backend/src/app/ee/pieces/piece-service/platform-piece-service-hooks.ts +++ b/packages/server/api/src/app/ee/pieces/piece-service/platform-piece-service-hooks.ts @@ -1,5 +1,14 @@ -import { FileCompression, FileId, FileType, PieceType, isNil } from '@activepieces/shared' -import { GetPieceArchivePackageParams, PieceServiceHooks } from '../../../pieces/piece-service/piece-service-hooks' +import { + FileCompression, + FileId, + FileType, + PieceType, + isNil, +} from '@activepieces/shared' +import { + GetPieceArchivePackageParams, + PieceServiceHooks, +} from '../../../pieces/piece-service/piece-service-hooks' import { fileService } from '../../../file/file.service' export const platformPieceServiceHooks: PieceServiceHooks = { @@ -15,7 +24,9 @@ export const platformPieceServiceHooks: PieceServiceHooks = { }, } -const saveArchive = async (params: GetPieceArchivePackageParams): Promise => { +const saveArchive = async ( + params: GetPieceArchivePackageParams, +): Promise => { const { projectId, platformId, archive } = params const archiveFile = await fileService.save({ diff --git a/packages/server/api/src/app/ee/pieces/platform-piece-module.ts b/packages/server/api/src/app/ee/pieces/platform-piece-module.ts new file mode 100644 index 0000000000..2c0c151132 --- /dev/null +++ b/packages/server/api/src/app/ee/pieces/platform-piece-module.ts @@ -0,0 +1,89 @@ +import { + FastifyPluginAsyncTypebox, + Type, +} from '@fastify/type-provider-typebox' +import { FastifyPluginCallbackTypebox } from '@fastify/type-provider-typebox' +import { + ActivepiecesError, + AddPieceRequestBody, + EndpointScope, + ErrorCode, + PieceScope, + PlatformRole, + Principal, + PrincipalType, +} from '@activepieces/shared' +import { pieceService } from '../../pieces/piece-service' +import { StatusCodes } from 'http-status-codes' + +export const platformPieceModule: FastifyPluginAsyncTypebox = async (app) => { + await app.register(platformPieceController, { prefix: '/v1/pieces' }) +} + +const platformPieceController: FastifyPluginCallbackTypebox = ( + app, + _opts, + done, +) => { + app.post( + '/', + { + config: { + allowedPrincipals: [PrincipalType.USER, PrincipalType.SERVICE], + scope: EndpointScope.PLATFORM, + }, + schema: { + tags: ['pieces'], + summary: 'Add a piece to a platform', + description: 'Add a piece to a platform', + body: AddPieceRequestBody, + response: { + [StatusCodes.CREATED]: Type.Object({}), + }, + }, + }, + async (req, reply) => { + const platformId = req.principal.platform?.id + assertPrincipalIsPlatformOwner(req.body.scope, req.principal) + assertProjectScopeOnlyAllowedForUser(req.body.scope, req.principal) + await pieceService.installPiece( + platformId, + req.principal.projectId, + req.body, + ) + await reply.status(StatusCodes.CREATED).send({}) + }, + ) + + done() +} + +function assertPrincipalIsPlatformOwner( + scope: PieceScope, + principal: Principal, +): void { + if (scope == PieceScope.PLATFORM) { + if (principal.platform?.role !== PlatformRole.OWNER) { + throw new ActivepiecesError({ + code: ErrorCode.ENGINE_OPERATION_FAILURE, + params: { + message: 'Principal is not platform owner', + }, + }) + } + } +} + +function assertProjectScopeOnlyAllowedForUser( + scope: PieceScope, + principal: Principal, +): void { + if (scope === PieceScope.PROJECT && principal.type !== PrincipalType.USER) { + throw new ActivepiecesError({ + code: ErrorCode.ENGINE_OPERATION_FAILURE, + params: { + message: 'Project scope is only allowed for user token', + }, + }) + } +} diff --git a/packages/backend/src/app/ee/platform/admin-platform.controller.ts b/packages/server/api/src/app/ee/platform/admin-platform.controller.ts similarity index 86% rename from packages/backend/src/app/ee/platform/admin-platform.controller.ts rename to packages/server/api/src/app/ee/platform/admin-platform.controller.ts index 84e88fb975..87a6abc9b6 100644 --- a/packages/backend/src/app/ee/platform/admin-platform.controller.ts +++ b/packages/server/api/src/app/ee/platform/admin-platform.controller.ts @@ -4,13 +4,13 @@ import { StatusCodes } from 'http-status-codes' import { adminPlatformService } from './admin-platform.service' import { PrincipalType } from '@activepieces/shared' -export const adminPlatformController: FastifyPluginAsyncTypebox = async (app) => { +export const adminPlatformController: FastifyPluginAsyncTypebox = async ( + app, +) => { app.post('/', AdminAddPlatformRequest, async (req, res) => { const newPlatform = await adminPlatformService.add(req.body) - return res - .status(StatusCodes.CREATED) - .send(newPlatform) + return res.status(StatusCodes.CREATED).send(newPlatform) }) } diff --git a/packages/backend/src/app/ee/platform/admin-platform.service.ts b/packages/server/api/src/app/ee/platform/admin-platform.service.ts similarity index 78% rename from packages/backend/src/app/ee/platform/admin-platform.service.ts rename to packages/server/api/src/app/ee/platform/admin-platform.service.ts index d7432564e9..eb81b55aeb 100644 --- a/packages/backend/src/app/ee/platform/admin-platform.service.ts +++ b/packages/server/api/src/app/ee/platform/admin-platform.service.ts @@ -1,10 +1,21 @@ -import { ActivepiecesError, ErrorCode, Project, ProjectId, UserId, isNil } from '@activepieces/shared' +import { + ActivepiecesError, + ErrorCode, + Project, + ProjectId, + UserId, + isNil, +} from '@activepieces/shared' import { projectService } from '../../project/project-service' import { platformService } from './platform.service' import { Platform } from '@activepieces/ee-shared' export const adminPlatformService = { - async add({ userId, projectId, name }: AdminAddPlatformParams): Promise { + async add({ + userId, + projectId, + name, + }: AdminAddPlatformParams): Promise { const project = await getProjectOrThrow(projectId) return platformService.add({ diff --git a/packages/backend/src/app/ee/platform/lib/platform-utils.ts b/packages/server/api/src/app/ee/platform/lib/platform-utils.ts similarity index 61% rename from packages/backend/src/app/ee/platform/lib/platform-utils.ts rename to packages/server/api/src/app/ee/platform/lib/platform-utils.ts index 9fa143e211..8e8d84332a 100644 --- a/packages/backend/src/app/ee/platform/lib/platform-utils.ts +++ b/packages/server/api/src/app/ee/platform/lib/platform-utils.ts @@ -6,28 +6,37 @@ import { platformService } from '../platform.service' const edition = getEdition() -export const resolvePlatformIdForRequest = async (request: FastifyRequest): Promise => { +export const resolvePlatformIdForRequest = async ( + request: FastifyRequest, +): Promise => { if (edition === ApEdition.COMMUNITY) { return null } - return await extractPlatformIdFromAuthenticatedPrincipal(request.principal) - ?? await getPlatformIdForHostname(request.hostname) + return ( + (await extractPlatformIdFromAuthenticatedPrincipal(request.principal)) ?? + (await getPlatformIdForHostname(request.hostname)) + ) } -const extractPlatformIdFromAuthenticatedPrincipal = async (principal: Principal): Promise => { +const extractPlatformIdFromAuthenticatedPrincipal = async ( + principal: Principal, +): Promise => { return principal.platform?.id ?? getDefaultPlatformId() } -const getPlatformIdForHostname = async (hostname: string): Promise => { - const customDomain = await customDomainService.getOneByDomain({ domain: hostname }) +const getPlatformIdForHostname = async ( + hostname: string, +): Promise => { + const customDomain = await customDomainService.getOneByDomain({ + domain: hostname, + }) return customDomain?.platformId ?? getDefaultPlatformId() } - async function getDefaultPlatformId(): Promise { if (edition === ApEdition.ENTERPRISE) { const platform = await platformService.getOldestPlatform() return platform?.id ?? null } return null -} \ No newline at end of file +} diff --git a/packages/backend/src/app/ee/platform/platform.controller.ts b/packages/server/api/src/app/ee/platform/platform.controller.ts old mode 100755 new mode 100644 similarity index 77% rename from packages/backend/src/app/ee/platform/platform.controller.ts rename to packages/server/api/src/app/ee/platform/platform.controller.ts index 8fc12a208d..4e18fa1d55 --- a/packages/backend/src/app/ee/platform/platform.controller.ts +++ b/packages/server/api/src/app/ee/platform/platform.controller.ts @@ -1,5 +1,12 @@ -import { FastifyPluginAsyncTypebox, Type } from '@fastify/type-provider-typebox' -import { Platform, PlatformWithoutSensitiveData, UpdatePlatformRequestBody } from '@activepieces/ee-shared' +import { + FastifyPluginAsyncTypebox, + Type, +} from '@fastify/type-provider-typebox' +import { + Platform, + PlatformWithoutSensitiveData, + UpdatePlatformRequestBody, +} from '@activepieces/ee-shared' import { ApId, Principal, assertEqual } from '@activepieces/shared' import { platformService } from './platform.service' import { platformMustBeOwnedByCurrentUser } from '../authentication/ee-authorization' @@ -16,7 +23,12 @@ export const platformController: FastifyPluginAsyncTypebox = async (app) => { }) app.get('/:id', GetPlatformRequest, async (req) => { - assertEqual(req.principal.platform?.id, req.params.id, 'userPlatformId', 'paramId') + assertEqual( + req.principal.platform?.id, + req.params.id, + 'userPlatformId', + 'paramId', + ) const platform = await platformService.getOneOrThrow(req.params.id) return buildResponse({ @@ -26,7 +38,10 @@ export const platformController: FastifyPluginAsyncTypebox = async (app) => { }) } -const buildResponse = ({ platform, principal }: BuildResponseParams): Platform | PlatformBasics => { +const buildResponse = ({ + platform, + principal, +}: BuildResponseParams): Platform | PlatformBasics => { if (platform.ownerId === principal.id) { return { ...platform, diff --git a/packages/backend/src/app/ee/platform/platform.entity.ts b/packages/server/api/src/app/ee/platform/platform.entity.ts similarity index 95% rename from packages/backend/src/app/ee/platform/platform.entity.ts rename to packages/server/api/src/app/ee/platform/platform.entity.ts index 29a91d3b5d..d8b4cc33a1 100644 --- a/packages/backend/src/app/ee/platform/platform.entity.ts +++ b/packages/server/api/src/app/ee/platform/platform.entity.ts @@ -1,6 +1,12 @@ import { EntitySchema } from 'typeorm' import { FilteredPieceBehavior, Platform } from '@activepieces/ee-shared' -import { ARRAY_COLUMN_TYPE, ApIdSchema, BaseColumnSchemaPart, JSONB_COLUMN_TYPE, isPostgres } from '../../database/database-common' +import { + ARRAY_COLUMN_TYPE, + ApIdSchema, + BaseColumnSchemaPart, + JSONB_COLUMN_TYPE, + isPostgres, +} from '../../database/database-common' import { LocalesEnum, User } from '@activepieces/shared' type PlatformSchema = Platform & { @@ -124,8 +130,7 @@ export const PlatformEntity = new EntitySchema({ nullable: false, }, }, - indices: [ - ], + indices: [], relations: { owner: { type: 'one-to-one', diff --git a/packages/backend/src/app/ee/platform/platform.module.ts b/packages/server/api/src/app/ee/platform/platform.module.ts similarity index 78% rename from packages/backend/src/app/ee/platform/platform.module.ts rename to packages/server/api/src/app/ee/platform/platform.module.ts index 5543e30c0a..956cacfc56 100644 --- a/packages/backend/src/app/ee/platform/platform.module.ts +++ b/packages/server/api/src/app/ee/platform/platform.module.ts @@ -3,6 +3,8 @@ import { platformController } from './platform.controller' import { adminPlatformController } from './admin-platform.controller' export const platformModule: FastifyPluginAsyncTypebox = async (app) => { - await app.register(adminPlatformController, { prefix: '/v1/admin/platforms' }) + await app.register(adminPlatformController, { + prefix: '/v1/admin/platforms', + }) await app.register(platformController, { prefix: '/v1/platforms' }) } diff --git a/packages/backend/src/app/ee/platform/platform.service.ts b/packages/server/api/src/app/ee/platform/platform.service.ts similarity index 80% rename from packages/backend/src/app/ee/platform/platform.service.ts rename to packages/server/api/src/app/ee/platform/platform.service.ts index 6be76ce0e2..d9e007cf59 100644 --- a/packages/backend/src/app/ee/platform/platform.service.ts +++ b/packages/server/api/src/app/ee/platform/platform.service.ts @@ -1,7 +1,21 @@ -import { ActivepiecesError, ErrorCode, LocalesEnum, ProjectId, UserId, apId, isNil, spreadIfDefined } from '@activepieces/shared' +import { + ActivepiecesError, + ErrorCode, + LocalesEnum, + ProjectId, + UserId, + apId, + isNil, + spreadIfDefined, +} from '@activepieces/shared' import { databaseConnection } from '../../database/database-connection' import { PlatformEntity } from './platform.entity' -import { FilteredPieceBehavior, Platform, PlatformId, UpdatePlatformRequestBody } from '@activepieces/ee-shared' +import { + FilteredPieceBehavior, + Platform, + PlatformId, + UpdatePlatformRequestBody, +} from '@activepieces/ee-shared' import { defaultTheme } from '../../flags/theme' import { userService } from '../../user/user-service' import { projectService } from '../../project/project-service' @@ -10,7 +24,15 @@ const repo = databaseConnection.getRepository(PlatformEntity) export const platformService = { async add(params: AddParams): Promise { - const { ownerId, projectId, name, primaryColor, logoIconUrl, fullLogoUrl, favIconUrl } = params + const { + ownerId, + projectId, + name, + primaryColor, + logoIconUrl, + fullLogoUrl, + favIconUrl, + } = params const newPlatform: NewPlatform = { id: apId(), @@ -74,7 +96,10 @@ export const platformService = { ...spreadIfDefined('filteredPieceBehavior', params.filteredPieceBehavior), ...spreadIfDefined('smtpHost', params.smtpHost), ...spreadIfDefined('smtpPort', params.smtpPort), - ...spreadIfDefined('federatedAuthProviders', params.federatedAuthProviders), + ...spreadIfDefined( + 'federatedAuthProviders', + params.federatedAuthProviders, + ), ...spreadIfDefined('smtpUser', params.smtpUser), ...spreadIfDefined('smtpPassword', params.smtpPassword), ...spreadIfDefined('smtpSenderEmail', params.smtpSenderEmail), @@ -88,7 +113,10 @@ export const platformService = { ...spreadIfDefined('embeddingEnabled', params.embeddingEnabled), ...spreadIfDefined('ssoEnabled', params.ssoEnabled), ...spreadIfDefined('emailAuthEnabled', params.emailAuthEnabled), - ...spreadIfDefined('enforceAllowedAuthDomains', params.enforceAllowedAuthDomains), + ...spreadIfDefined( + 'enforceAllowedAuthDomains', + params.enforceAllowedAuthDomains, + ), ...spreadIfDefined('allowedAuthDomains', params.allowedAuthDomains), } @@ -110,19 +138,26 @@ export const platformService = { }) }, - async getOneByOwner({ ownerId }: GetOneByOwnerParams): Promise { + async getOneByOwner({ + ownerId, + }: GetOneByOwnerParams): Promise { return repo.findOneBy({ ownerId, }) }, - async checkUserIsOwner({ platformId, userId }: CheckUserIsOwnerParams): Promise { + async checkUserIsOwner({ + platformId, + userId, + }: CheckUserIsOwnerParams): Promise { const platform = await this.getOneOrThrow(platformId) return platform.ownerId === userId }, } -const assertPlatformExists: (platform: Platform | null) => asserts platform is Platform = (platform) => { +const assertPlatformExists: ( + platform: Platform | null +) => asserts platform is Platform = (platform) => { if (isNil(platform)) { throw new ActivepiecesError({ code: ErrorCode.ENTITY_NOT_FOUND, @@ -133,7 +168,10 @@ const assertPlatformExists: (platform: Platform | null) => asserts platform is P } } -const assertPlatformOwnedByUser = (platform: Platform, userId: UserId): void => { +const assertPlatformOwnedByUser = ( + platform: Platform, + userId: UserId, +): void => { if (platform.ownerId !== userId) { throw new ActivepiecesError({ code: ErrorCode.AUTHORIZATION, @@ -142,14 +180,20 @@ const assertPlatformOwnedByUser = (platform: Platform, userId: UserId): void => } } -const addOwnerToPlatform = ({ platformId, ownerId }: AddOwnerToPlatformParams): Promise => { +const addOwnerToPlatform = ({ + platformId, + ownerId, +}: AddOwnerToPlatformParams): Promise => { return userService.updatePlatformId({ id: ownerId, platformId, }) } -const addProjectToPlatform = ({ platformId, projectId }: AddProjectToPlatformParams): Promise => { +const addProjectToPlatform = ({ + platformId, + projectId, +}: AddProjectToPlatformParams): Promise => { return projectService.addProjectToPlatform({ projectId, platformId, diff --git a/packages/backend/src/app/ee/project-members/project-member.controller.ts b/packages/server/api/src/app/ee/project-members/project-member.controller.ts similarity index 88% rename from packages/backend/src/app/ee/project-members/project-member.controller.ts rename to packages/server/api/src/app/ee/project-members/project-member.controller.ts index 2170735b2e..bb2f10b853 100644 --- a/packages/backend/src/app/ee/project-members/project-member.controller.ts +++ b/packages/server/api/src/app/ee/project-members/project-member.controller.ts @@ -1,9 +1,22 @@ -import { ListProjectMembersRequestQuery, AcceptProjectResponse, AddProjectMemberRequestBody, ProjectMember, ProjectMemberStatus } from '@activepieces/ee-shared' -import { ALL_PRINICPAL_TYPES, ActivepiecesError, ErrorCode, PrincipalType, assertNotNullOrUndefined, isNil } from '@activepieces/shared' +import { + ListProjectMembersRequestQuery, + AcceptProjectResponse, + AddProjectMemberRequestBody, + ProjectMember, + ProjectMemberStatus, +} from '@activepieces/ee-shared' +import { + ALL_PRINICPAL_TYPES, + ActivepiecesError, + ErrorCode, + PrincipalType, + assertNotNullOrUndefined, + isNil, +} from '@activepieces/shared' import { FastifyPluginAsyncTypebox } from '@fastify/type-provider-typebox' import { Type } from '@sinclair/typebox' import { StatusCodes } from 'http-status-codes' -import { logger } from '../../helper/logger' +import { logger } from 'server-shared' import { userService } from '../../user/user-service' import { projectMemberService } from './project-member.service' import { platformMustBeOwnedByCurrentUser } from '../authentication/ee-authorization' @@ -12,7 +25,9 @@ import { platformService } from '../platform/platform.service' const DEFAULT_LIMIT_SIZE = 10 -export const projectMemberController: FastifyPluginAsyncTypebox = async (app) => { +export const projectMemberController: FastifyPluginAsyncTypebox = async ( + app, +) => { app.get('/', ListProjectMembersRequestQueryOptions, async (request) => { return projectMemberService.list( request.principal.projectId, @@ -62,10 +77,13 @@ export const projectMemberController: FastifyPluginAsyncTypebox = async (app) => ) await reply.status(StatusCodes.NO_CONTENT).send() }) - } -async function assertFeatureIsEnabled(app: FastifyInstance, request: FastifyRequest, reply: FastifyReply): Promise { +async function assertFeatureIsEnabled( + app: FastifyInstance, + request: FastifyRequest, + reply: FastifyReply, +): Promise { await platformMustBeOwnedByCurrentUser.call(app, request, reply) const platformId = request.principal.platform?.id assertNotNullOrUndefined(platformId, 'platformId') diff --git a/packages/backend/src/app/ee/project-members/project-member.entity.ts b/packages/server/api/src/app/ee/project-members/project-member.entity.ts similarity index 92% rename from packages/backend/src/app/ee/project-members/project-member.entity.ts rename to packages/server/api/src/app/ee/project-members/project-member.entity.ts index 88591f5382..d84c95fcd1 100644 --- a/packages/backend/src/app/ee/project-members/project-member.entity.ts +++ b/packages/server/api/src/app/ee/project-members/project-member.entity.ts @@ -1,6 +1,9 @@ import { EntitySchema } from 'typeorm' import { ProjectMember } from '@activepieces/ee-shared' -import { ApIdSchema, BaseColumnSchemaPart } from '../../database/database-common' +import { + ApIdSchema, + BaseColumnSchemaPart, +} from '../../database/database-common' import { Project, User } from '@activepieces/shared' export type ProjectMemberSchema = ProjectMember & { @@ -35,7 +38,6 @@ export const ProjectMemberEntity = new EntitySchema({ }, ], relations: { - project: { type: 'many-to-one', target: 'project', diff --git a/packages/backend/src/app/ee/project-members/project-member.module.ts b/packages/server/api/src/app/ee/project-members/project-member.module.ts similarity index 70% rename from packages/backend/src/app/ee/project-members/project-member.module.ts rename to packages/server/api/src/app/ee/project-members/project-member.module.ts index 529d6066e4..e7b29f5a90 100644 --- a/packages/backend/src/app/ee/project-members/project-member.module.ts +++ b/packages/server/api/src/app/ee/project-members/project-member.module.ts @@ -2,5 +2,7 @@ import { FastifyPluginAsyncTypebox } from '@fastify/type-provider-typebox' import { projectMemberController } from './project-member.controller' export const projectMemberModule: FastifyPluginAsyncTypebox = async (app) => { - await app.register(projectMemberController, { prefix: '/v1/project-members' }) + await app.register(projectMemberController, { + prefix: '/v1/project-members', + }) } diff --git a/packages/backend/src/app/ee/project-members/project-member.service.ts b/packages/server/api/src/app/ee/project-members/project-member.service.ts similarity index 85% rename from packages/backend/src/app/ee/project-members/project-member.service.ts rename to packages/server/api/src/app/ee/project-members/project-member.service.ts index a5a7a923d4..dfe8f8d0a9 100644 --- a/packages/backend/src/app/ee/project-members/project-member.service.ts +++ b/packages/server/api/src/app/ee/project-members/project-member.service.ts @@ -1,4 +1,7 @@ -import { ProjectMemberEntity, ProjectMemberSchema } from './project-member.entity' +import { + ProjectMemberEntity, + ProjectMemberSchema, +} from './project-member.entity' import { databaseConnection } from '../../database/database-connection' import { userService } from '../../user/user-service' import { @@ -34,7 +37,12 @@ import { jwtUtils } from '../../helper/jwt-utils' const projectMemberRepo = databaseConnection.getRepository(ProjectMemberEntity) export const projectMemberService = { - async upsert({ email, projectId, role, status }: UpsertParams): Promise { + async upsert({ + email, + projectId, + role, + status, + }: UpsertParams): Promise { await projectMembersLimit.limit({ projectId, }) @@ -58,7 +66,11 @@ export const projectMemberService = { status: status ?? getStatusFromEdition(), } - const upsertResult = await projectMemberRepo.upsert(projectMember, ['projectId', 'email', 'platformId']) + const upsertResult = await projectMemberRepo.upsert(projectMember, [ + 'projectId', + 'email', + 'platformId', + ]) return { ...projectMember, @@ -66,7 +78,12 @@ export const projectMemberService = { } }, - async upsertAndSend({ projectId, email, role, status }: UpsertAndSendParams): Promise { + async upsertAndSend({ + projectId, + email, + role, + status, + }: UpsertAndSendParams): Promise { const projectMember = await this.upsert({ email, projectId, @@ -93,7 +110,9 @@ export const projectMemberService = { }, async accept({ invitationToken }: AcceptParams): Promise { - const { id: projectMemberId } = await getByInvitationTokenOrThrow(invitationToken) + const { id: projectMemberId } = await getByInvitationTokenOrThrow( + invitationToken, + ) const projectMember = await getOrThrow(projectMemberId) await projectMemberRepo.update(projectMemberId, { @@ -144,7 +163,13 @@ export const projectMemberService = { projectMembers.push(...data) return paginationHelper.createPage(projectMembers, cursor) }, - async getRole({ userId, projectId }: { projectId: ProjectId, userId: UserId }): Promise { + async getRole({ + userId, + projectId, + }: { + projectId: ProjectId + userId: UserId + }): Promise { const project = await projectService.getOne(projectId) if (project?.ownerId === userId) { return ProjectMemberRole.ADMIN @@ -159,7 +184,13 @@ export const projectMemberService = { }) return member?.role ?? null }, - async listByUser({ email, platformId }: { email: string, platformId: null | string }): Promise { + async listByUser({ + email, + platformId, + }: { + email: string + platformId: null | string + }): Promise { return projectMemberRepo.findBy({ email, status: ProjectMemberStatus.ACTIVE, @@ -173,14 +204,19 @@ export const projectMemberService = { await projectMemberRepo.delete({ projectId, id: invitationId }) }, async countTeamMembersIncludingOwner(projectId: ProjectId): Promise { - return await projectMemberRepo.countBy({ - projectId, - }) + 1 + return ( + (await projectMemberRepo.countBy({ + projectId, + })) + 1 + ) }, } -async function getByInvitationTokenOrThrow(invitationToken: string): Promise { - const { id: projectMemberId } = await jwtUtils.decodeAndVerify({ +async function getByInvitationTokenOrThrow( + invitationToken: string, +): Promise { + const { id: projectMemberId } = + await jwtUtils.decodeAndVerify({ jwt: invitationToken, key: await jwtUtils.getJwtSecret(), }) diff --git a/packages/backend/src/app/ee/projects/platform-project-controller.ts b/packages/server/api/src/app/ee/projects/platform-project-controller.ts old mode 100755 new mode 100644 similarity index 85% rename from packages/backend/src/app/ee/projects/platform-project-controller.ts rename to packages/server/api/src/app/ee/projects/platform-project-controller.ts index 529ab9d491..4db3e1b4d1 --- a/packages/backend/src/app/ee/projects/platform-project-controller.ts +++ b/packages/server/api/src/app/ee/projects/platform-project-controller.ts @@ -1,13 +1,31 @@ -import { EndpointScope, PrincipalType, ProjectType, SeekPage, assertNotNullOrUndefined } from '@activepieces/shared' -import { FastifyPluginCallbackTypebox, Type } from '@fastify/type-provider-typebox' +import { + EndpointScope, + PrincipalType, + ProjectType, + SeekPage, + assertNotNullOrUndefined, +} from '@activepieces/shared' +import { + FastifyPluginCallbackTypebox, + Type, +} from '@fastify/type-provider-typebox' import { platformProjectService } from './platform-project-service' import { projectService } from '../../project/project-service' -import { CreatePlatformProjectRequest, DEFAULT_PLATFORM_PLAN, ProjectWithUsageAndPlanResponse, UpdateProjectPlatformRequest } from '@activepieces/ee-shared' +import { + CreatePlatformProjectRequest, + DEFAULT_PLATFORM_PLAN, + ProjectWithUsageAndPlanResponse, + UpdateProjectPlatformRequest, +} from '@activepieces/ee-shared' import { plansService } from '../billing/project-plan/project-plan.service' import { StatusCodes } from 'http-status-codes' import { platformService } from '../platform/platform.service' -export const platformProjectController: FastifyPluginCallbackTypebox = (fastify, _opts, done) => { +export const platformProjectController: FastifyPluginCallbackTypebox = ( + fastify, + _opts, + done, +) => { fastify.post('/', CreateProjectRequest, async (request, reply) => { const platformId = request.principal.platform?.id assertNotNullOrUndefined(platformId, 'platformId') @@ -25,10 +43,10 @@ export const platformProjectController: FastifyPluginCallbackTypebox = (fastify, subscription: null, planLimits: DEFAULT_PLATFORM_PLAN, }) - const projectWithUsage = await platformProjectService.getWithPlanAndUsageOrThrow(project.id) + const projectWithUsage = + await platformProjectService.getWithPlanAndUsageOrThrow(project.id) await reply.status(StatusCodes.CREATED).send(projectWithUsage) - }, - ) + }) fastify.get('/', ListProjectRequestForApiKey, async (request) => { const platformId = request.principal.platform?.id @@ -40,7 +58,6 @@ export const platformProjectController: FastifyPluginCallbackTypebox = (fastify, }) }) - fastify.post('/:id', UpdateProjectRequest, async (request) => { let userId = request.principal.id if (request.principal.type === PrincipalType.SERVICE) { @@ -55,13 +72,11 @@ export const platformProjectController: FastifyPluginCallbackTypebox = (fastify, userId, request: request.body, }) - }) done() } - const UpdateProjectRequest = { config: { allowedPrincipals: [PrincipalType.USER, PrincipalType.SERVICE], diff --git a/packages/backend/src/app/ee/projects/platform-project-module.ts b/packages/server/api/src/app/ee/projects/platform-project-module.ts similarity index 100% rename from packages/backend/src/app/ee/projects/platform-project-module.ts rename to packages/server/api/src/app/ee/projects/platform-project-module.ts diff --git a/packages/backend/src/app/ee/projects/platform-project-service.ts b/packages/server/api/src/app/ee/projects/platform-project-service.ts similarity index 63% rename from packages/backend/src/app/ee/projects/platform-project-service.ts rename to packages/server/api/src/app/ee/projects/platform-project-service.ts index 34eaeeaceb..f15f98e50c 100644 --- a/packages/backend/src/app/ee/projects/platform-project-service.ts +++ b/packages/server/api/src/app/ee/projects/platform-project-service.ts @@ -1,6 +1,22 @@ -import { ActivepiecesError, ErrorCode, Project, ProjectId, ProjectType, UserId, isNil, SeekPage, assertNotNullOrUndefined, spreadIfDefined } from '@activepieces/shared' +import { + ActivepiecesError, + ErrorCode, + Project, + ProjectId, + ProjectType, + UserId, + isNil, + SeekPage, + assertNotNullOrUndefined, + spreadIfDefined, +} from '@activepieces/shared' import { Equal, In, IsNull } from 'typeorm' -import { PlatformId, ProjectMemberStatus, ProjectWithUsageAndPlanResponse, UpdateProjectPlatformRequest } from '@activepieces/ee-shared' +import { + PlatformId, + ProjectMemberStatus, + ProjectWithUsageAndPlanResponse, + UpdateProjectPlatformRequest, +} from '@activepieces/ee-shared' import { ProjectMemberEntity } from '../project-members/project-member.entity' import { ProjectEntity } from '../../project/project-entity' import { databaseConnection } from '../../database/database-connection' @@ -13,19 +29,47 @@ const projectRepo = databaseConnection.getRepository(ProjectEntity) const projectMemberRepo = databaseConnection.getRepository(ProjectMemberEntity) export const platformProjectService = { - async getAll({ ownerId, platformId, externalId }: { ownerId: UserId | undefined, platformId?: PlatformId, externalId?: string }): Promise> { + async getAll({ + ownerId, + platformId, + externalId, + }: { + ownerId: UserId | undefined + platformId?: PlatformId + externalId?: string + }): Promise> { const filters = await createFilters(ownerId, platformId, externalId) - const projectPlans = await projectRepo.createQueryBuilder('project') - .leftJoinAndMapOne('project.plan', 'project_plan', 'project_plan', 'project.id = "project_plan"."projectId"') + const projectPlans = await projectRepo + .createQueryBuilder('project') + .leftJoinAndMapOne( + 'project.plan', + 'project_plan', + 'project_plan', + 'project.id = "project_plan"."projectId"', + ) .where(filters) - // TODO add pagination + // TODO add pagination .limit(50) .getMany() - const projects: ProjectWithUsageAndPlanResponse[] = await Promise.all(projectPlans.map(enrichWithUsageAndPlan)) - return paginationHelper.createPage(projects, null) + const projects: ProjectWithUsageAndPlanResponse[] = await Promise.all( + projectPlans.map(enrichWithUsageAndPlan), + ) + return paginationHelper.createPage( + projects, + null, + ) }, - async update({ userId, projectId, request }: { userId: string, projectId: ProjectId, request: UpdateProjectPlatformRequest, platformId?: PlatformId }): Promise { + async update({ + userId, + projectId, + request, + }: { + userId: string + projectId: ProjectId + request: UpdateProjectPlatformRequest + platformId?: PlatformId + }): Promise { const project = await projectRepo.findOneBy({ id: projectId, }) @@ -61,14 +105,22 @@ export const platformProjectService = { } return this.getWithPlanAndUsageOrThrow(projectId) }, - async getWithPlanAndUsageOrThrow(projectId: string): Promise { - return enrichWithUsageAndPlan(await projectRepo.findOneByOrFail({ - id: projectId, - })) + async getWithPlanAndUsageOrThrow( + projectId: string, + ): Promise { + return enrichWithUsageAndPlan( + await projectRepo.findOneByOrFail({ + id: projectId, + }), + ) }, } -async function createFilters(ownerId: UserId | undefined, platformId?: PlatformId, externalId?: string | undefined) { +async function createFilters( + ownerId: UserId | undefined, + platformId?: PlatformId, + externalId?: string | undefined, +) { const extraFilter = { ...spreadIfDefined('platformId', platformId), ...spreadIfDefined('externalId', externalId), @@ -95,11 +147,15 @@ async function getIdsOfProjects(ownerId: UserId): Promise { platformId: isNil(user?.platformId) ? IsNull() : Equal(user?.platformId), status: Equal(ProjectMemberStatus.ACTIVE), }) - return members.map(member => member.projectId) + return members.map((member) => member.projectId) } -async function enrichWithUsageAndPlan(project: Project): Promise { - const clonedProject: ProjectWithUsageAndPlanResponse = JSON.parse(JSON.stringify(project)) +async function enrichWithUsageAndPlan( + project: Project, +): Promise { + const clonedProject: ProjectWithUsageAndPlanResponse = JSON.parse( + JSON.stringify(project), + ) if (isNil(clonedProject.plan)) { clonedProject.plan = await plansService.getOrCreateDefaultPlan({ @@ -107,7 +163,9 @@ async function enrichWithUsageAndPlan(project: Project): Promise { + fastify.get('/', ListProjectRequestForUser, async (request) => { + return platformProjectService.getAll({ + ownerId: request.principal.id, + platformId: request.query.platformId, + }) + }) + + fastify.post( + '/:projectId/token', + SwitchTokenRequestForUser, + async (request) => { + const allProjects = await platformProjectService.getAll({ + ownerId: request.principal.id, + }) + const project = allProjects.data.find( + (project) => project.id === request.params.projectId, + ) + if (!project) { + throw new ActivepiecesError({ + code: ErrorCode.ENTITY_NOT_FOUND, + params: { + entityId: request.params.projectId, + entityType: 'project', + }, + }) + } + const platform = isNil(project.platformId) + ? null + : await platformService.getOne(project.platformId) + return { + token: await accessTokenManager.generateToken({ + id: request.principal.id, + type: request.principal.type, + projectId: request.params.projectId, + projectType: project.type, + platform: isNil(platform) + ? undefined + : { + id: platform.id, + role: + platform.ownerId === request.principal.id + ? PlatformRole.OWNER + : PlatformRole.MEMBER, + }, + }), + } + }, + ) + + done() +} + +const SwitchTokenRequestForUser = { + config: { + allowedPrincipals: [PrincipalType.USER], + }, + schema: { + params: Type.Object({ + projectId: Type.String(), + }), + }, +} + +const ListProjectRequestForUser = { + config: { + allowedPrincipals: [PrincipalType.USER], + }, + schema: { + response: { + [StatusCodes.OK]: SeekPage(ProjectWithUsageAndPlanResponse), + }, + querystring: Type.Object({ + platformId: Type.Optional(Type.String()), + }), + }, +} diff --git a/packages/backend/src/app/ee/referrals/referral.entity.ts b/packages/server/api/src/app/ee/referrals/referral.entity.ts similarity index 93% rename from packages/backend/src/app/ee/referrals/referral.entity.ts rename to packages/server/api/src/app/ee/referrals/referral.entity.ts index bee51adcd6..7c94f238b6 100644 --- a/packages/backend/src/app/ee/referrals/referral.entity.ts +++ b/packages/server/api/src/app/ee/referrals/referral.entity.ts @@ -1,7 +1,10 @@ import { EntitySchema } from 'typeorm' import { User } from '@activepieces/shared' import { Referral } from '@activepieces/ee-shared' -import { ApIdSchema, BaseColumnSchemaPart } from '../../database/database-common' +import { + ApIdSchema, + BaseColumnSchemaPart, +} from '../../database/database-common' export type ReferralSchema = Referral & { referredUser: User @@ -44,4 +47,4 @@ export const ReferralEntity = new EntitySchema({ }, }, }, -}) \ No newline at end of file +}) diff --git a/packages/backend/src/app/ee/referrals/referral.module.ts b/packages/server/api/src/app/ee/referrals/referral.module.ts similarity index 55% rename from packages/backend/src/app/ee/referrals/referral.module.ts rename to packages/server/api/src/app/ee/referrals/referral.module.ts index ec3b802525..a6ac340097 100644 --- a/packages/backend/src/app/ee/referrals/referral.module.ts +++ b/packages/server/api/src/app/ee/referrals/referral.module.ts @@ -9,12 +9,19 @@ export const referralModule: FastifyPluginAsyncTypebox = async (app) => { const DEFAULT_LIMIT_SIZE = 10 const referralController: FastifyPluginAsyncTypebox = async (fastify) => { - - fastify.get('/', { - schema: { - querystring: ListReferralsRequest, + fastify.get( + '/', + { + schema: { + querystring: ListReferralsRequest, + }, + }, + async (request) => { + return referralService.list( + request.principal.id, + request.query.cursor ?? null, + request.query.limit ?? DEFAULT_LIMIT_SIZE, + ) }, - }, async (request) => { - return referralService.list(request.principal.id, request.query.cursor ?? null, request.query.limit ?? DEFAULT_LIMIT_SIZE) - }) + ) } diff --git a/packages/backend/src/app/ee/referrals/referral.service.ts b/packages/server/api/src/app/ee/referrals/referral.service.ts similarity index 78% rename from packages/backend/src/app/ee/referrals/referral.service.ts rename to packages/server/api/src/app/ee/referrals/referral.service.ts index 2b703e5cad..c999ce3fce 100644 --- a/packages/backend/src/app/ee/referrals/referral.service.ts +++ b/packages/server/api/src/app/ee/referrals/referral.service.ts @@ -1,4 +1,10 @@ -import { Cursor, SeekPage, TelemetryEventName, UserId, apId } from '@activepieces/shared' +import { + Cursor, + SeekPage, + TelemetryEventName, + UserId, + apId, +} from '@activepieces/shared' import { databaseConnection } from '../../database/database-connection' import { ReferralEntity } from './referral.entity' import { Referral } from '@activepieces/ee-shared' @@ -7,7 +13,7 @@ import { buildPaginator } from '../../helper/pagination/build-paginator' import { telemetry } from '../../helper/telemetry.utils' import { projectService } from '../../project/project-service' import { userService } from '../../user/user-service' -import { logger } from '../../helper/logger' +import { logger } from 'server-shared' import { plansService } from '../billing/project-plan/project-plan.service' const referralRepo = databaseConnection.getRepository(ReferralEntity) @@ -34,17 +40,19 @@ export const referralService = { ['referredUserId', 'referringUserId'], ) - telemetry.trackUser(referringUserId, { - name: TelemetryEventName.REFERRAL, - payload: { - referredUserId, - }, - }) - .catch((e) => logger.error(e, '[ReferralService#upsert] telemetry.trackUser')) + telemetry + .trackUser(referringUserId, { + name: TelemetryEventName.REFERRAL, + payload: { + referredUserId, + }, + }) + .catch((e) => + logger.error(e, '[ReferralService#upsert] telemetry.trackUser'), + ) await addExtraTasks(referringUserId) await addExtraTasks(referredUserId) - }, async list( referringUserId: UserId, @@ -69,7 +77,9 @@ export const referralService = { } async function addExtraTasks(userId: string) { - const referralsCount = await referralRepo.countBy({ referringUserId: userId }) + const referralsCount = await referralRepo.countBy({ + referringUserId: userId, + }) if (referralsCount > 5) { return } @@ -83,5 +93,7 @@ async function addExtraTasks(userId: string) { projectId: ownerProject.id, tasks: newTasks, }) - logger.info(`Referral from ${userId} created and plan for project ${ownerProject.id} updated to add ${newTasks} tasks.`) + logger.info( + `Referral from ${userId} created and plan for project ${ownerProject.id} updated to add ${newTasks} tasks.`, + ) } diff --git a/packages/backend/src/app/ee/signing-key/signing-key-controller.ts b/packages/server/api/src/app/ee/signing-key/signing-key-controller.ts similarity index 88% rename from packages/backend/src/app/ee/signing-key/signing-key-controller.ts rename to packages/server/api/src/app/ee/signing-key/signing-key-controller.ts index 2a48e773a5..d7816a286b 100644 --- a/packages/backend/src/app/ee/signing-key/signing-key-controller.ts +++ b/packages/server/api/src/app/ee/signing-key/signing-key-controller.ts @@ -1,5 +1,14 @@ -import { FastifyPluginAsyncTypebox, Type } from '@fastify/type-provider-typebox' -import { ActivepiecesError, ApId, ErrorCode, assertNotNullOrUndefined, isNil } from '@activepieces/shared' +import { + FastifyPluginAsyncTypebox, + Type, +} from '@fastify/type-provider-typebox' +import { + ActivepiecesError, + ApId, + ErrorCode, + assertNotNullOrUndefined, + isNil, +} from '@activepieces/shared' import { signingKeyService } from './signing-key-service' import { StatusCodes } from 'http-status-codes' import { AddSigningKeyRequestBody } from '@activepieces/ee-shared' @@ -15,9 +24,7 @@ export const signingKeyController: FastifyPluginAsyncTypebox = async (app) => { displayName: req.body.displayName, }) - return res - .status(StatusCodes.CREATED) - .send(newSigningKey) + return res.status(StatusCodes.CREATED).send(newSigningKey) }) app.get('/', {}, async (req) => { @@ -56,8 +63,6 @@ export const signingKeyController: FastifyPluginAsyncTypebox = async (app) => { }) } - - const AddSigningKeyRequest = { schema: { body: AddSigningKeyRequestBody, diff --git a/packages/backend/src/app/ee/signing-key/signing-key-entity.ts b/packages/server/api/src/app/ee/signing-key/signing-key-entity.ts similarity index 93% rename from packages/backend/src/app/ee/signing-key/signing-key-entity.ts rename to packages/server/api/src/app/ee/signing-key/signing-key-entity.ts index 260db885a0..8d42349ebe 100644 --- a/packages/backend/src/app/ee/signing-key/signing-key-entity.ts +++ b/packages/server/api/src/app/ee/signing-key/signing-key-entity.ts @@ -1,6 +1,9 @@ import { KeyAlgorithm, SigningKey, Platform } from '@activepieces/ee-shared' import { EntitySchema } from 'typeorm' -import { ApIdSchema, BaseColumnSchemaPart } from '../../database/database-common' +import { + ApIdSchema, + BaseColumnSchemaPart, +} from '../../database/database-common' import { User } from '@activepieces/shared' type SigningKeySchema = SigningKey & { @@ -34,8 +37,7 @@ export const SigningKeyEntity = new EntitySchema({ nullable: false, }, }, - indices: [ - ], + indices: [], relations: { platform: { type: 'many-to-one', diff --git a/packages/backend/src/app/ee/signing-key/signing-key-generator.ts b/packages/server/api/src/app/ee/signing-key/signing-key-generator.ts similarity index 89% rename from packages/backend/src/app/ee/signing-key/signing-key-generator.ts rename to packages/server/api/src/app/ee/signing-key/signing-key-generator.ts index fc4ab8942a..9d546d37d0 100644 --- a/packages/backend/src/app/ee/signing-key/signing-key-generator.ts +++ b/packages/server/api/src/app/ee/signing-key/signing-key-generator.ts @@ -1,5 +1,8 @@ import { promisify } from 'node:util' -import { RSAKeyPairOptions, generateKeyPair as generateKeyPairCallback } from 'node:crypto' +import { + RSAKeyPairOptions, + generateKeyPair as generateKeyPairCallback, +} from 'node:crypto' import { KeyAlgorithm } from '@activepieces/ee-shared' const generateKeyPair = promisify(generateKeyPairCallback) diff --git a/packages/backend/src/app/ee/signing-key/signing-key-module.ts b/packages/server/api/src/app/ee/signing-key/signing-key-module.ts similarity index 100% rename from packages/backend/src/app/ee/signing-key/signing-key-module.ts rename to packages/server/api/src/app/ee/signing-key/signing-key-module.ts diff --git a/packages/backend/src/app/ee/signing-key/signing-key-service.ts b/packages/server/api/src/app/ee/signing-key/signing-key-service.ts similarity index 84% rename from packages/backend/src/app/ee/signing-key/signing-key-service.ts rename to packages/server/api/src/app/ee/signing-key/signing-key-service.ts index c4ecd2cb68..062c13a478 100644 --- a/packages/backend/src/app/ee/signing-key/signing-key-service.ts +++ b/packages/server/api/src/app/ee/signing-key/signing-key-service.ts @@ -1,5 +1,17 @@ -import { SigningKey, SigningKeyId, PlatformId, AddSigningKeyResponse } from '@activepieces/ee-shared' -import { ActivepiecesError, ErrorCode, SeekPage, UserId, apId, isNil } from '@activepieces/shared' +import { + SigningKey, + SigningKeyId, + PlatformId, + AddSigningKeyResponse, +} from '@activepieces/ee-shared' +import { + ActivepiecesError, + ErrorCode, + SeekPage, + UserId, + apId, + isNil, +} from '@activepieces/shared' import { signingKeyGenerator } from './signing-key-generator' import { databaseConnection } from '../../database/database-connection' import { SigningKeyEntity } from './signing-key-entity' @@ -7,8 +19,11 @@ import { SigningKeyEntity } from './signing-key-entity' const repo = databaseConnection.getRepository(SigningKeyEntity) export const signingKeyService = { - async add({ userId, platformId, displayName }: AddParams): Promise { - + async add({ + userId, + platformId, + displayName, + }: AddParams): Promise { const generatedSigningKey = await signingKeyGenerator.generate() const newSigningKey: NewSigningKey = { @@ -66,7 +81,6 @@ export const signingKeyService = { }, } - type AddParams = { userId: UserId platformId: PlatformId diff --git a/packages/backend/src/app/ee/user/enterprise-user-controller.ts b/packages/server/api/src/app/ee/user/enterprise-user-controller.ts similarity index 84% rename from packages/backend/src/app/ee/user/enterprise-user-controller.ts rename to packages/server/api/src/app/ee/user/enterprise-user-controller.ts index 1cfd02f57d..ecd3d848b7 100644 --- a/packages/backend/src/app/ee/user/enterprise-user-controller.ts +++ b/packages/server/api/src/app/ee/user/enterprise-user-controller.ts @@ -1,10 +1,22 @@ -import { FastifyPluginAsyncTypebox, Type } from '@fastify/type-provider-typebox' -import { ApId, EndpointScope, PrincipalType, SeekPage, UserResponse, assertNotNullOrUndefined } from '@activepieces/shared' +import { + FastifyPluginAsyncTypebox, + Type, +} from '@fastify/type-provider-typebox' +import { + ApId, + EndpointScope, + PrincipalType, + SeekPage, + UserResponse, + assertNotNullOrUndefined, +} from '@activepieces/shared' import { enterpriseUserService } from './enterprise-user-service' import { StatusCodes } from 'http-status-codes' import { UpdateUserRequestBody } from '@activepieces/ee-shared' -export const enterpriseUserController: FastifyPluginAsyncTypebox = async (app) => { +export const enterpriseUserController: FastifyPluginAsyncTypebox = async ( + app, +) => { app.get('/', ListUsersRequest, async (req) => { const platformId = req.principal.platform?.id assertNotNullOrUndefined(platformId, 'platformId') @@ -23,9 +35,7 @@ export const enterpriseUserController: FastifyPluginAsyncTypebox = async (app) = platformId, status: req.body.status, }) - }) - } const ListUsersRequest = { diff --git a/packages/backend/src/app/ee/user/enterprise-user-module.ts b/packages/server/api/src/app/ee/user/enterprise-user-module.ts similarity index 100% rename from packages/backend/src/app/ee/user/enterprise-user-module.ts rename to packages/server/api/src/app/ee/user/enterprise-user-module.ts diff --git a/packages/backend/src/app/ee/user/enterprise-user-service.ts b/packages/server/api/src/app/ee/user/enterprise-user-service.ts similarity index 78% rename from packages/backend/src/app/ee/user/enterprise-user-service.ts rename to packages/server/api/src/app/ee/user/enterprise-user-service.ts index fb7695c172..8b21092859 100644 --- a/packages/backend/src/app/ee/user/enterprise-user-service.ts +++ b/packages/server/api/src/app/ee/user/enterprise-user-service.ts @@ -1,4 +1,11 @@ -import { ActivepiecesError, ErrorCode, SeekPage, User, UserId, UserStatus } from '@activepieces/shared' +import { + ActivepiecesError, + ErrorCode, + SeekPage, + User, + UserId, + UserStatus, +} from '@activepieces/shared' import { PlatformId } from '@activepieces/ee-shared' import { databaseConnection } from '../../database/database-connection' import { UserEntity } from '../../user/user-entity' @@ -19,12 +26,15 @@ export const enterpriseUserService = { }, async update({ id, status, platformId }: UpdateParams): Promise { - const updateResult = await repo.update({ - id, - platformId, - }, { - status, - }) + const updateResult = await repo.update( + { + id, + platformId, + }, + { + status, + }, + ) if (updateResult.affected !== 1) { throw new ActivepiecesError({ code: ErrorCode.ENTITY_NOT_FOUND, diff --git a/packages/backend/src/app/file/file.controller.ts b/packages/server/api/src/app/file/file.controller.ts old mode 100755 new mode 100644 similarity index 61% rename from packages/backend/src/app/file/file.controller.ts rename to packages/server/api/src/app/file/file.controller.ts index 0d3a0ac7c1..d7612e5e31 --- a/packages/backend/src/app/file/file.controller.ts +++ b/packages/server/api/src/app/file/file.controller.ts @@ -14,8 +14,14 @@ export const fileController = async (fastify: FastifyInstance) => { }>, reply, ) => { - const file = await fileService.getOneOrThrow({ projectId: request.principal.projectId, fileId: request.params.fileId }) - return reply.type('application/zip').status(StatusCodes.OK).send(file.data) + const file = await fileService.getOneOrThrow({ + projectId: request.principal.projectId, + fileId: request.params.fileId, + }) + return reply + .type('application/zip') + .status(StatusCodes.OK) + .send(file.data) }, ) } diff --git a/packages/backend/src/app/file/file.entity.ts b/packages/server/api/src/app/file/file.entity.ts old mode 100755 new mode 100644 similarity index 90% rename from packages/backend/src/app/file/file.entity.ts rename to packages/server/api/src/app/file/file.entity.ts index d2af74eee0..7b4c2121e6 --- a/packages/backend/src/app/file/file.entity.ts +++ b/packages/server/api/src/app/file/file.entity.ts @@ -1,5 +1,9 @@ import { EntitySchema } from 'typeorm' -import { ApIdSchema, BLOB_COLUMN_TYPE, BaseColumnSchemaPart } from '../database/database-common' +import { + ApIdSchema, + BLOB_COLUMN_TYPE, + BaseColumnSchemaPart, +} from '../database/database-common' import { File, FileCompression, FileType, Project } from '@activepieces/shared' type FileSchema = File & { diff --git a/packages/backend/src/app/file/file.module.ts b/packages/server/api/src/app/file/file.module.ts old mode 100755 new mode 100644 similarity index 100% rename from packages/backend/src/app/file/file.module.ts rename to packages/server/api/src/app/file/file.module.ts diff --git a/packages/backend/src/app/file/file.service.ts b/packages/server/api/src/app/file/file.service.ts old mode 100755 new mode 100644 similarity index 79% rename from packages/backend/src/app/file/file.service.ts rename to packages/server/api/src/app/file/file.service.ts index b1c90e5b92..cd28a652c7 --- a/packages/backend/src/app/file/file.service.ts +++ b/packages/server/api/src/app/file/file.service.ts @@ -1,9 +1,17 @@ -import { ActivepiecesError, apId, ErrorCode, File, FileCompression, FileId, FileType, ProjectId } from '@activepieces/shared' +import { + ActivepiecesError, + apId, + ErrorCode, + File, + FileCompression, + FileId, + FileType, + ProjectId, +} from '@activepieces/shared' import { isNil } from '@activepieces/shared' import { databaseConnection } from '../database/database-connection' -import { logger } from '../helper/logger' +import { fileCompressor, logger } from 'server-shared' import { FileEntity } from './file.entity' -import { fileCompressor } from './utils/file-compressor' type SaveParams = { fileId?: FileId | undefined @@ -14,8 +22,6 @@ type SaveParams = { compression: FileCompression } - - type GetOneParams = { fileId: FileId projectId?: ProjectId @@ -29,7 +35,14 @@ type DeleteOneParams = { const fileRepo = databaseConnection.getRepository(FileEntity) export const fileService = { - async save({ fileId, projectId, platformId, data, type, compression }: SaveParams): Promise { + async save({ + fileId, + projectId, + platformId, + data, + type, + compression, + }: SaveParams): Promise { const file = { id: fileId ?? apId(), projectId, @@ -41,7 +54,9 @@ export const fileService = { const savedFile = await fileRepo.save(file) - logger.info(`[FileService#save] fileId=${savedFile.id} data.length=${data.length}`) + logger.info( + `[FileService#save] fileId=${savedFile.id} data.length=${data.length}`, + ) return savedFile }, diff --git a/packages/backend/src/app/flags/flag.entity.ts b/packages/server/api/src/app/flags/flag.entity.ts old mode 100755 new mode 100644 similarity index 78% rename from packages/backend/src/app/flags/flag.entity.ts rename to packages/server/api/src/app/flags/flag.entity.ts index 9e42e90cc1..86242d66d5 --- a/packages/backend/src/app/flags/flag.entity.ts +++ b/packages/server/api/src/app/flags/flag.entity.ts @@ -1,5 +1,8 @@ import { EntitySchema } from 'typeorm' -import { BaseColumnSchemaPart, JSONB_COLUMN_TYPE } from '../database/database-common' +import { + BaseColumnSchemaPart, + JSONB_COLUMN_TYPE, +} from '../database/database-common' import { Flag } from '@activepieces/shared' type FlagSchema = Flag diff --git a/packages/backend/src/app/flags/flag.module.ts b/packages/server/api/src/app/flags/flag.module.ts old mode 100755 new mode 100644 similarity index 89% rename from packages/backend/src/app/flags/flag.module.ts rename to packages/server/api/src/app/flags/flag.module.ts index 7fbe1e1763..87d01a0c82 --- a/packages/backend/src/app/flags/flag.module.ts +++ b/packages/server/api/src/app/flags/flag.module.ts @@ -19,7 +19,10 @@ export const flagController: FastifyPluginAsyncTypebox = async (app) => { }, async (request: FastifyRequest) => { const flags = await flagService.getAll() - const flagsMap: Record = flags.reduce((map, flag) => ({ ...map, [flag.id as string]: flag.value }), {}) + const flagsMap: Record = flags.reduce( + (map, flag) => ({ ...map, [flag.id as string]: flag.value }), + {}, + ) return flagHooks.get().modify({ flags: flagsMap, request, diff --git a/packages/backend/src/app/flags/flag.service.ts b/packages/server/api/src/app/flags/flag.service.ts old mode 100755 new mode 100644 similarity index 88% rename from packages/backend/src/app/flags/flag.service.ts rename to packages/server/api/src/app/flags/flag.service.ts index 2b889ec935..9ce8ae2449 --- a/packages/backend/src/app/flags/flag.service.ts +++ b/packages/server/api/src/app/flags/flag.service.ts @@ -1,7 +1,6 @@ import { ApEdition, ApFlagId, Flag, isNil } from '@activepieces/shared' import { databaseConnection } from '../database/database-connection' -import { system } from '../helper/system/system' -import { SystemProp } from '../helper/system/system-prop' +import { system, SystemProp } from 'server-shared' import { FlagEntity } from './flag.entity' import axios from 'axios' import { webhookService } from '../webhooks/webhook-service' @@ -104,7 +103,9 @@ export const flagService = { }, { id: ApFlagId.THIRD_PARTY_AUTH_PROVIDER_REDIRECT_URL, - value: [ApEdition.CLOUD, ApEdition.ENTERPRISE].includes(getEdition()) ? this.getThirdPartyRedirectUrl(undefined, undefined) : undefined, + value: [ApEdition.CLOUD, ApEdition.ENTERPRISE].includes(getEdition()) + ? this.getThirdPartyRedirectUrl(undefined, undefined) + : undefined, created, updated, }, @@ -220,13 +221,19 @@ export const flagService = { return flags }, - getThirdPartyRedirectUrl(platformId: string | undefined, hostname: string | undefined): string { - const isCustomerPlatform = platformId && !flagService.isCloudPlatform(platformId) + getThirdPartyRedirectUrl( + platformId: string | undefined, + hostname: string | undefined, + ): string { + const isCustomerPlatform = + platformId && !flagService.isCloudPlatform(platformId) if (isCustomerPlatform) { return `https://${hostname}/redirect` } const frontendUrl = system.get(SystemProp.FRONTEND_URL) - const trimmedFrontendUrl = frontendUrl?.endsWith('/') ? frontendUrl.slice(0, -1) : frontendUrl + const trimmedFrontendUrl = frontendUrl?.endsWith('/') + ? frontendUrl.slice(0, -1) + : frontendUrl return `${trimmedFrontendUrl}/redirect` }, async getCurrentRelease(): Promise { @@ -236,7 +243,9 @@ export const flagService = { async getLatestRelease(): Promise { try { - const response = await axios.get('https://raw.githubusercontent.com/activepieces/activepieces/main/package.json') + const response = await axios.get( + 'https://raw.githubusercontent.com/activepieces/activepieces/main/package.json', + ) return response.data.version } catch (ex) { @@ -253,11 +262,11 @@ export const flagService = { } export type FlagType = - | BaseFlagStructure - | BaseFlagStructure - | BaseFlagStructure - | BaseFlagStructure - | BaseFlagStructure + | BaseFlagStructure + | BaseFlagStructure + | BaseFlagStructure + | BaseFlagStructure + | BaseFlagStructure type BaseFlagStructure = { id: K diff --git a/packages/backend/src/app/flags/flags.hooks.ts b/packages/server/api/src/app/flags/flags.hooks.ts similarity index 100% rename from packages/backend/src/app/flags/flags.hooks.ts rename to packages/server/api/src/app/flags/flags.hooks.ts diff --git a/packages/backend/src/app/flags/theme.ts b/packages/server/api/src/app/flags/theme.ts similarity index 78% rename from packages/backend/src/app/flags/theme.ts rename to packages/server/api/src/app/flags/theme.ts index b560dc42bf..5d7b20a31d 100644 --- a/packages/backend/src/app/flags/theme.ts +++ b/packages/server/api/src/app/flags/theme.ts @@ -16,20 +16,26 @@ function generateColors(hex: string) { '700': tinycolor.mix(baseDark, hex, 70).toHexString(), '800': tinycolor.mix(baseDark, hex, 54).toHexString(), '900': tinycolor.mix(baseDark, hex, 25).toHexString(), - A100: tinycolor.mix(baseDark, baseTriad[3], 15).saturate(80) - .lighten(65).toHexString(), + A100: tinycolor + .mix(baseDark, baseTriad[3], 15) + .saturate(80) + .lighten(65) + .toHexString(), A200: tinycolor .mix(baseDark, baseTriad[3], 15) .saturate(80) - .lighten(55).toHexString(), + .lighten(55) + .toHexString(), A400: tinycolor .mix(baseDark, baseTriad[3], 15) .saturate(100) - .lighten(45).toHexString(), + .lighten(45) + .toHexString(), A700: tinycolor .mix(baseDark, baseTriad[3], 15) .saturate(100) - .lighten(40).toHexString(), + .lighten(40) + .toHexString(), contrast: { '50': '#000000', '100': '#000000', @@ -49,13 +55,14 @@ function generateColors(hex: string) { } } - function generateColorVariations(defaultColor: string) { const defaultColorObj = tinycolor(defaultColor) const darkColor = defaultColorObj.clone().darken(2) const baseLight = tinycolor('#ffffff') - const lightColor = tinycolor.mix(baseLight, defaultColorObj.toHex(), 12).toHexString() + const lightColor = tinycolor + .mix(baseLight, defaultColorObj.toHex(), 12) + .toHexString() const mediumColor = defaultColorObj.clone().lighten(26) return { @@ -72,24 +79,36 @@ function generateSelectionColor(defaultColor: string) { return lightColor.toHexString() } -export function generateTheme({ primaryColor, fullLogoUrl, favIconUrl, logoIconUrl, websiteName }: { primaryColor: string, fullLogoUrl: string, favIconUrl: string, logoIconUrl: string, websiteName: string }) { +export function generateTheme({ + primaryColor, + fullLogoUrl, + favIconUrl, + logoIconUrl, + websiteName, +}: { + primaryColor: string + fullLogoUrl: string + favIconUrl: string + logoIconUrl: string + websiteName: string +}) { return { websiteName, colors: { avatar: '#515151', 'blue-link': '#1890ff', danger: '#dc3545', - 'primary': generateColorVariations(primaryColor), - 'warn': { + primary: generateColorVariations(primaryColor), + warn: { default: '#f78a3b', light: '#fff6e4', dark: '#cc8805', }, - 'success': { + success: { default: '#14ae5c', light: '#3cad71', }, - 'selection': generateSelectionColor(primaryColor), + selection: generateSelectionColor(primaryColor), }, logos: { fullLogoUrl, @@ -135,10 +154,7 @@ export function generateTheme({ primaryColor, fullLogoUrl, favIconUrl, logoIconU export const defaultTheme = generateTheme({ primaryColor: '#6e41e2', websiteName: 'Activepieces', - fullLogoUrl: - 'https://cdn.activepieces.com/brand/full-logo.png', - favIconUrl: - 'https://cdn.activepieces.com/brand/favicon.ico', - logoIconUrl: - 'https://cdn.activepieces.com/brand/logo.svg', + fullLogoUrl: 'https://cdn.activepieces.com/brand/full-logo.png', + favIconUrl: 'https://cdn.activepieces.com/brand/favicon.ico', + logoIconUrl: 'https://cdn.activepieces.com/brand/logo.svg', }) diff --git a/packages/server/api/src/app/flow-templates/community-flow-template.module.ts b/packages/server/api/src/app/flow-templates/community-flow-template.module.ts new file mode 100644 index 0000000000..003acc688e --- /dev/null +++ b/packages/server/api/src/app/flow-templates/community-flow-template.module.ts @@ -0,0 +1,63 @@ +import { + ListFlowTemplatesRequest, + ALL_PRINICPAL_TYPES, + isNil, +} from '@activepieces/shared' +import { FastifyPluginAsyncTypebox } from '@fastify/type-provider-typebox' +import { system, SystemProp } from 'server-shared' +import { paginationHelper } from '../helper/pagination/pagination-utils' + +export const communityFlowTemplateModule: FastifyPluginAsyncTypebox = async ( + app, +) => { + await app.register(flowTemplateController, { prefix: '/v1/flow-templates' }) +} + +const flowTemplateController: FastifyPluginAsyncTypebox = async (fastify) => { + fastify.get( + '/', + { + config: { + allowedPrincipals: ALL_PRINICPAL_TYPES, + }, + schema: { + querystring: ListFlowTemplatesRequest, + }, + }, + async (request) => { + const templateSource = system.get(SystemProp.TEMPLATES_SOURCE_URL) + if (isNil(templateSource)) { + return paginationHelper.createPage([], null) + } + const queryString = convertToQueryString(request.query) + const url = `${templateSource}?${queryString}` + const response = await fetch(url, { + method: 'GET', + headers: { + 'Content-Type': 'application/json', + }, + }) + const templates = await response.json() + return templates + }, + ) +} + +function convertToQueryString(params: ListFlowTemplatesRequest): string { + const searchParams = new URLSearchParams() + + Object.entries(params).forEach(([key, value]) => { + if (Array.isArray(value)) { + value.forEach((val) => { + if (!isNil(val)) { + searchParams.append(key, val) + } + }) + } + else if (!isNil(value)) { + searchParams.set(key, value.toString()) + } + }) + + return searchParams.toString() +} diff --git a/packages/backend/src/app/flows/common/piece-manager/index.ts b/packages/server/api/src/app/flows/common/piece-manager/index.ts similarity index 76% rename from packages/backend/src/app/flows/common/piece-manager/index.ts rename to packages/server/api/src/app/flows/common/piece-manager/index.ts index 5a928a476d..b30c445241 100644 --- a/packages/backend/src/app/flows/common/piece-manager/index.ts +++ b/packages/server/api/src/app/flows/common/piece-manager/index.ts @@ -1,5 +1,4 @@ -import { PiecesSource, system } from '../../../helper/system/system' -import { SystemProp } from '../../../helper/system/system-prop' +import { PiecesSource, SystemProp, system } from 'server-shared' import { PieceManager } from './piece-manager' import { LocalPieceManager } from './local-piece-manager' import { RegistryPieceManager } from './registry-piece-manager' @@ -16,4 +15,4 @@ const getPieceManager = (): PieceManager => { return new pieceManagerVariant[source]() } -export const pieceManager = getPieceManager() \ No newline at end of file +export const pieceManager = getPieceManager() diff --git a/packages/backend/src/app/flows/common/piece-manager/local-piece-manager.ts b/packages/server/api/src/app/flows/common/piece-manager/local-piece-manager.ts similarity index 75% rename from packages/backend/src/app/flows/common/piece-manager/local-piece-manager.ts rename to packages/server/api/src/app/flows/common/piece-manager/local-piece-manager.ts index 976e745f49..d4569380ec 100644 --- a/packages/backend/src/app/flows/common/piece-manager/local-piece-manager.ts +++ b/packages/server/api/src/app/flows/common/piece-manager/local-piece-manager.ts @@ -1,20 +1,27 @@ import { resolve, join, sep } from 'node:path' import { writeFile, readFile } from 'node:fs/promises' -import { logger } from '../../../helper/logger' +import { logger, packageManager } from 'server-shared' import { PieceManager } from './piece-manager' -import { packageManager } from '../../../helper/package-manager' import { FilePieceMetadataService } from '../../../pieces/piece-metadata-service/file-piece-metadata-service' import { PiecePackage } from '@activepieces/shared' const pieceMetadataService = FilePieceMetadataService() export class LocalPieceManager extends PieceManager { - protected override async installDependencies(params: InstallParams): Promise { + protected override async installDependencies( + params: InstallParams, + ): Promise { logger.debug(params, '[linkDependencies] params') const { projectPath, pieces } = params const basePath = resolve(__dirname.split(`${sep}dist`)[0]) - const baseLinkPath = join(basePath, 'dist', 'packages', 'pieces', 'community') + const baseLinkPath = join( + basePath, + 'dist', + 'packages', + 'pieces', + 'community', + ) const frameworkPackages = { '@activepieces/pieces-common': `link:${baseLinkPath}/common`, @@ -40,7 +47,11 @@ export class LocalPieceManager extends PieceManager { } } -const linkFrameworkPackages = async (projectPath: string, baseLinkPath: string, frameworkPackages: Record): Promise => { +const linkFrameworkPackages = async ( + projectPath: string, + baseLinkPath: string, + frameworkPackages: Record, +): Promise => { await updatePackageJson(join(baseLinkPath, 'framework'), frameworkPackages) await packageManager.link({ packageName: '@activepieces/pieces-framework', @@ -55,12 +66,20 @@ const linkFrameworkPackages = async (projectPath: string, baseLinkPath: string, }) } -const updatePackageJson = async (directoryPath: string, frameworkPackages: Record): Promise => { +const updatePackageJson = async ( + directoryPath: string, + frameworkPackages: Record, +): Promise => { const packageJsonForPiece = join(directoryPath, 'package.json') - const packageJson = await readFile(packageJsonForPiece, 'utf-8').then(JSON.parse) + const packageJson = await readFile(packageJsonForPiece, 'utf-8').then( + JSON.parse, + ) for (const [key, value] of Object.entries(frameworkPackages)) { - if (packageJson.dependencies && Object.keys(packageJson.dependencies).includes(key)) { + if ( + packageJson.dependencies && + Object.keys(packageJson.dependencies).includes(key) + ) { packageJson.dependencies[key] = value } } diff --git a/packages/backend/src/app/flows/common/piece-manager/piece-manager.ts b/packages/server/api/src/app/flows/common/piece-manager/piece-manager.ts similarity index 71% rename from packages/backend/src/app/flows/common/piece-manager/piece-manager.ts rename to packages/server/api/src/app/flows/common/piece-manager/piece-manager.ts index 4b1d0acb23..06d084537c 100644 --- a/packages/backend/src/app/flows/common/piece-manager/piece-manager.ts +++ b/packages/server/api/src/app/flows/common/piece-manager/piece-manager.ts @@ -1,14 +1,18 @@ import { resolve } from 'node:path' -import { PackageType, PiecePackage, getPackageAliasForPiece, getPackageArchivePathForPiece, isEmpty } from '@activepieces/shared' -import { system } from '../../../helper/system/system' -import { SystemProp } from '../../../helper/system/system-prop' -import { PackageInfo } from '../../../helper/package-manager' -import { enrichErrorContext } from '../../../helper/error-handler' - -export const PACKAGE_ARCHIVE_PATH = resolve(system.getOrThrow(SystemProp.PACKAGE_ARCHIVE_PATH)) +import { + PackageType, + PiecePackage, + getPackageAliasForPiece, + getPackageArchivePathForPiece, + isEmpty, +} from '@activepieces/shared' +import { PackageInfo, SystemProp, enrichErrorContext, system } from 'server-shared' + +export const PACKAGE_ARCHIVE_PATH = resolve( + system.getOrThrow(SystemProp.PACKAGE_ARCHIVE_PATH), +) export abstract class PieceManager { - async install({ projectPath, pieces }: InstallParams): Promise { try { if (isEmpty(pieces)) { @@ -52,8 +56,14 @@ export abstract class PieceManager { } private removeDuplicatedPieces(pieces: PiecePackage[]): PiecePackage[] { - return pieces.filter((piece, index, self) => - index === self.findIndex((p) => p.pieceName === piece.pieceName && p.pieceVersion === piece.pieceVersion), + return pieces.filter( + (piece, index, self) => + index === + self.findIndex( + (p) => + p.pieceName === piece.pieceName && + p.pieceVersion === piece.pieceVersion, + ), ) } } @@ -63,7 +73,10 @@ type InstallParams = { pieces: PiecePackage[] } -const getPackageSpecForPiece = (packageArchivePath: string, params: PiecePackage): string => { +const getPackageSpecForPiece = ( + packageArchivePath: string, + params: PiecePackage, +): string => { const { packageType, pieceName, pieceVersion } = params switch (packageType) { @@ -80,4 +93,4 @@ const getPackageSpecForPiece = (packageArchivePath: string, params: PiecePackage return `file:${archivePath}` } } -} \ No newline at end of file +} diff --git a/packages/backend/src/app/flows/common/piece-manager/registry-piece-manager.ts b/packages/server/api/src/app/flows/common/piece-manager/registry-piece-manager.ts similarity index 70% rename from packages/backend/src/app/flows/common/piece-manager/registry-piece-manager.ts rename to packages/server/api/src/app/flows/common/piece-manager/registry-piece-manager.ts index 7899ca1136..2dff2fe31d 100644 --- a/packages/backend/src/app/flows/common/piece-manager/registry-piece-manager.ts +++ b/packages/server/api/src/app/flows/common/piece-manager/registry-piece-manager.ts @@ -5,16 +5,18 @@ import { PrivatePiecePackage, getPackageArchivePathForPiece, } from '@activepieces/shared' -import { packageManager } from '../../../helper/package-manager' import { PACKAGE_ARCHIVE_PATH, PieceManager } from './piece-manager' import { fileService } from '../../../file/file.service' -import { fileExists } from '../../../helper/file-system' import { mkdir, writeFile } from 'node:fs/promises' +import { packageManager, fileExists } from 'server-shared' export class RegistryPieceManager extends PieceManager { - protected override async installDependencies({ projectPath, pieces }: InstallParams): Promise { + protected override async installDependencies({ + projectPath, + pieces, + }: InstallParams): Promise { await this.savePackageArchivesToDiskIfNotCached(pieces) - const dependencies = pieces.map(piece => this.pieceToDependency(piece)) + const dependencies = pieces.map((piece) => this.pieceToDependency(piece)) await packageManager.add({ path: projectPath, @@ -22,13 +24,19 @@ export class RegistryPieceManager extends PieceManager { }) } - private async savePackageArchivesToDiskIfNotCached(pieces: PiecePackage[]): Promise { + private async savePackageArchivesToDiskIfNotCached( + pieces: PiecePackage[], + ): Promise { const packages = await this.getUncachedArchivePackages(pieces) - const saveToDiskJobs = packages.map((piece) => this.getArchiveAndSaveToDisk(piece)) + const saveToDiskJobs = packages.map((piece) => + this.getArchiveAndSaveToDisk(piece), + ) await Promise.all(saveToDiskJobs) } - private async getUncachedArchivePackages(pieces: PiecePackage[]): Promise { + private async getUncachedArchivePackages( + pieces: PiecePackage[], + ): Promise { const packages: PrivatePiecePackage[] = [] for (const piece of pieces) { @@ -36,7 +44,6 @@ export class RegistryPieceManager extends PieceManager { continue } - const archivePath = getPackageArchivePathForPiece({ archiveId: piece.archiveId, archivePath: PACKAGE_ARCHIVE_PATH, @@ -52,7 +59,9 @@ export class RegistryPieceManager extends PieceManager { return packages } - private async getArchiveAndSaveToDisk(piece: PrivatePiecePackage): Promise { + private async getArchiveAndSaveToDisk( + piece: PrivatePiecePackage, + ): Promise { const archiveId = piece.archiveId const archiveFile = await fileService.getOneOrThrow({ @@ -67,7 +76,6 @@ export class RegistryPieceManager extends PieceManager { await mkdir(dirname(archivePath), { recursive: true }) await writeFile(archivePath, archiveFile.data) } - } type InstallParams = { diff --git a/packages/backend/src/app/flows/flow-run/flow-response-watcher.ts b/packages/server/api/src/app/flows/flow-run/flow-response-watcher.ts similarity index 72% rename from packages/backend/src/app/flows/flow-run/flow-response-watcher.ts rename to packages/server/api/src/app/flows/flow-run/flow-response-watcher.ts index 5daaaa2bbb..412ed05bf6 100644 --- a/packages/backend/src/app/flows/flow-run/flow-response-watcher.ts +++ b/packages/server/api/src/app/flows/flow-run/flow-response-watcher.ts @@ -1,9 +1,15 @@ import { logger } from '@sentry/utils' -import { ExecutionOutput, ExecutionOutputStatus, PauseExecutionOutput, PauseType, StopExecutionOutput, apId } from '@activepieces/shared' +import { + ExecutionOutput, + ExecutionOutputStatus, + PauseExecutionOutput, + PauseType, + StopExecutionOutput, + apId, +} from '@activepieces/shared' import { StatusCodes } from 'http-status-codes' import { pubSub } from '../../helper/pubsub' -import { system } from '../../helper/system/system' -import { SystemProp } from '../../helper/system/system-prop' +import { SystemProp, system } from 'server-shared' const listeners = new Map void>() @@ -18,7 +24,8 @@ type FlowResponseWithId = { flowResponse: FlowResponse } -const WEBHOOK_TIMEOUT_MS = (system.getNumber(SystemProp.WEBHOOK_TIMEOUT_SECONDS) ?? 30) * 1000 +const WEBHOOK_TIMEOUT_MS = + (system.getNumber(SystemProp.WEBHOOK_TIMEOUT_SECONDS) ?? 30) * 1000 const HANDLER_ID = apId() export const flowResponseWatcher = { getHandlerId(): string { @@ -27,15 +34,20 @@ export const flowResponseWatcher = { async init(): Promise { logger.info('[flowRunWatcher#init] Initializing flow run watcher') - await pubSub.subscribe(`flow-run:sync:${HANDLER_ID}`, (_channel, message) => { - const parsedMessasge: FlowResponseWithId = JSON.parse(message) - const listener = listeners.get(parsedMessasge.flowRunId) - if (listener) { - listener(parsedMessasge.flowResponse) - listeners.delete(parsedMessasge.flowRunId) - } - logger.info(`[flowRunWatcher#init] message=${parsedMessasge.flowRunId}`) - }) + await pubSub.subscribe( + `flow-run:sync:${HANDLER_ID}`, + (_channel, message) => { + const parsedMessasge: FlowResponseWithId = JSON.parse(message) + const listener = listeners.get(parsedMessasge.flowRunId) + if (listener) { + listener(parsedMessasge.flowResponse) + listeners.delete(parsedMessasge.flowRunId) + } + logger.info( + `[flowRunWatcher#init] message=${parsedMessasge.flowRunId}`, + ) + }, + ) }, async listen(flowRunId: string): Promise { logger.info(`[flowRunWatcher#listen] flowRunId=${flowRunId}`) @@ -55,7 +67,11 @@ export const flowResponseWatcher = { }) }) }, - async publish(flowRunId: string, handlerId: string, executionOutput: ExecutionOutput): Promise { + async publish( + flowRunId: string, + handlerId: string, + executionOutput: ExecutionOutput, + ): Promise { logger.info(`[flowRunWatcher#publish] flowRunId=${flowRunId}`) const flowResponse = await getFlowResponse(executionOutput) const message: FlowResponseWithId = { flowRunId, flowResponse } @@ -66,9 +82,9 @@ export const flowResponseWatcher = { }, } - -async function getFlowResponse(executionOutput: ExecutionOutput): Promise { - +async function getFlowResponse( + executionOutput: ExecutionOutput, +): Promise { switch (executionOutput.status) { case ExecutionOutputStatus.PAUSED: return getResponseForPausedRun(executionOutput) @@ -107,11 +123,11 @@ async function getFlowResponse(executionOutput: ExecutionOutput): Promise { - +async function getResponseForPausedRun( + executionOutput: PauseExecutionOutput, +): Promise { if (executionOutput.pauseMetadata.type === PauseType.WEBHOOK) { return { status: StatusCodes.OK, @@ -124,10 +140,11 @@ async function getResponseForPausedRun(executionOutput: PauseExecutionOutput): P body: {}, headers: {}, } - } -async function getResponseForStoppedRun(executionOutput: StopExecutionOutput): Promise { +async function getResponseForStoppedRun( + executionOutput: StopExecutionOutput, +): Promise { return { status: executionOutput.stopResponse?.status ?? StatusCodes.OK, body: executionOutput.stopResponse?.body, diff --git a/packages/backend/src/app/flows/flow-run/flow-run-controller.ts b/packages/server/api/src/app/flows/flow-run/flow-run-controller.ts old mode 100755 new mode 100644 similarity index 66% rename from packages/backend/src/app/flows/flow-run/flow-run-controller.ts rename to packages/server/api/src/app/flows/flow-run/flow-run-controller.ts index 2c43101eb0..10aeaa3a9f --- a/packages/backend/src/app/flows/flow-run/flow-run-controller.ts +++ b/packages/server/api/src/app/flows/flow-run/flow-run-controller.ts @@ -1,7 +1,20 @@ import { FastifyReply, FastifyRequest } from 'fastify' -import { FastifyPluginCallbackTypebox, Type } from '@fastify/type-provider-typebox' -import { FlowRunId, ListFlowRunsRequestQuery, ApId, ALL_PRINICPAL_TYPES, ExecutionType } from '@activepieces/shared' -import { ActivepiecesError, ErrorCode, RetryFlowRequestBody } from '@activepieces/shared' +import { + FastifyPluginCallbackTypebox, + Type, +} from '@fastify/type-provider-typebox' +import { + FlowRunId, + ListFlowRunsRequestQuery, + ApId, + ALL_PRINICPAL_TYPES, + ExecutionType, +} from '@activepieces/shared' +import { + ActivepiecesError, + ErrorCode, + RetryFlowRequestBody, +} from '@activepieces/shared' import { flowRunService } from './flow-run-service' const DEFAULT_PAGING_LIMIT = 10 @@ -30,7 +43,11 @@ const RetryFlowRequest = { }, } -export const flowRunController: FastifyPluginCallbackTypebox = (app, _options, done): void => { +export const flowRunController: FastifyPluginCallbackTypebox = ( + app, + _options, + done, +): void => { // list app.get('/', ListRequest, async (request, reply) => { const flowRunPage = await flowRunService.list({ @@ -48,24 +65,29 @@ export const flowRunController: FastifyPluginCallbackTypebox = (app, _options, d }) // get one - app.get('/:id', async (request: FastifyRequest<{ Params: GetOnePathParams }>, reply: FastifyReply) => { - const flowRun = await flowRunService.getOne({ - projectId: request.principal.projectId, - id: request.params.id, - }) - - if (flowRun == null) { - throw new ActivepiecesError({ - code: ErrorCode.FLOW_RUN_NOT_FOUND, - params: { - id: request.params.id, - }, + app.get( + '/:id', + async ( + request: FastifyRequest<{ Params: GetOnePathParams }>, + reply: FastifyReply, + ) => { + const flowRun = await flowRunService.getOne({ + projectId: request.principal.projectId, + id: request.params.id, }) - } - await reply.send(flowRun) - }) + if (flowRun == null) { + throw new ActivepiecesError({ + code: ErrorCode.FLOW_RUN_NOT_FOUND, + params: { + id: request.params.id, + }, + }) + } + await reply.send(flowRun) + }, + ) app.all('/:id/resume', ResumeFlowRunRequest, async (req) => { const headers = req.headers as Record @@ -81,7 +103,6 @@ export const flowRunController: FastifyPluginCallbackTypebox = (app, _options, d }) }) - app.post('/:id/retry', RetryFlowRequest, async (req) => { await flowRunService.retry({ flowRunId: req.params.id, @@ -96,4 +117,4 @@ const ListRequest = { schema: { querystring: ListFlowRunsRequestQuery, }, -} \ No newline at end of file +} diff --git a/packages/backend/src/app/flows/flow-run/flow-run-entity.ts b/packages/server/api/src/app/flows/flow-run/flow-run-entity.ts old mode 100755 new mode 100644 similarity index 89% rename from packages/backend/src/app/flows/flow-run/flow-run-entity.ts rename to packages/server/api/src/app/flows/flow-run/flow-run-entity.ts index 25575f037e..e1fe8362c5 --- a/packages/backend/src/app/flows/flow-run/flow-run-entity.ts +++ b/packages/server/api/src/app/flows/flow-run/flow-run-entity.ts @@ -1,6 +1,18 @@ import { EntitySchema } from 'typeorm' -import { ARRAY_COLUMN_TYPE, ApIdSchema, BaseColumnSchemaPart, JSONB_COLUMN_TYPE, TIMESTAMP_COLUMN_TYPE, isPostgres } from '../../database/database-common' -import { Flow, FlowRun, Project, RunTerminationReason } from '@activepieces/shared' +import { + ARRAY_COLUMN_TYPE, + ApIdSchema, + BaseColumnSchemaPart, + JSONB_COLUMN_TYPE, + TIMESTAMP_COLUMN_TYPE, + isPostgres, +} from '../../database/database-common' +import { + Flow, + FlowRun, + Project, + RunTerminationReason, +} from '@activepieces/shared' type FlowRunSchema = FlowRun & { project: Project diff --git a/packages/backend/src/app/flows/flow-run/flow-run-hooks.ts b/packages/server/api/src/app/flows/flow-run/flow-run-hooks.ts similarity index 69% rename from packages/backend/src/app/flows/flow-run/flow-run-hooks.ts rename to packages/server/api/src/app/flows/flow-run/flow-run-hooks.ts index 82dc0aafbd..9ca06e6115 100644 --- a/packages/backend/src/app/flows/flow-run/flow-run-hooks.ts +++ b/packages/server/api/src/app/flows/flow-run/flow-run-hooks.ts @@ -1,15 +1,20 @@ - export type FlowRunHooks = { onPreStart({ projectId }: { projectId: string }): Promise - onFinish({ projectId, tasks }: { projectId: string, tasks: number }): Promise + onFinish({ + projectId, + tasks, + }: { + projectId: string + tasks: number + }): Promise } const emptyHooks: FlowRunHooks = { async onPreStart() { - // DO NOTHING + // DO NOTHING }, async onFinish() { - // DO NOTHING + // DO NOTHING }, } @@ -22,4 +27,4 @@ export const flowRunHooks = { getHooks() { return hooks }, -} \ No newline at end of file +} diff --git a/packages/backend/src/app/flows/flow-run/flow-run-module.ts b/packages/server/api/src/app/flows/flow-run/flow-run-module.ts old mode 100755 new mode 100644 similarity index 100% rename from packages/backend/src/app/flows/flow-run/flow-run-module.ts rename to packages/server/api/src/app/flows/flow-run/flow-run-module.ts diff --git a/packages/backend/src/app/flows/flow-run/flow-run-service.ts b/packages/server/api/src/app/flows/flow-run/flow-run-service.ts similarity index 76% rename from packages/backend/src/app/flows/flow-run/flow-run-service.ts rename to packages/server/api/src/app/flows/flow-run/flow-run-service.ts index b4d61a0481..25b957614a 100644 --- a/packages/backend/src/app/flows/flow-run/flow-run-service.ts +++ b/packages/server/api/src/app/flows/flow-run/flow-run-service.ts @@ -22,7 +22,10 @@ import { PauseType, ResumePayload, } from '@activepieces/shared' -import { APArrayContains, databaseConnection } from '../../database/database-connection' +import { + APArrayContains, + databaseConnection, +} from '../../database/database-connection' import { flowVersionService } from '../../flows/flow-version/flow-version.service' import { buildPaginator } from '../../helper/pagination/build-paginator' import { paginationHelper } from '../../helper/pagination/pagination-utils' @@ -30,16 +33,20 @@ import { Order } from '../../helper/pagination/paginator' import { telemetry } from '../../helper/telemetry.utils' import { FlowRunEntity } from './flow-run-entity' import { flowRunSideEffects } from './flow-run-side-effects' -import { logger } from '../../helper/logger' +import { logger } from 'server-shared' import { flowService } from '../flow/flow.service' import { MoreThanOrEqual } from 'typeorm' import { flowRunHooks } from './flow-run-hooks' import { flowResponseWatcher } from './flow-response-watcher' -export const flowRunRepo = databaseConnection.getRepository(FlowRunEntity) +export const flowRunRepo = + databaseConnection.getRepository(FlowRunEntity) -const getFlowRunOrCreate = async (params: GetOrCreateParams): Promise> => { - const { id, projectId, flowId, flowVersionId, flowDisplayName, environment } = params +const getFlowRunOrCreate = async ( + params: GetOrCreateParams, +): Promise> => { + const { id, projectId, flowId, flowVersionId, flowDisplayName, environment } = + params if (id) { return flowRunService.getOneOrThrow({ @@ -59,16 +66,29 @@ const getFlowRunOrCreate = async (params: GetOrCreateParams): Promise { +async function updateFlowRunToLatestFlowVersionId( + flowRunId: FlowRunId, +): Promise { const flowRun = await flowRunRepo.findOneByOrFail({ id: flowRunId }) - const flowVersion = await flowVersionService.getLatestLockedVersionOrThrow(flowRun.flowId) + const flowVersion = await flowVersionService.getLatestLockedVersionOrThrow( + flowRun.flowId, + ) await flowRunRepo.update(flowRunId, { flowVersionId: flowVersion.id, }) } export const flowRunService = { - async list({ projectId, flowId, status, cursor, limit, tags, createdAfter, createdBefore }: ListParams): Promise> { + async list({ + projectId, + flowId, + status, + cursor, + limit, + tags, + createdAfter, + createdBefore, + }: ListParams): Promise> { const decodedCursor = paginationHelper.decodeCursor(cursor) const paginator = buildPaginator({ entity: FlowRunEntity, @@ -87,10 +107,14 @@ export const flowRunService = { environment: RunEnvironment.PRODUCTION, }) if (createdAfter) { - query = query.andWhere('flow_run.created >= :createdAfter', { createdAfter }) + query = query.andWhere('flow_run.created >= :createdAfter', { + createdAfter, + }) } if (createdBefore) { - query = query.andWhere('flow_run.created <= :createdBefore', { createdBefore }) + query = query.andWhere('flow_run.created <= :createdBefore', { + createdBefore, + }) } if (tags) { query = APArrayContains('tags', tags, query) @@ -111,13 +135,16 @@ export const flowRunService = { await flowRunService.addToQueue({ flowRunId, executionType: ExecutionType.BEGIN, - }) break } } }, - async addToQueue({ flowRunId, resumePayload, executionType }: { + async addToQueue({ + flowRunId, + resumePayload, + executionType, + }: { flowRunId: FlowRunId resumePayload?: ResumePayload executionType: ExecutionType @@ -137,9 +164,11 @@ export const flowRunService = { }) } const pauseMetadata = flowRunToResume.pauseMetadata - const matchRequestId = !isNil(resumePayload) && pauseMetadata - && pauseMetadata.type === PauseType.WEBHOOK - && resumePayload.queryParams.requestId === pauseMetadata.requestId + const matchRequestId = + !isNil(resumePayload) && + pauseMetadata && + pauseMetadata.type === PauseType.WEBHOOK && + resumePayload.queryParams.requestId === pauseMetadata.requestId if (matchRequestId) { await flowRunService.start({ payload: resumePayload, @@ -150,19 +179,22 @@ export const flowRunService = { environment: RunEnvironment.PRODUCTION, }) } - - }, - async finish( - { flowRunId, status, tasks, logsFileId, tags, terminationReason }: { - flowRunId: FlowRunId - status: ExecutionOutputStatus - tasks: number - terminationReason?: RunTerminationReason - tags: string[] - logsFileId: FileId | null - }, - ): Promise { + async finish({ + flowRunId, + status, + tasks, + logsFileId, + tags, + terminationReason, + }: { + flowRunId: FlowRunId + status: ExecutionOutputStatus + tasks: number + terminationReason?: RunTerminationReason + tags: string[] + logsFileId: FileId | null + }): Promise { await flowRunRepo.update(flowRunId, { ...spreadIfDefined('logsFileId', logsFileId), status, @@ -171,14 +203,28 @@ export const flowRunService = { tags, finishTime: new Date().toISOString(), }) - const flowRun = await this.getOneOrThrow({ id: flowRunId, projectId: undefined }) + const flowRun = await this.getOneOrThrow({ + id: flowRunId, + projectId: undefined, + }) await flowRunSideEffects.finish({ flowRun }) return flowRun }, - async start({ projectId, flowVersionId, flowRunId, payload, environment, executionType, synchronousHandlerId, hookType }: StartParams): Promise { - logger.info(`[flowRunService#start] flowRunId=${flowRunId} executionType=${executionType}`) + async start({ + projectId, + flowVersionId, + flowRunId, + payload, + environment, + executionType, + synchronousHandlerId, + hookType, + }: StartParams): Promise { + logger.info( + `[flowRunService#start] flowRunId=${flowRunId} executionType=${executionType}`, + ) const flowVersion = await flowVersionService.getOneOrThrow(flowVersionId) @@ -202,14 +248,18 @@ export const flowRunService = { const savedFlowRun = await flowRunRepo.save(flowRun) - telemetry.trackProject(flow.projectId, { - name: TelemetryEventName.FLOW_RUN_CREATED, - payload: { - projectId: savedFlowRun.projectId, - flowId: savedFlowRun.flowId, - environment: savedFlowRun.environment, - }, - }).catch((e) => logger.error(e, '[FlowRunService#Start] telemetry.trackProject')) + telemetry + .trackProject(flow.projectId, { + name: TelemetryEventName.FLOW_RUN_CREATED, + payload: { + projectId: savedFlowRun.projectId, + flowId: savedFlowRun.flowId, + environment: savedFlowRun.environment, + }, + }) + .catch((e) => + logger.error(e, '[FlowRunService#Start] telemetry.trackProject'), + ) await flowRunSideEffects.start({ flowRun: savedFlowRun, @@ -225,7 +275,8 @@ export const flowRunService = { async test({ projectId, flowVersionId }: TestParams): Promise { const flowVersion = await flowVersionService.getOneOrThrow(flowVersionId) - const payload = flowVersion.trigger.settings.inputUiInfo.currentSelectedData + const payload = + flowVersion.trigger.settings.inputUiInfo.currentSelectedData return this.start({ projectId, @@ -239,7 +290,9 @@ export const flowRunService = { }, async pause(params: PauseParams): Promise { - logger.info(`[FlowRunService#pause] flowRunId=${params.flowRunId} pauseType=${params.pauseMetadata.type}`) + logger.info( + `[FlowRunService#pause] flowRunId=${params.flowRunId} pauseType=${params.pauseMetadata.type}`, + ) const { flowRunId, logFileId, pauseMetadata } = params @@ -250,7 +303,6 @@ export const flowRunService = { pauseMetadata: pauseMetadata as any, }) - const flowRun = await flowRunRepo.findOneByOrFail({ id: flowRunId }) await flowRunSideEffects.pause({ flowRun }) @@ -281,7 +333,8 @@ export const flowRunService = { async getAllProdRuns(params: GetAllProdRuns): Promise { const { projectId, created } = params - const sumOfTasks = await flowRunRepo.createQueryBuilder('flow_run') + const sumOfTasks = await flowRunRepo + .createQueryBuilder('flow_run') .select('COALESCE(SUM(flow_run.tasks), 0)', 'tasks') .where({ projectId, diff --git a/packages/backend/src/app/flows/flow-run/flow-run-side-effects.ts b/packages/server/api/src/app/flows/flow-run/flow-run-side-effects.ts similarity index 72% rename from packages/backend/src/app/flows/flow-run/flow-run-side-effects.ts rename to packages/server/api/src/app/flows/flow-run/flow-run-side-effects.ts index 5b13e8fe47..3b2514ba2c 100644 --- a/packages/backend/src/app/flows/flow-run/flow-run-side-effects.ts +++ b/packages/server/api/src/app/flows/flow-run/flow-run-side-effects.ts @@ -1,9 +1,18 @@ import { isNil } from '@activepieces/shared' import dayjs from 'dayjs' -import { ActivepiecesError, ErrorCode, ExecutionType, FlowRun, PauseType } from '@activepieces/shared' +import { + ActivepiecesError, + ErrorCode, + ExecutionType, + FlowRun, + PauseType, +} from '@activepieces/shared' import { flowQueue } from '../../workers/flow-worker/flow-queue' -import { logger } from '../../helper/logger' -import { LATEST_JOB_DATA_SCHEMA_VERSION, RepeatableJobType } from '../../workers/flow-worker/job-data' +import { logger } from 'server-shared' +import { + LATEST_JOB_DATA_SCHEMA_VERSION, + RepeatableJobType, +} from '../../workers/flow-worker/job-data' import { JobType } from '../../workers/flow-worker/queues/queue' import { notifications } from '../../helper/notifications' import { flowRunHooks } from './flow-run-hooks' @@ -21,7 +30,9 @@ type PauseParams = { flowRun: FlowRun } -const calculateDelayForResumeJob = (resumeDateTimeIsoString: string): number => { +const calculateDelayForResumeJob = ( + resumeDateTimeIsoString: string, +): number => { const now = dayjs() const resumeDateTime = dayjs(resumeDateTimeIsoString) const delayInMilliSeconds = resumeDateTime.diff(now) @@ -35,16 +46,24 @@ const calculateDelayForResumeJob = (resumeDateTimeIsoString: string): number => } export const flowRunSideEffects = { - async finish({ flowRun }: { - flowRun: FlowRun - }): Promise { - await flowRunHooks.getHooks().onFinish({ projectId: flowRun.projectId, tasks: flowRun.tasks! }) + async finish({ flowRun }: { flowRun: FlowRun }): Promise { + await flowRunHooks + .getHooks() + .onFinish({ projectId: flowRun.projectId, tasks: flowRun.tasks! }) await notifications.notifyRun({ flowRun, }) }, - async start({ flowRun, executionType, payload, synchronousHandlerId, hookType }: StartParams): Promise { - logger.info(`[FlowRunSideEffects#start] flowRunId=${flowRun.id} executionType=${executionType}`) + async start({ + flowRun, + executionType, + payload, + synchronousHandlerId, + hookType, + }: StartParams): Promise { + logger.info( + `[FlowRunSideEffects#start] flowRunId=${flowRun.id} executionType=${executionType}`, + ) await flowQueue.add({ id: flowRun.id, @@ -64,7 +83,9 @@ export const flowRunSideEffects = { }, async pause({ flowRun }: PauseParams): Promise { - logger.info(`[FlowRunSideEffects#pause] flowRunId=${flowRun.id} pauseType=${flowRun.pauseMetadata?.type}`) + logger.info( + `[FlowRunSideEffects#pause] flowRunId=${flowRun.id} pauseType=${flowRun.pauseMetadata?.type}`, + ) const { pauseMetadata } = flowRun diff --git a/packages/backend/src/app/flows/flow-version/flow-version-entity.ts b/packages/server/api/src/app/flows/flow-version/flow-version-entity.ts old mode 100755 new mode 100644 similarity index 92% rename from packages/backend/src/app/flows/flow-version/flow-version-entity.ts rename to packages/server/api/src/app/flows/flow-version/flow-version-entity.ts index cb7d0a7dad..efc2541c15 --- a/packages/backend/src/app/flows/flow-version/flow-version-entity.ts +++ b/packages/server/api/src/app/flows/flow-version/flow-version-entity.ts @@ -1,6 +1,10 @@ import { EntitySchema } from 'typeorm' import { Flow, FlowVersion, User } from '@activepieces/shared' -import { ApIdSchema, BaseColumnSchemaPart, JSONB_COLUMN_TYPE } from '../../database/database-common' +import { + ApIdSchema, + BaseColumnSchemaPart, + JSONB_COLUMN_TYPE, +} from '../../database/database-common' type FlowVersionSchema = { flow: Flow diff --git a/packages/backend/src/app/flows/flow-version/flow-version-side-effects.ts b/packages/server/api/src/app/flows/flow-version/flow-version-side-effects.ts similarity index 60% rename from packages/backend/src/app/flows/flow-version/flow-version-side-effects.ts rename to packages/server/api/src/app/flows/flow-version/flow-version-side-effects.ts index 9da6c79d42..f59b23b02c 100644 --- a/packages/backend/src/app/flows/flow-version/flow-version-side-effects.ts +++ b/packages/server/api/src/app/flows/flow-version/flow-version-side-effects.ts @@ -1,6 +1,14 @@ -import { ActivepiecesError, ErrorCode, FlowId, FlowOperationRequest, FlowOperationType, FlowVersion, ProjectId } from '@activepieces/shared' +import { + ActivepiecesError, + ErrorCode, + FlowId, + FlowOperationRequest, + FlowOperationType, + FlowVersion, + ProjectId, +} from '@activepieces/shared' import { webhookSimulationService } from '../../webhooks/webhook-simulation/webhook-simulation-service' -import { captureException } from '../../helper/logger' +import { exceptionHandler } from 'server-shared' type OnApplyOperationParams = { projectId: ProjectId @@ -13,7 +21,9 @@ type DeleteWebhookSimulationParams = { flowId: FlowId } -const deleteWebhookSimulation = async (params: DeleteWebhookSimulationParams): Promise => { +const deleteWebhookSimulation = async ( + params: DeleteWebhookSimulationParams, +): Promise => { const { projectId, flowId } = params try { @@ -23,7 +33,10 @@ const deleteWebhookSimulation = async (params: DeleteWebhookSimulationParams): P }) } catch (e: unknown) { - const notWebhookSimulationNotFoundError = !(e instanceof ActivepiecesError && e.error.code === ErrorCode.ENTITY_NOT_FOUND) + const notWebhookSimulationNotFoundError = !( + e instanceof ActivepiecesError && + e.error.code === ErrorCode.ENTITY_NOT_FOUND + ) if (notWebhookSimulationNotFoundError) { throw e } @@ -31,7 +44,11 @@ const deleteWebhookSimulation = async (params: DeleteWebhookSimulationParams): P } export const flowVersionSideEffects = { - async preApplyOperation({ projectId, flowVersion, operation }: OnApplyOperationParams): Promise { + async preApplyOperation({ + projectId, + flowVersion, + operation, + }: OnApplyOperationParams): Promise { if (operation.type === FlowOperationType.UPDATE_TRIGGER) { try { await deleteWebhookSimulation({ @@ -41,7 +58,7 @@ export const flowVersionSideEffects = { } catch (e) { // Ignore error and continue the operation peacefully - captureException(e) + exceptionHandler.handle(e) } } }, diff --git a/packages/backend/src/app/flows/flow-version/flow-version.service.ts b/packages/server/api/src/app/flows/flow-version/flow-version.service.ts old mode 100755 new mode 100644 similarity index 71% rename from packages/backend/src/app/flows/flow-version/flow-version.service.ts rename to packages/server/api/src/app/flows/flow-version/flow-version.service.ts index 96e761ccc3..c58881fefb --- a/packages/backend/src/app/flows/flow-version/flow-version.service.ts +++ b/packages/server/api/src/app/flows/flow-version/flow-version.service.ts @@ -31,24 +31,34 @@ import { DEFAULT_SAMPLE_DATA_SETTINGS } from '@activepieces/shared' import { isNil } from '@activepieces/shared' import { pieceMetadataService } from '../../pieces/piece-metadata-service' import dayjs from 'dayjs' -import { logger } from '../../helper/logger' +import { logger } from 'server-shared' import { stepFileService } from '../step-file/step-file.service' import { buildPaginator } from '../../helper/pagination/build-paginator' import { paginationHelper } from '../../helper/pagination/pagination-utils' -const branchSettingsValidator = TypeCompiler.Compile(BranchActionSettingsWithValidation) -const loopSettingsValidator = TypeCompiler.Compile(LoopOnItemsActionSettingsWithValidation) +const branchSettingsValidator = TypeCompiler.Compile( + BranchActionSettingsWithValidation, +) +const loopSettingsValidator = TypeCompiler.Compile( + LoopOnItemsActionSettingsWithValidation, +) const flowVersionRepo = repoFactory(FlowVersionEntity) export const flowVersionService = { - async lockPieceVersions({ projectId, flowVersion, entityManager }: LockPieceVersionsParams): Promise { + async lockPieceVersions({ + projectId, + flowVersion, + entityManager, + }: LockPieceVersionsParams): Promise { if (flowVersion.state === FlowVersionState.LOCKED) { return flowVersion } return flowHelper.transferFlowAsync(flowVersion, async (step) => { const clonedStep = JSON.parse(JSON.stringify(step)) - const stepTypeIsPiece = [ActionType.PIECE, TriggerType.PIECE].includes(step.type) + const stepTypeIsPiece = [ActionType.PIECE, TriggerType.PIECE].includes( + step.type, + ) if (stepTypeIsPiece) { const pieceMetadata = await pieceMetadataService.getOrThrow({ @@ -65,7 +75,13 @@ export const flowVersionService = { }) }, - async applyOperation({ flowVersion, projectId, userId, userOperation, entityManager }: ApplyOperationParams): Promise { + async applyOperation({ + flowVersion, + projectId, + userId, + userOperation, + entityManager, + }: ApplyOperationParams): Promise { let operations: FlowOperationRequest[] = [] let mutatedFlowVersion: FlowVersion = flowVersion @@ -82,7 +98,10 @@ export const flowVersionService = { } case FlowOperationType.IMPORT_FLOW: { - operations = handleImportFlowOperation(flowVersion, userOperation.request) + operations = handleImportFlowOperation( + flowVersion, + userOperation.request, + ) break } @@ -114,7 +133,11 @@ export const flowVersionService = { } for (const operation of operations) { - mutatedFlowVersion = await applySingleOperation(projectId, mutatedFlowVersion, operation) + mutatedFlowVersion = await applySingleOperation( + projectId, + mutatedFlowVersion, + operation, + ) } mutatedFlowVersion.updated = dayjs().toISOString() @@ -158,7 +181,15 @@ export const flowVersionService = { return flowVersion }, - async list({ cursorRequest, limit, flowId }: { cursorRequest: Cursor | null, limit: number, flowId: string }): Promise> { + async list({ + cursorRequest, + limit, + flowId, + }: { + cursorRequest: Cursor | null + limit: number + flowId: string + }): Promise> { const decodedCursor = paginationHelper.decodeCursor(cursorRequest) const paginator = buildPaginator({ entity: FlowVersionEntity, @@ -169,12 +200,21 @@ export const flowVersionService = { beforeCursor: decodedCursor.previousCursor, }, }) - const paginationResult = await paginator.paginate(flowVersionRepo().createQueryBuilder('flow_version').where({ - flowId, - })) - return paginationHelper.createPage(paginationResult.data, paginationResult.cursor) + const paginationResult = await paginator.paginate( + flowVersionRepo().createQueryBuilder('flow_version').where({ + flowId, + }), + ) + return paginationHelper.createPage( + paginationResult.data, + paginationResult.cursor, + ) }, - async getFlowVersionOrThrow({ flowId, versionId, removeSecrets = false }: GetFlowVersionOrThrowParams): Promise { + async getFlowVersionOrThrow({ + flowId, + versionId, + removeSecrets = false, + }: GetFlowVersionOrThrowParams): Promise { let flowVersion: FlowVersion | null = await flowVersionRepo().findOne({ where: { flowId, @@ -203,9 +243,12 @@ export const flowVersionService = { return flowVersion }, - async createEmptyVersion(flowId: FlowId, request: { - displayName: string - }): Promise { + async createEmptyVersion( + flowId: FlowId, + request: { + displayName: string + }, + ): Promise { const flowVersion: NewFlowVersion = { id: apId(), displayName: request.displayName, @@ -224,7 +267,11 @@ export const flowVersionService = { }, } -async function applySingleOperation(projectId: ProjectId, flowVersion: FlowVersion, operation: FlowOperationRequest): Promise { +async function applySingleOperation( + projectId: ProjectId, + flowVersion: FlowVersion, + operation: FlowOperationRequest, +): Promise { logger.info(`applying ${operation.type} to ${flowVersion.displayName}`) await flowVersionSideEffects.preApplyOperation({ projectId, @@ -235,11 +282,15 @@ async function applySingleOperation(projectId: ProjectId, flowVersion: FlowVersi return flowHelper.apply(flowVersion, operation) } -async function removeSecretsFromFlow(flowVersion: FlowVersion): Promise { - const flowVersionWithArtifacts: FlowVersion = JSON.parse(JSON.stringify(flowVersion)) +async function removeSecretsFromFlow( + flowVersion: FlowVersion, +): Promise { + const flowVersionWithArtifacts: FlowVersion = JSON.parse( + JSON.stringify(flowVersion), + ) const steps = flowHelper.getAllSteps(flowVersionWithArtifacts.trigger) for (const step of steps) { - /* + /* Remove Sample Data & connections */ step.settings.inputUiInfo = DEFAULT_SAMPLE_DATA_SETTINGS @@ -248,7 +299,9 @@ async function removeSecretsFromFlow(flowVersion: FlowVersion): Promise): Record { +function replaceConnections( + obj: Record, +): Record { if (isNil(obj)) { return obj } @@ -272,10 +325,14 @@ function replaceConnections(obj: Record): Record flowHelper.isAction(step.type)) - const operations: FlowOperationRequest[] = actionsToRemove.map(step => ({ +function handleImportFlowOperation( + flowVersion: FlowVersion, + operation: ImportFlowRequest, +): FlowOperationRequest[] { + const actionsToRemove = flowHelper + .getAllStepsAtFirstLevel(flowVersion.trigger) + .filter((step) => flowHelper.isAction(step.type)) + const operations: FlowOperationRequest[] = actionsToRemove.map((step) => ({ type: FlowOperationType.DELETE_ACTION, request: { name: step.name, @@ -289,17 +346,27 @@ function handleImportFlowOperation(flowVersion: FlowVersion, operation: ImportFl return operations } -async function prepareRequest(projectId: ProjectId, flowVersion: FlowVersion, request: FlowOperationRequest): Promise { - const clonedRequest: FlowOperationRequest = JSON.parse(JSON.stringify(request)) +async function prepareRequest( + projectId: ProjectId, + flowVersion: FlowVersion, + request: FlowOperationRequest, +): Promise { + const clonedRequest: FlowOperationRequest = JSON.parse( + JSON.stringify(request), + ) switch (clonedRequest.type) { case FlowOperationType.ADD_ACTION: clonedRequest.request.action.valid = true switch (clonedRequest.request.action.type) { case ActionType.LOOP_ON_ITEMS: - clonedRequest.request.action.valid = loopSettingsValidator.Check(clonedRequest.request.action.settings) + clonedRequest.request.action.valid = loopSettingsValidator.Check( + clonedRequest.request.action.settings, + ) break case ActionType.BRANCH: - clonedRequest.request.action.valid = branchSettingsValidator.Check(clonedRequest.request.action.settings) + clonedRequest.request.action.valid = branchSettingsValidator.Check( + clonedRequest.request.action.settings, + ) break case ActionType.PIECE: clonedRequest.request.action.valid = await validateAction({ @@ -316,23 +383,35 @@ async function prepareRequest(projectId: ProjectId, flowVersion: FlowVersion, re clonedRequest.request.valid = true switch (clonedRequest.request.type) { case ActionType.LOOP_ON_ITEMS: - clonedRequest.request.valid = loopSettingsValidator.Check(clonedRequest.request.settings) + clonedRequest.request.valid = loopSettingsValidator.Check( + clonedRequest.request.settings, + ) break case ActionType.BRANCH: - clonedRequest.request.valid = branchSettingsValidator.Check(clonedRequest.request.settings) + clonedRequest.request.valid = branchSettingsValidator.Check( + clonedRequest.request.settings, + ) break case ActionType.PIECE: { clonedRequest.request.valid = await validateAction({ settings: clonedRequest.request.settings, projectId, }) - const previousStep = flowHelper.getStep(flowVersion, clonedRequest.request.name) + const previousStep = flowHelper.getStep( + flowVersion, + clonedRequest.request.name, + ) if ( previousStep !== undefined && - previousStep.type === ActionType.PIECE && - clonedRequest.request.settings.pieceName !== previousStep.settings.pieceName + previousStep.type === ActionType.PIECE && + clonedRequest.request.settings.pieceName !== + previousStep.settings.pieceName ) { - await stepFileService.deleteAll({ projectId, flowId: flowVersion.flowId, stepName: previousStep.name }) + await stepFileService.deleteAll({ + projectId, + flowId: flowVersion.flowId, + stepName: previousStep.name, + }) } break } @@ -342,9 +421,19 @@ async function prepareRequest(projectId: ProjectId, flowVersion: FlowVersion, re } break case FlowOperationType.DELETE_ACTION: { - const previousStep = flowHelper.getStep(flowVersion, clonedRequest.request.name) - if (previousStep !== undefined && previousStep.type === ActionType.PIECE) { - await stepFileService.deleteAll({ projectId, flowId: flowVersion.flowId, stepName: previousStep.name }) + const previousStep = flowHelper.getStep( + flowVersion, + clonedRequest.request.name, + ) + if ( + previousStep !== undefined && + previousStep.type === ActionType.PIECE + ) { + await stepFileService.deleteAll({ + projectId, + flowId: flowVersion.flowId, + stepName: previousStep.name, + }) } break } @@ -371,14 +460,18 @@ async function prepareRequest(projectId: ProjectId, flowVersion: FlowVersion, re return clonedRequest } - -async function validateAction({ projectId, settings }: { projectId: ProjectId, settings: PieceActionSettings }): Promise { - +async function validateAction({ + projectId, + settings, +}: { + projectId: ProjectId + settings: PieceActionSettings +}): Promise { if ( isNil(settings.pieceName) || - isNil(settings.pieceVersion) || - isNil(settings.actionName) || - isNil(settings.input) + isNil(settings.pieceVersion) || + isNil(settings.actionName) || + isNil(settings.input) ) { return false } @@ -403,12 +496,18 @@ async function validateAction({ projectId, settings }: { projectId: ProjectId, s return validateProps(props, settings.input) } -async function validateTrigger({ settings, projectId }: { settings: PieceTriggerSettings, projectId: ProjectId }): Promise { +async function validateTrigger({ + settings, + projectId, +}: { + settings: PieceTriggerSettings + projectId: ProjectId +}): Promise { if ( isNil(settings.pieceName) || - isNil(settings.pieceVersion) || - isNil(settings.triggerName) || - isNil(settings.input) + isNil(settings.pieceVersion) || + isNil(settings.triggerName) || + isNil(settings.input) ) { return false } @@ -433,7 +532,10 @@ async function validateTrigger({ settings, projectId }: { settings: PieceTrigger return validateProps(props, settings.input) } -function validateProps(props: PiecePropertyMap, input: Record): boolean { +function validateProps( + props: PiecePropertyMap, + input: Record, +): boolean { const propsSchema = buildSchema(props) const propsValidator = TypeCompiler.Compile(propsSchema) return propsValidator.Check(input) @@ -441,12 +543,17 @@ function validateProps(props: PiecePropertyMap, input: Record): function buildSchema(props: PiecePropertyMap): TSchema { const entries = Object.entries(props) - const nonNullableUnknownPropType = Type.Not(Type.Union([Type.Null(), Type.Undefined()]), Type.Unknown()) + const nonNullableUnknownPropType = Type.Not( + Type.Union([Type.Null(), Type.Undefined()]), + Type.Unknown(), + ) const propsSchema: Record = {} for (const [name, property] of entries) { switch (property.type) { case PropertyType.MARKDOWN: - propsSchema[name] = Type.Optional(Type.Union([Type.Null(), Type.Undefined(), Type.Never()])) + propsSchema[name] = Type.Optional( + Type.Union([Type.Null(), Type.Undefined(), Type.Never()]), + ) break case PropertyType.DATE_TIME: case PropertyType.SHORT_TEXT: @@ -474,17 +581,30 @@ function buildSchema(props: PiecePropertyMap): TSchema { case PropertyType.SECRET_TEXT: case PropertyType.OAUTH2: // Only accepts connections variable. - propsSchema[name] = Type.Union([Type.RegEx(RegExp('{{1}{connections.(.*?)}{1}}')), Type.String()]) + propsSchema[name] = Type.Union([ + Type.RegEx(RegExp('{{1}{connections.(.*?)}{1}}')), + Type.String(), + ]) break case PropertyType.ARRAY: // Only accepts connections variable. - propsSchema[name] = Type.Union([Type.Array(Type.Unknown({})), Type.String()]) + propsSchema[name] = Type.Union([ + Type.Array(Type.Unknown({})), + Type.String(), + ]) break case PropertyType.OBJECT: - propsSchema[name] = Type.Union([Type.Record(Type.String(), Type.Any()), Type.String()]) + propsSchema[name] = Type.Union([ + Type.Record(Type.String(), Type.Any()), + Type.String(), + ]) break case PropertyType.JSON: - propsSchema[name] = Type.Union([Type.Record(Type.String(), Type.Any()), Type.Array(Type.Any()), Type.String()]) + propsSchema[name] = Type.Union([ + Type.Record(Type.String(), Type.Any()), + Type.Array(Type.Any()), + Type.String(), + ]) break case PropertyType.MULTI_SELECT_DROPDOWN: propsSchema[name] = Type.Union([Type.Array(Type.Any()), Type.String()]) @@ -498,7 +618,9 @@ function buildSchema(props: PiecePropertyMap): TSchema { } if (!property.required) { - propsSchema[name] = Type.Optional(Type.Union([Type.Null(), Type.Undefined(), propsSchema[name]])) + propsSchema[name] = Type.Optional( + Type.Union([Type.Null(), Type.Undefined(), propsSchema[name]]), + ) } } diff --git a/packages/backend/src/app/flows/flow.module.ts b/packages/server/api/src/app/flows/flow.module.ts old mode 100755 new mode 100644 similarity index 100% rename from packages/backend/src/app/flows/flow.module.ts rename to packages/server/api/src/app/flows/flow.module.ts diff --git a/packages/backend/src/app/flows/flow/flow-service-hooks.ts b/packages/server/api/src/app/flows/flow/flow-service-hooks.ts similarity index 68% rename from packages/backend/src/app/flows/flow/flow-service-hooks.ts rename to packages/server/api/src/app/flows/flow/flow-service-hooks.ts index 7352b3cdbd..c79d1ce3ef 100644 --- a/packages/backend/src/app/flows/flow/flow-service-hooks.ts +++ b/packages/server/api/src/app/flows/flow/flow-service-hooks.ts @@ -1,15 +1,32 @@ -import { Flow, FlowScheduleOptions, FlowStatus, FlowVersion, ScheduleOptions, ScheduleType, assertNotNullOrUndefined, isNil } from '@activepieces/shared' +import { + Flow, + FlowScheduleOptions, + FlowStatus, + FlowVersion, + ScheduleOptions, + ScheduleType, + assertNotNullOrUndefined, + isNil, +} from '@activepieces/shared' import { flowVersionService } from '../flow-version/flow-version.service' import { triggerHooks } from '../trigger' export const flowServiceHooks = { - async preUpdateStatus({ flowToUpdate, newStatus }: PreUpdateStatusParams): Promise { - assertNotNullOrUndefined(flowToUpdate.publishedVersionId, 'publishedVersionId') - - const publishedFlowVersion = await flowVersionService.getFlowVersionOrThrow({ - flowId: flowToUpdate.id, - versionId: flowToUpdate.publishedVersionId, - }) + async preUpdateStatus({ + flowToUpdate, + newStatus, + }: PreUpdateStatusParams): Promise { + assertNotNullOrUndefined( + flowToUpdate.publishedVersionId, + 'publishedVersionId', + ) + + const publishedFlowVersion = await flowVersionService.getFlowVersionOrThrow( + { + flowId: flowToUpdate.id, + versionId: flowToUpdate.publishedVersionId, + }, + ) let scheduleOptions: ScheduleOptions | undefined @@ -47,10 +64,18 @@ export const flowServiceHooks = { } }, - async preUpdatePublishedVersionId({ flowToUpdate, flowVersionToPublish }: PreUpdatePublishedVersionIdParams): Promise { - if (flowToUpdate.status === FlowStatus.ENABLED && flowToUpdate.publishedVersionId) { + async preUpdatePublishedVersionId({ + flowToUpdate, + flowVersionToPublish, + }: PreUpdatePublishedVersionIdParams): Promise { + if ( + flowToUpdate.status === FlowStatus.ENABLED && + flowToUpdate.publishedVersionId + ) { await triggerHooks.disable({ - flowVersion: await flowVersionService.getOneOrThrow(flowToUpdate.publishedVersionId), + flowVersion: await flowVersionService.getOneOrThrow( + flowToUpdate.publishedVersionId, + ), projectId: flowToUpdate.projectId, simulate: false, }) @@ -79,14 +104,19 @@ export const flowServiceHooks = { }, async preDelete({ flowToDelete }: PreDeleteParams): Promise { - if (flowToDelete.status === FlowStatus.DISABLED || isNil(flowToDelete.publishedVersionId)) { + if ( + flowToDelete.status === FlowStatus.DISABLED || + isNil(flowToDelete.publishedVersionId) + ) { return } - const publishedFlowVersion = await flowVersionService.getFlowVersionOrThrow({ - flowId: flowToDelete.id, - versionId: flowToDelete.publishedVersionId, - }) + const publishedFlowVersion = await flowVersionService.getFlowVersionOrThrow( + { + flowId: flowToDelete.id, + versionId: flowToDelete.publishedVersionId, + }, + ) await triggerHooks.disable({ flowVersion: publishedFlowVersion, diff --git a/packages/server/api/src/app/flows/flow/flow-version.controller.ts b/packages/server/api/src/app/flows/flow/flow-version.controller.ts new file mode 100644 index 0000000000..584f65473e --- /dev/null +++ b/packages/server/api/src/app/flows/flow/flow-version.controller.ts @@ -0,0 +1,41 @@ +import { ListFlowVersionRequest, SeekPage } from '@activepieces/shared' +import { StatusCodes } from 'http-status-codes' +import { flowService } from './flow.service' +import { + FastifyPluginAsyncTypebox, + Type, +} from '@fastify/type-provider-typebox' +import { flowVersionService } from '../flow-version/flow-version.service' +import { FlowVersionMetadata } from '@activepieces/shared' + +const DEFUALT_PAGE_SIZE = 10 + +export const flowVersionController: FastifyPluginAsyncTypebox = async ( + fastify, +) => { + fastify.get( + '/:flowId/versions', + { + schema: { + params: Type.Object({ + flowId: Type.String(), + }), + querystring: ListFlowVersionRequest, + response: { + [StatusCodes.OK]: SeekPage(FlowVersionMetadata), + }, + }, + }, + async (request) => { + const flow = await flowService.getOneOrThrow({ + id: request.params.flowId, + projectId: request.principal.projectId, + }) + return flowVersionService.list({ + flowId: flow.id, + limit: request.query.limit ?? DEFUALT_PAGE_SIZE, + cursorRequest: request.query.cursor ?? null, + }) + }, + ) +} diff --git a/packages/backend/src/app/flows/flow/flow.controller.ts b/packages/server/api/src/app/flows/flow/flow.controller.ts old mode 100755 new mode 100644 similarity index 93% rename from packages/backend/src/app/flows/flow/flow.controller.ts rename to packages/server/api/src/app/flows/flow/flow.controller.ts index 52048baac3..8db1ff0e64 --- a/packages/backend/src/app/flows/flow/flow.controller.ts +++ b/packages/server/api/src/app/flows/flow/flow.controller.ts @@ -16,9 +16,12 @@ import { CountFlowsRequest } from '@activepieces/shared' import dayjs from 'dayjs' import { isNil } from 'lodash' import { entitiesMustBeOwnedByCurrentProject } from '../../authentication/authorization' -import { FastifyPluginAsyncTypebox, Type } from '@fastify/type-provider-typebox' +import { + FastifyPluginAsyncTypebox, + Type, +} from '@fastify/type-provider-typebox' import { projectService } from '../../project/project-service' -import { eventsHooks } from '../../helper/audit-events' +import { eventsHooks } from '../../helper/application-events' import { ApplicationEventName } from '@activepieces/ee-shared' const DEFAULT_PAGE_SIZE = 10 @@ -50,9 +53,10 @@ export const flowController: FastifyPluginAsyncTypebox = async (app) => { const currentTime = dayjs() const userId = await extractUserIdFromPrincipal(request.principal) - if (!isNil(flow.version.updatedBy) && - flow.version.updatedBy !== userId && - currentTime.diff(dayjs(flow.version.updated), 'minute') <= 1 + if ( + !isNil(flow.version.updatedBy) && + flow.version.updatedBy !== userId && + currentTime.diff(dayjs(flow.version.updated), 'minute') <= 1 ) { return reply.status(StatusCodes.CONFLICT).send() } @@ -118,7 +122,9 @@ export const flowController: FastifyPluginAsyncTypebox = async (app) => { }) } -async function extractUserIdFromPrincipal(principal: Principal): Promise { +async function extractUserIdFromPrincipal( + principal: Principal, +): Promise { if (principal.type === PrincipalType.USER) { return principal.id } @@ -152,8 +158,6 @@ const UpdateFlowRequestOptions = { }, } - - const ListFlowsRequestOptions = { config: { allowedPrincipals: [PrincipalType.USER, PrincipalType.SERVICE], diff --git a/packages/backend/src/app/flows/flow/flow.entity.ts b/packages/server/api/src/app/flows/flow/flow.entity.ts old mode 100755 new mode 100644 similarity index 91% rename from packages/backend/src/app/flows/flow/flow.entity.ts rename to packages/server/api/src/app/flows/flow/flow.entity.ts index 9216b4a76d..81ccde771e --- a/packages/backend/src/app/flows/flow/flow.entity.ts +++ b/packages/server/api/src/app/flows/flow/flow.entity.ts @@ -1,6 +1,18 @@ import { EntitySchema } from 'typeorm' -import { Flow, Folder, FlowRun, FlowVersion, Project, TriggerEvent, FlowStatus } from '@activepieces/shared' -import { ApIdSchema, BaseColumnSchemaPart, JSONB_COLUMN_TYPE } from '../../database/database-common' +import { + Flow, + Folder, + FlowRun, + FlowVersion, + Project, + TriggerEvent, + FlowStatus, +} from '@activepieces/shared' +import { + ApIdSchema, + BaseColumnSchemaPart, + JSONB_COLUMN_TYPE, +} from '../../database/database-common' export type FlowSchema = Flow & { versions: FlowVersion[] diff --git a/packages/backend/src/app/flows/flow/flow.repo.ts b/packages/server/api/src/app/flows/flow/flow.repo.ts similarity index 100% rename from packages/backend/src/app/flows/flow/flow.repo.ts rename to packages/server/api/src/app/flows/flow/flow.repo.ts diff --git a/packages/backend/src/app/flows/flow/flow.service.ts b/packages/server/api/src/app/flows/flow/flow.service.ts old mode 100755 new mode 100644 similarity index 80% rename from packages/backend/src/app/flows/flow/flow.service.ts rename to packages/server/api/src/app/flows/flow/flow.service.ts index 90dece113c..6e5132a971 --- a/packages/backend/src/app/flows/flow/flow.service.ts +++ b/packages/server/api/src/app/flows/flow/flow.service.ts @@ -28,7 +28,7 @@ import { flowRepo } from './flow.repo' import { telemetry } from '../../helper/telemetry.utils' import { EntityManager, IsNull } from 'typeorm' import { isNil } from '@activepieces/shared' -import { logger } from '../../helper/logger' +import { logger } from 'server-shared' import { flowServiceHooks as hooks } from './flow-service-hooks' import { transaction } from '../../core/db/transaction' @@ -45,20 +45,23 @@ export const flowService = { const savedFlow = await flowRepo().save(newFlow) - const savedFlowVersion = await flowVersionService.createEmptyVersion(savedFlow.id, { - displayName: request.displayName, - }) - - telemetry.trackProject( - savedFlow.projectId, + const savedFlowVersion = await flowVersionService.createEmptyVersion( + savedFlow.id, { + displayName: request.displayName, + }, + ) + + telemetry + .trackProject(savedFlow.projectId, { name: TelemetryEventName.CREATED_FLOW, payload: { flowId: savedFlow.id, }, - }, - ) - .catch((e) => logger.error(e, '[FlowService#create] telemetry.trackProject')) + }) + .catch((e) => + logger.error(e, '[FlowService#create] telemetry.trackProject'), + ) return { ...savedFlow, @@ -66,7 +69,13 @@ export const flowService = { } }, - async list({ projectId, cursorRequest, limit, folderId, status }: ListParams): Promise> { + async list({ + projectId, + cursorRequest, + limit, + folderId, + status, + }: ListParams): Promise> { const decodedCursor = paginationHelper.decodeCursor(cursorRequest) const paginator = buildPaginator({ @@ -82,14 +91,16 @@ export const flowService = { const queryWhere: Record = { projectId } if (folderId !== undefined) { - queryWhere.folderId = (folderId === 'NULL' ? IsNull() : folderId) + queryWhere.folderId = folderId === 'NULL' ? IsNull() : folderId } if (status !== undefined) { queryWhere.status = status } - const paginationResult = await paginator.paginate(flowRepo().createQueryBuilder('flow').where(queryWhere)) + const paginationResult = await paginator.paginate( + flowRepo().createQueryBuilder('flow').where(queryWhere), + ) const populatedFlowPromises = paginationResult.data.map(async (flow) => { const version = await flowVersionService.getFlowVersionOrThrow({ @@ -121,7 +132,12 @@ export const flowService = { return flow }, - async getOnePopulated({ id, projectId, versionId, removeSecrets = false }: GetOnePopulatedParams): Promise { + async getOnePopulated({ + id, + projectId, + versionId, + removeSecrets = false, + }: GetOnePopulatedParams): Promise { const flow = await flowRepo().findOneBy({ id, projectId, @@ -143,17 +159,35 @@ export const flowService = { } }, - async getOnePopulatedOrThrow({ id, projectId, versionId, removeSecrets = false }: GetOnePopulatedParams): Promise { - const flow = await this.getOnePopulated({ id, projectId, versionId, removeSecrets }) + async getOnePopulatedOrThrow({ + id, + projectId, + versionId, + removeSecrets = false, + }: GetOnePopulatedParams): Promise { + const flow = await this.getOnePopulated({ + id, + projectId, + versionId, + removeSecrets, + }) assertFlowIsNotNull(flow) return flow }, - async update({ id, userId, projectId, operation, lock = true }: UpdateParams): Promise { - const flowLock = lock ? await acquireLock({ - key: id, - timeout: 10000, - }) : null + async update({ + id, + userId, + projectId, + operation, + lock = true, + }: UpdateParams): Promise { + const flowLock = lock + ? await acquireLock({ + key: id, + timeout: 10000, + }) + : null try { if (operation.type === FlowOperationType.LOCK_AND_PUBLISH) { @@ -182,10 +216,11 @@ export const flowService = { }) if (lastVersion.state === FlowVersionState.LOCKED) { - const lastVersionWithArtifacts = await flowVersionService.getFlowVersionOrThrow({ - flowId: id, - versionId: undefined, - }) + const lastVersionWithArtifacts = + await flowVersionService.getFlowVersionOrThrow({ + flowId: id, + versionId: undefined, + }) lastVersion = await flowVersionService.createEmptyVersion(id, { displayName: lastVersionWithArtifacts.displayName, @@ -221,7 +256,11 @@ export const flowService = { }) }, - async updateStatus({ id, projectId, newStatus }: UpdateStatusParams): Promise { + async updateStatus({ + id, + projectId, + newStatus, + }: UpdateStatusParams): Promise { const flowToUpdate = await this.getOneOrThrow({ id, projectId }) if (flowToUpdate.status !== newStatus) { @@ -242,13 +281,19 @@ export const flowService = { }) }, - async updatedPublishedVersionId({ id, userId, projectId }: UpdatePublishedVersionIdParams): Promise { + async updatedPublishedVersionId({ + id, + userId, + projectId, + }: UpdatePublishedVersionIdParams): Promise { const flowToUpdate = await this.getOneOrThrow({ id, projectId }) - const flowVersionToPublish = await flowVersionService.getFlowVersionOrThrow({ - flowId: id, - versionId: undefined, - }) + const flowVersionToPublish = await flowVersionService.getFlowVersionOrThrow( + { + flowId: id, + versionId: undefined, + }, + ) const { scheduleOptions } = await hooks.preUpdatePublishedVersionId({ flowToUpdate, @@ -305,7 +350,11 @@ export const flowService = { }) }, - async getTemplate({ flowId, versionId, projectId }: GetTemplateParams): Promise { + async getTemplate({ + flowId, + versionId, + projectId, + }: GetTemplateParams): Promise { const flow = await this.getOnePopulatedOrThrow({ id: flowId, projectId, @@ -337,7 +386,12 @@ export const flowService = { }, } -const lockFlowVersionIfNotLocked = async ({ flowVersion, userId, projectId, entityManager }: LockFlowVersionIfNotLockedParams): Promise => { +const lockFlowVersionIfNotLocked = async ({ + flowVersion, + userId, + projectId, + entityManager, +}: LockFlowVersionIfNotLockedParams): Promise => { if (flowVersion.state === FlowVersionState.LOCKED) { return flowVersion } @@ -356,7 +410,9 @@ const lockFlowVersionIfNotLocked = async ({ flowVersion, userId, projectId, enti }) } -const assertFlowIsNotNull: (flow: T | null) => asserts flow is T = (flow: T | null) => { +const assertFlowIsNotNull: ( + flow: T | null +) => asserts flow is T = (flow: T | null) => { if (isNil(flow)) { throw new ActivepiecesError({ code: ErrorCode.ENTITY_NOT_FOUND, diff --git a/packages/backend/src/app/flows/folder/folder.controller.ts b/packages/server/api/src/app/flows/folder/folder.controller.ts similarity index 65% rename from packages/backend/src/app/flows/folder/folder.controller.ts rename to packages/server/api/src/app/flows/folder/folder.controller.ts index 322833496d..e7b7d4d124 100644 --- a/packages/backend/src/app/flows/folder/folder.controller.ts +++ b/packages/server/api/src/app/flows/folder/folder.controller.ts @@ -1,16 +1,19 @@ import { FastifyPluginAsyncTypebox } from '@fastify/type-provider-typebox' -import { CreateOrRenameFolderRequest, FolderId, ListFolderRequest } from '@activepieces/shared' +import { + CreateOrRenameFolderRequest, + FolderId, + ListFolderRequest, +} from '@activepieces/shared' import { FastifyRequest } from 'fastify' import { flowFolderService as folderService } from './folder.service' import { StatusCodes } from 'http-status-codes' import { Static, Type } from '@sinclair/typebox' import { entitiesMustBeOwnedByCurrentProject } from '../../authentication/authorization' -import { eventsHooks } from '../../helper/audit-events' +import { eventsHooks } from '../../helper/application-events' import { ApplicationEventName } from '@activepieces/ee-shared' const DEFUALT_PAGE_SIZE = 10 - const FolderIdParam = Type.Object({ folderId: Type.String(), }) @@ -27,7 +30,10 @@ export const folderController: FastifyPluginAsyncTypebox = async (fastify) => { }, }, async (request) => { - const createdFolder = await folderService.create({ projectId: request.principal.projectId, request: request.body }) + const createdFolder = await folderService.create({ + projectId: request.principal.projectId, + request: request.body, + }) eventsHooks.get().send(request, { action: ApplicationEventName.CREATED_FOLDER, folder: createdFolder, @@ -37,7 +43,6 @@ export const folderController: FastifyPluginAsyncTypebox = async (fastify) => { }, ) - fastify.post( '/:folderId', { @@ -47,7 +52,11 @@ export const folderController: FastifyPluginAsyncTypebox = async (fastify) => { }, }, async (request) => { - const updatedFlow = await folderService.update({ projectId: request.principal.projectId, folderId: request.params.folderId, request: request.body }) + const updatedFlow = await folderService.update({ + projectId: request.principal.projectId, + folderId: request.params.folderId, + request: request.body, + }) eventsHooks.get().send(request, { action: ApplicationEventName.UPDATED_FOLDER, @@ -59,7 +68,6 @@ export const folderController: FastifyPluginAsyncTypebox = async (fastify) => { }, ) - fastify.get( '/:folderId', async ( @@ -69,11 +77,13 @@ export const folderController: FastifyPluginAsyncTypebox = async (fastify) => { } }>, ) => { - return folderService.getOneOrThrow({ projectId: request.principal.projectId, folderId: request.params.folderId }) + return folderService.getOneOrThrow({ + projectId: request.principal.projectId, + folderId: request.params.folderId, + }) }, ) - fastify.get( '/', { @@ -82,11 +92,14 @@ export const folderController: FastifyPluginAsyncTypebox = async (fastify) => { }, }, async (request) => { - return folderService.list({ projectId: request.principal.projectId, cursorRequest: request.query.cursor ?? null, limit: request.query.limit ?? DEFUALT_PAGE_SIZE }) + return folderService.list({ + projectId: request.principal.projectId, + cursorRequest: request.query.cursor ?? null, + limit: request.query.limit ?? DEFUALT_PAGE_SIZE, + }) }, ) - fastify.delete( '/:folderId', async ( @@ -97,14 +110,19 @@ export const folderController: FastifyPluginAsyncTypebox = async (fastify) => { }>, reply, ) => { - - const folder = await folderService.getOneOrThrow({ projectId: request.principal.projectId, folderId: request.params.folderId }) + const folder = await folderService.getOneOrThrow({ + projectId: request.principal.projectId, + folderId: request.params.folderId, + }) eventsHooks.get().send(request, { action: ApplicationEventName.DELETED_FOLDER, folder, userId: request.principal.id, }) - await folderService.delete({ projectId: request.principal.projectId, folderId: request.params.folderId }) + await folderService.delete({ + projectId: request.principal.projectId, + folderId: request.params.folderId, + }) return reply.status(StatusCodes.OK).send() }, ) diff --git a/packages/backend/src/app/flows/folder/folder.entity.ts b/packages/server/api/src/app/flows/folder/folder.entity.ts similarity index 92% rename from packages/backend/src/app/flows/folder/folder.entity.ts rename to packages/server/api/src/app/flows/folder/folder.entity.ts index a47279f4d5..3a345b9526 100644 --- a/packages/backend/src/app/flows/folder/folder.entity.ts +++ b/packages/server/api/src/app/flows/folder/folder.entity.ts @@ -1,6 +1,9 @@ import { EntitySchema } from 'typeorm' import { Flow, Folder as Folder, Project } from '@activepieces/shared' -import { ApIdSchema, BaseColumnSchemaPart } from '../../database/database-common' +import { + ApIdSchema, + BaseColumnSchemaPart, +} from '../../database/database-common' export type FolderSchema = { flows: Flow[] diff --git a/packages/backend/src/app/flows/folder/folder.service.ts b/packages/server/api/src/app/flows/folder/folder.service.ts similarity index 62% rename from packages/backend/src/app/flows/folder/folder.service.ts rename to packages/server/api/src/app/flows/folder/folder.service.ts index 4d55df3bea..4f3528a0bf 100644 --- a/packages/backend/src/app/flows/folder/folder.service.ts +++ b/packages/server/api/src/app/flows/folder/folder.service.ts @@ -1,7 +1,18 @@ -import { ActivepiecesError, Cursor, ErrorCode, Folder, FolderDto, ProjectId } from '@activepieces/shared' +import { + ActivepiecesError, + Cursor, + ErrorCode, + Folder, + FolderDto, + ProjectId, +} from '@activepieces/shared' import { databaseConnection } from '../../database/database-connection' import { FolderEntity } from './folder.entity' -import { CreateOrRenameFolderRequest, FolderId, apId } from '@activepieces/shared' +import { + CreateOrRenameFolderRequest, + FolderId, + apId, +} from '@activepieces/shared' import { paginationHelper } from '../../helper/pagination/pagination-utils' import { buildPaginator } from '../../helper/pagination/build-paginator' import { flowService } from '../flow/flow.service' @@ -10,13 +21,27 @@ import { isNil } from '@activepieces/shared' export const folderRepo = databaseConnection.getRepository(FolderEntity) export const flowFolderService = { - async delete({ projectId, folderId }: { projectId: ProjectId, folderId: FolderId }) { + async delete({ + projectId, + folderId, + }: { + projectId: ProjectId + folderId: FolderId + }) { await folderRepo.delete({ id: folderId, projectId, }) }, - async update({ projectId, folderId, request }: { projectId: ProjectId, folderId: FolderId, request: CreateOrRenameFolderRequest }): Promise { + async update({ + projectId, + folderId, + request, + }: { + projectId: ProjectId + folderId: FolderId + request: CreateOrRenameFolderRequest + }): Promise { const folder = await folderRepo.findOneBy({ projectId, id: folderId, @@ -26,7 +51,10 @@ export const flowFolderService = { displayName: request.displayName, }) if (folderWithDisplayName && folderWithDisplayName.id !== folderId) { - throw new ActivepiecesError({ code: ErrorCode.VALIDATION, params: { message: 'Folder displayName is used' } }) + throw new ActivepiecesError({ + code: ErrorCode.VALIDATION, + params: { message: 'Folder displayName is used' }, + }) } if (isNil(folder)) { throw new ActivepiecesError({ @@ -43,13 +71,22 @@ export const flowFolderService = { await folderRepo.update(folderId, updatedFolder) return updatedFolder }, - async create({ projectId, request }: { projectId: ProjectId, request: CreateOrRenameFolderRequest }): Promise { + async create({ + projectId, + request, + }: { + projectId: ProjectId + request: CreateOrRenameFolderRequest + }): Promise { const folderWithDisplayName = await folderRepo.findOneBy({ projectId, displayName: request.displayName, }) if (folderWithDisplayName) { - throw new ActivepiecesError({ code: ErrorCode.VALIDATION, params: { message: 'Folder displayName is used' } }) + throw new ActivepiecesError({ + code: ErrorCode.VALIDATION, + params: { message: 'Folder displayName is used' }, + }) } const folder = await folderRepo.save({ id: apId(), @@ -61,7 +98,15 @@ export const flowFolderService = { numberOfFlows: 0, } }, - async list({ projectId, cursorRequest, limit }: { projectId: ProjectId, cursorRequest: Cursor | null, limit: number }) { + async list({ + projectId, + cursorRequest, + limit, + }: { + projectId: ProjectId + cursorRequest: Cursor | null + limit: number + }) { const decodedCursor = paginationHelper.decodeCursor(cursorRequest) const paginator = buildPaginator({ entity: FolderEntity, @@ -72,18 +117,31 @@ export const flowFolderService = { beforeCursor: decodedCursor.previousCursor, }, }) - const paginationResponse = await paginator.paginate(folderRepo.createQueryBuilder('folder').where({ projectId })) + const paginationResponse = await paginator.paginate( + folderRepo.createQueryBuilder('folder').where({ projectId }), + ) const numberOfFlowForEachFolder: Promise[] = [] const dtosList: FolderDto[] = [] paginationResponse.data.forEach((f) => { - numberOfFlowForEachFolder.push(flowService.count({ projectId, folderId: f.id })) + numberOfFlowForEachFolder.push( + flowService.count({ projectId, folderId: f.id }), + ) }); (await Promise.all(numberOfFlowForEachFolder)).forEach((num, idx) => { dtosList.push({ ...paginationResponse.data[idx], numberOfFlows: num }) }) - return paginationHelper.createPage(dtosList, paginationResponse.cursor) + return paginationHelper.createPage( + dtosList, + paginationResponse.cursor, + ) }, - async getOneOrThrow({ projectId, folderId }: { projectId: ProjectId, folderId: FolderId }): Promise { + async getOneOrThrow({ + projectId, + folderId, + }: { + projectId: ProjectId + folderId: FolderId + }): Promise { const folder = await folderRepo.findOneBy({ projectId, id: folderId }) if (!folder) { throw new ActivepiecesError({ @@ -99,5 +157,4 @@ export const flowFolderService = { numberOfFlows, } }, - } diff --git a/packages/backend/src/app/flows/step-file/step-file.entity.ts b/packages/server/api/src/app/flows/step-file/step-file.entity.ts similarity index 93% rename from packages/backend/src/app/flows/step-file/step-file.entity.ts rename to packages/server/api/src/app/flows/step-file/step-file.entity.ts index 2cac0d8f6b..6861fa6c12 100644 --- a/packages/backend/src/app/flows/step-file/step-file.entity.ts +++ b/packages/server/api/src/app/flows/step-file/step-file.entity.ts @@ -1,6 +1,10 @@ import { EntitySchema } from 'typeorm' import { Flow, Project, StepFile } from '@activepieces/shared' -import { ApIdSchema, BLOB_COLUMN_TYPE, BaseColumnSchemaPart } from '../../database/database-common' +import { + ApIdSchema, + BLOB_COLUMN_TYPE, + BaseColumnSchemaPart, +} from '../../database/database-common' type StepFileSchema = StepFile & { project: Project diff --git a/packages/server/api/src/app/flows/step-file/step-file.module.ts b/packages/server/api/src/app/flows/step-file/step-file.module.ts new file mode 100644 index 0000000000..50163944e1 --- /dev/null +++ b/packages/server/api/src/app/flows/step-file/step-file.module.ts @@ -0,0 +1,109 @@ +import { FastifyPluginAsyncTypebox } from '@fastify/type-provider-typebox' +import { entitiesMustBeOwnedByCurrentProject } from '../../authentication/authorization' +import { Type } from '@sinclair/typebox' +import { stepFileService } from './step-file.service' +import { + ALL_PRINICPAL_TYPES, + PrincipalType, + StepFileUpsert, +} from '@activepieces/shared' +import { StatusCodes } from 'http-status-codes' + +export const stepFileModule: FastifyPluginAsyncTypebox = async (app) => { + app.addHook('preSerialization', entitiesMustBeOwnedByCurrentProject) + await app.register(stepFileController, { prefix: '/v1/step-files' }) +} + +export const stepFileController: FastifyPluginAsyncTypebox = async (app) => { + app.get( + '/signed', + { + config: { + allowedPrincipals: ALL_PRINICPAL_TYPES, + }, + schema: { + querystring: Type.Object({ + token: Type.String(), + }), + }, + }, + async (request, reply) => { + const stepFile = await stepFileService.getByToken(request.query.token) + await reply + .header( + 'Content-Disposition', + `attachment; filename="${stepFile?.name}"`, + ) + .type('application/octet-stream') + .status(StatusCodes.OK) + .send(stepFile?.data) + }, + ) + + app.get( + '/:id', + { + config: { + allowedPrincipals: [PrincipalType.WORKER], + }, + schema: { + params: Type.Object({ + id: Type.String(), + }), + }, + }, + async (request, reply) => { + const stepFile = await stepFileService.get({ + projectId: request.principal.projectId, + id: request.params.id, + }) + return reply + .header( + 'Content-Disposition', + `attachment; filename="${stepFile?.name}"`, + ) + .type('application/octet-stream') + .status(StatusCodes.OK) + .send(stepFile?.data) + }, + ) + + app.post( + '/', + { + config: { + allowedPrincipals: [PrincipalType.WORKER], + }, + schema: { + body: StepFileUpsert, + }, + }, + async (request) => { + return stepFileService.upsert({ + hostname: request.hostname, + projectId: request.principal.projectId, + request: request.body, + }) + }, + ) + + app.delete( + '/:id', + { + config: { + allowedPrincipals: [PrincipalType.WORKER], + }, + schema: { + params: Type.Object({ + id: Type.String(), + }), + }, + }, + async (request) => { + return stepFileService.delete({ + projectId: request.principal.projectId, + id: request.params.id, + }) + }, + ) +} diff --git a/packages/backend/src/app/flows/step-file/step-file.service.ts b/packages/server/api/src/app/flows/step-file/step-file.service.ts similarity index 68% rename from packages/backend/src/app/flows/step-file/step-file.service.ts rename to packages/server/api/src/app/flows/step-file/step-file.service.ts index 071c17d5c2..6408cdec65 100644 --- a/packages/backend/src/app/flows/step-file/step-file.service.ts +++ b/packages/server/api/src/app/flows/step-file/step-file.service.ts @@ -1,4 +1,13 @@ -import { StepFileWithUrl, ActivepiecesError, ErrorCode, StepFile, StepFileGet, StepFileUpsert, apId, isNil } from '@activepieces/shared' +import { + StepFileWithUrl, + ActivepiecesError, + ErrorCode, + StepFile, + StepFileGet, + StepFileUpsert, + apId, + isNil, +} from '@activepieces/shared' import { databaseConnection } from '../../database/database-connection' import { StepFileEntity } from './step-file.entity' import { jwtUtils } from '../../helper/jwt-utils' @@ -6,28 +15,41 @@ import { domainHelper } from '../../helper/domain-helper' const stepFileRepo = databaseConnection.getRepository(StepFileEntity) - type FileToken = { fileId: string } export const stepFileService = { - async upsert({ hostname, request, projectId }: { hostname: string, request: StepFileUpsert, projectId: string }): Promise { + async upsert({ + hostname, + request, + projectId, + }: { + hostname: string + request: StepFileUpsert + projectId: string + }): Promise { const fileId = apId() const bufferFile = request.file as Buffer - await stepFileRepo.upsert({ - id: fileId, - flowId: request.flowId, - projectId, - stepName: request.stepName, - size: bufferFile.byteLength, - data: bufferFile, - name: request.name, - }, ['flowId', 'projectId', 'stepName', 'name']) - return encrichWithUrl(hostname, await stepFileRepo.findOneByOrFail({ - id: fileId, - projectId, - })) + await stepFileRepo.upsert( + { + id: fileId, + flowId: request.flowId, + projectId, + stepName: request.stepName, + size: bufferFile.byteLength, + data: bufferFile, + name: request.name, + }, + ['flowId', 'projectId', 'stepName', 'name'], + ) + return encrichWithUrl( + hostname, + await stepFileRepo.findOneByOrFail({ + id: fileId, + projectId, + }), + ) }, async getByToken(token: string): Promise { try { @@ -82,7 +104,15 @@ export const stepFileService = { projectId, }) }, - async deleteAll({ projectId, flowId, stepName }: { projectId: string, flowId: string, stepName: string }): Promise { + async deleteAll({ + projectId, + flowId, + stepName, + }: { + projectId: string + flowId: string + stepName: string + }): Promise { await stepFileRepo.delete({ projectId, flowId, @@ -91,8 +121,10 @@ export const stepFileService = { }, } -async function encrichWithUrl(hostname: string, file: StepFile): Promise { - +async function encrichWithUrl( + hostname: string, + file: StepFile, +): Promise { const jwtSecret = await jwtUtils.getJwtSecret() const accessToken = await jwtUtils.sign({ payload: { diff --git a/packages/backend/src/app/flows/step-run/step-run-controller.ts b/packages/server/api/src/app/flows/step-run/step-run-controller.ts similarity index 90% rename from packages/backend/src/app/flows/step-run/step-run-controller.ts rename to packages/server/api/src/app/flows/step-run/step-run-controller.ts index 69f96cd69c..0e4cab1f1f 100644 --- a/packages/backend/src/app/flows/step-run/step-run-controller.ts +++ b/packages/server/api/src/app/flows/step-run/step-run-controller.ts @@ -8,7 +8,11 @@ const CreateStepRunRequest = { }, } -export const stepRunController: FastifyPluginCallbackTypebox = (app, _opts, done) => { +export const stepRunController: FastifyPluginCallbackTypebox = ( + app, + _opts, + done, +) => { app.post('/', CreateStepRunRequest, async (req) => { const { flowVersionId, stepName } = req.body const { projectId } = req.principal @@ -16,12 +20,11 @@ export const stepRunController: FastifyPluginCallbackTypebox = (app, _opts, done const result = await stepRunService.create({ projectId, flowVersionId, - userId: req.principal.id, + userId: req.principal.id, stepName, }) return result - }) done() diff --git a/packages/backend/src/app/flows/step-run/step-run-service.ts b/packages/server/api/src/app/flows/step-run/step-run-service.ts similarity index 70% rename from packages/backend/src/app/flows/step-run/step-run-service.ts rename to packages/server/api/src/app/flows/step-run/step-run-service.ts index 5a23eb501c..72cf369d39 100644 --- a/packages/backend/src/app/flows/step-run/step-run-service.ts +++ b/packages/server/api/src/app/flows/step-run/step-run-service.ts @@ -13,11 +13,18 @@ import { flowVersionService } from '../flow-version/flow-version.service' import { isNil } from '@activepieces/shared' export const stepRunService = { - async create({ projectId, flowVersionId, stepName }: CreateParams): Promise { + async create({ + projectId, + flowVersionId, + stepName, + }: CreateParams): Promise { const flowVersion = await flowVersionService.getOneOrThrow(flowVersionId) const step = flowHelper.getStep(flowVersion, stepName) - if (isNil(step) || !Object.values(ActionType).includes(step.type as ActionType)) { + if ( + isNil(step) || + !Object.values(ActionType).includes(step.type as ActionType) + ) { throw new ActivepiecesError({ code: ErrorCode.STEP_NOT_FOUND, params: { @@ -25,18 +32,18 @@ export const stepRunService = { }, }) } - const { result, standardError, standardOutput } = await engineHelper.executeAction({ - stepName, - flowVersion, - projectId, - }) + const { result, standardError, standardOutput } = + await engineHelper.executeAction({ + stepName, + flowVersion, + projectId, + }) return { success: result.success, output: result.output, standardError, standardOutput, } - }, } diff --git a/packages/backend/src/app/flows/test-trigger/test-trigger-controller.ts b/packages/server/api/src/app/flows/test-trigger/test-trigger-controller.ts similarity index 91% rename from packages/backend/src/app/flows/test-trigger/test-trigger-controller.ts rename to packages/server/api/src/app/flows/test-trigger/test-trigger-controller.ts index cddb1ed89b..17ab5e8b6c 100644 --- a/packages/backend/src/app/flows/test-trigger/test-trigger-controller.ts +++ b/packages/server/api/src/app/flows/test-trigger/test-trigger-controller.ts @@ -21,8 +21,6 @@ const TestTriggerRequest = { body: TestTriggerRequestBody, }, config: { - allowedPrincipals: [ - PrincipalType.USER, - ], + allowedPrincipals: [PrincipalType.USER], }, } diff --git a/packages/backend/src/app/flows/test-trigger/test-trigger-service.ts b/packages/server/api/src/app/flows/test-trigger/test-trigger-service.ts similarity index 59% rename from packages/backend/src/app/flows/test-trigger/test-trigger-service.ts rename to packages/server/api/src/app/flows/test-trigger/test-trigger-service.ts index 8047a5fc2e..764e98ab4a 100644 --- a/packages/backend/src/app/flows/test-trigger/test-trigger-service.ts +++ b/packages/server/api/src/app/flows/test-trigger/test-trigger-service.ts @@ -1,15 +1,24 @@ import { TriggerTestStrategy } from '@activepieces/shared' import { triggerEventService } from '../trigger-events/trigger-event.service' -import { FlowId, FlowVersionId, ProjectId, SeekPage, WebhookSimulation } from '@activepieces/shared' +import { + FlowId, + FlowVersionId, + ProjectId, + SeekPage, + WebhookSimulation, +} from '@activepieces/shared' import { flowService } from '../flow/flow.service' import { webhookSimulationService } from '../../webhooks/webhook-simulation/webhook-simulation-service' -import { logger } from '../../helper/logger' +import { logger } from 'server-shared' export const testTriggerService = { async test(params: TestParams): Promise { const { testStrategy, ...executeParams } = params - const testExecutors: Record Promise> = { + const testExecutors: Record< + TriggerTestStrategy, + (p: ExecuteTestParams) => Promise + > = { [TriggerTestStrategy.SIMULATION]: executeSimulation, [TriggerTestStrategy.TEST_FUNCTION]: executeTestFunction, } @@ -19,8 +28,17 @@ export const testTriggerService = { }, } -const executeSimulation = async ({ flowId, flowVersionId, projectId }: ExecuteTestParams): Promise => { - logger.debug({ name: 'testTriggerService.executeSimulation', flowId, flowVersionId, projectId }) +const executeSimulation = async ({ + flowId, + flowVersionId, + projectId, +}: ExecuteTestParams): Promise => { + logger.debug({ + name: 'testTriggerService.executeSimulation', + flowId, + flowVersionId, + projectId, + }) return webhookSimulationService.create({ flowId, @@ -29,8 +47,17 @@ const executeSimulation = async ({ flowId, flowVersionId, projectId }: ExecuteTe }) } -const executeTestFunction = async ({ flowId, flowVersionId, projectId }: ExecuteTestParams): Promise> => { - logger.debug({ name: 'testTriggerService.executeTestFunction', flowId, flowVersionId, projectId }) +const executeTestFunction = async ({ + flowId, + flowVersionId, + projectId, +}: ExecuteTestParams): Promise> => { + logger.debug({ + name: 'testTriggerService.executeTestFunction', + flowId, + flowVersionId, + projectId, + }) const flow = await flowService.getOnePopulatedOrThrow({ id: flowId, diff --git a/packages/backend/src/app/flows/trigger-events/trigger-event.entity.ts b/packages/server/api/src/app/flows/trigger-events/trigger-event.entity.ts old mode 100755 new mode 100644 similarity index 92% rename from packages/backend/src/app/flows/trigger-events/trigger-event.entity.ts rename to packages/server/api/src/app/flows/trigger-events/trigger-event.entity.ts index 801a5fcacb..7042b84ff0 --- a/packages/backend/src/app/flows/trigger-events/trigger-event.entity.ts +++ b/packages/server/api/src/app/flows/trigger-events/trigger-event.entity.ts @@ -1,6 +1,10 @@ import { EntitySchema } from 'typeorm' import { Flow, Project, TriggerEvent } from '@activepieces/shared' -import { ApIdSchema, BaseColumnSchemaPart, JSONB_COLUMN_TYPE } from '../../database/database-common' +import { + ApIdSchema, + BaseColumnSchemaPart, + JSONB_COLUMN_TYPE, +} from '../../database/database-common' type TriggerEventSchema = { flow: Flow diff --git a/packages/backend/src/app/flows/trigger-events/trigger-event.module.ts b/packages/server/api/src/app/flows/trigger-events/trigger-event.module.ts old mode 100755 new mode 100644 similarity index 95% rename from packages/backend/src/app/flows/trigger-events/trigger-event.module.ts rename to packages/server/api/src/app/flows/trigger-events/trigger-event.module.ts index 16e955c09e..d9f958b425 --- a/packages/backend/src/app/flows/trigger-events/trigger-event.module.ts +++ b/packages/server/api/src/app/flows/trigger-events/trigger-event.module.ts @@ -1,5 +1,8 @@ import { FastifyPluginAsyncTypebox } from '@fastify/type-provider-typebox' -import { ListTriggerEventsRequest, TestPollingTriggerRequest } from '@activepieces/shared' +import { + ListTriggerEventsRequest, + TestPollingTriggerRequest, +} from '@activepieces/shared' import { triggerEventService } from './trigger-event.service' import { flowService } from '../flow/flow.service' diff --git a/packages/backend/src/app/flows/trigger-events/trigger-event.service.ts b/packages/server/api/src/app/flows/trigger-events/trigger-event.service.ts similarity index 86% rename from packages/backend/src/app/flows/trigger-events/trigger-event.service.ts rename to packages/server/api/src/app/flows/trigger-events/trigger-event.service.ts index f48195608f..c7bfcc6a5b 100644 --- a/packages/backend/src/app/flows/trigger-events/trigger-event.service.ts +++ b/packages/server/api/src/app/flows/trigger-events/trigger-event.service.ts @@ -27,7 +27,15 @@ import { stepFileService } from '../step-file/step-file.service' const triggerEventRepo = databaseConnection.getRepository(TriggerEventEntity) export const triggerEventService = { - async saveEvent({ projectId, flowId, payload }: { projectId: ProjectId, flowId: FlowId, payload: unknown }): Promise { + async saveEvent({ + projectId, + flowId, + payload, + }: { + projectId: ProjectId + flowId: FlowId + payload: unknown + }): Promise { const flow = await flowService.getOnePopulatedOrThrow({ id: flowId, projectId, @@ -44,7 +52,13 @@ export const triggerEventService = { }) }, - async test({ projectId, flow }: { projectId: ProjectId, flow: PopulatedFlow }): Promise> { + async test({ + projectId, + flow, + }: { + projectId: ProjectId + flow: PopulatedFlow + }): Promise> { const trigger = flow.version.trigger const emptyPage = paginationHelper.createPage([], null) switch (trigger.type) { @@ -98,7 +112,12 @@ export const triggerEventService = { } }, - async list({ projectId, flow, cursor, limit }: ListParams): Promise> { + async list({ + projectId, + flow, + cursor, + limit, + }: ListParams): Promise> { const decodedCursor = paginationHelper.decodeCursor(cursor) const sourceName = getSourceName(flow.version.trigger) const flowId = flow.id @@ -121,7 +140,15 @@ export const triggerEventService = { }, } -async function deleteOldFilesForTestData({ projectId, flowId, stepName }: { projectId: string, flowId: string, stepName: string }): Promise { +async function deleteOldFilesForTestData({ + projectId, + flowId, + stepName, +}: { + projectId: string + flowId: string + stepName: string +}): Promise { await stepFileService.deleteAll({ projectId, flowId, @@ -133,7 +160,9 @@ function getSourceName(trigger: Trigger): string { case TriggerType.PIECE: { const pieceTrigger = trigger as PieceTrigger const pieceName = pieceTrigger.settings.pieceName - const pieceVersion = getPieceMajorAndMinorVersion(pieceTrigger.settings.pieceVersion) + const pieceVersion = getPieceMajorAndMinorVersion( + pieceTrigger.settings.pieceVersion, + ) const triggerName = pieceTrigger.settings.triggerName return `${pieceName}@${pieceVersion}:${triggerName}` } diff --git a/packages/backend/src/app/flows/trigger/hooks/disable-trigger-hook.ts b/packages/server/api/src/app/flows/trigger/hooks/disable-trigger-hook.ts similarity index 74% rename from packages/backend/src/app/flows/trigger/hooks/disable-trigger-hook.ts rename to packages/server/api/src/app/flows/trigger/hooks/disable-trigger-hook.ts index 3abdc92d32..9c2b7039cb 100644 --- a/packages/backend/src/app/flows/trigger/hooks/disable-trigger-hook.ts +++ b/packages/server/api/src/app/flows/trigger/hooks/disable-trigger-hook.ts @@ -1,13 +1,29 @@ -import { FlowVersion, PieceTrigger, ProjectId, TriggerHookType, TriggerType } from '@activepieces/shared' -import { EngineHelperResponse, EngineHelperTriggerResult, engineHelper } from '../../../helper/engine-helper' +import { + FlowVersion, + PieceTrigger, + ProjectId, + TriggerHookType, + TriggerType, +} from '@activepieces/shared' +import { + EngineHelperResponse, + EngineHelperTriggerResult, + engineHelper, +} from '../../../helper/engine-helper' import { getPieceTrigger } from './trigger-utils' import { webhookService } from '../../../webhooks/webhook-service' -import { TriggerBase, TriggerStrategy, WebhookRenewStrategy } from '@activepieces/pieces-framework' +import { + TriggerBase, + TriggerStrategy, + WebhookRenewStrategy, +} from '@activepieces/pieces-framework' import { appEventRoutingService } from '../../../app-event-routing/app-event-routing.service' import { flowQueue } from '../../../workers/flow-worker/flow-queue' -import { captureException } from '@sentry/node' +import { exceptionHandler } from 'server-shared' -export const disablePieceTrigger = async (params: DisableParams): Promise > | null> => { const { flowVersion, projectId, simulate } = params @@ -32,7 +48,7 @@ EngineHelperTriggerResult }) } catch (error) { - captureException(error) + exceptionHandler.handle(error) if (!params.ignoreError) { throw error } @@ -41,10 +57,13 @@ EngineHelperTriggerResult finally { await sideeffect(pieceTrigger, projectId, flowVersion) } - } -async function sideeffect(pieceTrigger: TriggerBase, projectId: string, flowVersion: FlowVersion): Promise { +async function sideeffect( + pieceTrigger: TriggerBase, + projectId: string, + flowVersion: FlowVersion, +): Promise { switch (pieceTrigger.type) { case TriggerStrategy.APP_WEBHOOK: await appEventRoutingService.deleteListeners({ @@ -73,4 +92,4 @@ type DisableParams = { flowVersion: FlowVersion simulate: boolean ignoreError?: boolean -} \ No newline at end of file +} diff --git a/packages/backend/src/app/flows/trigger/hooks/enable-trigger-hook.ts b/packages/server/api/src/app/flows/trigger/hooks/enable-trigger-hook.ts similarity index 82% rename from packages/backend/src/app/flows/trigger/hooks/enable-trigger-hook.ts rename to packages/server/api/src/app/flows/trigger/hooks/enable-trigger-hook.ts index d467791c27..d4f898e328 100644 --- a/packages/backend/src/app/flows/trigger/hooks/enable-trigger-hook.ts +++ b/packages/server/api/src/app/flows/trigger/hooks/enable-trigger-hook.ts @@ -1,18 +1,39 @@ -import { ApEdition, EngineResponseStatus, FlowVersion, PieceTrigger, ProjectId, RunEnvironment, TriggerHookType, TriggerType, isNil } from '@activepieces/shared' -import { system } from '../../../helper/system/system' -import { SystemProp } from '../../../helper/system/system-prop' +import { + ApEdition, + EngineResponseStatus, + FlowVersion, + PieceTrigger, + ProjectId, + RunEnvironment, + TriggerHookType, + TriggerType, + isNil, +} from '@activepieces/shared' +import { SystemProp, system } from 'server-shared' import { getEdition } from '../../../helper/secret-helper' -import { LATEST_JOB_DATA_SCHEMA_VERSION, RepeatableJobType } from '../../../workers/flow-worker/job-data' +import { + LATEST_JOB_DATA_SCHEMA_VERSION, + RepeatableJobType, +} from '../../../workers/flow-worker/job-data' import { JobType } from '../../../workers/flow-worker/queues/queue' import { flowQueue } from '../../../workers/flow-worker/flow-queue' import { plansService } from '../../../ee/billing/project-plan/project-plan.service' -import { TriggerStrategy, WebhookRenewStrategy } from '@activepieces/pieces-framework' +import { + TriggerStrategy, + WebhookRenewStrategy, +} from '@activepieces/pieces-framework' import { appEventRoutingService } from '../../../app-event-routing/app-event-routing.service' -import { EngineHelperResponse, EngineHelperTriggerResult, engineHelper } from '../../../helper/engine-helper' +import { + EngineHelperResponse, + EngineHelperTriggerResult, + engineHelper, +} from '../../../helper/engine-helper' import { webhookService } from '../../../webhooks/webhook-service' import { getPieceTrigger } from './trigger-utils' -const POLLING_FREQUENCY_CRON_EXPRESSON = constructEveryXMinuteCron(system.getNumber(SystemProp.TRIGGER_DEFAULT_POLL_INTERVAL) ?? 5) +const POLLING_FREQUENCY_CRON_EXPRESSON = constructEveryXMinuteCron( + system.getNumber(SystemProp.TRIGGER_DEFAULT_POLL_INTERVAL) ?? 5, +) function constructEveryXMinuteCron(minute: number): string { const edition = getEdition() @@ -21,13 +42,15 @@ function constructEveryXMinuteCron(minute: number): string { return `*/${minute} * * * *` case ApEdition.COMMUNITY: case ApEdition.ENTERPRISE: - return `*/${system.getNumber( - SystemProp.TRIGGER_DEFAULT_POLL_INTERVAL, - ) ?? 5} * * * *` + return `*/${ + system.getNumber(SystemProp.TRIGGER_DEFAULT_POLL_INTERVAL) ?? 5 + } * * * *` } } -export const enablePieceTrigger = async (params: EnableParams): Promise > | null> => { const { flowVersion, projectId, simulate } = params @@ -108,7 +131,8 @@ EngineHelperTriggerResult const plan = await plansService.getOrCreateDefaultPlan({ projectId, }) - engineHelperResponse.result.scheduleOptions.cronExpression = constructEveryXMinuteCron(plan.minimumPollingInterval) + engineHelperResponse.result.scheduleOptions.cronExpression = + constructEveryXMinuteCron(plan.minimumPollingInterval) } // END EE } @@ -137,4 +161,4 @@ type EnableParams = { projectId: ProjectId flowVersion: FlowVersion simulate: boolean -} \ No newline at end of file +} diff --git a/packages/backend/src/app/flows/trigger/hooks/execute-trigger-hooks.ts b/packages/server/api/src/app/flows/trigger/hooks/execute-trigger-hooks.ts similarity index 83% rename from packages/backend/src/app/flows/trigger/hooks/execute-trigger-hooks.ts rename to packages/server/api/src/app/flows/trigger/hooks/execute-trigger-hooks.ts index c0e797489d..0d4f5b4990 100644 --- a/packages/backend/src/app/flows/trigger/hooks/execute-trigger-hooks.ts +++ b/packages/server/api/src/app/flows/trigger/hooks/execute-trigger-hooks.ts @@ -1,10 +1,18 @@ -import { FlowVersion, ProjectId, TriggerHookType, TriggerPayload, TriggerType } from '@activepieces/shared' +import { + FlowVersion, + ProjectId, + TriggerHookType, + TriggerPayload, + TriggerType, +} from '@activepieces/shared' import { getPieceTrigger } from './trigger-utils' -import { logger } from '../../../helper/logger' +import { logger } from 'server-shared' import { engineHelper } from '../../../helper/engine-helper' import { webhookService } from '../../../webhooks/webhook-service' -export async function executeTrigger(params: ExecuteTrigger): Promise { +export async function executeTrigger( + params: ExecuteTrigger, +): Promise { const { payload, flowVersion, projectId, simulate } = params const flowTrigger = flowVersion.trigger let payloads: unknown[] = [] @@ -31,7 +39,7 @@ export async function executeTrigger(params: ExecuteTrigger): Promise else { logger.error( `Flow ${flowTrigger.name} with ${pieceTrigger.name} trigger throws and error, returning as zero payload ` + - JSON.stringify(result), + JSON.stringify(result), ) payloads = [] } diff --git a/packages/backend/src/app/flows/trigger/hooks/handshake-trigger.hook.ts b/packages/server/api/src/app/flows/trigger/hooks/handshake-trigger.hook.ts similarity index 81% rename from packages/backend/src/app/flows/trigger/hooks/handshake-trigger.hook.ts rename to packages/server/api/src/app/flows/trigger/hooks/handshake-trigger.hook.ts index 96f79c804b..50865f54f1 100644 --- a/packages/backend/src/app/flows/trigger/hooks/handshake-trigger.hook.ts +++ b/packages/server/api/src/app/flows/trigger/hooks/handshake-trigger.hook.ts @@ -1,10 +1,22 @@ -import { FlowVersion, ProjectId, TriggerHookType, TriggerPayload, TriggerType, isNil } from '@activepieces/shared' +import { + FlowVersion, + ProjectId, + TriggerHookType, + TriggerPayload, + TriggerType, + isNil, +} from '@activepieces/shared' import { engineHelper } from '../../../helper/engine-helper' import { webhookService } from '../../../webhooks/webhook-service' -import { WebhookHandshakeStrategy, WebhookResponse } from '@activepieces/pieces-framework' +import { + WebhookHandshakeStrategy, + WebhookResponse, +} from '@activepieces/pieces-framework' import { getPieceTrigger } from './trigger-utils' -export async function tryHandshake(params: ExecuteHandshakeParams): Promise { +export async function tryHandshake( + params: ExecuteHandshakeParams, +): Promise { const { payload, flowVersion, projectId } = params const flowTrigger = flowVersion.trigger if (flowTrigger.type === TriggerType.PIECE) { @@ -21,7 +33,7 @@ export async function tryHandshake(params: ExecuteHandshakeParams): Promise { - const { flowVersion, projectId, simulate } = params + const { flowVersion, projectId, simulate } = params try { await engineHelper.executeTrigger({ hookType: TriggerHookType.RENEW, @@ -17,7 +17,10 @@ export async function renewWebhook(params: Params): Promise { }) } catch (e) { - logger.error(`Failed to renew webhook for flow ${flowVersion.flowId} in project ${projectId}`, e) + logger.error( + `Failed to renew webhook for flow ${flowVersion.flowId} in project ${projectId}`, + e, + ) } } diff --git a/packages/backend/src/app/flows/trigger/hooks/trigger-utils.ts b/packages/server/api/src/app/flows/trigger/hooks/trigger-utils.ts similarity index 90% rename from packages/backend/src/app/flows/trigger/hooks/trigger-utils.ts rename to packages/server/api/src/app/flows/trigger/hooks/trigger-utils.ts index b6146dfcc4..9862f52b60 100644 --- a/packages/backend/src/app/flows/trigger/hooks/trigger-utils.ts +++ b/packages/server/api/src/app/flows/trigger/hooks/trigger-utils.ts @@ -1,4 +1,10 @@ -import { ActivepiecesError, ErrorCode, PieceTrigger, ProjectId, isNil } from '@activepieces/shared' +import { + ActivepiecesError, + ErrorCode, + PieceTrigger, + ProjectId, + isNil, +} from '@activepieces/shared' import { pieceMetadataService } from '../../../pieces/piece-metadata-service' import { TriggerBase } from '@activepieces/pieces-framework' @@ -36,4 +42,4 @@ export async function getPieceTrigger({ }) } return pieceTrigger -} \ No newline at end of file +} diff --git a/packages/backend/src/app/flows/trigger/index.ts b/packages/server/api/src/app/flows/trigger/index.ts old mode 100755 new mode 100644 similarity index 99% rename from packages/backend/src/app/flows/trigger/index.ts rename to packages/server/api/src/app/flows/trigger/index.ts index 24d582d094..9ea589e486 --- a/packages/backend/src/app/flows/trigger/index.ts +++ b/packages/server/api/src/app/flows/trigger/index.ts @@ -11,4 +11,3 @@ export const triggerHooks = { enable: enablePieceTrigger, disable: disablePieceTrigger, } - diff --git a/packages/server/api/src/app/helper/application-events/index.ts b/packages/server/api/src/app/helper/application-events/index.ts new file mode 100644 index 0000000000..f3f4035581 --- /dev/null +++ b/packages/server/api/src/app/helper/application-events/index.ts @@ -0,0 +1,56 @@ +import { ApplicationEventName } from '@activepieces/ee-shared' +import { AppConnection, Folder, PopulatedFlow } from '@activepieces/shared' +import { FastifyRequest } from 'fastify' + +export type CreateAuditEventParam = + | { + action: + | ApplicationEventName.UPDATED_FOLDER + | ApplicationEventName.DELETED_FOLDER + | ApplicationEventName.CREATED_FOLDER + folder: Folder + userId: string + } + | { + action: + | ApplicationEventName.UPSERTED_CONNECTION + | ApplicationEventName.DELETED_CONNECTION + connection: AppConnection + userId: string + } + | { + action: + | ApplicationEventName.CREATED_FLOW + | ApplicationEventName.DELETED_FLOW + flow: PopulatedFlow + userId: string + } + | { + action: + | ApplicationEventName.SIGNED_IN + | ApplicationEventName.SIGNED_UP + | ApplicationEventName.RESET_PASSWORD + | ApplicationEventName.VERIFIED_EMAIL + userId: string + projectId: string + } + +let hooks: ApplicationEventHooks = { + async send(_request, _params) { + return + }, +} + +export const eventsHooks = { + set(newHooks: ApplicationEventHooks): void { + hooks = newHooks + }, + + get(): ApplicationEventHooks { + return hooks + }, +} + +export type ApplicationEventHooks = { + send(request: FastifyRequest, params: CreateAuditEventParam): void +} diff --git a/packages/backend/src/app/helper/crypto.ts b/packages/server/api/src/app/helper/crypto.ts similarity index 99% rename from packages/backend/src/app/helper/crypto.ts rename to packages/server/api/src/app/helper/crypto.ts index 6e4def3dd5..4a88ea09e3 100644 --- a/packages/backend/src/app/helper/crypto.ts +++ b/packages/server/api/src/app/helper/crypto.ts @@ -8,7 +8,6 @@ export const generateRandomPassword = async (): Promise => { return passwordBytes.toString('hex') } - export function hashSHA256(input: string): string { const hash = createHash('sha256') hash.update(input) diff --git a/packages/backend/src/app/helper/dayjs-helper.ts b/packages/server/api/src/app/helper/dayjs-helper.ts similarity index 71% rename from packages/backend/src/app/helper/dayjs-helper.ts rename to packages/server/api/src/app/helper/dayjs-helper.ts index c5988e11e9..8d705afca1 100644 --- a/packages/backend/src/app/helper/dayjs-helper.ts +++ b/packages/server/api/src/app/helper/dayjs-helper.ts @@ -5,10 +5,11 @@ import timezone from 'dayjs/plugin/timezone' dayjs.extend(utc) dayjs.extend(timezone) -export function apDayjs(time: undefined | number | string = undefined): dayjs.Dayjs { +export function apDayjs( + time: undefined | number | string = undefined, +): dayjs.Dayjs { if (time === undefined) { return dayjs() } return dayjs(time) } - diff --git a/packages/server/api/src/app/helper/domain-helper.ts b/packages/server/api/src/app/helper/domain-helper.ts new file mode 100644 index 0000000000..92050dd65d --- /dev/null +++ b/packages/server/api/src/app/helper/domain-helper.ts @@ -0,0 +1,47 @@ +import { getServerUrl } from './network-utils' +import { SystemProp, system } from 'server-shared' + +type DomainHelper = { + constructFrontendUrlFromRequest({ + domain, + path, + }: { + domain: string + path: string + }): Promise + constructApiUrlFromRequest({ + domain, + path, + }: { + domain: string + path: string + }): Promise +} + +let _domainHelper: DomainHelper = { + async constructApiUrlFromRequest({ + path, + }: { + domain: string + path: string + }): Promise { + return `${await getServerUrl()}${path}` + }, + async constructFrontendUrlFromRequest({ + path, + }: { + domain: string + path: string + }): Promise { + const frontendUrl = system.getOrThrow(SystemProp.FRONTEND_URL) + return `${frontendUrl}${frontendUrl.endsWith('/') ? '' : '/'}${path}` + }, +} +export const domainHelper = { + set(newHelper: DomainHelper): void { + _domainHelper = newHelper + }, + get(): DomainHelper { + return _domainHelper + }, +} diff --git a/packages/backend/src/app/helper/encryption.ts b/packages/server/api/src/app/helper/encryption.ts similarity index 82% rename from packages/backend/src/app/helper/encryption.ts rename to packages/server/api/src/app/helper/encryption.ts index 60fd3d850f..3068f0f0e9 100644 --- a/packages/backend/src/app/helper/encryption.ts +++ b/packages/server/api/src/app/helper/encryption.ts @@ -1,16 +1,22 @@ import * as crypto from 'crypto' -import { QueueMode, system } from './system/system' -import { SystemProp } from './system/system-prop' -import { ActivepiecesError, ErrorCode, assertNotNullOrUndefined, isNil } from '@activepieces/shared' -import { localFileStore } from './store' +import { + ActivepiecesError, + ErrorCode, + assertNotNullOrUndefined, + isNil, +} from '@activepieces/shared' import { promisify } from 'util' import { randomBytes } from 'node:crypto' +import { QueueMode, SystemProp, system } from 'server-shared' +import { localFileStore } from './store' + let secret: string | null const algorithm = 'aes-256-cbc' const ivLength = 16 - -export const loadEncryptionKey = async (queueMode: QueueMode): Promise => { +export const loadEncryptionKey = async ( + queueMode: QueueMode, +): Promise => { secret = system.get(SystemProp.ENCRYPTION_KEY) ?? null if (queueMode === QueueMode.MEMORY) { if (isNil(secret)) { @@ -21,12 +27,15 @@ export const loadEncryptionKey = async (queueMode: QueueMode): Promise => } } if (isNil(secret)) { - throw new ActivepiecesError({ - code: ErrorCode.SYSTEM_PROP_INVALID, - params: { - prop: SystemProp.ENCRYPTION_KEY, + throw new ActivepiecesError( + { + code: ErrorCode.SYSTEM_PROP_INVALID, + params: { + prop: SystemProp.ENCRYPTION_KEY, + }, }, - }, `System property AP_${SystemProp.ENCRYPTION_KEY} must be defined`) + `System property AP_${SystemProp.ENCRYPTION_KEY} must be defined`, + ) } } @@ -61,7 +70,6 @@ export function encryptObject(object: unknown): EncryptedObject { return encryptString(objectString) } - export function decryptObject(encryptedObject: EncryptedObject): T { const iv = Buffer.from(encryptedObject.iv, 'hex') const key = Buffer.from(secret!, 'binary') @@ -79,10 +87,9 @@ export function decryptString(encryptedObject: EncryptedObject): string { return decrypted } - export function hashObject(object: Record) { const algorithm = 'sha256' const hash = crypto.createHash(algorithm) hash.update(JSON.stringify(object)) return hash.digest('hex') -} \ No newline at end of file +} diff --git a/packages/backend/src/app/helper/engine-helper.ts b/packages/server/api/src/app/helper/engine-helper.ts similarity index 72% rename from packages/backend/src/app/helper/engine-helper.ts rename to packages/server/api/src/app/helper/engine-helper.ts index 6a25eb46d4..e1036ec61c 100644 --- a/packages/backend/src/app/helper/engine-helper.ts +++ b/packages/server/api/src/app/helper/engine-helper.ts @@ -29,18 +29,21 @@ import { FlowVersion, ExecuteFlowOperation, } from '@activepieces/shared' -import { Sandbox } from '../workers/sandbox' +import { Sandbox } from 'server-worker' import { accessTokenManager } from '../authentication/lib/access-token-manager' import { DropdownState, DynamicPropsValue, PieceMetadata, } from '@activepieces/pieces-framework' -import { logger } from '../helper/logger' +import { logger } from 'server-shared' import chalk from 'chalk' import { getEdition, getWebhookSecret } from './secret-helper' import { appEventRoutingService } from '../app-event-routing/app-event-routing.service' -import { getPiecePackage, pieceMetadataService } from '../pieces/piece-metadata-service' +import { + getPiecePackage, + pieceMetadataService, +} from '../pieces/piece-metadata-service' import { flowVersionService } from '../flows/flow-version/flow-version.service' import { sandboxProvisioner } from '../workers/sandbox/provisioner/sandbox-provisioner' import { SandBoxCacheType } from '../workers/sandbox/provisioner/sandbox-cache-key' @@ -58,8 +61,8 @@ export type EngineHelperTriggerResult< > = ExecuteTriggerResponse export type EngineHelperPropResult = - | DropdownState - | Record + | DropdownState + | Record export type EngineHelperActionResult = ExecuteActionResponse @@ -69,13 +72,13 @@ export type EngineHelperCodeResult = ExecuteActionResponse export type EngineHelperExtractPieceInformation = PieceMetadata export type EngineHelperResult = - | EngineHelperFlowResult - | EngineHelperTriggerResult - | EngineHelperPropResult - | EngineHelperCodeResult - | EngineHelperExtractPieceInformation - | EngineHelperActionResult - | EngineHelperValidateAuthResult + | EngineHelperFlowResult + | EngineHelperTriggerResult + | EngineHelperPropResult + | EngineHelperCodeResult + | EngineHelperExtractPieceInformation + | EngineHelperActionResult + | EngineHelperValidateAuthResult export type EngineHelperResponse = { status: EngineResponseStatus @@ -84,7 +87,9 @@ export type EngineHelperResponse = { standardOutput: string } -const generateWorkerToken = ({ projectId }: GenerateWorkerTokenParams): Promise => { +const generateWorkerToken = ({ + projectId, +}: GenerateWorkerTokenParams): Promise => { return accessTokenManager.generateToken({ id: apId(), type: PrincipalType.WORKER, @@ -107,11 +112,13 @@ const execute = async ( input: EngineOperation, ): Promise> => { try { - logger.debug({ operation, sandboxId: sandbox.boxId }, '[EngineHelper#execute]') + logger.debug( + { operation, sandboxId: sandbox.boxId }, + '[EngineHelper#execute]', + ) const sandboxPath = sandbox.getSandboxFolderPath() - await fs.writeFile(`${sandboxPath}/input.json`, JSON.stringify(input)) const sandboxResponse = await sandbox.runOperation(operation) @@ -151,18 +158,25 @@ const execute = async ( export const engineHelper = { async executeFlow( sandbox: Sandbox, - operation: Omit | Omit, + operation: + | Omit + | Omit, ): Promise> { - logger.debug({ - executionType: operation.executionType, - flowRunId: operation.flowRunId, - projectId: operation.projectId, - sandboxId: sandbox.boxId, - }, '[EngineHelper#executeFlow]') + logger.debug( + { + executionType: operation.executionType, + flowRunId: operation.flowRunId, + projectId: operation.projectId, + sandboxId: sandbox.boxId, + }, + '[EngineHelper#executeFlow]', + ) const input: ExecuteFlowOperation = { ...operation, - workerToken: await generateWorkerToken({ projectId: operation.projectId }), + workerToken: await generateWorkerToken({ + projectId: operation.projectId, + }), serverUrl: await getServerUrl(), } return execute(EngineOperationType.EXECUTE_FLOW, sandbox, input) @@ -171,14 +185,18 @@ export const engineHelper = { async executeTrigger( operation: Omit, EngineConstants>, ): Promise>> { - logger.debug({ hookType: operation.hookType, projectId: operation.projectId }, '[EngineHelper#executeTrigger]') + logger.debug( + { hookType: operation.hookType, projectId: operation.projectId }, + '[EngineHelper#executeTrigger]', + ) const lockedFlowVersion = await flowVersionService.lockPieceVersions({ projectId: operation.projectId, flowVersion: operation.flowVersion, }) - const triggerSettings = (lockedFlowVersion.trigger as PieceTrigger).settings + const triggerSettings = (lockedFlowVersion.trigger as PieceTrigger) + .settings const { packageType, pieceType, pieceName, pieceVersion } = triggerSettings const exactPieceVersion = await pieceMetadataService.getExactPieceVersion({ @@ -211,24 +229,25 @@ export const engineHelper = { }), serverUrl: await getServerUrl(), webhookSecret: await getWebhookSecret(operation.flowVersion), - workerToken: await generateWorkerToken({ projectId: operation.projectId }), + workerToken: await generateWorkerToken({ + projectId: operation.projectId, + }), } - return execute( - EngineOperationType.EXECUTE_TRIGGER_HOOK, - sandbox, - input, - ) + return execute(EngineOperationType.EXECUTE_TRIGGER_HOOK, sandbox, input) }, async executeProp( operation: Omit, ): Promise> { - logger.debug({ - piece: operation.piece, - projectId: operation.projectId, - stepName: operation.stepName, - }, '[EngineHelper#executeProp]') + logger.debug( + { + piece: operation.piece, + projectId: operation.projectId, + stepName: operation.stepName, + }, + '[EngineHelper#executeProp]', + ) const { piece } = operation @@ -248,14 +267,12 @@ export const engineHelper = { const input = { ...operation, serverUrl: await getServerUrl(), - workerToken: await generateWorkerToken({ projectId: operation.projectId }), + workerToken: await generateWorkerToken({ + projectId: operation.projectId, + }), } - return execute( - EngineOperationType.EXECUTE_PROPERTY, - sandbox, - input, - ) + return execute(EngineOperationType.EXECUTE_PROPERTY, sandbox, input) }, async extractPieceMetadata( operation: ExecuteExtractPieceMetadata, @@ -279,21 +296,34 @@ export const engineHelper = { ) }, - async executeAction(operation: Omit): Promise> { - logger.debug({ - flowVersionId: operation.flowVersion.id, - stepName: operation.stepName, - }, '[EngineHelper#executeAction]') + async executeAction( + operation: Omit, + ): Promise> { + logger.debug( + { + flowVersionId: operation.flowVersion.id, + stepName: operation.stepName, + }, + '[EngineHelper#executeAction]', + ) const lockedFlowVersion = await lockPieceAction(operation) - const step = flowHelper.getStep(lockedFlowVersion, operation.stepName) as Action | undefined + const step = flowHelper.getStep(lockedFlowVersion, operation.stepName) as + | Action + | undefined assertNotNullOrUndefined(step, 'Step not found') - const sandbox = await getSandboxForAction(operation.projectId, operation.flowVersion.flowId, step) + const sandbox = await getSandboxForAction( + operation.projectId, + operation.flowVersion.flowId, + step, + ) const input: ExecuteStepOperation = { flowVersion: lockedFlowVersion, stepName: operation.stepName, projectId: operation.projectId, serverUrl: await getServerUrl(), - workerToken: await generateWorkerToken({ projectId: operation.projectId }), + workerToken: await generateWorkerToken({ + projectId: operation.projectId, + }), } return execute(EngineOperationType.EXECUTE_STEP, sandbox, input) @@ -302,7 +332,10 @@ export const engineHelper = { async executeValidateAuth( operation: Omit, ): Promise> { - logger.debug({ piece: operation.piece }, '[EngineHelper#executeValidateAuth]') + logger.debug( + { piece: operation.piece }, + '[EngineHelper#executeValidateAuth]', + ) const { piece } = operation @@ -322,33 +355,47 @@ export const engineHelper = { const input = { ...operation, serverUrl: await getServerUrl(), - workerToken: await generateWorkerToken({ projectId: operation.projectId }), + workerToken: await generateWorkerToken({ + projectId: operation.projectId, + }), } - return execute( - EngineOperationType.EXECUTE_VALIDATE_AUTH, - sandbox, - input, - ) + return execute(EngineOperationType.EXECUTE_VALIDATE_AUTH, sandbox, input) }, - async executeTest(sandbox: Sandbox, operation: Omit): Promise> { - logger.debug({ - flowVersionId: operation.sourceFlowVersion.id, - projectId: operation.projectId, - sandboxId: sandbox.boxId, - executionType: operation.executionType, - }, '[EngineHelper#executeTest]') + async executeTest( + sandbox: Sandbox, + operation: Omit, + ): Promise> { + logger.debug( + { + flowVersionId: operation.sourceFlowVersion.id, + projectId: operation.projectId, + sandboxId: sandbox.boxId, + executionType: operation.executionType, + }, + '[EngineHelper#executeTest]', + ) return execute(EngineOperationType.EXECUTE_TEST_FLOW, sandbox, { ...operation, serverUrl: await getServerUrl(), - workerToken: await generateWorkerToken({ projectId: operation.projectId }), + workerToken: await generateWorkerToken({ + projectId: operation.projectId, + }), }) }, } -async function lockPieceAction({ projectId, flowVersion, stepName }: { projectId: string, flowVersion: FlowVersion, stepName: string }): Promise { +async function lockPieceAction({ + projectId, + flowVersion, + stepName, +}: { + projectId: string + flowVersion: FlowVersion + stepName: string +}): Promise { return flowHelper.transferFlowAsync(flowVersion, async (step) => { if (step.name === stepName && step.type === ActionType.PIECE) { return { @@ -367,10 +414,15 @@ async function lockPieceAction({ projectId, flowVersion, stepName }: { projectId }) } -async function getSandboxForAction(projectId: string, flowId: string, action: Action): Promise { +async function getSandboxForAction( + projectId: string, + flowId: string, + action: Action, +): Promise { switch (action.type) { - case ActionType.PIECE:{ - const { packageType, pieceType, pieceName, pieceVersion } = action.settings + case ActionType.PIECE: { + const { packageType, pieceType, pieceName, pieceVersion } = + action.settings const piece = { packageType, pieceType, diff --git a/packages/backend/src/app/helper/error-handler.ts b/packages/server/api/src/app/helper/error-handler.ts similarity index 58% rename from packages/backend/src/app/helper/error-handler.ts rename to packages/server/api/src/app/helper/error-handler.ts index db59c84826..49ef72ca86 100644 --- a/packages/backend/src/app/helper/error-handler.ts +++ b/packages/server/api/src/app/helper/error-handler.ts @@ -1,13 +1,9 @@ import { FastifyError, FastifyReply, FastifyRequest } from 'fastify' import { StatusCodes } from 'http-status-codes' import { ActivepiecesError, ErrorCode } from '@activepieces/shared' -import { captureException, logger } from './logger' -import { system } from './system/system' -import { SystemProp } from './system/system-prop' +import { exceptionHandler, logger } from 'server-shared' -const ENRICH_ERROR_CONTEXT = system.getBoolean(SystemProp.ENRICH_ERROR_CONTEXT) ?? false - export const errorHandler = async ( error: FastifyError, _request: FastifyRequest, @@ -35,7 +31,8 @@ export const errorHandler = async ( [ErrorCode.AUTHENTICATION]: StatusCodes.UNAUTHORIZED, } - const statusCode = statusCodeMap[error.error.code] ?? StatusCodes.BAD_REQUEST + const statusCode = + statusCodeMap[error.error.code] ?? StatusCodes.BAD_REQUEST await reply.status(statusCode).send({ code: error.error.code, @@ -44,43 +41,14 @@ export const errorHandler = async ( } else { logger.error('[errorHandler]: ' + JSON.stringify(error)) - if (!error.statusCode || error.statusCode === StatusCodes.INTERNAL_SERVER_ERROR.valueOf()) { - captureException(error) + if ( + !error.statusCode || + error.statusCode === StatusCodes.INTERNAL_SERVER_ERROR.valueOf() + ) { + exceptionHandler.handle(error) } - await reply.status(error.statusCode ?? StatusCodes.INTERNAL_SERVER_ERROR).send(error) - } -} - -export const enrichErrorContext = ({ error, key, value }: EnrichErrorContextParams): unknown => { - if (!ENRICH_ERROR_CONTEXT) { - return error + await reply + .status(error.statusCode ?? StatusCodes.INTERNAL_SERVER_ERROR) + .send(error) } - - if (error instanceof Error) { - if ('context' in error && error.context instanceof Object) { - const enrichedError = Object.assign(error, { - ...error.context, - [key]: value, - }) - - return enrichedError - } - else { - const enrichedError = Object.assign(error, { - context: { - [key]: value, - }, - }) - - return enrichedError - } - } - - return error -} - -type EnrichErrorContextParams = { - error: unknown - key: string - value: unknown } diff --git a/packages/backend/src/app/helper/jwt-utils.ts b/packages/server/api/src/app/helper/jwt-utils.ts similarity index 82% rename from packages/backend/src/app/helper/jwt-utils.ts rename to packages/server/api/src/app/helper/jwt-utils.ts index 3ef713925f..6bfd836bd7 100644 --- a/packages/backend/src/app/helper/jwt-utils.ts +++ b/packages/server/api/src/app/helper/jwt-utils.ts @@ -1,9 +1,17 @@ -import { ActivepiecesError, ErrorCode, isNil, spreadIfDefined } from '@activepieces/shared' -import jwtLibrary, { DecodeOptions, SignOptions, VerifyOptions } from 'jsonwebtoken' +import { + ActivepiecesError, + ErrorCode, + isNil, + spreadIfDefined, +} from '@activepieces/shared' +import jwtLibrary, { + DecodeOptions, + SignOptions, + VerifyOptions, +} from 'jsonwebtoken' import { localFileStore } from './store' -import { SystemProp } from './system/system-prop' +import { QueueMode, SystemProp, system } from 'server-shared' import { promisify } from 'util' -import { QueueMode, system } from './system/system' import { randomBytes } from 'crypto' export enum JwtSignAlgorithm { @@ -16,7 +24,6 @@ const KEY_ID = '1' const ISSUER = 'activepieces' const ALGORITHM = JwtSignAlgorithm.HS256 - let secret: string | null = null const queueMode = system.getOrThrow(SystemProp.QUEUE_MODE) @@ -35,12 +42,15 @@ const getSecret = async (): Promise => { } } if (isNil(secret)) { - throw new ActivepiecesError({ - code: ErrorCode.SYSTEM_PROP_INVALID, - params: { - prop: SystemProp.JWT_SECRET, + throw new ActivepiecesError( + { + code: ErrorCode.SYSTEM_PROP_INVALID, + params: { + prop: SystemProp.JWT_SECRET, + }, }, - }, `System property AP_${SystemProp.JWT_SECRET} must be defined`) + `System property AP_${SystemProp.JWT_SECRET} must be defined`, + ) } return secret } @@ -65,7 +75,6 @@ export const jwtUtils = { keyId = KEY_ID, algorithm = ALGORITHM, }: SignParams): Promise { - const signOptions: SignOptions = { algorithm, keyid: keyId, @@ -93,7 +102,13 @@ export const jwtUtils = { }) }, getJwtSecret: getSecret, - async decodeAndVerify({ jwt, key, algorithm = ALGORITHM, issuer = ISSUER, audience }: VerifyParams): Promise { + async decodeAndVerify({ + jwt, + key, + algorithm = ALGORITHM, + issuer = ISSUER, + audience, + }: VerifyParams): Promise { const verifyOptions: VerifyOptions = { algorithms: [algorithm], ...spreadIfDefined('issuer', issuer), diff --git a/packages/backend/src/app/helper/lock.ts b/packages/server/api/src/app/helper/lock.ts similarity index 68% rename from packages/backend/src/app/helper/lock.ts rename to packages/server/api/src/app/helper/lock.ts index 1153d9d91e..ce70cc2153 100644 --- a/packages/backend/src/app/helper/lock.ts +++ b/packages/server/api/src/app/helper/lock.ts @@ -1,10 +1,8 @@ -import { captureException } from '../helper/logger' import RedLock from 'redlock' import { Redis } from 'ioredis' import { createRedisClient } from '../database/redis-connection' import { Mutex } from 'async-mutex' -import { QueueMode, system } from './system/system' -import { SystemProp } from './system/system-prop' +import { QueueMode, SystemProp, exceptionHandler, system } from 'server-shared' let redLock: RedLock let redisConnection: Redis @@ -28,27 +26,23 @@ class MutexLockWrapper { const initializeLock = () => { switch (queueMode) { - case QueueMode.REDIS:{ + case QueueMode.REDIS: { redisConnection = createRedisClient() - redLock = new RedLock( - [redisConnection], - { - driftFactor: 0.01, - retryCount: 30, - retryDelay: 2000, - retryJitter: 200, - automaticExtensionThreshold: 500, - }, - ) + redLock = new RedLock([redisConnection], { + driftFactor: 0.01, + retryCount: 30, + retryDelay: 2000, + retryJitter: 200, + automaticExtensionThreshold: 500, + }) break } - case QueueMode.MEMORY:{ + case QueueMode.MEMORY: { break } } } - const acquireMemoryLock = async (key: string): Promise => { let lock = memoryLocks.get(key) if (!lock) { @@ -59,8 +53,10 @@ const acquireMemoryLock = async (key: string): Promise => { return lock } - -const acquireRedisLock = async (key: string, timeout: number): Promise => { +const acquireRedisLock = async ( + key: string, + timeout: number, +): Promise => { try { return await redLock.acquire([key], timeout, { retryCount: Math.ceil(timeout / 2000) * 2, @@ -68,7 +64,7 @@ const acquireRedisLock = async (key: string, timeout: number): Promise = }) } catch (e) { - captureException(e) + exceptionHandler.handle(e) throw e } } @@ -82,7 +78,10 @@ export type ApLock = { release(): Promise } -export const acquireLock = async ({ key, timeout = 3000 }: AcquireLockParams): Promise => { +export const acquireLock = async ({ + key, + timeout = 3000, +}: AcquireLockParams): Promise => { switch (queueMode) { case QueueMode.REDIS: return acquireRedisLock(key, timeout) diff --git a/packages/backend/src/app/helper/network-utils.ts b/packages/server/api/src/app/helper/network-utils.ts similarity index 81% rename from packages/backend/src/app/helper/network-utils.ts rename to packages/server/api/src/app/helper/network-utils.ts index 88b50fb572..05f7805f65 100644 --- a/packages/backend/src/app/helper/network-utils.ts +++ b/packages/server/api/src/app/helper/network-utils.ts @@ -1,12 +1,13 @@ import dns from 'node:dns/promises' -import { system } from './system/system' -import { SystemProp } from './system/system-prop' +import { SystemProp, system } from 'server-shared' import { ApEnvironment } from '@activepieces/shared' import { FastifyRequest } from 'fastify' const GOOGLE_DNS = '216.239.32.10' const PUBLIC_IP_ADDRESS_QUERY = 'o-o.myaddr.l.google.com' -const CLIENT_REAL_IP_HEADER = system.getOrThrow(SystemProp.CLIENT_REAL_IP_HEADER) +const CLIENT_REAL_IP_HEADER = system.getOrThrow( + SystemProp.CLIENT_REAL_IP_HEADER, +) let ipMetadata: IpMetadata | undefined @@ -30,22 +31,23 @@ type IpMetadata = { ip: string } - - export const extractClientRealIp = (request: FastifyRequest): string => { return request.headers[CLIENT_REAL_IP_HEADER] as string } - export const getServerUrl = async (): Promise => { const environment = system.get(SystemProp.ENVIRONMENT) - let url = environment === ApEnvironment.PRODUCTION + let url = + environment === ApEnvironment.PRODUCTION ? system.get(SystemProp.FRONTEND_URL)! : system.get(SystemProp.WEBHOOK_URL)! // Localhost doesn't work with webhooks, so we need try to use the public ip - if (extractHostname(url) == 'localhost' && environment === ApEnvironment.PRODUCTION) { + if ( + extractHostname(url) == 'localhost' && + environment === ApEnvironment.PRODUCTION + ) { url = `http://${(await getPublicIp()).ip}` } @@ -55,7 +57,6 @@ export const getServerUrl = async (): Promise => { return `${url}${slash}${redirect}` } - function extractHostname(url: string): string | null { try { const hostname = new URL(url).hostname diff --git a/packages/backend/src/app/helper/notifications.ts b/packages/server/api/src/app/helper/notifications.ts similarity index 72% rename from packages/backend/src/app/helper/notifications.ts rename to packages/server/api/src/app/helper/notifications.ts index 1a79531323..ec800df58d 100644 --- a/packages/backend/src/app/helper/notifications.ts +++ b/packages/server/api/src/app/helper/notifications.ts @@ -1,7 +1,11 @@ -import { ExecutionOutputStatus, FlowRun, NotificationStatus, RunEnvironment, UserMeta } from '@activepieces/shared' -import { captureException, logger } from './logger' -import { system } from './system/system' -import { SystemProp } from './system/system-prop' +import { + ExecutionOutputStatus, + FlowRun, + NotificationStatus, + RunEnvironment, + UserMeta, +} from '@activepieces/shared' +import { SystemProp, exceptionHandler, logger, system } from 'server-shared' import axios from 'axios' import { projectService } from '../project/project-service' import { userService } from '../user/user-service' @@ -13,7 +17,12 @@ export const notifications = { if (flowRun.environment === RunEnvironment.TESTING) { return } - if (![ExecutionOutputStatus.FAILED, ExecutionOutputStatus.INTERNAL_ERROR].includes(flowRun.status)) { + if ( + ![ + ExecutionOutputStatus.FAILED, + ExecutionOutputStatus.INTERNAL_ERROR, + ].includes(flowRun.status) + ) { return } if (!notificationUrl) { @@ -57,9 +66,11 @@ async function sendWebhook(payload: RunFailedWebhookPayload): Promise { 'Content-Type': 'application/json', }, }) - logger.info(`Webhook sent to ${notificationUrl} with status code ${response.status}`) + logger.info( + `Webhook sent to ${notificationUrl} with status code ${response.status}`, + ) } catch (error) { - captureException(error) + exceptionHandler.handle(error) } } diff --git a/packages/server/api/src/app/helper/openapi/openapi.controller.ts b/packages/server/api/src/app/helper/openapi/openapi.controller.ts new file mode 100644 index 0000000000..0fa8414793 --- /dev/null +++ b/packages/server/api/src/app/helper/openapi/openapi.controller.ts @@ -0,0 +1,7 @@ +import { FastifyInstance } from 'fastify' + +export const openapiController = async (fastify: FastifyInstance) => { + fastify.get('/', async () => { + return JSON.stringify(fastify.swagger(), null, 2) + }) +} diff --git a/packages/backend/src/app/helper/openapi/openapi.module.ts b/packages/server/api/src/app/helper/openapi/openapi.module.ts similarity index 100% rename from packages/backend/src/app/helper/openapi/openapi.module.ts rename to packages/server/api/src/app/helper/openapi/openapi.module.ts diff --git a/packages/backend/src/app/helper/pagination/build-paginator.ts b/packages/server/api/src/app/helper/pagination/build-paginator.ts old mode 100755 new mode 100644 similarity index 76% rename from packages/backend/src/app/helper/pagination/build-paginator.ts rename to packages/server/api/src/app/helper/pagination/build-paginator.ts index 988dbed4fa..c28d4f22aa --- a/packages/backend/src/app/helper/pagination/build-paginator.ts +++ b/packages/server/api/src/app/helper/pagination/build-paginator.ts @@ -14,8 +14,14 @@ export type PaginationOptions = { query?: PagingQuery } -export function buildPaginator(options: PaginationOptions): Paginator { - const { entity, query = {}, alias = entity.options.name.toLowerCase() } = options +export function buildPaginator( + options: PaginationOptions, +): Paginator { + const { + entity, + query = {}, + alias = entity.options.name.toLowerCase(), + } = options const paginator = new Paginator(entity) diff --git a/packages/backend/src/app/helper/pagination/pagination-utils.ts b/packages/server/api/src/app/helper/pagination/pagination-utils.ts old mode 100755 new mode 100644 similarity index 85% rename from packages/backend/src/app/helper/pagination/pagination-utils.ts rename to packages/server/api/src/app/helper/pagination/pagination-utils.ts index eb93121a68..41778911b1 --- a/packages/backend/src/app/helper/pagination/pagination-utils.ts +++ b/packages/server/api/src/app/helper/pagination/pagination-utils.ts @@ -17,7 +17,9 @@ export function encodeByType(type: string, value: unknown): string | null { case 'timestamp with time zone': case 'datetime': case 'date': { - return dayjs(value as string).valueOf().toString() + return dayjs(value as string) + .valueOf() + .toString() } case 'number': { return `${value}` @@ -26,7 +28,7 @@ export function encodeByType(type: string, value: unknown): string | null { return encodeURIComponent(value as string) } case 'object': { - /** + /** * if reflection type is Object, check whether an object is a date. * see: https://github.com/rbuckton/reflect-metadata/issues/84 */ @@ -43,7 +45,10 @@ export function encodeByType(type: string, value: unknown): string | null { throw new Error(`unknown type in cursor: [${type}]${value}`) } -export function decodeByType(type: string, value: string): string | number | Date { +export function decodeByType( + type: string, + value: string, +): string | number | Date { switch (type) { case 'object': case 'timestamp with time zone': @@ -76,8 +81,10 @@ export function decodeByType(type: string, value: string): string | number | Dat } } -const decode = (str: string): string => Buffer.from(str, 'base64').toString('binary') -const encode = (str: string): string => Buffer.from(str, 'binary').toString('base64') +const decode = (str: string): string => + Buffer.from(str, 'base64').toString('binary') +const encode = (str: string): string => + Buffer.from(str, 'binary').toString('base64') function encodeNextCursor(cursor: string | null | undefined) { if (cursor === null) { @@ -101,7 +108,10 @@ export const paginationHelper = { data, } }, - decodeCursor(encodedCursor: string | null): { nextCursor: string | undefined, previousCursor: string | undefined } { + decodeCursor(encodedCursor: string | null): { + nextCursor: string | undefined + previousCursor: string | undefined + } { if (encodedCursor === null || encodedCursor === undefined) { return { nextCursor: undefined, diff --git a/packages/backend/src/app/helper/pagination/paginator.ts b/packages/server/api/src/app/helper/pagination/paginator.ts old mode 100755 new mode 100644 similarity index 90% rename from packages/backend/src/app/helper/pagination/paginator.ts rename to packages/server/api/src/app/helper/pagination/paginator.ts index 5e46741c8c..f127d84f9f --- a/packages/backend/src/app/helper/pagination/paginator.ts +++ b/packages/server/api/src/app/helper/pagination/paginator.ts @@ -7,8 +7,7 @@ import { WhereExpressionBuilder, } from 'typeorm' import { atob, btoa, decodeByType, encodeByType } from './pagination-utils' -import { DatabaseType, system } from '../system/system' -import { SystemProp } from '../system/system-prop' +import { DatabaseType, SystemProp, system } from 'server-shared' export enum Order { ASC = 'ASC', @@ -44,9 +43,7 @@ export default class Paginator { private order: Order = Order.DESC - public constructor( - private readonly entity: EntitySchema, - ) { } + public constructor(private readonly entity: EntitySchema) {} public setAlias(alias: string): void { this.alias = alias @@ -68,7 +65,9 @@ export default class Paginator { this.order = order } - public async paginate(builder: SelectQueryBuilder): Promise> { + public async paginate( + builder: SelectQueryBuilder, + ): Promise> { const entities = await this.appendPagingQuery(builder).getMany() const hasMore = entities.length > this.limit @@ -102,7 +101,9 @@ export default class Paginator { } } - private appendPagingQuery(builder: SelectQueryBuilder): SelectQueryBuilder { + private appendPagingQuery( + builder: SelectQueryBuilder, + ): SelectQueryBuilder { const cursors: CursorParam = {} const clonedBuilder = new SelectQueryBuilder(builder) @@ -114,7 +115,9 @@ export default class Paginator { } if (Object.keys(cursors).length > 0) { - clonedBuilder.andWhere(new Brackets((where) => this.buildCursorQuery(where, cursors))) + clonedBuilder.andWhere( + new Brackets((where) => this.buildCursorQuery(where, cursors)), + ) } clonedBuilder.take(this.limit + 1) @@ -123,7 +126,10 @@ export default class Paginator { return clonedBuilder } - private buildCursorQuery(where: WhereExpressionBuilder, cursors: CursorParam): void { + private buildCursorQuery( + where: WhereExpressionBuilder, + cursors: CursorParam, + ): void { const dbType = system.get(SystemProp.DB_TYPE) const operator = this.getOperator() let queryString: string @@ -137,7 +143,7 @@ export default class Paginator { else { throw new Error('Unsupported database type') } - + where.orWhere(queryString, cursors) } diff --git a/packages/backend/src/app/helper/pubsub/index.ts b/packages/server/api/src/app/helper/pubsub/index.ts similarity index 50% rename from packages/backend/src/app/helper/pubsub/index.ts rename to packages/server/api/src/app/helper/pubsub/index.ts index 66c4e65b36..7474c89e40 100644 --- a/packages/backend/src/app/helper/pubsub/index.ts +++ b/packages/server/api/src/app/helper/pubsub/index.ts @@ -1,9 +1,11 @@ import { createRedisClient } from '../../database/redis-connection' -import { QueueMode, system } from '../system/system' -import { SystemProp } from '../system/system-prop' +import { QueueMode, SystemProp, system } from 'server-shared' import { memoryPubSub } from './memory-pubsub' import { redisPubSub } from './redis-pubsub' const queueMode = system.getOrThrow(SystemProp.QUEUE_MODE) -export const pubSub = queueMode === QueueMode.MEMORY ? memoryPubSub : redisPubSub(createRedisClient(), createRedisClient()) \ No newline at end of file +export const pubSub = + queueMode === QueueMode.MEMORY + ? memoryPubSub + : redisPubSub(createRedisClient(), createRedisClient()) diff --git a/packages/backend/src/app/helper/pubsub/memory-pubsub.ts b/packages/server/api/src/app/helper/pubsub/memory-pubsub.ts similarity index 60% rename from packages/backend/src/app/helper/pubsub/memory-pubsub.ts rename to packages/server/api/src/app/helper/pubsub/memory-pubsub.ts index 459daebb06..2a5c024c5c 100644 --- a/packages/backend/src/app/helper/pubsub/memory-pubsub.ts +++ b/packages/server/api/src/app/helper/pubsub/memory-pubsub.ts @@ -1,8 +1,13 @@ -const subscriptions = new Map void)[]>() +const subscriptions = new Map< +string, +((channel: string, message: string) => void)[] +>() export const memoryPubSub = { - - async subscribe(channel: string, listener: (channel: string, message: string) => void): Promise { + async subscribe( + channel: string, + listener: (channel: string, message: string) => void, + ): Promise { if (!subscriptions.has(channel)) { subscriptions.set(channel, []) } @@ -12,10 +17,10 @@ export const memoryPubSub = { async publish(channel: string, message: string): Promise { const listeners = subscriptions.get(channel) if (listeners) { - listeners.forEach(listener => listener(channel, message)) + listeners.forEach((listener) => listener(channel, message)) } }, async unsubscribe(channel: string): Promise { subscriptions.delete(channel) }, -} \ No newline at end of file +} diff --git a/packages/backend/src/app/helper/pubsub/redis-pubsub.ts b/packages/server/api/src/app/helper/pubsub/redis-pubsub.ts similarity index 64% rename from packages/backend/src/app/helper/pubsub/redis-pubsub.ts rename to packages/server/api/src/app/helper/pubsub/redis-pubsub.ts index f696db7583..2577fb8b4a 100644 --- a/packages/backend/src/app/helper/pubsub/redis-pubsub.ts +++ b/packages/server/api/src/app/helper/pubsub/redis-pubsub.ts @@ -1,8 +1,14 @@ import { Redis } from 'ioredis' -export const redisPubSub = (redisClientSubscriber: Redis, redisClientPublisher: Redis) => { +export const redisPubSub = ( + redisClientSubscriber: Redis, + redisClientPublisher: Redis, +) => { return { - async subscribe(channel: string, listener: (channel: string, message: string) => void): Promise { + async subscribe( + channel: string, + listener: (channel: string, message: string) => void, + ): Promise { await redisClientSubscriber.subscribe(channel) redisClientSubscriber.on('message', listener) }, @@ -13,4 +19,4 @@ export const redisPubSub = (redisClientSubscriber: Redis, redisClientPublisher: await redisClientSubscriber.unsubscribe(channel) }, } -} \ No newline at end of file +} diff --git a/packages/backend/src/app/helper/secret-helper.ts b/packages/server/api/src/app/helper/secret-helper.ts similarity index 82% rename from packages/backend/src/app/helper/secret-helper.ts rename to packages/server/api/src/app/helper/secret-helper.ts index 2f861ecc8f..20fb033200 100644 --- a/packages/backend/src/app/helper/secret-helper.ts +++ b/packages/server/api/src/app/helper/secret-helper.ts @@ -1,8 +1,8 @@ import { ApEdition, FlowVersion, isNil } from '@activepieces/shared' -import { system } from './system/system' -import { SystemProp } from './system/system-prop' +import { SystemProp, system } from 'server-shared' -let webhookSecrets: Record | undefined = undefined +let webhookSecrets: Record | undefined = + undefined export function getEdition(): ApEdition { const edition = system.get(SystemProp.EDITION) @@ -22,7 +22,7 @@ export async function getWebhookSecret( return undefined } if (webhookSecrets === undefined) { - webhookSecrets = getWebhookSecrets() + webhookSecrets = getWebhookSecrets() } const appConfig = webhookSecrets[appName] if (isNil(appConfig)) { @@ -31,14 +31,16 @@ export async function getWebhookSecret( return appConfig.webhookSecret } - export function getSupportedAppWebhooks(): string[] { return Object.keys(getWebhookSecrets()) } -export function getWebhookSecrets(): Record { +} +> { const appSecret = system.get(SystemProp.APP_WEBHOOK_SECRETS) if (isNil(appSecret)) { return {} diff --git a/packages/backend/src/app/helper/store.ts b/packages/server/api/src/app/helper/store.ts similarity index 91% rename from packages/backend/src/app/helper/store.ts rename to packages/server/api/src/app/helper/store.ts index 9a6194c0e6..25042ff07a 100644 --- a/packages/backend/src/app/helper/store.ts +++ b/packages/server/api/src/app/helper/store.ts @@ -1,7 +1,6 @@ import fs from 'fs' import path from 'path' -import { system } from './system/system' -import { SystemProp } from './system/system-prop' +import { SystemProp, system } from 'server-shared' export const localFileStore = { async save(key: string, value: string): Promise { diff --git a/packages/backend/src/app/helper/telemetry.utils.ts b/packages/server/api/src/app/helper/telemetry.utils.ts similarity index 78% rename from packages/backend/src/app/helper/telemetry.utils.ts rename to packages/server/api/src/app/helper/telemetry.utils.ts index f70e0e0475..e5cbf904da 100644 --- a/packages/backend/src/app/helper/telemetry.utils.ts +++ b/packages/server/api/src/app/helper/telemetry.utils.ts @@ -1,17 +1,13 @@ import { PostHog } from 'posthog-node' -import { SystemProp } from './system/system-prop' -import { system } from './system/system' +import { SystemProp, system } from 'server-shared' import { ProjectId, TelemetryEvent, User, UserId } from '@activepieces/shared' import { projectService } from '../project/project-service' import { getEdition } from './secret-helper' -import { logger } from './logger' - +import { logger } from 'server-shared' const telemetryEnabled = system.getBoolean(SystemProp.TELEMETRY_ENABLED) -const client = new PostHog( - 'phc_7F92HoXJPeGnTKmYv0eOw62FurPMRW9Aqr0TPrDzvHh', -) +const client = new PostHog('phc_7F92HoXJPeGnTKmYv0eOw62FurPMRW9Aqr0TPrDzvHh') export const telemetry = { async identify(user: User, projectId: ProjectId): Promise { @@ -29,13 +25,17 @@ export const telemetry = { }, }) }, - async trackProject(projectId: ProjectId, event: TelemetryEvent): Promise { + async trackProject( + projectId: ProjectId, + event: TelemetryEvent, + ): Promise { if (!telemetryEnabled) { return } const project = await projectService.getOne(projectId) - this.trackUser(project!.ownerId, event) - .catch((e) => logger.error(e, '[Telemetry#trackProject] this.trackUser')) + this.trackUser(project!.ownerId, event).catch((e) => + logger.error(e, '[Telemetry#trackProject] this.trackUser'), + ) }, async trackUser(userId: UserId, event: TelemetryEvent): Promise { if (!telemetryEnabled) { diff --git a/packages/server/api/src/app/pieces/base-piece-module.ts b/packages/server/api/src/app/pieces/base-piece-module.ts new file mode 100644 index 0000000000..4d6a75bdc3 --- /dev/null +++ b/packages/server/api/src/app/pieces/base-piece-module.ts @@ -0,0 +1,218 @@ +import { + FastifyPluginAsyncTypebox, + Type, +} from '@fastify/type-provider-typebox' +import { + ALL_PRINICPAL_TYPES, + ActivepiecesError, + ApEdition, + ErrorCode, + GetPieceRequestParams, + GetPieceRequestQuery, + GetPieceRequestWithScopeParams, + ListPiecesRequestQuery, + PieceCategory, + PieceOptionRequest, + PrincipalType, +} from '@activepieces/shared' +import { engineHelper } from '../helper/engine-helper' +import { system, SystemProp } from 'server-shared' +import { + getPiecePackage, + pieceMetadataService, +} from './piece-metadata-service' +import { PieceMetadata } from '@activepieces/pieces-framework' +import { flagService } from '../flags/flag.service' +import { + PieceMetadataModel, + PieceMetadataModelSummary, +} from './piece-metadata-entity' +import { flowService } from '../flows/flow/flow.service' + +export const pieceModule: FastifyPluginAsyncTypebox = async (app) => { + await app.register(basePiecesController, { prefix: '/v1/pieces' }) +} + +const statsEnabled = system.getBoolean(SystemProp.STATS_ENABLED) + +const basePiecesController: FastifyPluginAsyncTypebox = async (app) => { + app.get( + '/categories', + { + config: { + allowedPrincipals: ALL_PRINICPAL_TYPES, + }, + schema: { + querystring: ListPiecesRequestQuery, + }, + }, + async (): Promise => { + return Object.values(PieceCategory) + }, + ) + + app.get( + '/', + { + config: { + allowedPrincipals: ALL_PRINICPAL_TYPES, + }, + schema: { + querystring: ListPiecesRequestQuery, + }, + }, + async (req): Promise => { + const latestRelease = await flagService.getCurrentRelease() + const release = req.query.release ?? latestRelease + const edition = req.query.edition ?? ApEdition.COMMUNITY + const pieceMetadataSummary = await pieceMetadataService.list({ + release, + includeHidden: req.query.includeHidden ?? false, + projectId: req.principal.projectId, + platformId: req.principal.platform?.id, + edition, + categories: req.query.categories, + searchQuery: req.query.searchQuery, + sortBy: req.query.sortBy, + orderBy: req.query.orderBy, + }) + return pieceMetadataSummary + }, + ) + + app.get( + '/:scope/:name', + { + config: { + allowedPrincipals: ALL_PRINICPAL_TYPES, + }, + schema: { + params: GetPieceRequestWithScopeParams, + querystring: GetPieceRequestQuery, + }, + }, + async (req): Promise => { + const { name, scope } = req.params + const { version } = req.query + + const decodeScope = decodeURIComponent(scope) + const decodedName = decodeURIComponent(name) + return pieceMetadataService.getOrThrow({ + projectId: + req.principal.type === PrincipalType.UNKNOWN + ? undefined + : req.principal.projectId, + name: `${decodeScope}/${decodedName}`, + version, + }) + }, + ) + + app.get( + '/:name', + { + config: { + allowedPrincipals: ALL_PRINICPAL_TYPES, + }, + schema: { + params: GetPieceRequestParams, + querystring: GetPieceRequestQuery, + }, + }, + async (req): Promise => { + const { name } = req.params + const { version } = req.query + + const decodedName = decodeURIComponent(name) + return pieceMetadataService.getOrThrow({ + projectId: + req.principal.type === PrincipalType.UNKNOWN + ? undefined + : req.principal.projectId, + name: decodedName, + version, + }) + }, + ) + + app.post( + '/options', + { + schema: { + body: PieceOptionRequest, + }, + }, + async (req) => { + const { + packageType, + pieceType, + pieceName, + pieceVersion, + propertyName, + stepName, + input, + flowVersionId, + flowId, + } = req.body + const { projectId } = req.principal + const flow = await flowService.getOnePopulatedOrThrow({ + projectId, + id: flowId, + versionId: flowVersionId, + }) + const { result } = await engineHelper.executeProp({ + piece: await getPiecePackage(projectId, { + packageType, + pieceType, + pieceName, + pieceVersion, + }), + flowVersion: flow.version, + propertyName, + stepName, + input, + projectId, + }) + + return result + }, + ) + + app.get( + '/stats', + { + config: { + allowedPrincipals: ALL_PRINICPAL_TYPES, + }, + }, + async () => { + if (!statsEnabled) { + throw new ActivepiecesError({ + code: ErrorCode.ENTITY_NOT_FOUND, + params: { + message: 'not found', + }, + }) + } + + return pieceMetadataService.stats() + }, + ) + + app.delete( + '/:id', + { + schema: { + params: Type.Object({ + id: Type.String(), + }), + }, + }, + async (req): Promise => { + return pieceMetadataService.delete({ + projectId: req.principal.projectId, + id: req.params.id, + }) + }, + ) +} diff --git a/packages/server/api/src/app/pieces/community-piece-module.ts b/packages/server/api/src/app/pieces/community-piece-module.ts new file mode 100644 index 0000000000..ba14f2651b --- /dev/null +++ b/packages/server/api/src/app/pieces/community-piece-module.ts @@ -0,0 +1,33 @@ +import { FastifyPluginAsyncTypebox } from '@fastify/type-provider-typebox' +import { AddPieceRequestBody, PrincipalType } from '@activepieces/shared' +import { pieceService } from './piece-service' +import { PieceMetadataModel } from './piece-metadata-entity' +import { StatusCodes } from 'http-status-codes' + +export const communityPiecesModule: FastifyPluginAsyncTypebox = async (app) => { + await app.register(communityPiecesController, { prefix: '/v1/pieces' }) +} + +const communityPiecesController: FastifyPluginAsyncTypebox = async (app) => { + app.post( + '/', + { + config: { + allowedPrincipals: [PrincipalType.USER], + }, + schema: { + body: AddPieceRequestBody, + }, + }, + async (req, res): Promise => { + const platformId = req.principal.platform?.id + const projectId = req.principal.projectId + const pieceMetadata = await pieceService.installPiece( + platformId, + projectId, + req.body, + ) + return res.code(StatusCodes.CREATED).send(pieceMetadata) + }, + ) +} diff --git a/packages/server/api/src/app/pieces/piece-metadata-entity.ts b/packages/server/api/src/app/pieces/piece-metadata-entity.ts new file mode 100644 index 0000000000..4e5553bd8c --- /dev/null +++ b/packages/server/api/src/app/pieces/piece-metadata-entity.ts @@ -0,0 +1,147 @@ +import { EntitySchema } from 'typeorm' +import { + PieceMetadata, + PieceMetadataSummary, +} from '@activepieces/pieces-framework' +import { + ApId, + BaseModel, + FileId, + PackageType, + PieceType, + Project, + ProjectId, +} from '@activepieces/shared' +import { + ARRAY_COLUMN_TYPE, + ApIdSchema, + BaseColumnSchemaPart, + COLLATION, + JSON_COLUMN_TYPE, + isPostgres, +} from '../database/database-common' + +type PiecePackageMetadata = { + projectId?: ProjectId + pieceType: PieceType + packageType: PackageType + archiveId?: FileId +} + +export type PieceMetadataModel = PieceMetadata & PiecePackageMetadata + +export type PieceMetadataModelSummary = PieceMetadataSummary & +PiecePackageMetadata + +export type PieceMetadataSchema = BaseModel & PieceMetadataModel + +type PieceMetadataSchemaWithRelations = PieceMetadataSchema & { + project: Project +} + +export const PieceMetadataEntity = + new EntitySchema({ + name: 'piece_metadata', + columns: { + ...BaseColumnSchemaPart, + name: { + type: String, + nullable: false, + }, + displayName: { + type: String, + nullable: false, + }, + logoUrl: { + type: String, + nullable: false, + }, + description: { + type: String, + nullable: true, + }, + projectId: { + type: String, + nullable: true, + }, + platformId: { + type: String, + nullable: true, + }, + version: { + type: String, + nullable: false, + collation: COLLATION, + }, + minimumSupportedRelease: { + type: String, + nullable: false, + collation: COLLATION, + }, + maximumSupportedRelease: { + type: String, + nullable: false, + collation: COLLATION, + }, + auth: { + type: JSON_COLUMN_TYPE, + nullable: true, + }, + actions: { + type: JSON_COLUMN_TYPE, + nullable: false, + }, + triggers: { + type: JSON_COLUMN_TYPE, + nullable: false, + }, + pieceType: { + type: String, + nullable: false, + }, + categories: { + type: ARRAY_COLUMN_TYPE, + nullable: true, + array: isPostgres(), + }, + packageType: { + type: String, + nullable: false, + }, + archiveId: { + ...ApIdSchema, + nullable: true, + }, + }, + indices: [ + { + name: 'idx_piece_metadata_name_project_id_version', + columns: ['name', 'version', 'projectId'], + unique: true, + }, + ], + relations: { + project: { + type: 'many-to-one', + target: 'project', + cascade: true, + onDelete: 'CASCADE', + joinColumn: { + name: 'projectId', + foreignKeyConstraintName: 'fk_piece_metadata_project_id', + }, + nullable: true, + }, + archiveId: { + type: 'one-to-one', + target: 'file', + onDelete: 'NO ACTION', + onUpdate: 'NO ACTION', + joinColumn: { + name: 'archiveId', + referencedColumnName: 'id', + foreignKeyConstraintName: 'fk_piece_metadata_file', + }, + }, + }, + }) diff --git a/packages/backend/src/app/pieces/piece-metadata-service/aggregated-metadata-service.ts b/packages/server/api/src/app/pieces/piece-metadata-service/aggregated-metadata-service.ts similarity index 73% rename from packages/backend/src/app/pieces/piece-metadata-service/aggregated-metadata-service.ts rename to packages/server/api/src/app/pieces/piece-metadata-service/aggregated-metadata-service.ts index 87b1f39872..fb5326d564 100644 --- a/packages/backend/src/app/pieces/piece-metadata-service/aggregated-metadata-service.ts +++ b/packages/server/api/src/app/pieces/piece-metadata-service/aggregated-metadata-service.ts @@ -2,8 +2,15 @@ import { PieceMetadataService } from './piece-metadata-service' import { AllPiecesStats } from './piece-stats-service' import { CloudPieceMetadataService } from './cloud-piece-metadata-service' import { DbPieceMetadataService } from './db-piece-metadata-service' -import { ActivepiecesError, EXACT_VERSION_PATTERN, ErrorCode } from '@activepieces/shared' -import { PieceMetadataModel, PieceMetadataModelSummary } from '../piece-metadata-entity' +import { + ActivepiecesError, + EXACT_VERSION_PATTERN, + ErrorCode, +} from '@activepieces/shared' +import { + PieceMetadataModel, + PieceMetadataModelSummary, +} from '../piece-metadata-entity' const cloudPieceProvider = CloudPieceMetadataService() const dbPieceProvider = DbPieceMetadataService() @@ -18,17 +25,28 @@ export const AggregatedPieceMetadataService = (): PieceMetadataService => { return [...cloudMetadata, ...dbMetadata] }, - async getOrThrow({ name, version, projectId }): Promise { + async getOrThrow({ + name, + version, + projectId, + }): Promise { try { const dbMetadata = await dbPieceProvider.getOrThrow({ - name, version, projectId, + name, + version, + projectId, }) return dbMetadata } catch (e) { - if (e instanceof ActivepiecesError && (e as ActivepiecesError).error.code === ErrorCode.ENTITY_NOT_FOUND) { + if ( + e instanceof ActivepiecesError && + (e as ActivepiecesError).error.code === ErrorCode.ENTITY_NOT_FOUND + ) { const cloudMetadata = await cloudPieceProvider.getOrThrow({ - name, version, projectId, + name, + version, + projectId, }) return cloudMetadata } diff --git a/packages/backend/src/app/pieces/piece-metadata-service/cloud-piece-metadata-service.ts b/packages/server/api/src/app/pieces/piece-metadata-service/cloud-piece-metadata-service.ts similarity index 77% rename from packages/backend/src/app/pieces/piece-metadata-service/cloud-piece-metadata-service.ts rename to packages/server/api/src/app/pieces/piece-metadata-service/cloud-piece-metadata-service.ts index dbf1faba65..45869e99ca 100644 --- a/packages/backend/src/app/pieces/piece-metadata-service/cloud-piece-metadata-service.ts +++ b/packages/server/api/src/app/pieces/piece-metadata-service/cloud-piece-metadata-service.ts @@ -1,8 +1,16 @@ -import { PieceMetadataModel, PieceMetadataModelSummary, PieceMetadataSchema } from '../piece-metadata-entity' +import { + PieceMetadataModel, + PieceMetadataModelSummary, + PieceMetadataSchema, +} from '../piece-metadata-entity' import { PieceMetadataService } from './piece-metadata-service' import { AllPiecesStats, pieceStatsService } from './piece-stats-service' import { StatusCodes } from 'http-status-codes' -import { ActivepiecesError, EXACT_VERSION_PATTERN, ErrorCode } from '@activepieces/shared' +import { + ActivepiecesError, + EXACT_VERSION_PATTERN, + ErrorCode, +} from '@activepieces/shared' const CLOUD_API_URL = 'https://cloud.activepieces.com/api/v1/pieces' @@ -23,7 +31,13 @@ const handleHttpErrors = async (response: Response): Promise => { export const CloudPieceMetadataService = (): PieceMetadataService => { return { - async list({ release, searchQuery, categories, sortBy, orderBy }): Promise { + async list({ + release, + searchQuery, + categories, + sortBy, + orderBy, + }): Promise { const queryParams = new URLSearchParams() queryParams.append('release', release) if (searchQuery) { @@ -45,15 +59,17 @@ export const CloudPieceMetadataService = (): PieceMetadataService => { await handleHttpErrors(response) - return await response.json() as PieceMetadataModelSummary[] + return (await response.json()) as PieceMetadataModelSummary[] }, async getOrThrow({ name, version }): Promise { - const response = await fetch(`${CLOUD_API_URL}/${name}${version ? '?version=' + version : ''}`) + const response = await fetch( + `${CLOUD_API_URL}/${name}${version ? '?version=' + version : ''}`, + ) await handleHttpErrors(response) - return await response.json() as PieceMetadataModel + return (await response.json()) as PieceMetadataModel }, async create(): Promise { diff --git a/packages/backend/src/app/pieces/piece-metadata-service/db-piece-metadata-service.ts b/packages/server/api/src/app/pieces/piece-metadata-service/db-piece-metadata-service.ts similarity index 82% rename from packages/backend/src/app/pieces/piece-metadata-service/db-piece-metadata-service.ts rename to packages/server/api/src/app/pieces/piece-metadata-service/db-piece-metadata-service.ts index 542f821769..4278b1f1c6 100644 --- a/packages/backend/src/app/pieces/piece-metadata-service/db-piece-metadata-service.ts +++ b/packages/server/api/src/app/pieces/piece-metadata-service/db-piece-metadata-service.ts @@ -1,6 +1,18 @@ -import { Equal, FindOperator, IsNull, LessThan, LessThanOrEqual, MoreThanOrEqual } from 'typeorm' +import { + Equal, + FindOperator, + IsNull, + LessThan, + LessThanOrEqual, + MoreThanOrEqual, +} from 'typeorm' import { repoFactory } from '../../core/db/repo-factory' -import { PieceMetadataEntity, PieceMetadataModel, PieceMetadataModelSummary, PieceMetadataSchema } from '../piece-metadata-entity' +import { + PieceMetadataEntity, + PieceMetadataModel, + PieceMetadataModelSummary, + PieceMetadataSchema, +} from '../piece-metadata-entity' import { PieceMetadataService } from './piece-metadata-service' import { EXACT_VERSION_PATTERN, PieceType, isNil } from '@activepieces/shared' import { ActivepiecesError, ErrorCode, apId } from '@activepieces/shared' @@ -20,7 +32,8 @@ export const DbPieceMetadataService = (): PieceMetadataService => { version: 'DESC', } as const - const pieceMetadataEntityList = await repo().createQueryBuilder() + const pieceMetadataEntityList = await repo() + .createQueryBuilder() .where([ { minimumSupportedRelease: LessThanOrEqual(release), @@ -54,14 +67,19 @@ export const DbPieceMetadataService = (): PieceMetadataService => { return toPieceMetadataModelSummary(pieces) }, - async getOrThrow({ name, version, projectId, entityManager }): Promise { - + async getOrThrow({ + name, + version, + projectId, + entityManager, + }): Promise { const filters = await constructPieceFilters({ name, version, projectId, }) - const pieceMetadataEntity = await repo(entityManager).createQueryBuilder() + const pieceMetadataEntity = await repo(entityManager) + .createQueryBuilder() .where(filters) .distinctOn(['name']) .orderBy({ @@ -82,7 +100,14 @@ export const DbPieceMetadataService = (): PieceMetadataService => { return toPieceMetadataModel(pieceMetadataEntity) }, - async create({ pieceMetadata, projectId, platformId, packageType, pieceType, archiveId }): Promise { + async create({ + pieceMetadata, + projectId, + platformId, + packageType, + pieceType, + archiveId, + }): Promise { const existingMetadata = await repo().findOneBy({ name: pieceMetadata.name, version: pieceMetadata.version, @@ -150,7 +175,15 @@ export const DbPieceMetadataService = (): PieceMetadataService => { } } -const constructPieceFilters = async ({ name, version, projectId }: { name: string, version: string | undefined, projectId: string | undefined }): Promise[]> => { +const constructPieceFilters = async ({ + name, + version, + projectId, +}: { + name: string + version: string | undefined + projectId: string | undefined +}): Promise[]> => { const officialPiecesFilter = createOfficialPiecesFilter(name) const filters = [officialPiecesFilter] @@ -182,28 +215,39 @@ const createOfficialPiecesFilter = (name: string): Record => ({ pieceType: Equal(PieceType.OFFICIAL), }) -const createProjectPieceFilter = (name: string, projectId: string): Record => ({ +const createProjectPieceFilter = ( + name: string, + projectId: string, +): Record => ({ name, projectId: Equal(projectId), pieceType: Equal(PieceType.CUSTOM), }) -const createPlatformPieceFilter = (name: string, platformId: string): Record => ({ +const createPlatformPieceFilter = ( + name: string, + platformId: string, +): Record => ({ name, platformId: Equal(platformId), projectId: IsNull(), pieceType: Equal(PieceType.CUSTOM), }) -const applyVersionFilter = (filters: Record[], version: string): Record[] => { - return filters.map(filter => ({ +const applyVersionFilter = ( + filters: Record[], + version: string, +): Record[] => { + return filters.map((filter) => ({ ...filter, version: findSearchOperation(version), })) } -const toPieceMetadataModelSummary = (pieceMetadataEntityList: PieceMetadataSchema[]): PieceMetadataModelSummary[] => { - return pieceMetadataEntityList.map(pieceMetadataEntity => { +const toPieceMetadataModelSummary = ( + pieceMetadataEntityList: PieceMetadataSchema[], +): PieceMetadataModelSummary[] => { + return pieceMetadataEntityList.map((pieceMetadataEntity) => { return { ...pieceMetadataEntity, actions: Object.keys(pieceMetadataEntity.actions).length, @@ -212,7 +256,9 @@ const toPieceMetadataModelSummary = (pieceMetadataEntityList: PieceMetadataSchem }) } -const toPieceMetadataModel = (pieceMetadataEntity: PieceMetadataSchema): PieceMetadataModel => { +const toPieceMetadataModel = ( + pieceMetadataEntity: PieceMetadataSchema, +): PieceMetadataModel => { return { ...pieceMetadataEntity, actions: pieceMetadataEntity.actions, diff --git a/packages/backend/src/app/pieces/piece-metadata-service/file-piece-metadata-service.ts b/packages/server/api/src/app/pieces/piece-metadata-service/file-piece-metadata-service.ts similarity index 80% rename from packages/backend/src/app/pieces/piece-metadata-service/file-piece-metadata-service.ts rename to packages/server/api/src/app/pieces/piece-metadata-service/file-piece-metadata-service.ts index 06455b1dea..2d71fb0dee 100644 --- a/packages/backend/src/app/pieces/piece-metadata-service/file-piece-metadata-service.ts +++ b/packages/server/api/src/app/pieces/piece-metadata-service/file-piece-metadata-service.ts @@ -2,14 +2,26 @@ import { readdir, stat } from 'node:fs/promises' import { resolve, join } from 'node:path' import { cwd } from 'node:process' import { Piece, PieceMetadata } from '@activepieces/pieces-framework' -import { ActivepiecesError, EXACT_VERSION_PATTERN, ErrorCode, PackageType, PieceType, ProjectId, extractPieceFromModule, isNil } from '@activepieces/shared' -import { captureException } from '../../helper/logger' +import { + ActivepiecesError, + EXACT_VERSION_PATTERN, + ErrorCode, + PackageType, + PieceType, + ProjectId, + extractPieceFromModule, + isNil, +} from '@activepieces/shared' import { PieceMetadataService } from './piece-metadata-service' import { AllPiecesStats } from './piece-stats-service' import importFresh from 'import-fresh' -import { PieceMetadataModel, PieceMetadataModelSummary } from '../piece-metadata-entity' +import { + PieceMetadataModel, + PieceMetadataModelSummary, +} from '../piece-metadata-entity' import { pieceMetadataServiceHooks } from './hooks' import { nanoid } from 'nanoid' +import { exceptionHandler } from 'server-shared' const loadPiecesMetadata = async (): Promise => { const pieces = await findAllPieces() @@ -31,8 +43,14 @@ async function traverseFolder(folderPath: string): Promise { for (const file of files) { const filePath = join(folderPath, file) const fileStats = await stat(filePath) - if (fileStats.isDirectory() && file !== 'node_modules' && file !== 'dist' && file !== 'framework' && file !== 'common') { - paths.push(...await traverseFolder(filePath)) + if ( + fileStats.isDirectory() && + file !== 'node_modules' && + file !== 'dist' && + file !== 'framework' && + file !== 'common' + ) { + paths.push(...(await traverseFolder(filePath))) } else if (file === 'package.json') { paths.push(folderPath) @@ -41,7 +59,9 @@ async function traverseFolder(folderPath: string): Promise { return paths } -async function loadPieceFromFolder(folderPath: string): Promise { +async function loadPieceFromFolder( + folderPath: string, +): Promise { try { const packageJson = importFresh>( join(folderPath, 'package.json'), @@ -64,7 +84,7 @@ async function loadPieceFromFolder(folderPath: string): Promise { const pieces = await pieceMetadataServiceHooks.get().filterPieces({ ...params, - pieces: piecesMetadata.map(p => { + pieces: piecesMetadata.map((p) => { return { id: nanoid(), ...p, @@ -87,13 +107,19 @@ export const FilePieceMetadataService = (): PieceMetadataService => { } }), }) - return pieces.map(p => toPieceMetadataModelSummary({ - pieceMetadata: p, - projectId, - })) + return pieces.map((p) => + toPieceMetadataModelSummary({ + pieceMetadata: p, + projectId, + }), + ) }, - async getOrThrow({ name, version, projectId }): Promise { + async getOrThrow({ + name, + version, + projectId, + }): Promise { const piecesMetadata = await loadPiecesMetadata() const pieceMetadata = piecesMetadata.find((p) => p.name === name) @@ -143,7 +169,10 @@ export const FilePieceMetadataService = (): PieceMetadataService => { } } -const toPieceMetadataModel = ({ pieceMetadata, projectId }: ToPieceMetadataModelParams): PieceMetadataModel => { +const toPieceMetadataModel = ({ + pieceMetadata, + projectId, +}: ToPieceMetadataModelParams): PieceMetadataModel => { return { name: pieceMetadata.name, displayName: pieceMetadata.displayName, @@ -163,7 +192,10 @@ const toPieceMetadataModel = ({ pieceMetadata, projectId }: ToPieceMetadataModel } } -const toPieceMetadataModelSummary = ({ pieceMetadata, projectId }: ToPieceMetadataModelParams): PieceMetadataModelSummary => { +const toPieceMetadataModelSummary = ({ + pieceMetadata, + projectId, +}: ToPieceMetadataModelParams): PieceMetadataModelSummary => { const pieceMetadataModel = toPieceMetadataModel({ pieceMetadata, projectId, diff --git a/packages/backend/src/app/pieces/piece-metadata-service/hooks/index.ts b/packages/server/api/src/app/pieces/piece-metadata-service/hooks/index.ts similarity index 90% rename from packages/backend/src/app/pieces/piece-metadata-service/hooks/index.ts rename to packages/server/api/src/app/pieces/piece-metadata-service/hooks/index.ts index b6e16665c4..b018828d54 100644 --- a/packages/backend/src/app/pieces/piece-metadata-service/hooks/index.ts +++ b/packages/server/api/src/app/pieces/piece-metadata-service/hooks/index.ts @@ -6,12 +6,15 @@ import { sortAndOrderPieces } from './piece-sorting' export const defaultPieceHooks: PieceMetadataServiceHooks = { async filterPieces(params) { - return sortAndOrderPieces(params.sortBy, params.orderBy, + return sortAndOrderPieces( + params.sortBy, + params.orderBy, filterPiecesBasedUser({ categories: params.categories, searchQuery: params.searchQuery, pieces: params.pieces, - })) + }), + ) }, } @@ -40,4 +43,3 @@ export type FilterPiecesParams = { orderBy?: PieceOrderBy pieces: PieceMetadataSchema[] } - diff --git a/packages/server/api/src/app/pieces/piece-metadata-service/hooks/piece-filtering.ts b/packages/server/api/src/app/pieces/piece-metadata-service/hooks/piece-filtering.ts new file mode 100644 index 0000000000..65753e72be --- /dev/null +++ b/packages/server/api/src/app/pieces/piece-metadata-service/hooks/piece-filtering.ts @@ -0,0 +1,65 @@ +import { PieceCategory } from '@activepieces/shared' +import { PieceMetadataSchema } from '../../piece-metadata-entity' +import Fuse from 'fuse.js' + +export const filterPiecesBasedUser = ({ + searchQuery, + pieces, + categories, +}: { + categories: PieceCategory[] | undefined + searchQuery: string | undefined + pieces: PieceMetadataSchema[] +}): PieceMetadataSchema[] => { + return filterBasedOnCategories({ + categories, + pieces: filterBasedOnSearchQuery({ searchQuery, pieces }), + }) +} + +const filterBasedOnSearchQuery = ({ + searchQuery, + pieces, +}: { + searchQuery: string | undefined + pieces: PieceMetadataSchema[] +}): PieceMetadataSchema[] => { + if (!searchQuery) { + return pieces + } + const fuse = new Fuse(pieces, { + isCaseSensitive: false, + shouldSort: true, + keys: [ + { + name: 'name', + weight: 5, + }, + { + name: 'description', + weight: 5, + }, + ], + threshold: 0.3, + }) + + return fuse + .search(searchQuery) + .map(({ item }) => pieces.find((p) => p.name === item.name)!) +} + +const filterBasedOnCategories = ({ + categories, + pieces, +}: { + categories: PieceCategory[] | undefined + pieces: PieceMetadataSchema[] +}): PieceMetadataSchema[] => { + if (!categories) { + return pieces + } + + return pieces.filter((p) => { + return categories.some((item) => (p.categories ?? []).includes(item)) + }) +} diff --git a/packages/backend/src/app/pieces/piece-metadata-service/hooks/piece-sorting.ts b/packages/server/api/src/app/pieces/piece-metadata-service/hooks/piece-sorting.ts similarity index 58% rename from packages/backend/src/app/pieces/piece-metadata-service/hooks/piece-sorting.ts rename to packages/server/api/src/app/pieces/piece-metadata-service/hooks/piece-sorting.ts index e3852cf7ec..16a35a0fd6 100644 --- a/packages/backend/src/app/pieces/piece-metadata-service/hooks/piece-sorting.ts +++ b/packages/server/api/src/app/pieces/piece-metadata-service/hooks/piece-sorting.ts @@ -1,9 +1,12 @@ - import { PieceSortBy, PieceOrderBy } from '@activepieces/shared' import { PieceMetadataSchema } from '../../piece-metadata-entity' import dayjs from 'dayjs' -export const sortAndOrderPieces = (sortBy: PieceSortBy | undefined, orderBy: PieceOrderBy | undefined, pieces: PieceMetadataSchema[]): PieceMetadataSchema[] => { +export const sortAndOrderPieces = ( + sortBy: PieceSortBy | undefined, + orderBy: PieceOrderBy | undefined, + pieces: PieceMetadataSchema[], +): PieceMetadataSchema[] => { const sortByDefault = sortBy ?? PieceSortBy.NAME const orderByDefault = orderBy ?? PieceOrderBy.ASC const sortedPiece = sortPieces(sortByDefault, pieces) @@ -11,7 +14,10 @@ export const sortAndOrderPieces = (sortBy: PieceSortBy | undefined, orderBy: Pie return reverseIfDesc(orderByDefault, sortedPiece) } -const sortPieces = (sortBy: PieceSortBy | undefined, pieces: PieceMetadataSchema[]): PieceMetadataSchema[] => { +const sortPieces = ( + sortBy: PieceSortBy | undefined, + pieces: PieceMetadataSchema[], +): PieceMetadataSchema[] => { const sortByDefault = sortBy ?? PieceSortBy.NAME switch (sortByDefault) { case PieceSortBy.NAME: { @@ -22,7 +28,10 @@ const sortPieces = (sortBy: PieceSortBy | undefined, pieces: PieceMetadataSchema } } } -const reverseIfDesc = (orderBy: PieceOrderBy, pieces: PieceMetadataSchema[]): PieceMetadataSchema[] => { +const reverseIfDesc = ( + orderBy: PieceOrderBy, + pieces: PieceMetadataSchema[], +): PieceMetadataSchema[] => { if (orderBy === PieceOrderBy.ASC) { return pieces } @@ -30,10 +39,13 @@ const reverseIfDesc = (orderBy: PieceOrderBy, pieces: PieceMetadataSchema[]): Pi } const sortByName = (pieces: PieceMetadataSchema[]): PieceMetadataSchema[] => { - return pieces.sort((a, b) => a.name.toLocaleLowerCase().localeCompare(b.name.toLocaleLowerCase())) + return pieces.sort((a, b) => + a.name.toLocaleLowerCase().localeCompare(b.name.toLocaleLowerCase()), + ) } const sortByDate = (pieces: PieceMetadataSchema[]): PieceMetadataSchema[] => { - return pieces.sort((a, b) => dayjs(a.created).unix() - dayjs(b.created).unix()) + return pieces.sort( + (a, b) => dayjs(a.created).unix() - dayjs(b.created).unix(), + ) } - diff --git a/packages/backend/src/app/pieces/piece-metadata-service/index.ts b/packages/server/api/src/app/pieces/piece-metadata-service/index.ts similarity index 78% rename from packages/backend/src/app/pieces/piece-metadata-service/index.ts rename to packages/server/api/src/app/pieces/piece-metadata-service/index.ts index 21a040b0f3..10d9609241 100644 --- a/packages/backend/src/app/pieces/piece-metadata-service/index.ts +++ b/packages/server/api/src/app/pieces/piece-metadata-service/index.ts @@ -1,10 +1,14 @@ -import { PiecesSource, system } from '../../helper/system/system' -import { SystemProp } from '../../helper/system/system-prop' +import { PiecesSource, SystemProp, system } from 'server-shared' import { PieceMetadataService } from './piece-metadata-service' import { FilePieceMetadataService } from './file-piece-metadata-service' import { DbPieceMetadataService } from './db-piece-metadata-service' import { AggregatedPieceMetadataService } from './aggregated-metadata-service' -import { PackageType, PiecePackage, PrivatePiecePackage, PublicPiecePackage } from '@activepieces/shared' +import { + PackageType, + PiecePackage, + PrivatePiecePackage, + PublicPiecePackage, +} from '@activepieces/shared' const initPieceMetadataService = (): PieceMetadataService => { const source = system.getOrThrow(SystemProp.PIECES_SOURCE) @@ -20,7 +24,10 @@ const initPieceMetadataService = (): PieceMetadataService => { export const pieceMetadataService = initPieceMetadataService() -export const getPiecePackage = async (projectId: string, pkg: PublicPiecePackage | Omit): Promise => { +export const getPiecePackage = async ( + projectId: string, + pkg: PublicPiecePackage | Omit, +): Promise => { switch (pkg.packageType) { case PackageType.ARCHIVE: { const pieceMetadata = await pieceMetadataService.getOrThrow({ @@ -40,4 +47,4 @@ export const getPiecePackage = async (projectId: string, pkg: PublicPiecePackage return pkg } } -} \ No newline at end of file +} diff --git a/packages/backend/src/app/pieces/piece-metadata-service/piece-metadata-service.ts b/packages/server/api/src/app/pieces/piece-metadata-service/piece-metadata-service.ts similarity index 83% rename from packages/backend/src/app/pieces/piece-metadata-service/piece-metadata-service.ts rename to packages/server/api/src/app/pieces/piece-metadata-service/piece-metadata-service.ts index e8606cd06e..4e9255d059 100644 --- a/packages/backend/src/app/pieces/piece-metadata-service/piece-metadata-service.ts +++ b/packages/server/api/src/app/pieces/piece-metadata-service/piece-metadata-service.ts @@ -1,7 +1,18 @@ import { PieceMetadata } from '@activepieces/pieces-framework' import { AllPiecesStats } from './piece-stats-service' -import { ApEdition, PackageType, PieceCategory, PieceOrderBy, PieceSortBy, PieceType, ProjectId } from '@activepieces/shared' -import { PieceMetadataModel, PieceMetadataModelSummary } from '../piece-metadata-entity' +import { + ApEdition, + PackageType, + PieceCategory, + PieceOrderBy, + PieceSortBy, + PieceType, + ProjectId, +} from '@activepieces/shared' +import { + PieceMetadataModel, + PieceMetadataModelSummary, +} from '../piece-metadata-entity' import { EntityManager } from 'typeorm' type ListParams = { @@ -51,4 +62,3 @@ export type PieceMetadataService = { stats(): Promise getExactPieceVersion(params: GetExactPieceVersionParams): Promise } - diff --git a/packages/backend/src/app/pieces/piece-metadata-service/piece-stats-service.ts b/packages/server/api/src/app/pieces/piece-metadata-service/piece-stats-service.ts similarity index 68% rename from packages/backend/src/app/pieces/piece-metadata-service/piece-stats-service.ts rename to packages/server/api/src/app/pieces/piece-metadata-service/piece-stats-service.ts index 269c41855f..2eb99aac31 100644 --- a/packages/backend/src/app/pieces/piece-metadata-service/piece-stats-service.ts +++ b/packages/server/api/src/app/pieces/piece-metadata-service/piece-stats-service.ts @@ -1,4 +1,13 @@ -import { FlowId, ProjectId, flowHelper, TriggerType, ActionType, isNil, ApEdition, FlowStatus } from '@activepieces/shared' +import { + FlowId, + ProjectId, + flowHelper, + TriggerType, + ActionType, + isNil, + ApEdition, + FlowStatus, +} from '@activepieces/shared' import { flowRepo } from '../../flows/flow/flow.repo' import { flowService } from '../../flows/flow/flow.service' import { CloudPieceMetadataService } from './cloud-piece-metadata-service' @@ -22,19 +31,37 @@ const TWENTY_FOUR_HOURS_IN_MILLISECONDS = 24 * 60 * 60 * 1000 export const pieceStatsService = { async get(): Promise { const pieceMetaService = CloudPieceMetadataService() - if (cachedStats && (Date.now() - cacheTime) < TWENTY_FOUR_HOURS_IN_MILLISECONDS) { + if ( + cachedStats && + Date.now() - cacheTime < TWENTY_FOUR_HOURS_IN_MILLISECONDS + ) { return cachedStats } const flows = await flowRepo().find() const stats: Record = {} - const uniqueStatsPerPiece: Record projects: Set activeprojects: Set activeFlows: Set - }> = {} - const defaultStats = { activeSteps: 0, allSteps: 0, allProjects: 0, activeFlows: 0, allFlows: 0, activeProjects: 0 } - const pieces = await pieceMetaService.list({ release: await flagService.getCurrentRelease(), projectId: undefined, edition: ApEdition.ENTERPRISE, includeHidden: true }) + } + > = {} + const defaultStats = { + activeSteps: 0, + allSteps: 0, + allProjects: 0, + activeFlows: 0, + allFlows: 0, + activeProjects: 0, + } + const pieces = await pieceMetaService.list({ + release: await flagService.getCurrentRelease(), + projectId: undefined, + edition: ApEdition.ENTERPRISE, + includeHidden: true, + }) for (const piece of pieces) { uniqueStatsPerPiece[piece.name] = { flows: new Set(), @@ -68,25 +95,37 @@ export const pieceStatsService = { } stats[step.settings.pieceName] = { ...defaultStats } } - uniqueStatsPerPiece[step.settings.pieceName].projects.add(flow.projectId) + uniqueStatsPerPiece[step.settings.pieceName].projects.add( + flow.projectId, + ) uniqueStatsPerPiece[step.settings.pieceName].flows.add(flow.id) stats[step.settings.pieceName].allSteps++ if (flow.status === FlowStatus.ENABLED) { - uniqueStatsPerPiece[step.settings.pieceName].activeFlows.add(flow.id) - uniqueStatsPerPiece[step.settings.pieceName].activeprojects.add(flow.projectId) + uniqueStatsPerPiece[step.settings.pieceName].activeFlows.add( + flow.id, + ) + uniqueStatsPerPiece[step.settings.pieceName].activeprojects.add( + flow.projectId, + ) stats[step.settings.pieceName].activeSteps++ } } } } for (const pieceName in uniqueStatsPerPiece) { - stats[pieceName].allProjects = uniqueStatsPerPiece[pieceName].projects.size - stats[pieceName].activeProjects = uniqueStatsPerPiece[pieceName].activeprojects.size + stats[pieceName].allProjects = + uniqueStatsPerPiece[pieceName].projects.size + stats[pieceName].activeProjects = + uniqueStatsPerPiece[pieceName].activeprojects.size stats[pieceName].allFlows = uniqueStatsPerPiece[pieceName].flows.size - stats[pieceName].activeFlows = uniqueStatsPerPiece[pieceName].activeFlows.size + stats[pieceName].activeFlows = + uniqueStatsPerPiece[pieceName].activeFlows.size } cachedStats = Object.entries(stats) - .sort(([, valueA], [, valueB]) => valueB.activeProjects - valueA.activeProjects) + .sort( + ([, valueA], [, valueB]) => + valueB.activeProjects - valueA.activeProjects, + ) .reduce((acc, [key, value]) => ({ ...acc, [key]: value }), {}) cacheTime = Date.now() diff --git a/packages/backend/src/app/pieces/piece-service/index.ts b/packages/server/api/src/app/pieces/piece-service/index.ts similarity index 72% rename from packages/backend/src/app/pieces/piece-service/index.ts rename to packages/server/api/src/app/pieces/piece-service/index.ts index 83d530cd1b..0cbd4e69be 100644 --- a/packages/backend/src/app/pieces/piece-service/index.ts +++ b/packages/server/api/src/app/pieces/piece-service/index.ts @@ -12,25 +12,29 @@ import { import { engineHelper } from '../../helper/engine-helper' import { pieceMetadataService } from '../piece-metadata-service' import { PieceMetadataModel } from '../piece-metadata-entity' -import { logger } from '../../helper/logger' +import { logger } from 'server-shared' import { pieceServiceHooks } from './piece-service-hooks' -import { ExecutionMode, system } from '../../helper/system/system' -import { SystemProp } from '../../helper/system/system-prop' +import { ExecutionMode, SystemProp, system } from 'server-shared' import { getEdition } from '../../helper/secret-helper' import { PieceMetadata } from '@activepieces/pieces-framework' export const pieceService = { - async installPiece(platformId: string | undefined, projectId: string, params: AddPieceRequestBody): Promise { + async installPiece( + platformId: string | undefined, + projectId: string, + params: AddPieceRequestBody, + ): Promise { assertInstallProjectEnabled(params.scope) try { - const piecePackage = await getPiecePackage(platformId, projectId, params) const pieceInformation = await extractPieceInformation(piecePackage) const savedPiece = await pieceMetadataService.create({ pieceMetadata: { ...pieceInformation, - minimumSupportedRelease: pieceInformation.minimumSupportedRelease ?? '0.0.0', - maximumSupportedRelease: pieceInformation.maximumSupportedRelease ?? '999.999.999', + minimumSupportedRelease: + pieceInformation.minimumSupportedRelease ?? '0.0.0', + maximumSupportedRelease: + pieceInformation.maximumSupportedRelease ?? '999.999.999', name: pieceInformation.name, version: pieceInformation.version, }, @@ -38,7 +42,10 @@ export const pieceService = { packageType: params.packageType, platformId, pieceType: PieceType.CUSTOM, - archiveId: piecePackage.packageType === PackageType.ARCHIVE ? piecePackage.archiveId : undefined, + archiveId: + piecePackage.packageType === PackageType.ARCHIVE + ? piecePackage.archiveId + : undefined, }) return savedPiece @@ -63,19 +70,26 @@ const assertInstallProjectEnabled = (scope: PieceScope): void => { if (scope === PieceScope.PROJECT) { const sandboxMode = system.getOrThrow(SystemProp.EXECUTION_MODE) const edition = getEdition() - if (sandboxMode === ExecutionMode.UNSANDBOXED && [ApEdition.ENTERPRISE, ApEdition.CLOUD].includes(edition)) { + if ( + sandboxMode === ExecutionMode.UNSANDBOXED && + [ApEdition.ENTERPRISE, ApEdition.CLOUD].includes(edition) + ) { throw new ActivepiecesError({ code: ErrorCode.AUTHORIZATION, params: { - message: 'Project pieces are not supported in this edition with unsandboxed execution mode', + message: + 'Project pieces are not supported in this edition with unsandboxed execution mode', }, }) } } } - -const getPiecePackage = async (platformId: string | undefined, projectId: string | undefined, params: AddPieceRequestBody): Promise => { +const getPiecePackage = async ( + platformId: string | undefined, + projectId: string | undefined, + params: AddPieceRequestBody, +): Promise => { switch (params.packageType) { case PackageType.ARCHIVE: { return pieceServiceHooks.get().savePieceArchivePackage({ @@ -97,9 +111,9 @@ const getPiecePackage = async (platformId: string | undefined, projectId: string } } - - -const extractPieceInformation = async (piecePackage: PiecePackage): Promise => { +const extractPieceInformation = async ( + piecePackage: PiecePackage, +): Promise => { const engineResponse = await engineHelper.extractPieceMetadata(piecePackage) if (engineResponse.status !== EngineResponseStatus.OK) { diff --git a/packages/backend/src/app/pieces/piece-service/piece-service-hooks.ts b/packages/server/api/src/app/pieces/piece-service/piece-service-hooks.ts similarity index 87% rename from packages/backend/src/app/pieces/piece-service/piece-service-hooks.ts rename to packages/server/api/src/app/pieces/piece-service/piece-service-hooks.ts index 9e14c37890..490ae736e5 100644 --- a/packages/backend/src/app/pieces/piece-service/piece-service-hooks.ts +++ b/packages/server/api/src/app/pieces/piece-service/piece-service-hooks.ts @@ -20,7 +20,9 @@ export const pieceServiceHooks = { } export type PieceServiceHooks = { - savePieceArchivePackage(p: GetPieceArchivePackageParams): Promise + savePieceArchivePackage( + p: GetPieceArchivePackageParams + ): Promise } export type GetPieceArchivePackageParams = { diff --git a/packages/backend/src/app/project/project-controller.ts b/packages/server/api/src/app/project/project-controller.ts old mode 100755 new mode 100644 similarity index 63% rename from packages/backend/src/app/project/project-controller.ts rename to packages/server/api/src/app/project/project-controller.ts index f6e8656e1e..025dd02183 --- a/packages/backend/src/app/project/project-controller.ts +++ b/packages/server/api/src/app/project/project-controller.ts @@ -2,12 +2,17 @@ import { projectService } from './project-service' import { FastifyPluginCallbackTypebox } from '@fastify/type-provider-typebox' import { paginationHelper } from '../helper/pagination/pagination-utils' -export const projectController: FastifyPluginCallbackTypebox = (fastify, _opts, done) => { - +export const projectController: FastifyPluginCallbackTypebox = ( + fastify, + _opts, + done, +) => { fastify.get('/', async (request) => { - return paginationHelper.createPage([await projectService.getUserProjectOrThrow(request.principal.id)], null) + return paginationHelper.createPage( + [await projectService.getUserProjectOrThrow(request.principal.id)], + null, + ) }) - done() } diff --git a/packages/backend/src/app/project/project-entity.ts b/packages/server/api/src/app/project/project-entity.ts old mode 100755 new mode 100644 similarity index 94% rename from packages/backend/src/app/project/project-entity.ts rename to packages/server/api/src/app/project/project-entity.ts index 9ac459fc7b..1f80ad2295 --- a/packages/backend/src/app/project/project-entity.ts +++ b/packages/server/api/src/app/project/project-entity.ts @@ -1,5 +1,13 @@ import { EntitySchema } from 'typeorm' -import { AppConnection, Flow, Folder, Project, ProjectType, TriggerEvent, User } from '@activepieces/shared' +import { + AppConnection, + Flow, + Folder, + Project, + ProjectType, + TriggerEvent, + User, +} from '@activepieces/shared' import { ApIdSchema, BaseColumnSchemaPart } from '../database/database-common' import { Platform } from '@activepieces/ee-shared' diff --git a/packages/backend/src/app/project/project-module.ts b/packages/server/api/src/app/project/project-module.ts old mode 100755 new mode 100644 similarity index 100% rename from packages/backend/src/app/project/project-module.ts rename to packages/server/api/src/app/project/project-module.ts diff --git a/packages/backend/src/app/project/project-service.ts b/packages/server/api/src/app/project/project-service.ts old mode 100755 new mode 100644 similarity index 83% rename from packages/backend/src/app/project/project-service.ts rename to packages/server/api/src/app/project/project-service.ts index da8b4d62d9..c67fc18de5 --- a/packages/backend/src/app/project/project-service.ts +++ b/packages/server/api/src/app/project/project-service.ts @@ -1,7 +1,15 @@ import { ApId, isNil, ProjectType } from '@activepieces/shared' import { databaseConnection } from '../database/database-connection' import { ProjectEntity } from './project-entity' -import { ActivepiecesError, apId, ErrorCode, NotificationStatus, Project, ProjectId, UserId } from '@activepieces/shared' +import { + ActivepiecesError, + apId, + ErrorCode, + NotificationStatus, + Project, + ProjectId, + UserId, +} from '@activepieces/shared' const projectRepo = databaseConnection.getRepository(ProjectEntity) @@ -52,14 +60,20 @@ export const projectService = { }) }, - async addProjectToPlatform({ projectId, platformId }: AddProjectToPlatformParams): Promise { + async addProjectToPlatform({ + projectId, + platformId, + }: AddProjectToPlatformParams): Promise { await projectRepo.update(projectId, { type: ProjectType.PLATFORM_MANAGED, platformId, }) }, - async getByPlatformIdAndExternalId({ platformId, externalId }: GetByPlatformIdAndExternalIdParams): Promise { + async getByPlatformIdAndExternalId({ + platformId, + externalId, + }: GetByPlatformIdAndExternalIdParams): Promise { return projectRepo.findOneBy({ platformId, externalId, diff --git a/packages/backend/src/app/project/project-worker-controller.ts b/packages/server/api/src/app/project/project-worker-controller.ts similarity index 95% rename from packages/backend/src/app/project/project-worker-controller.ts rename to packages/server/api/src/app/project/project-worker-controller.ts index 465d1ca206..2f8e255fcf 100644 --- a/packages/backend/src/app/project/project-worker-controller.ts +++ b/packages/server/api/src/app/project/project-worker-controller.ts @@ -2,7 +2,9 @@ import { FastifyPluginAsyncTypebox } from '@fastify/type-provider-typebox' import { PrincipalType } from '@activepieces/shared' import { projectService } from './project-service' -export const projectWorkerController: FastifyPluginAsyncTypebox = async (app) => { +export const projectWorkerController: FastifyPluginAsyncTypebox = async ( + app, +) => { app.get('/', GetWorkerProjectRequest, async (req) => { const projectId = req.principal.projectId return projectService.getOneOrThrow(projectId) diff --git a/packages/backend/src/app/store-entry/store-entry-entity.ts b/packages/server/api/src/app/store-entry/store-entry-entity.ts old mode 100755 new mode 100644 similarity index 80% rename from packages/backend/src/app/store-entry/store-entry-entity.ts rename to packages/server/api/src/app/store-entry/store-entry-entity.ts index 7b5c9b616d..3967ad65ba --- a/packages/backend/src/app/store-entry/store-entry-entity.ts +++ b/packages/server/api/src/app/store-entry/store-entry-entity.ts @@ -1,5 +1,9 @@ import { EntitySchema } from 'typeorm' -import { ApIdSchema, BaseColumnSchemaPart, JSONB_COLUMN_TYPE } from '../database/database-common' +import { + ApIdSchema, + BaseColumnSchemaPart, + JSONB_COLUMN_TYPE, +} from '../database/database-common' import { StoreEntry } from '@activepieces/shared' type StoreEntrySchema = StoreEntry diff --git a/packages/backend/src/app/store-entry/store-entry.controller.ts b/packages/server/api/src/app/store-entry/store-entry.controller.ts old mode 100755 new mode 100644 similarity index 81% rename from packages/backend/src/app/store-entry/store-entry.controller.ts rename to packages/server/api/src/app/store-entry/store-entry.controller.ts index a7bd600ee5..b541ec568a --- a/packages/backend/src/app/store-entry/store-entry.controller.ts +++ b/packages/server/api/src/app/store-entry/store-entry.controller.ts @@ -1,13 +1,20 @@ import { FastifyRequest } from 'fastify' import { storeEntryService } from './store-entry.service' -import { DeletStoreEntryRequest, GetStoreEntryRequest, PrincipalType, PutStoreEntryRequest } from '@activepieces/shared' +import { + DeletStoreEntryRequest, + GetStoreEntryRequest, + PrincipalType, + PutStoreEntryRequest, +} from '@activepieces/shared' import { StatusCodes } from 'http-status-codes' import { FastifyPluginAsyncTypebox } from '@fastify/type-provider-typebox' -export const storeEntryController: FastifyPluginAsyncTypebox = async (fastify) => { +export const storeEntryController: FastifyPluginAsyncTypebox = async ( + fastify, +) => { fastify.post( '/', - { + { schema: { body: PutStoreEntryRequest, }, @@ -39,12 +46,12 @@ export const storeEntryController: FastifyPluginAsyncTypebox = async (fastify) = _reply, ) => { return storeEntryService.getOne({ - projectId: request.principal.projectId, key: request.query.key, + projectId: request.principal.projectId, + key: request.query.key, }) }, ) - fastify.delete( '/', { @@ -63,7 +70,8 @@ export const storeEntryController: FastifyPluginAsyncTypebox = async (fastify) = } else { return storeEntryService.delete({ - projectId: request.principal.projectId, key: request.query.key, + projectId: request.principal.projectId, + key: request.query.key, }) } }, diff --git a/packages/backend/src/app/store-entry/store-entry.module.ts b/packages/server/api/src/app/store-entry/store-entry.module.ts old mode 100755 new mode 100644 similarity index 78% rename from packages/backend/src/app/store-entry/store-entry.module.ts rename to packages/server/api/src/app/store-entry/store-entry.module.ts index 68084fe77e..2ce3964e00 --- a/packages/backend/src/app/store-entry/store-entry.module.ts +++ b/packages/server/api/src/app/store-entry/store-entry.module.ts @@ -1,5 +1,8 @@ import { storeEntryController } from './store-entry.controller' -import { allowWorkersOnly, entitiesMustBeOwnedByCurrentProject } from '../authentication/authorization' +import { + allowWorkersOnly, + entitiesMustBeOwnedByCurrentProject, +} from '../authentication/authorization' import { FastifyPluginAsyncTypebox } from '@fastify/type-provider-typebox' export const storeEntryModule: FastifyPluginAsyncTypebox = async (app) => { diff --git a/packages/backend/src/app/store-entry/store-entry.service.ts b/packages/server/api/src/app/store-entry/store-entry.service.ts old mode 100755 new mode 100644 similarity index 58% rename from packages/backend/src/app/store-entry/store-entry.service.ts rename to packages/server/api/src/app/store-entry/store-entry.service.ts index 7099d0e285..086ee07c44 --- a/packages/backend/src/app/store-entry/store-entry.service.ts +++ b/packages/server/api/src/app/store-entry/store-entry.service.ts @@ -1,11 +1,23 @@ -import { apId, ProjectId, PutStoreEntryRequest, StoreEntry } from '@activepieces/shared' +import { + apId, + ProjectId, + PutStoreEntryRequest, + StoreEntry, +} from '@activepieces/shared' import { databaseConnection } from '../database/database-connection' import { StoreEntryEntity } from './store-entry-entity' -const storeEntryRepo = databaseConnection.getRepository(StoreEntryEntity) +const storeEntryRepo = + databaseConnection.getRepository(StoreEntryEntity) export const storeEntryService = { - async upsert({ projectId, request }: { projectId: ProjectId, request: PutStoreEntryRequest }): Promise { + async upsert({ + projectId, + request, + }: { + projectId: ProjectId + request: PutStoreEntryRequest + }): Promise { const previousEntry = await this.getOne({ projectId, key: request.key }) if (previousEntry !== null) { await storeEntryRepo.update(previousEntry.id, request) @@ -21,13 +33,25 @@ export const storeEntryService = { return storeEntryRepo.save(entryRequest) } }, - async getOne({ projectId, key }: { projectId: ProjectId, key: string }): Promise { + async getOne({ + projectId, + key, + }: { + projectId: ProjectId + key: string + }): Promise { return storeEntryRepo.findOneBy({ projectId, key, }) }, - async delete({ projectId, key }: { projectId: ProjectId, key: string }): Promise { + async delete({ + projectId, + key, + }: { + projectId: ProjectId + key: string + }): Promise { await storeEntryRepo.delete({ projectId, key, diff --git a/packages/backend/src/app/user/user-entity.ts b/packages/server/api/src/app/user/user-entity.ts old mode 100755 new mode 100644 similarity index 100% rename from packages/backend/src/app/user/user-entity.ts rename to packages/server/api/src/app/user/user-entity.ts diff --git a/packages/backend/src/app/user/user-service.ts b/packages/server/api/src/app/user/user-service.ts old mode 100755 new mode 100644 similarity index 77% rename from packages/backend/src/app/user/user-service.ts rename to packages/server/api/src/app/user/user-service.ts index d48c3f3909..2b117d74c8 --- a/packages/backend/src/app/user/user-service.ts +++ b/packages/server/api/src/app/user/user-service.ts @@ -1,4 +1,14 @@ -import { apId, SignUpRequest, User, UserId, UserMeta, UserStatus, isNil, ActivepiecesError, ErrorCode } from '@activepieces/shared' +import { + apId, + SignUpRequest, + User, + UserId, + UserMeta, + UserStatus, + isNil, + ActivepiecesError, + ErrorCode, +} from '@activepieces/shared' import { passwordHasher } from '../authentication/lib/password-hasher' import { databaseConnection } from '../database/database-connection' import { UserEntity } from './user-entity' @@ -62,23 +72,35 @@ export const userService = { } }, - async getByPlatformAndEmail({ platformId, email }: GetByPlatformAndEmailParams): Promise { - const platformWhereQuery = platformId ? { platformId } : { platformId: IsNull() } + async getByPlatformAndEmail({ + platformId, + email, + }: GetByPlatformAndEmailParams): Promise { + const platformWhereQuery = platformId + ? { platformId } + : { platformId: IsNull() } - return userRepo.createQueryBuilder() + return userRepo + .createQueryBuilder() .where(platformWhereQuery) .andWhere('LOWER(email) = LOWER(:email)', { email }) .getOne() }, - async getByPlatformAndExternalId({ platformId, externalId }: GetByPlatformAndExternalIdParams): Promise { + async getByPlatformAndExternalId({ + platformId, + externalId, + }: GetByPlatformAndExternalIdParams): Promise { return userRepo.findOneBy({ platformId, externalId, }) }, - async updatePassword({ id, newPassword }: UpdatePasswordParams): Promise { + async updatePassword({ + id, + newPassword, + }: UpdatePasswordParams): Promise { const hashedPassword = await passwordHasher.hash(newPassword) await userRepo.update(id, { @@ -87,7 +109,10 @@ export const userService = { }) }, - async updatePlatformId({ id, platformId }: UpdatePlatformIdParams): Promise { + async updatePlatformId({ + id, + platformId, + }: UpdatePlatformIdParams): Promise { await userRepo.update(id, { updated: dayjs().toISOString(), platformId, diff --git a/packages/backend/src/app/user/user.module.ts b/packages/server/api/src/app/user/user.module.ts old mode 100755 new mode 100644 similarity index 61% rename from packages/backend/src/app/user/user.module.ts rename to packages/server/api/src/app/user/user.module.ts index cd32dd4dd0..95d37dd9c2 --- a/packages/backend/src/app/user/user.module.ts +++ b/packages/server/api/src/app/user/user.module.ts @@ -7,15 +7,10 @@ export const userModule: FastifyPluginAsyncTypebox = async (app) => { } const usersController: FastifyPluginAsyncTypebox = async (app) => { - - app.get( - '/me', - async (request: FastifyRequest) => { - const user = await userService.getMetaInfo({ - id: request.principal.id, - }) - return user - }, - ) - -} \ No newline at end of file + app.get('/me', async (request: FastifyRequest) => { + const user = await userService.getMetaInfo({ + id: request.principal.id, + }) + return user + }) +} diff --git a/packages/backend/src/app/webhooks/webhook-controller.ts b/packages/server/api/src/app/webhooks/webhook-controller.ts similarity index 74% rename from packages/backend/src/app/webhooks/webhook-controller.ts rename to packages/server/api/src/app/webhooks/webhook-controller.ts index 0353e5859e..2619a81d24 100644 --- a/packages/backend/src/app/webhooks/webhook-controller.ts +++ b/packages/server/api/src/app/webhooks/webhook-controller.ts @@ -1,8 +1,17 @@ import { FastifyReply, FastifyRequest } from 'fastify' import { StatusCodes } from 'http-status-codes' -import { ALL_PRINICPAL_TYPES, ActivepiecesError, ApEdition, ErrorCode, EventPayload, Flow, FlowId, FlowStatus, WebhookUrlParams } from '@activepieces/shared' +import { + ALL_PRINICPAL_TYPES, + ActivepiecesError, + ApEdition, + ErrorCode, + EventPayload, + Flow, + FlowId, + FlowStatus, + WebhookUrlParams, +} from '@activepieces/shared' import { webhookService } from './webhook-service' -import { captureException, logger } from '../helper/logger' import { isNil } from '@activepieces/shared' import { flowRepo } from '../flows/flow/flow.repo' import { FastifyPluginAsyncTypebox } from '@fastify/type-provider-typebox' @@ -10,9 +19,9 @@ import { getEdition } from '../helper/secret-helper' import { tasksLimit } from '../ee/billing/limits/tasks-limit' import { flowResponseWatcher } from '../flows/flow-run/flow-response-watcher' import { flowService } from '../flows/flow/flow.service' +import { exceptionHandler, logger } from 'server-shared' export const webhookController: FastifyPluginAsyncTypebox = async (app) => { - app.all( '/:flowId/sync', { @@ -30,22 +39,27 @@ export const webhookController: FastifyPluginAsyncTypebox = async (app) => { if (isHandshake) { return } - const run = (await webhookService.callback({ - flow, - synchronousHandlerId: flowResponseWatcher.getHandlerId(), - payload: { - method: request.method, - headers: request.headers as Record, - body: await convertBody(request), - queryParams: request.query as Record, - }, - }))[0] + const run = ( + await webhookService.callback({ + flow, + synchronousHandlerId: flowResponseWatcher.getHandlerId(), + payload: { + method: request.method, + headers: request.headers as Record, + body: await convertBody(request), + queryParams: request.query as Record, + }, + }) + )[0] if (isNil(run)) { await reply.status(StatusCodes.NOT_FOUND).send() return } const response = await flowResponseWatcher.listen(run.id) - await reply.status(response.status).headers(response.headers).send(response.body) + await reply + .status(response.status) + .headers(response.headers) + .send(response.body) }, ) @@ -66,8 +80,7 @@ export const webhookController: FastifyPluginAsyncTypebox = async (app) => { if (isHandshake) { return } - asyncHandler(payload, flow) - .catch(captureException) + asyncHandler(payload, flow).catch(exceptionHandler.handle) await reply.status(StatusCodes.OK).headers({}).send({}) }, ) @@ -82,15 +95,17 @@ export const webhookController: FastifyPluginAsyncTypebox = async (app) => { querystring: WebhookUrlParams, }, }, - async (request: FastifyRequest<{ Querystring: WebhookUrlParams }>, reply) => { + async ( + request: FastifyRequest<{ Querystring: WebhookUrlParams }>, + reply, + ) => { const flow = await getFlowOrThrow(request.query.flowId) const payload = await convertRequest(request) const isHandshake = await handshakeHandler(flow, payload, false, reply) if (isHandshake) { return } - asyncHandler(payload, flow) - .catch(captureException) + asyncHandler(payload, flow).catch(exceptionHandler.handle) await reply.status(StatusCodes.OK).send() }, ) @@ -106,7 +121,9 @@ export const webhookController: FastifyPluginAsyncTypebox = async (app) => { }, }, async (request: FastifyRequest<{ Params: WebhookUrlParams }>, reply) => { - logger.debug(`[WebhookController#simulate] flowId=${request.params.flowId}`) + logger.debug( + `[WebhookController#simulate] flowId=${request.params.flowId}`, + ) const flow = await getFlowOrThrow(request.params.flowId) const payload = await convertRequest(request) const isHandshake = await handshakeHandler(flow, payload, true, reply) @@ -141,10 +158,13 @@ async function convertRequest(request: FastifyRequest): Promise { const convertBody = async (request: FastifyRequest): Promise => { if (request.isMultipart()) { const jsonResult: Record = {} - const requestBodyEntries = Object.entries(request.body as Record) + const requestBodyEntries = Object.entries( + request.body as Record, + ) for (const [key, value] of requestBodyEntries) { - jsonResult[key] = value instanceof Buffer ? value.toString('base64') : value + jsonResult[key] = + value instanceof Buffer ? value.toString('base64') : value } logger.debug({ name: 'WebhookController#convertBody', jsonResult }) @@ -152,10 +172,14 @@ const convertBody = async (request: FastifyRequest): Promise => { return jsonResult } return request.body - } -async function handshakeHandler(flow: Flow, payload: EventPayload, simulate: boolean, reply: FastifyReply): Promise { +async function handshakeHandler( + flow: Flow, + payload: EventPayload, + simulate: boolean, + reply: FastifyReply, +): Promise { const handshakeResponse = await webhookService.handshake({ flow, payload, @@ -165,7 +189,10 @@ async function handshakeHandler(flow: Flow, payload: EventPayload, simulate: boo reply = reply.status(handshakeResponse.status) if (handshakeResponse.headers !== undefined) { for (const header of Object.keys(handshakeResponse.headers)) { - reply = reply.header(header, handshakeResponse.headers[header] as string) + reply = reply.header( + header, + handshakeResponse.headers[header] as string, + ) } } await reply.send(handshakeResponse.body) @@ -195,7 +222,9 @@ const getFlowOrThrow = async (flowId: FlowId): Promise => { const flow = await flowRepo().findOneBy({ id: flowId }) if (isNil(flow)) { - logger.error(`[WebhookService#getFlowOrThrow] error=flow_not_found flowId=${flowId}`) + logger.error( + `[WebhookService#getFlowOrThrow] error=flow_not_found flowId=${flowId}`, + ) throw new ActivepiecesError({ code: ErrorCode.FLOW_NOT_FOUND, @@ -215,8 +244,13 @@ const getFlowOrThrow = async (flowId: FlowId): Promise => { }) } catch (e) { - if (e instanceof ActivepiecesError && e.error.code === ErrorCode.QUOTA_EXCEEDED) { - logger.info(`[webhookController] removing flow.id=${flow.id} run out of flow quota`) + if ( + e instanceof ActivepiecesError && + e.error.code === ErrorCode.QUOTA_EXCEEDED + ) { + logger.info( + `[webhookController] removing flow.id=${flow.id} run out of flow quota`, + ) await flowService.updateStatus({ id: flow.id, projectId: flow.projectId, diff --git a/packages/backend/src/app/webhooks/webhook-module.ts b/packages/server/api/src/app/webhooks/webhook-module.ts similarity index 76% rename from packages/backend/src/app/webhooks/webhook-module.ts rename to packages/server/api/src/app/webhooks/webhook-module.ts index 7e2d3806d2..01ad469a8e 100644 --- a/packages/backend/src/app/webhooks/webhook-module.ts +++ b/packages/server/api/src/app/webhooks/webhook-module.ts @@ -4,5 +4,7 @@ import { webhookSimulationController } from './webhook-simulation/webhook-simula export const webhookModule: FastifyPluginAsync = async (app) => { await app.register(webhookController, { prefix: '/v1/webhooks' }) - await app.register(webhookSimulationController, { prefix: '/v1/webhook-simulation' }) + await app.register(webhookSimulationController, { + prefix: '/v1/webhook-simulation', + }) } diff --git a/packages/backend/src/app/webhooks/webhook-service.ts b/packages/server/api/src/app/webhooks/webhook-service.ts similarity index 79% rename from packages/backend/src/app/webhooks/webhook-service.ts rename to packages/server/api/src/app/webhooks/webhook-service.ts index 23d25d3416..0d7889ea86 100644 --- a/packages/backend/src/app/webhooks/webhook-service.ts +++ b/packages/server/api/src/app/webhooks/webhook-service.ts @@ -15,7 +15,7 @@ import { ActivepiecesError, ErrorCode } from '@activepieces/shared' import { getServerUrl } from '../helper/network-utils' import { triggerEventService } from '../flows/trigger-events/trigger-event.service' import { isNil } from '@activepieces/shared' -import { logger } from '../helper/logger' +import { logger } from 'server-shared' import { webhookSimulationService } from './webhook-simulation/webhook-simulation-service' import { WebhookResponse } from '@activepieces/pieces-framework' import { flowService } from '../flows/flow/flow.service' @@ -30,7 +30,15 @@ export const webhookService = { logger.info(`[WebhookService#handshake] flowId=${flow.id}`) const { projectId } = flow - const flowVersionId = simulate ? (await flowVersionService.getFlowVersionOrThrow({ flowId: flow.id, versionId: undefined, removeSecrets: false })).id : flow.publishedVersionId + const flowVersionId = simulate + ? ( + await flowVersionService.getFlowVersionOrThrow({ + flowId: flow.id, + versionId: undefined, + removeSecrets: false, + }) + ).id + : flow.publishedVersionId if (isNil(flowVersionId)) { logger.info( `[WebhookService#handshake] flowInstance not found, flowId=${flow.id}`, @@ -51,7 +59,11 @@ export const webhookService = { } return response }, - async callback({ flow, payload, synchronousHandlerId }: SyncParams): Promise { + async callback({ + flow, + payload, + synchronousHandlerId, + }: SyncParams): Promise { logger.info(`[WebhookService#callback] flowId=${flow.id}`) const { projectId } = flow @@ -60,10 +72,12 @@ export const webhookService = { logger.info( `[WebhookService#callback] flowInstance not found, flowId=${flow.id}`, ) - const flowVersion = (await flowService.getOnePopulatedOrThrow({ - projectId, - id: flow.id, - })).version + const flowVersion = ( + await flowService.getOnePopulatedOrThrow({ + projectId, + id: flow.id, + }) + ).version const payloads: unknown[] = await triggerHooks.executeTrigger({ projectId, flowVersion, @@ -81,7 +95,9 @@ export const webhookService = { ) return [] } - const flowVersion = await flowVersionService.getOneOrThrow(flow.publishedVersionId) + const flowVersion = await flowVersionService.getOneOrThrow( + flow.publishedVersionId, + ) const payloads: unknown[] = await triggerHooks.executeTrigger({ projectId, flowVersion, @@ -90,12 +106,18 @@ export const webhookService = { }) payloads.forEach((payload) => { - triggerEventService.saveEvent({ - flowId: flow.id, - payload, - projectId, - }) - .catch((e) => logger.error(e, '[WebhookService#callback] triggerEventService.saveEvent')) + triggerEventService + .saveEvent({ + flowId: flow.id, + payload, + projectId, + }) + .catch((e) => + logger.error( + e, + '[WebhookService#callback] triggerEventService.saveEvent', + ), + ) }) const createFlowRuns = payloads.map((payload) => @@ -185,16 +207,19 @@ const getLatestFlowVersionOrThrow = async ( return flowVersion } -function saveSampleDataForWebhookTesting( - flow: Flow, - payload: unknown, -): void { - triggerEventService.saveEvent({ - flowId: flow.id, - payload, - projectId: flow.projectId, - }) - .catch((e) => logger.error(e, '[WebhookService#saveSampleDataForWebhookTesting] triggerEventService.saveEvent')) +function saveSampleDataForWebhookTesting(flow: Flow, payload: unknown): void { + triggerEventService + .saveEvent({ + flowId: flow.id, + payload, + projectId: flow.projectId, + }) + .catch((e) => + logger.error( + e, + '[WebhookService#saveSampleDataForWebhookTesting] triggerEventService.saveEvent', + ), + ) } type WebhookUrlSuffix = '' | '/simulate' @@ -215,7 +240,6 @@ type HandshakeParams = { simulate: boolean } - type SyncParams = { flow: Flow payload: EventPayload diff --git a/packages/backend/src/app/webhooks/webhook-simulation/webhook-simulation-controller.ts b/packages/server/api/src/app/webhooks/webhook-simulation/webhook-simulation-controller.ts similarity index 91% rename from packages/backend/src/app/webhooks/webhook-simulation/webhook-simulation-controller.ts rename to packages/server/api/src/app/webhooks/webhook-simulation/webhook-simulation-controller.ts index 168417c824..fd8b0c40bf 100644 --- a/packages/backend/src/app/webhooks/webhook-simulation/webhook-simulation-controller.ts +++ b/packages/server/api/src/app/webhooks/webhook-simulation/webhook-simulation-controller.ts @@ -1,8 +1,15 @@ -import { FastifyPluginCallbackTypebox, Type } from '@fastify/type-provider-typebox' +import { + FastifyPluginCallbackTypebox, + Type, +} from '@fastify/type-provider-typebox' import { webhookSimulationService } from './webhook-simulation-service' import { ALL_PRINICPAL_TYPES } from '@activepieces/shared' -export const webhookSimulationController: FastifyPluginCallbackTypebox = (app, _opts, done) => { +export const webhookSimulationController: FastifyPluginCallbackTypebox = ( + app, + _opts, + done, +) => { app.post('/', CreateWebhookSimulationRequest, async (req) => { const { flowId } = req.body const { projectId } = req.principal diff --git a/packages/server/api/src/app/webhooks/webhook-simulation/webhook-simulation-entity.ts b/packages/server/api/src/app/webhooks/webhook-simulation/webhook-simulation-entity.ts new file mode 100644 index 0000000000..05670ffa6a --- /dev/null +++ b/packages/server/api/src/app/webhooks/webhook-simulation/webhook-simulation-entity.ts @@ -0,0 +1,25 @@ +import { EntitySchema } from 'typeorm' +import { WebhookSimulation } from '@activepieces/shared' +import { + ApIdSchema, + BaseColumnSchemaPart, +} from '../../database/database-common' + +export type WebhookSimulationSchema = WebhookSimulation + +export const WebhookSimulationEntity = + new EntitySchema({ + name: 'webhook_simulation', + columns: { + ...BaseColumnSchemaPart, + flowId: ApIdSchema, + projectId: ApIdSchema, + }, + indices: [ + { + name: 'idx_webhook_simulation_flow_id', + columns: ['flowId'], + unique: true, + }, + ], + }) diff --git a/packages/backend/src/app/webhooks/webhook-simulation/webhook-simulation-service.ts b/packages/server/api/src/app/webhooks/webhook-simulation/webhook-simulation-service.ts similarity index 88% rename from packages/backend/src/app/webhooks/webhook-simulation/webhook-simulation-service.ts rename to packages/server/api/src/app/webhooks/webhook-simulation/webhook-simulation-service.ts index 6a5732e5b8..c23f3b9fc6 100644 --- a/packages/backend/src/app/webhooks/webhook-simulation/webhook-simulation-service.ts +++ b/packages/server/api/src/app/webhooks/webhook-simulation/webhook-simulation-service.ts @@ -1,10 +1,17 @@ import { FlowVersionId, isNil } from '@activepieces/shared' -import { ActivepiecesError, apId, ErrorCode, FlowId, ProjectId, WebhookSimulation } from '@activepieces/shared' +import { + ActivepiecesError, + apId, + ErrorCode, + FlowId, + ProjectId, + WebhookSimulation, +} from '@activepieces/shared' import { acquireLock, ApLock } from '../../helper/lock' import { databaseConnection } from '../../database/database-connection' import { WebhookSimulationEntity } from './webhook-simulation-entity' import { webhookSideEffects } from './webhook-simulation-side-effects' -import { logger } from '../../helper/logger' +import { logger } from 'server-shared' type BaseParams = { flowId: FlowId @@ -28,7 +35,9 @@ const createLock = async ({ flowId }: AcquireLockParams): Promise => { return acquireLock({ key, timeout: 5000 }) } -const webhookSimulationRepo = databaseConnection.getRepository(WebhookSimulationEntity) +const webhookSimulationRepo = databaseConnection.getRepository( + WebhookSimulationEntity, +) export const webhookSimulationService = { async create(params: CreateParams): Promise { @@ -41,7 +50,9 @@ export const webhookSimulationService = { }) try { - const webhookSimulationExists = await webhookSimulationRepo.exist({ where: { flowId } }) + const webhookSimulationExists = await webhookSimulationRepo.exist({ + where: { flowId }, + }) if (webhookSimulationExists) { await this.delete({ @@ -52,10 +63,11 @@ export const webhookSimulationService = { }) } - const webhookSimulation: Omit = { - id: apId(), - ...params, - } + const webhookSimulation: Omit = + { + id: apId(), + ...params, + } await webhookSideEffects.preCreate({ flowId, diff --git a/packages/backend/src/app/webhooks/webhook-simulation/webhook-simulation-side-effects.ts b/packages/server/api/src/app/webhooks/webhook-simulation/webhook-simulation-side-effects.ts similarity index 80% rename from packages/backend/src/app/webhooks/webhook-simulation/webhook-simulation-side-effects.ts rename to packages/server/api/src/app/webhooks/webhook-simulation/webhook-simulation-side-effects.ts index 56a687e7e5..868c2ac2da 100644 --- a/packages/backend/src/app/webhooks/webhook-simulation/webhook-simulation-side-effects.ts +++ b/packages/server/api/src/app/webhooks/webhook-simulation/webhook-simulation-side-effects.ts @@ -1,4 +1,12 @@ -import { ActivepiecesError, EngineResponseStatus, ErrorCode, FlowId, FlowVersionId, PopulatedFlow, ProjectId } from '@activepieces/shared' +import { + ActivepiecesError, + EngineResponseStatus, + ErrorCode, + FlowId, + FlowVersionId, + PopulatedFlow, + ProjectId, +} from '@activepieces/shared' import { flowService } from '../../flows/flow/flow.service' import { isNil } from '@activepieces/shared' import { triggerHooks } from '../../flows/trigger' @@ -13,7 +21,11 @@ type GetFlowParams = BaseParams type PreCreateParams = BaseParams type PreDeleteParams = BaseParams -const getFlowOrThrow = async ({ projectId, flowId, flowVersionId }: GetFlowParams): Promise => { +const getFlowOrThrow = async ({ + projectId, + flowId, + flowVersionId, +}: GetFlowParams): Promise => { return flowService.getOnePopulatedOrThrow({ id: flowId, projectId, @@ -44,7 +56,11 @@ export const webhookSideEffects = { } }, - async preDelete({ projectId, flowId, flowVersionId }: PreDeleteParams): Promise { + async preDelete({ + projectId, + flowId, + flowVersionId, + }: PreDeleteParams): Promise { const { version: flowVersion } = await getFlowOrThrow({ flowId, projectId, diff --git a/packages/backend/src/app/websockets/websockets.service.ts b/packages/server/api/src/app/websockets/websockets.service.ts similarity index 94% rename from packages/backend/src/app/websockets/websockets.service.ts rename to packages/server/api/src/app/websockets/websockets.service.ts index e6599cfb05..33e17032a5 100644 --- a/packages/backend/src/app/websockets/websockets.service.ts +++ b/packages/server/api/src/app/websockets/websockets.service.ts @@ -1,5 +1,5 @@ import { Socket } from 'socket.io' -import { logger } from '../helper/logger' +import { logger } from 'server-shared' import { flowRunService } from '../flows/flow-run/flow-run-service' import { flowResponseWatcher } from '../flows/flow-run/flow-response-watcher' @@ -21,4 +21,4 @@ export const websocketService = { socket.emit('flowRunFinished', flowRun) }) }, -} \ No newline at end of file +} diff --git a/packages/backend/src/app/workers/flow-worker/flow-queue-consumer.ts b/packages/server/api/src/app/workers/flow-worker/flow-queue-consumer.ts similarity index 85% rename from packages/backend/src/app/workers/flow-worker/flow-queue-consumer.ts rename to packages/server/api/src/app/workers/flow-worker/flow-queue-consumer.ts index 6b2853475e..69d83e12dc 100644 --- a/packages/backend/src/app/workers/flow-worker/flow-queue-consumer.ts +++ b/packages/server/api/src/app/workers/flow-worker/flow-queue-consumer.ts @@ -18,16 +18,13 @@ import { RepeatingJobData, ScheduledJobData, } from './job-data' -import { captureException, logger } from '../../helper/logger' import { flowVersionService } from '../../flows/flow-version/flow-version.service' import { isNil } from '@activepieces/shared' import { consumeJobsInMemory } from './queues/memory/memory-consumer' import { inMemoryQueueManager } from './queues/memory/memory-queue' import { redisConsumer } from './queues/redis/redis-consumer' import { redisQueueManager } from './queues/redis/redis-queue' -import { QueueMode, system } from '../../helper/system/system' -import { SystemProp } from '../../helper/system/system-prop' -import { enrichErrorContext } from '../../helper/error-handler' +import { QueueMode, SystemProp, enrichErrorContext, exceptionHandler, logger, system } from 'server-shared' import { flowService } from '../../flows/flow/flow.service' import { triggerHooks } from '../../flows/trigger' @@ -37,8 +34,9 @@ const initFlowQueueConsumer = async (): Promise => { switch (queueMode) { case QueueMode.MEMORY: { await inMemoryQueueManager.init() - consumeJobsInMemory() - .catch((e) => logger.error(e, '[FlowQueueConsumer#init] consumeJobsInMemory')) + consumeJobsInMemory().catch((e) => + logger.error(e, '[FlowQueueConsumer#init] consumeJobsInMemory'), + ) break } case QueueMode.REDIS: { @@ -96,19 +94,24 @@ async function consumeScheduledJobs(data: ScheduledJobData): Promise { } } catch (e) { - captureException(e) + exceptionHandler.handle(e) } } -const consumeRenewWebhookJob = async (data: RenewWebhookJobData): Promise => { - logger.info(`[FlowQueueConsumer#consumeRenewWebhookJob] flowVersionId=${data.flowVersionId}`) - const flowVersion = await flowVersionService.getOneOrThrow(data.flowVersionId) +const consumeRenewWebhookJob = async ( + data: RenewWebhookJobData, +): Promise => { + logger.info( + `[FlowQueueConsumer#consumeRenewWebhookJob] flowVersionId=${data.flowVersionId}`, + ) + const flowVersion = await flowVersionService.getOneOrThrow( + data.flowVersionId, + ) await triggerHooks.renewWebhook({ flowVersion, projectId: data.projectId, simulate: false, }) - } const consumeDelayedJob = async (data: DelayedJobData): Promise => { logger.info(`[FlowQueueConsumer#consumeDelayedJob] flowRunId=${data.runId}`) @@ -125,17 +128,18 @@ const consumeDelayedJob = async (data: DelayedJobData): Promise => { const consumeRepeatingJob = async (data: RepeatingJobData): Promise => { try { - // TODO REMOVE AND FIND PERMANENT SOLUTION + // TODO REMOVE AND FIND PERMANENT SOLUTION const flow = await flowService.getOne({ id: data.flowId, projectId: data.projectId, }) - if (isNil(flow) || - flow.status !== FlowStatus.ENABLED || - flow.publishedVersionId !== data.flowVersionId + if ( + isNil(flow) || + flow.status !== FlowStatus.ENABLED || + flow.publishedVersionId !== data.flowVersionId ) { - captureException( + exceptionHandler.handle( new Error( `[repeatableJobConsumer] removing project.id=${data.projectId} instance.flowVersionId=${flow?.publishedVersionId} data.flowVersion.id=${data.flowVersionId}`, ), @@ -166,7 +170,7 @@ const consumeRepeatingJob = async (data: RepeatingJobData): Promise => { catch (e) { if ( e instanceof ActivepiecesError && - e.error.code === ErrorCode.QUOTA_EXCEEDED + e.error.code === ErrorCode.QUOTA_EXCEEDED ) { logger.info( `[repeatableJobConsumer] removing project.id=${data.projectId} run out of flow quota`, @@ -178,7 +182,7 @@ const consumeRepeatingJob = async (data: RepeatingJobData): Promise => { }) } else { - captureException(e) + exceptionHandler.handle(e) } } } @@ -212,7 +216,6 @@ const consumePieceTrigger = async (data: RepeatingJobData): Promise => { await Promise.all(createFlowRuns) } - export const flowQueueConsumer = { consumeOnetimeJob, consumeScheduledJobs, diff --git a/packages/server/api/src/app/workers/flow-worker/flow-queue.ts b/packages/server/api/src/app/workers/flow-worker/flow-queue.ts new file mode 100644 index 0000000000..57abb5e0f8 --- /dev/null +++ b/packages/server/api/src/app/workers/flow-worker/flow-queue.ts @@ -0,0 +1,7 @@ +import { QueueMode, SystemProp, system } from 'server-shared' +import { inMemoryQueueManager } from './queues/memory/memory-queue' +import { redisQueueManager } from './queues/redis/redis-queue' + +const queueMode = system.get(SystemProp.QUEUE_MODE) +export const flowQueue = + queueMode === QueueMode.MEMORY ? inMemoryQueueManager : redisQueueManager diff --git a/packages/backend/src/app/workers/flow-worker/flow-worker-hooks.ts b/packages/server/api/src/app/workers/flow-worker/flow-worker-hooks.ts similarity index 65% rename from packages/backend/src/app/workers/flow-worker/flow-worker-hooks.ts rename to packages/server/api/src/app/workers/flow-worker/flow-worker-hooks.ts index 4d1b734c5f..60fb44eff0 100644 --- a/packages/backend/src/app/workers/flow-worker/flow-worker-hooks.ts +++ b/packages/server/api/src/app/workers/flow-worker/flow-worker-hooks.ts @@ -1,11 +1,16 @@ - export type FlowWorkerHooks = { - preExecute({ projectId, runId }: { projectId: string, runId: string }): Promise + preExecute({ + projectId, + runId, + }: { + projectId: string + runId: string + }): Promise } const emptyHooks: FlowWorkerHooks = { async preExecute() { - // DO NOTHING + // DO NOTHING }, } @@ -18,4 +23,4 @@ export const flowWorkerHooks = { getHooks() { return hooks }, -} \ No newline at end of file +} diff --git a/packages/backend/src/app/workers/flow-worker/flow-worker-module.ts b/packages/server/api/src/app/workers/flow-worker/flow-worker-module.ts similarity index 99% rename from packages/backend/src/app/workers/flow-worker/flow-worker-module.ts rename to packages/server/api/src/app/workers/flow-worker/flow-worker-module.ts index b81c78e08f..ff01532b27 100644 --- a/packages/backend/src/app/workers/flow-worker/flow-worker-module.ts +++ b/packages/server/api/src/app/workers/flow-worker/flow-worker-module.ts @@ -3,4 +3,3 @@ import { flowQueueConsumer } from './flow-queue-consumer' export const flowWorkerModule = async (): Promise => { await flowQueueConsumer.init() } - diff --git a/packages/backend/src/app/workers/flow-worker/flow-worker.ts b/packages/server/api/src/app/workers/flow-worker/flow-worker.ts old mode 100755 new mode 100644 similarity index 65% rename from packages/backend/src/app/workers/flow-worker/flow-worker.ts rename to packages/server/api/src/app/workers/flow-worker/flow-worker.ts index e90fc0bf6b..e6bfd4d2db --- a/packages/backend/src/app/workers/flow-worker/flow-worker.ts +++ b/packages/server/api/src/app/workers/flow-worker/flow-worker.ts @@ -26,21 +26,24 @@ import { Trigger, TriggerType, } from '@activepieces/shared' -import { Sandbox } from '../sandbox' +import { Sandbox } from 'server-worker' import { flowVersionService } from '../../flows/flow-version/flow-version.service' import { fileService } from '../../file/file.service' -import { flowRunService, HookType } from '../../flows/flow-run/flow-run-service' +import { + flowRunService, + HookType, +} from '../../flows/flow-run/flow-run-service' import { OneTimeJobData } from './job-data' import { engineHelper } from '../../helper/engine-helper' -import { captureException, logger } from '../../helper/logger' import { isNil } from '@activepieces/shared' import { MAX_LOG_SIZE } from '@activepieces/shared' import { sandboxProvisioner } from '../sandbox/provisioner/sandbox-provisioner' import { SandBoxCacheType } from '../sandbox/provisioner/sandbox-cache-key' import { flowWorkerHooks } from './flow-worker-hooks' -import { logSerializer } from '../../flows/common/log-serializer' import { flowResponseWatcher } from '../../flows/flow-run/flow-response-watcher' import { getPiecePackage } from '../../pieces/piece-metadata-service' +import { exceptionHandler, logger } from 'server-shared' +import { logSerializer } from 'server-worker' type FinishExecutionParams = { flowRunId: FlowRunId @@ -54,30 +57,39 @@ type LoadInputAndLogFileIdParams = { } type LoadInputAndLogFileIdResponse = { - input: Omit | Omit + input: + | Omit + | Omit logFileId?: FileId | undefined } -const extractFlowPieces = async ({ projectId, flowVersion }: ExtractFlowPiecesParams): Promise => { +const extractFlowPieces = async ({ + projectId, + flowVersion, +}: ExtractFlowPiecesParams): Promise => { const pieces: PiecePackage[] = [] const steps = flowHelper.getAllSteps(flowVersion.trigger) for (const step of steps) { if (step.type === TriggerType.PIECE || step.type === ActionType.PIECE) { const { packageType, pieceType, pieceName, pieceVersion } = step.settings - pieces.push(await getPiecePackage(projectId, { - packageType, - pieceType, - pieceName, - pieceVersion, - })) + pieces.push( + await getPiecePackage(projectId, { + packageType, + pieceType, + pieceName, + pieceVersion, + }), + ) } } return pieces } -const finishExecution = async (params: FinishExecutionParams): Promise => { +const finishExecution = async ( + params: FinishExecutionParams, +): Promise => { logger.trace(params, '[FlowWorker#finishExecution] params') const { flowRunId, logFileId, executionOutput } = params @@ -101,12 +113,17 @@ const finishExecution = async (params: FinishExecutionParams): Promise => } } -const getTerminalStatus = (executionOutputStatus: ExecutionOutputStatus): ExecutionOutputStatus => { - return executionOutputStatus == ExecutionOutputStatus.STOPPED ? ExecutionOutputStatus.SUCCEEDED : executionOutputStatus +const getTerminalStatus = ( + executionOutputStatus: ExecutionOutputStatus, +): ExecutionOutputStatus => { + return executionOutputStatus == ExecutionOutputStatus.STOPPED + ? ExecutionOutputStatus.SUCCEEDED + : executionOutputStatus } - -const getTerminationReason = (executionOutput: ExecutionOutput): RunTerminationReason | undefined => { +const getTerminationReason = ( + executionOutput: ExecutionOutput, +): RunTerminationReason | undefined => { if (executionOutput.status === ExecutionOutputStatus.STOPPED) { return RunTerminationReason.STOPPED_BY_HOOK } @@ -161,8 +178,13 @@ const loadInputAndLogFileId = async ({ logsFileId: flowRun.logsFileId, projectId: jobData.projectId, }) - const trigger = Object.values(executionOutput.executionState.steps).find((step) => flowHelper.isTrigger(step.type)) - assertNotNullOrUndefined(trigger, 'Trigger not found in execution state') + const trigger = Object.values( + executionOutput.executionState.steps, + ).find((step) => flowHelper.isTrigger(step.type)) + assertNotNullOrUndefined( + trigger, + 'Trigger not found in execution state', + ) jobData.payload = trigger.output } return { @@ -175,7 +197,13 @@ const loadInputAndLogFileId = async ({ } } -async function loadPayload({ logsFileId, projectId }: { logsFileId: string, projectId: string }): Promise { +async function loadPayload({ + logsFileId, + projectId, +}: { + logsFileId: string + projectId: string +}): Promise { const logFile = await fileService.getOneOrThrow({ fileId: logsFileId, projectId, @@ -189,11 +217,15 @@ async function loadPayload({ logsFileId, projectId }: { logsFileId: string, proj } async function executeFlow(jobData: OneTimeJobData): Promise { - logger.info(`[FlowWorker#executeFlow] flowRunId=${jobData.runId} executionType=${jobData.executionType}`) + logger.info( + `[FlowWorker#executeFlow] flowRunId=${jobData.runId} executionType=${jobData.executionType}`, + ) const startTime = Date.now() - const flowVersionWithLockedPieces = await flowVersionService.getOne(jobData.flowVersionId) + const flowVersionWithLockedPieces = await flowVersionService.getOne( + jobData.flowVersionId, + ) if (isNil(flowVersionWithLockedPieces)) { logger.info({ @@ -207,11 +239,11 @@ async function executeFlow(jobData: OneTimeJobData): Promise { flowVersion: flowVersionWithLockedPieces, }) - await flowWorkerHooks.getHooks().preExecute({ projectId: jobData.projectId, runId: jobData.runId }) - + await flowWorkerHooks + .getHooks() + .preExecute({ projectId: jobData.projectId, runId: jobData.runId }) try { - const { input, logFileId } = await loadInputAndLogFileId({ flowVersion, jobData, @@ -223,15 +255,26 @@ async function executeFlow(jobData: OneTimeJobData): Promise { runEnvironment: jobData.environment, }) - logger.info(`[FlowWorker#executeFlow] flowRunId=${jobData.runId} sandboxId=${sandbox.boxId} prepareTime=${Date.now() - startTime}ms`) + logger.info( + `[FlowWorker#executeFlow] flowRunId=${jobData.runId} sandboxId=${ + sandbox.boxId + } prepareTime=${Date.now() - startTime}ms`, + ) const { result: executionOutput } = await engineHelper.executeFlow( sandbox, input, ) - if (jobData.synchronousHandlerId && jobData.hookType === HookType.BEFORE_LOG) { - await flowResponseWatcher.publish(jobData.runId, jobData.synchronousHandlerId, executionOutput) + if ( + jobData.synchronousHandlerId && + jobData.hookType === HookType.BEFORE_LOG + ) { + await flowResponseWatcher.publish( + jobData.runId, + jobData.synchronousHandlerId, + executionOutput, + ) } const logsFile = await saveToLogFile({ @@ -246,21 +289,42 @@ async function executeFlow(jobData: OneTimeJobData): Promise { executionOutput, }) - if (jobData.synchronousHandlerId && jobData.hookType === HookType.AFTER_LOG) { - await flowResponseWatcher.publish(jobData.runId, jobData.synchronousHandlerId, executionOutput) + if ( + jobData.synchronousHandlerId && + jobData.hookType === HookType.AFTER_LOG + ) { + await flowResponseWatcher.publish( + jobData.runId, + jobData.synchronousHandlerId, + executionOutput, + ) } logger.info( - `[FlowWorker#executeFlow] flowRunId=${jobData.runId - } executionOutputStatus=${executionOutput.status} sandboxId=${sandbox.boxId + `[FlowWorker#executeFlow] flowRunId=${ + jobData.runId + } executionOutputStatus=${executionOutput.status} sandboxId=${ + sandbox.boxId } duration=${Date.now() - startTime} ms`, ) } catch (e: unknown) { - if (e instanceof ActivepiecesError && (e as ActivepiecesError).error.code === ErrorCode.QUOTA_EXCEEDED) { - await flowRunService.finish({ flowRunId: jobData.runId, status: ExecutionOutputStatus.QUOTA_EXCEEDED, tasks: 0, logsFileId: null, tags: [] }) + if ( + e instanceof ActivepiecesError && + (e as ActivepiecesError).error.code === ErrorCode.QUOTA_EXCEEDED + ) { + await flowRunService.finish({ + flowRunId: jobData.runId, + status: ExecutionOutputStatus.QUOTA_EXCEEDED, + tasks: 0, + logsFileId: null, + tags: [], + }) } - else if (e instanceof ActivepiecesError && e.error.code === ErrorCode.EXECUTION_TIMEOUT) { + else if ( + e instanceof ActivepiecesError && + e.error.code === ErrorCode.EXECUTION_TIMEOUT + ) { await flowRunService.finish({ flowRunId: jobData.runId, status: ExecutionOutputStatus.TIMEOUT, @@ -284,17 +348,30 @@ async function executeFlow(jobData: OneTimeJobData): Promise { } function throwErrorToRetry(error: Error, runId: string): void { - captureException(error) - logger.error(error, '[FlowWorker#executeFlow] Error executing flow run id' + runId) + exceptionHandler.handle(error) + logger.error( + error, + '[FlowWorker#executeFlow] Error executing flow run id' + runId, + ) throw error } -async function saveToLogFile({ fileId, projectId, executionOutput }: { fileId: FileId | undefined, projectId: ProjectId, executionOutput: ExecutionOutput }): Promise { +async function saveToLogFile({ + fileId, + projectId, + executionOutput, +}: { + fileId: FileId | undefined + projectId: ProjectId + executionOutput: ExecutionOutput +}): Promise { const serializedLogs = await logSerializer.serialize(executionOutput) if (serializedLogs.byteLength > MAX_LOG_SIZE) { - const errors = new Error('Execution Output is too large, maximum size is ' + MAX_LOG_SIZE) - captureException(errors) + const errors = new Error( + 'Execution Output is too large, maximum size is ' + MAX_LOG_SIZE, + ) + exceptionHandler.handle(errors) throw errors } @@ -309,18 +386,26 @@ async function saveToLogFile({ fileId, projectId, executionOutput }: { fileId: F return logsFile } - -function getCodeSteps(flowVersion: FlowVersion): { name: string, sourceCode: SourceCode }[] { - return flowHelper.getAllSteps(flowVersion.trigger).filter((step) => step.type === ActionType.CODE).map(((step: Action | Trigger) => { - const codeAction = step as CodeAction - return { - name: codeAction.name, - sourceCode: codeAction.settings.sourceCode, - } - })) +function getCodeSteps( + flowVersion: FlowVersion, +): { name: string, sourceCode: SourceCode }[] { + return flowHelper + .getAllSteps(flowVersion.trigger) + .filter((step) => step.type === ActionType.CODE) + .map((step: Action | Trigger) => { + const codeAction = step as CodeAction + return { + name: codeAction.name, + sourceCode: codeAction.settings.sourceCode, + } + }) } -const getSandbox = async ({ projectId, flowVersion, runEnvironment }: GetSandboxParams): Promise => { +const getSandbox = async ({ + projectId, + flowVersion, + runEnvironment, +}: GetSandboxParams): Promise => { const pieces = await extractFlowPieces({ flowVersion, projectId, diff --git a/packages/backend/src/app/workers/flow-worker/job-data.ts b/packages/server/api/src/app/workers/flow-worker/job-data.ts similarity index 81% rename from packages/backend/src/app/workers/flow-worker/job-data.ts rename to packages/server/api/src/app/workers/flow-worker/job-data.ts index fbc6cddf98..037b3de1a8 100644 --- a/packages/backend/src/app/workers/flow-worker/job-data.ts +++ b/packages/server/api/src/app/workers/flow-worker/job-data.ts @@ -1,4 +1,13 @@ -import { ExecutionType, FlowId, FlowRetryPayload, FlowRunId, FlowVersionId, ProjectId, RunEnvironment, TriggerType } from '@activepieces/shared' +import { + ExecutionType, + FlowId, + FlowRetryPayload, + FlowRunId, + FlowVersionId, + ProjectId, + RunEnvironment, + TriggerType, +} from '@activepieces/shared' import { HookType } from '../../flows/flow-run/flow-run-service' export const LATEST_JOB_DATA_SCHEMA_VERSION = 4 @@ -40,7 +49,10 @@ export type DelayedJobData = BaseJobData & { jobType: RepeatableJobType.DELAYED_FLOW } -export type ScheduledJobData = RepeatingJobData | DelayedJobData | RenewWebhookJobData +export type ScheduledJobData = + | RepeatingJobData + | DelayedJobData + | RenewWebhookJobData export type OneTimeJobData = BaseJobData & { flowVersionId: FlowVersionId @@ -52,4 +64,4 @@ export type OneTimeJobData = BaseJobData & { hookType?: HookType } -export type JobData = ScheduledJobData | OneTimeJobData \ No newline at end of file +export type JobData = ScheduledJobData | OneTimeJobData diff --git a/packages/backend/src/app/workers/flow-worker/queues/memory/memory-consumer.ts b/packages/server/api/src/app/workers/flow-worker/queues/memory/memory-consumer.ts similarity index 71% rename from packages/backend/src/app/workers/flow-worker/queues/memory/memory-consumer.ts rename to packages/server/api/src/app/workers/flow-worker/queues/memory/memory-consumer.ts index 2a86ec06f9..f3c1f0270a 100644 --- a/packages/backend/src/app/workers/flow-worker/queues/memory/memory-consumer.ts +++ b/packages/server/api/src/app/workers/flow-worker/queues/memory/memory-consumer.ts @@ -1,10 +1,9 @@ import dayjs from 'dayjs' import { inMemoryQueueManager } from './memory-queue' -import { system } from '../../../../helper/system/system' -import { SystemProp } from '../../../../helper/system/system-prop' +import { SystemProp, system } from 'server-shared' import { flowQueueConsumer } from '../../flow-queue-consumer' import { OneTimeJobData, ScheduledJobData } from '../../job-data' -import { logger } from '../../../../helper/logger' +import { logger } from 'server-shared' class Semaphore { private maxConcurrent: number @@ -45,8 +44,12 @@ export async function consumeJobsInMemory(): Promise { while (inMemoryQueueManager.queues.ONE_TIME.length > 0) { const job = inMemoryQueueManager.queues.ONE_TIME.shift()! - processOneTimeJob(job.data) - .catch((e) => logger.error(e, '[MemoryConsumer#consumeJobsInMemory] processOneTimeJob')) + processOneTimeJob(job.data).catch((e) => + logger.error( + e, + '[MemoryConsumer#consumeJobsInMemory] processOneTimeJob', + ), + ) } const delayedJobs = inMemoryQueueManager.queues.DELAYED.filter( @@ -55,8 +58,12 @@ export async function consumeJobsInMemory(): Promise { for (const job of delayedJobs) { inMemoryQueueManager.queues.DELAYED = inMemoryQueueManager.queues.DELAYED.filter((j) => j.id !== job.id) - processScheduledJob(job.data) - .catch((e) => logger.error(e, '[MemoryConsumer#consumeJobsInMemory] processScheduledJob')) + processScheduledJob(job.data).catch((e) => + logger.error( + e, + '[MemoryConsumer#consumeJobsInMemory] processScheduledJob', + ), + ) } const repeatedJob = inMemoryQueueManager.queues.REPEATING.filter( @@ -65,10 +72,20 @@ export async function consumeJobsInMemory(): Promise { for (const job of repeatedJob) { inMemoryQueueManager.queues.REPEATING = inMemoryQueueManager.queues.REPEATING.filter((j) => j.id !== job.id) - processScheduledJob(job.data) - .catch((e) => logger.error(e, '[MemoryConsumer#consumeJobsInMemory] processScheduledJob')) - inMemoryQueueManager.add(job) - .catch((e) => logger.error(e, '[MemoryConsumer#consumeJobsInMemory] inMemoryQueueManager.add')) + processScheduledJob(job.data).catch((e) => + logger.error( + e, + '[MemoryConsumer#consumeJobsInMemory] processScheduledJob', + ), + ) + inMemoryQueueManager + .add(job) + .catch((e) => + logger.error( + e, + '[MemoryConsumer#consumeJobsInMemory] inMemoryQueueManager.add', + ), + ) } await new Promise((resolve) => setTimeout(resolve, 500)) diff --git a/packages/backend/src/app/workers/flow-worker/queues/memory/memory-queue.ts b/packages/server/api/src/app/workers/flow-worker/queues/memory/memory-queue.ts similarity index 69% rename from packages/backend/src/app/workers/flow-worker/queues/memory/memory-queue.ts rename to packages/server/api/src/app/workers/flow-worker/queues/memory/memory-queue.ts index 1dcfb8b0ff..ee10fa0ab1 100644 --- a/packages/backend/src/app/workers/flow-worker/queues/memory/memory-queue.ts +++ b/packages/server/api/src/app/workers/flow-worker/queues/memory/memory-queue.ts @@ -10,16 +10,29 @@ import { RepeatingJobAddParams, } from '../queue' import cronParser from 'cron-parser' -import { logger } from '../../../../helper/logger' -import { DelayPauseMetadata, ExecutionOutputStatus, Flow, PauseType, RunEnvironment, TriggerType } from '@activepieces/shared' +import { logger } from 'server-shared' +import { + DelayPauseMetadata, + ExecutionOutputStatus, + Flow, + PauseType, + RunEnvironment, + TriggerType, +} from '@activepieces/shared' import { flowRunRepo } from '../../../../flows/flow-run/flow-run-service' import { flowService } from '../../../../flows/flow/flow.service' -import { LATEST_JOB_DATA_SCHEMA_VERSION, RepeatableJobType } from '../../job-data' +import { + LATEST_JOB_DATA_SCHEMA_VERSION, + RepeatableJobType, +} from '../../job-data' import { WebhookRenewStrategy } from '@activepieces/pieces-framework' import { flowVersionService } from '../../../../flows/flow-version/flow-version.service' import { getPieceTrigger } from '../../../../flows/trigger/hooks/trigger-utils' -function calculateNextFireForCron(cronExpression: string, timezone: string): number | null { +function calculateNextFireForCron( + cronExpression: string, + timezone: string, +): number | null { try { const options = { tz: timezone, @@ -36,7 +49,9 @@ function calculateNextFireForCron(cronExpression: string, timezone: string): num } } -type RepeatableJob = RepeatingJobAddParams | RenewWebhookJobAddParams +type RepeatableJob = + | RepeatingJobAddParams + | RenewWebhookJobAddParams type InMemoryQueueManager = { queues: { @@ -44,7 +59,9 @@ type InMemoryQueueManager = { [JobType.REPEATING]: (RepeatableJob & { nextFireEpochMsAt: number })[] - [JobType.DELAYED]: (DelayedJobAddParams & { nextFireEpochSeconds: number })[] + [JobType.DELAYED]: (DelayedJobAddParams & { + nextFireEpochSeconds: number + })[] } } & QueueManager @@ -71,36 +88,46 @@ export const inMemoryQueueManager: InMemoryQueueManager = { } const enabledFlows = await flowService.getAllEnabled() const enabledRepeatingFlows = enabledFlows.filter((flow) => flow.schedule) - const enabledRenewWebhookFlows = (await Promise.all(enabledFlows.map(async (flow) => { - const flowVersion = await flowVersionService.getOneOrThrow(flow.publishedVersionId!) - const trigger = flowVersion.trigger - - if (trigger.type !== TriggerType.PIECE) { - return null - } - - const piece = await getPieceTrigger({ - trigger, - projectId: flow.projectId, - }) - - const renewConfiguration = piece.renewConfiguration - - if (renewConfiguration?.strategy !== WebhookRenewStrategy.CRON) { - return null - } - - return { - scheduleOptions: { - cronExpression: renewConfiguration.cronExpression, - timezone: 'UTC', - }, - flow, - } - }))).filter((flow): flow is FlowWithRenewWebhook => flow !== null) - - logger.info(`Adding ${enabledRepeatingFlows.length} repeated flows to the queue manager.`) - logger.info(`Adding ${enabledRenewWebhookFlows.length} renew flows to the queue manager.`) + const enabledRenewWebhookFlows = ( + await Promise.all( + enabledFlows.map(async (flow) => { + const flowVersion = await flowVersionService.getOneOrThrow( + flow.publishedVersionId!, + ) + const trigger = flowVersion.trigger + + if (trigger.type !== TriggerType.PIECE) { + return null + } + + const piece = await getPieceTrigger({ + trigger, + projectId: flow.projectId, + }) + + const renewConfiguration = piece.renewConfiguration + + if (renewConfiguration?.strategy !== WebhookRenewStrategy.CRON) { + return null + } + + return { + scheduleOptions: { + cronExpression: renewConfiguration.cronExpression, + timezone: 'UTC', + }, + flow, + } + }), + ) + ).filter((flow): flow is FlowWithRenewWebhook => flow !== null) + + logger.info( + `Adding ${enabledRepeatingFlows.length} repeated flows to the queue manager.`, + ) + logger.info( + `Adding ${enabledRenewWebhookFlows.length} renew flows to the queue manager.`, + ) enabledRenewWebhookFlows.forEach(({ flow, scheduleOptions }) => { this.add({ @@ -115,7 +142,6 @@ export const inMemoryQueueManager: InMemoryQueueManager = { }, scheduleOptions, }).catch((e) => logger.error(e, '[MemoryQueue#init] add')) - }) enabledRepeatingFlows.forEach((flow) => { this.add({ @@ -134,8 +160,7 @@ export const inMemoryQueueManager: InMemoryQueueManager = { cronExpression: flow.schedule!.cronExpression, timezone: flow.schedule!.timezone, }, - }) - .catch((e) => logger.error(e, '[MemoryQueue#init] add')) + }).catch((e) => logger.error(e, '[MemoryQueue#init] add')) }) const flowRuns = await flowRunRepo.findBy({ @@ -144,9 +169,11 @@ export const inMemoryQueueManager: InMemoryQueueManager = { logger.info(`Adding ${flowRuns.length} flow runs to the queue manager.`) flowRuns.forEach((flowRun) => { if (flowRun.pauseMetadata?.type === PauseType.DELAY) { - const delayPauseMetadata = flowRun.pauseMetadata as DelayPauseMetadata - const delay = Math.max(0, dayjs(delayPauseMetadata.resumeDateTime).diff(dayjs(), 'ms')) + const delay = Math.max( + 0, + dayjs(delayPauseMetadata.resumeDateTime).diff(dayjs(), 'ms'), + ) this.add({ id: flowRun.id, @@ -160,11 +187,10 @@ export const inMemoryQueueManager: InMemoryQueueManager = { jobType: RepeatableJobType.DELAYED_FLOW, }, delay, - }) - .catch((e) => logger.error(e, '[MemoryQueue#init] add')) + }).catch((e) => logger.error(e, '[MemoryQueue#init] add')) } }) - // TODO add run with status RUNNING + // TODO add run with status RUNNING }, async add(params: AddParams): Promise { switch (params.type) { diff --git a/packages/backend/src/app/workers/flow-worker/queues/queue.ts b/packages/server/api/src/app/workers/flow-worker/queues/queue.ts similarity index 74% rename from packages/backend/src/app/workers/flow-worker/queues/queue.ts rename to packages/server/api/src/app/workers/flow-worker/queues/queue.ts index cb609f58ca..b073f23735 100644 --- a/packages/backend/src/app/workers/flow-worker/queues/queue.ts +++ b/packages/server/api/src/app/workers/flow-worker/queues/queue.ts @@ -1,5 +1,4 @@ -import { QueueMode, system } from '../../../helper/system/system' -import { SystemProp } from '../../../helper/system/system-prop' +import { QueueMode, SystemProp, system } from 'server-shared' import { DelayedJobData, OneTimeJobData, @@ -36,12 +35,10 @@ RepeatingJobData scheduleOptions: ScheduleOptions } -export type RenewWebhookJobAddParams = BaseAddParams< -JT, -RenewWebhookJobData -> & { - scheduleOptions: ScheduleOptions -} +export type RenewWebhookJobAddParams = + BaseAddParams & { + scheduleOptions: ScheduleOptions + } export type DelayedJobAddParams = BaseAddParams< JT, @@ -57,12 +54,13 @@ OneTimeJobData priority: 'high' | 'medium' } - -export type AddParams = JT extends JobType.ONE_TIME ? OneTimeJobAddParams : - JT extends JobType.REPEATING ? RepeatingJobAddParams | RenewWebhookJobAddParams : - JT extends JobType.DELAYED ? DelayedJobAddParams : - never - +export type AddParams = JT extends JobType.ONE_TIME + ? OneTimeJobAddParams + : JT extends JobType.REPEATING + ? RepeatingJobAddParams | RenewWebhookJobAddParams + : JT extends JobType.DELAYED + ? DelayedJobAddParams + : never export type RemoveParams = { id: ApId diff --git a/packages/backend/src/app/workers/flow-worker/queues/redis/redis-consumer.ts b/packages/server/api/src/app/workers/flow-worker/queues/redis/redis-consumer.ts similarity index 88% rename from packages/backend/src/app/workers/flow-worker/queues/redis/redis-consumer.ts rename to packages/server/api/src/app/workers/flow-worker/queues/redis/redis-consumer.ts index 8142d98c02..b514f62334 100644 --- a/packages/backend/src/app/workers/flow-worker/queues/redis/redis-consumer.ts +++ b/packages/server/api/src/app/workers/flow-worker/queues/redis/redis-consumer.ts @@ -4,14 +4,13 @@ import { ONE_TIME_JOB_QUEUE, SCHEDULED_JOB_QUEUE } from './redis-queue' import { OneTimeJobData, ScheduledJobData } from '../../job-data' import { flowQueueConsumer } from '../../flow-queue-consumer' import { createRedisClient } from '../../../../database/redis-connection' -import { system } from '../../../../helper/system/system' -import { SystemProp } from '../../../../helper/system/system-prop' +import { SystemProp, system } from 'server-shared' import { ApId } from '@activepieces/shared' - let redisScheduledJobConsumer: Worker let redisOneTimeJobConsumer: Worker -const flowConcurrency = system.getNumber(SystemProp.FLOW_WORKER_CONCURRENCY) ?? 10 +const flowConcurrency = + system.getNumber(SystemProp.FLOW_WORKER_CONCURRENCY) ?? 10 export const redisConsumer = { async init(): Promise { @@ -38,7 +37,7 @@ export const redisConsumer = { concurrency: flowConcurrency, }, ) - const startWorkers = [ + const startWorkers = [ redisOneTimeJobConsumer.waitUntilReady(), redisScheduledJobConsumer.waitUntilReady(), ] diff --git a/packages/backend/src/app/workers/flow-worker/queues/redis/redis-queue.ts b/packages/server/api/src/app/workers/flow-worker/queues/redis/redis-queue.ts similarity index 80% rename from packages/backend/src/app/workers/flow-worker/queues/redis/redis-queue.ts rename to packages/server/api/src/app/workers/flow-worker/queues/redis/redis-queue.ts index 8e72ac9eab..ccf281e84e 100644 --- a/packages/backend/src/app/workers/flow-worker/queues/redis/redis-queue.ts +++ b/packages/server/api/src/app/workers/flow-worker/queues/redis/redis-queue.ts @@ -2,11 +2,19 @@ import { DefaultJobOptions, Queue } from 'bullmq' import { ApEdition, ApEnvironment, ApId } from '@activepieces/shared' import { createRedisClient } from '../../../../database/redis-connection' import { ActivepiecesError, ErrorCode } from '@activepieces/shared' -import { logger } from '../../../../helper/logger' +import { logger } from 'server-shared' import { isNil } from '@activepieces/shared' -import { OneTimeJobData, RepeatableJobType, ScheduledJobData } from '../../job-data' +import { + OneTimeJobData, + RepeatableJobType, + ScheduledJobData, +} from '../../job-data' import { AddParams, JobType, QueueManager, RemoveParams } from '../queue' -import { ExecutionType, RunEnvironment, ScheduleType } from '@activepieces/shared' +import { + ExecutionType, + RunEnvironment, + ScheduleType, +} from '@activepieces/shared' import { LATEST_JOB_DATA_SCHEMA_VERSION } from '../../job-data' import { Job } from 'bullmq' import { acquireLock } from '../../../../helper/lock' @@ -15,8 +23,7 @@ import { BullMQAdapter } from '@bull-board/api/bullMQAdapter' import { FastifyAdapter } from '@bull-board/fastify' import { FastifyInstance } from 'fastify' import basicAuth from '@fastify/basic-auth' -import { system } from '../../../../helper/system/system' -import { SystemProp } from '../../../../helper/system/system-prop' +import { SystemProp, system } from 'server-shared' import { getEdition } from '../../../../helper/secret-helper' import { flowRepo } from '../../../../flows/flow/flow.repo' @@ -55,7 +62,9 @@ export async function setupBullMQBoard(app: FastifyInstance): Promise { } const queueUsername = system.getOrThrow(SystemProp.QUEUE_UI_USERNAME) const queuePassword = system.getOrThrow(SystemProp.QUEUE_UI_PASSWORD) - logger.info('[setupBullMQBoard] Setting up bull board, visit /ui to see the queues') + logger.info( + '[setupBullMQBoard] Setting up bull board, visit /ui to see the queues', + ) await app.register(basicAuth, { validate: (username, password, _req, reply, done) => { @@ -69,13 +78,16 @@ export async function setupBullMQBoard(app: FastifyInstance): Promise { authenticate: true, }) - const serverAdapter = new FastifyAdapter() createBullBoard({ - queues: [new BullMQAdapter(oneTimeJobQueue), new BullMQAdapter(scheduledJobQueue)], + queues: [ + new BullMQAdapter(oneTimeJobQueue), + new BullMQAdapter(scheduledJobQueue), + ], serverAdapter, }) - const environment = system.get(SystemProp.ENVIRONMENT) ?? ApEnvironment.DEVELOPMENT + const environment = + system.get(SystemProp.ENVIRONMENT) ?? ApEnvironment.DEVELOPMENT switch (environment) { case ApEnvironment.DEVELOPMENT: serverAdapter.setBasePath(QUEUE_BASE_PATH) @@ -87,7 +99,6 @@ export async function setupBullMQBoard(app: FastifyInstance): Promise { throw new Error('Not supported') } - app.addHook('onRequest', (req, reply, next) => { if (!req.routerPath.startsWith(QUEUE_BASE_PATH)) { next() @@ -96,7 +107,9 @@ export async function setupBullMQBoard(app: FastifyInstance): Promise { app.basicAuth(req, reply, function (error?: unknown) { const castedError = error as { statusCode: number, name: string } if (!isNil(castedError)) { - void reply.code(castedError.statusCode || 500).send({ error: castedError.name }) + void reply + .code(castedError.statusCode || 500) + .send({ error: castedError.name }) } else { next() @@ -105,22 +118,30 @@ export async function setupBullMQBoard(app: FastifyInstance): Promise { } }) - await app.register(serverAdapter.registerPlugin(), { prefix: QUEUE_BASE_PATH, basePath: QUEUE_BASE_PATH }) + await app.register(serverAdapter.registerPlugin(), { + prefix: QUEUE_BASE_PATH, + basePath: QUEUE_BASE_PATH, + }) } export const redisQueueManager: QueueManager = { async init() { logger.info('[redisQueueManager#init] Initializing redis queues') - oneTimeJobQueue = new Queue(ONE_TIME_JOB_QUEUE, { - connection: createRedisClient(), - defaultJobOptions, - }) - scheduledJobQueue = new Queue(SCHEDULED_JOB_QUEUE, { - connection: createRedisClient(), - defaultJobOptions, - }) + oneTimeJobQueue = new Queue( + ONE_TIME_JOB_QUEUE, + { + connection: createRedisClient(), + defaultJobOptions, + }, + ) + scheduledJobQueue = new Queue( + SCHEDULED_JOB_QUEUE, + { + connection: createRedisClient(), + defaultJobOptions, + }, + ) await migrateScheduledJobs() - }, async add(params: AddParams): Promise { logger.debug(params, '[flowQueue#add] params') @@ -144,7 +165,9 @@ export const redisQueueManager: QueueManager = { await client.set(repeatingJobKey(id), job.repeatJobKey) } else if (params.type === JobType.DELAYED) { - logger.info(`[FlowQueue#add] flowRunId=${params.id} delay=${params.delay}`) + logger.info( + `[FlowQueue#add] flowRunId=${params.id} delay=${params.delay}`, + ) const { id, data, delay } = params @@ -173,7 +196,9 @@ export const redisQueueManager: QueueManager = { message indicating that the job with key "${jobKey}" couldn't be found, even though it should exist, and proceed to skip the deletion. */ - logger.error(`Couldn't find job ${jobKey}, even though It should exists, skipping delete`) + logger.error( + `Couldn't find job ${jobKey}, even though It should exists, skipping delete`, + ) } else { const result = await scheduledJobQueue.removeRepeatableByKey(jobKey) @@ -191,11 +216,16 @@ export const redisQueueManager: QueueManager = { }, } - type MaybeJob = Job | undefined -const jobDataSchemaVersionIsNotLatest = (job: MaybeJob): job is Job => { - return !isNil(job) && !isNil(job.data) && job.data.schemaVersion !== LATEST_JOB_DATA_SCHEMA_VERSION +const jobDataSchemaVersionIsNotLatest = ( + job: MaybeJob, +): job is Job => { + return ( + !isNil(job) && + !isNil(job.data) && + job.data.schemaVersion !== LATEST_JOB_DATA_SCHEMA_VERSION + ) } const migrateScheduledJobs = async (): Promise => { @@ -207,12 +237,17 @@ const migrateScheduledJobs = async (): Promise => { logger.info('[migrateScheduledJobs] Starting migration') let migratedJobs = 0 const scheduledJobs: MaybeJob[] = await scheduledJobQueue.getJobs() - logger.info(`[migrateScheduledJobs] Found ${scheduledJobs.length} total jobs`) + logger.info( + `[migrateScheduledJobs] Found ${scheduledJobs.length} total jobs`, + ) const jobsToMigrate = scheduledJobs.filter(jobDataSchemaVersionIsNotLatest) for (const job of jobsToMigrate) { // Cast as we are not sure about the schema let modifiedJobData = JSON.parse(JSON.stringify(job.data)) - if (modifiedJobData.schemaVersion === undefined || modifiedJobData.schemaVersion === 1) { + if ( + modifiedJobData.schemaVersion === undefined || + modifiedJobData.schemaVersion === 1 + ) { const { flowVersion, projectId, triggerType } = modifiedJobData modifiedJobData = { schemaVersion: 2, @@ -255,7 +290,9 @@ const migrateScheduledJobs = async (): Promise => { } } -async function updateCronExpressionOfRedisToPostgresTable(job: Job): Promise { +async function updateCronExpressionOfRedisToPostgresTable( + job: Job, +): Promise { const tz = job.opts.repeat?.tz const pattern = job.opts.repeat?.pattern if (isNil(tz) || isNil(pattern)) { diff --git a/packages/backend/src/app/workers/sandbox/cache/cached-sandbox-state.ts b/packages/server/api/src/app/workers/sandbox/cache/cached-sandbox-state.ts similarity index 100% rename from packages/backend/src/app/workers/sandbox/cache/cached-sandbox-state.ts rename to packages/server/api/src/app/workers/sandbox/cache/cached-sandbox-state.ts diff --git a/packages/backend/src/app/workers/sandbox/cache/cached-sandbox.ts b/packages/server/api/src/app/workers/sandbox/cache/cached-sandbox.ts similarity index 91% rename from packages/backend/src/app/workers/sandbox/cache/cached-sandbox.ts rename to packages/server/api/src/app/workers/sandbox/cache/cached-sandbox.ts index f2d11c8bd1..93fad6c5f0 100644 --- a/packages/backend/src/app/workers/sandbox/cache/cached-sandbox.ts +++ b/packages/server/api/src/app/workers/sandbox/cache/cached-sandbox.ts @@ -1,17 +1,12 @@ import { mkdir, rm } from 'node:fs/promises' import { resolve } from 'node:path' -import { system } from '../../../helper/system/system' -import { SystemProp } from '../../../helper/system/system-prop' +import { logger, SystemProp, enrichErrorContext, packageManager, system } from 'server-shared' import { CachedSandboxState } from './cached-sandbox-state' import { pieceManager } from '../../../flows/common/piece-manager' -import { engineInstaller } from '../../engine/engine-installer' -import { logger } from '../../../helper/logger' +import { engineInstaller, codeBuilder } from 'server-worker' import { Mutex } from 'async-mutex' import dayjs from 'dayjs' import { PiecePackage, SourceCode } from '@activepieces/shared' -import { codeBuilder } from '../../code-worker/code-builder' -import { enrichErrorContext } from '../../../helper/error-handler' -import { packageManager } from '../../../helper/package-manager' export class CachedSandbox { private static readonly CACHE_PATH = system.get(SystemProp.CACHE_PATH) ?? resolve('dist', 'cache') diff --git a/packages/backend/src/app/workers/sandbox/cache/sandbox-cache-pool.ts b/packages/server/api/src/app/workers/sandbox/cache/sandbox-cache-pool.ts similarity index 94% rename from packages/backend/src/app/workers/sandbox/cache/sandbox-cache-pool.ts rename to packages/server/api/src/app/workers/sandbox/cache/sandbox-cache-pool.ts index 7f9e6ba447..dc96998e8e 100644 --- a/packages/backend/src/app/workers/sandbox/cache/sandbox-cache-pool.ts +++ b/packages/server/api/src/app/workers/sandbox/cache/sandbox-cache-pool.ts @@ -1,9 +1,8 @@ import { Mutex } from 'async-mutex' import { CachedSandbox } from './cached-sandbox' -import { logger } from '../../../helper/logger' +import { logger } from 'server-shared' import { ApEnvironment, isNil } from '@activepieces/shared' -import { system } from '../../../helper/system/system' -import { SystemProp } from '../../../helper/system/system-prop' +import { SystemProp, system } from 'server-shared' import { ProvisionCacheInfo, SandBoxCacheType, extractProvisionCacheKey } from '../provisioner/sandbox-cache-key' const CACHED_SANDBOX_LIMIT = 1000 diff --git a/packages/backend/src/app/workers/sandbox/provisioner/sandbox-cache-key.ts b/packages/server/api/src/app/workers/sandbox/provisioner/sandbox-cache-key.ts similarity index 58% rename from packages/backend/src/app/workers/sandbox/provisioner/sandbox-cache-key.ts rename to packages/server/api/src/app/workers/sandbox/provisioner/sandbox-cache-key.ts index d754351adf..520f261174 100644 --- a/packages/backend/src/app/workers/sandbox/provisioner/sandbox-cache-key.ts +++ b/packages/server/api/src/app/workers/sandbox/provisioner/sandbox-cache-key.ts @@ -1,5 +1,5 @@ import { FlowVersionId, apId } from '@activepieces/shared' -import { logger } from '../../../helper/logger' +import { logger } from 'server-shared' export enum SandBoxCacheType { CODE = 'CODE', @@ -8,21 +8,23 @@ export enum SandBoxCacheType { PIECE = 'PIECE', } - -export type TypedProvisionCacheInfo = - T extends SandBoxCacheType.CODE - ? CodeProvisionCacheInfo - : T extends SandBoxCacheType.FLOW - ? FlowProvisionCacheInfo - : T extends SandBoxCacheType.NONE - ? NoneProvisionCacheInfo - : T extends SandBoxCacheType.PIECE - ? PieceProvisionCacheInfo - : never +export type TypedProvisionCacheInfo< + T extends SandBoxCacheType = SandBoxCacheType, +> = T extends SandBoxCacheType.CODE + ? CodeProvisionCacheInfo + : T extends SandBoxCacheType.FLOW + ? FlowProvisionCacheInfo + : T extends SandBoxCacheType.NONE + ? NoneProvisionCacheInfo + : T extends SandBoxCacheType.PIECE + ? PieceProvisionCacheInfo + : never export type ProvisionCacheInfo = TypedProvisionCacheInfo -export const extractProvisionCacheKey = (params: ProvisionCacheInfo): string => { +export const extractProvisionCacheKey = ( + params: ProvisionCacheInfo, +): string => { logger.debug({ type: params.type }, '[SandboxProvisioner#extractCacheKey]') switch (params.type) { case SandBoxCacheType.CODE: @@ -36,13 +38,17 @@ export const extractProvisionCacheKey = (params: ProvisionCacheInfo): string => } } - - -const extractCodeCacheKey = ({ sourceCodeHash, name, flowId }: CodeProvisionCacheInfo): string => { +const extractCodeCacheKey = ({ + sourceCodeHash, + name, + flowId, +}: CodeProvisionCacheInfo): string => { return `CODE-sourceCodeHash-${sourceCodeHash}-name-${name}-flowId-${flowId}` } -const extractFlowCacheKey = ({ flowVersionId }: FlowProvisionCacheInfo): string => { +const extractFlowCacheKey = ({ + flowVersionId, +}: FlowProvisionCacheInfo): string => { return `FLOW-flowVersionId-${flowVersionId}` } @@ -50,11 +56,13 @@ const extractNoneCacheKey = (_params: NoneProvisionCacheInfo): string => { return `NONE-apId-${apId()}` } -const extractPieceCacheKey = ({ pieceName, pieceVersion }: PieceProvisionCacheInfo): string => { +const extractPieceCacheKey = ({ + pieceName, + pieceVersion, +}: PieceProvisionCacheInfo): string => { return `PIECE-pieceName-${pieceName}-pieceVersion-${pieceVersion}` } - type BaseProvisionCacheInfo = { type: T } @@ -71,9 +79,8 @@ type FlowProvisionCacheInfo = BaseProvisionCacheInfo & { type NoneProvisionCacheInfo = BaseProvisionCacheInfo -type PieceProvisionCacheInfo = BaseProvisionCacheInfo & { - pieceName: string - pieceVersion: string -} - - +type PieceProvisionCacheInfo = + BaseProvisionCacheInfo & { + pieceName: string + pieceVersion: string + } diff --git a/packages/backend/src/app/workers/sandbox/provisioner/sandbox-provisioner.ts b/packages/server/api/src/app/workers/sandbox/provisioner/sandbox-provisioner.ts similarity index 74% rename from packages/backend/src/app/workers/sandbox/provisioner/sandbox-provisioner.ts rename to packages/server/api/src/app/workers/sandbox/provisioner/sandbox-provisioner.ts index 6b3b14223a..e5fb88f22d 100644 --- a/packages/backend/src/app/workers/sandbox/provisioner/sandbox-provisioner.ts +++ b/packages/server/api/src/app/workers/sandbox/provisioner/sandbox-provisioner.ts @@ -1,13 +1,15 @@ -import { Sandbox } from '..' +import { Sandbox, sandboxManager } from 'server-worker' import { sandboxCachePool } from '../cache/sandbox-cache-pool' -import { sandboxManager } from '../sandbox-manager' import { PiecePackage, SourceCode } from '@activepieces/shared' import { SandBoxCacheType, TypedProvisionCacheInfo } from './sandbox-cache-key' -import { logger } from '../../../helper/logger' -import { enrichErrorContext } from '../../../helper/error-handler' +import { enrichErrorContext, logger } from 'server-shared' export const sandboxProvisioner = { - async provision({ pieces = [], codeSteps = [], ...cacheInfo }: ProvisionParams): Promise { + async provision({ + pieces = [], + codeSteps = [], + ...cacheInfo + }: ProvisionParams): Promise { try { const cachedSandbox = await sandboxCachePool.findOrCreate(cacheInfo) @@ -40,7 +42,10 @@ export const sandboxProvisioner = { }, async release({ sandbox }: ReleaseParams): Promise { - logger.debug({ boxId: sandbox.boxId, cacheKey: sandbox.cacheKey }, '[SandboxProvisioner#release]') + logger.debug( + { boxId: sandbox.boxId, cacheKey: sandbox.cacheKey }, + '[SandboxProvisioner#release]', + ) await sandboxManager.release(sandbox.boxId) @@ -57,10 +62,11 @@ type CodeArtifact = { sourceCode: SourceCode } -type ProvisionParams = TypedProvisionCacheInfo & { - pieces?: PiecePackage[] - codeSteps?: CodeArtifact[] -} +type ProvisionParams = + TypedProvisionCacheInfo & { + pieces?: PiecePackage[] + codeSteps?: CodeArtifact[] + } type ReleaseParams = { sandbox: Sandbox diff --git a/packages/backend/src/assets/default.cf b/packages/server/api/src/assets/default.cf old mode 100644 new mode 100755 similarity index 100% rename from packages/backend/src/assets/default.cf rename to packages/server/api/src/assets/default.cf diff --git a/packages/server/api/src/assets/emails/invitation-email.html b/packages/server/api/src/assets/emails/invitation-email.html new file mode 100755 index 0000000000..256e9c9646 --- /dev/null +++ b/packages/server/api/src/assets/emails/invitation-email.html @@ -0,0 +1,622 @@ + + + + + + + + + + + + + + + Finish creating your account + + + + + + +
+ +
+ +
+  ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌  +
+ + + + + + + + + diff --git a/packages/server/api/src/assets/emails/quota-100.html b/packages/server/api/src/assets/emails/quota-100.html new file mode 100755 index 0000000000..df099c29c4 --- /dev/null +++ b/packages/server/api/src/assets/emails/quota-100.html @@ -0,0 +1,642 @@ + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+  ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌  +
+ + + + + + + + + diff --git a/packages/server/api/src/assets/emails/quota-50.html b/packages/server/api/src/assets/emails/quota-50.html new file mode 100755 index 0000000000..f0f761ead9 --- /dev/null +++ b/packages/server/api/src/assets/emails/quota-50.html @@ -0,0 +1,641 @@ + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+  ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌  +
+ + + + + + + + + diff --git a/packages/server/api/src/assets/emails/quota-90.html b/packages/server/api/src/assets/emails/quota-90.html new file mode 100755 index 0000000000..a3e9464f89 --- /dev/null +++ b/packages/server/api/src/assets/emails/quota-90.html @@ -0,0 +1,642 @@ + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+  ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌  +
+ + + + + + + + + diff --git a/packages/server/api/src/assets/emails/reset-password.html b/packages/server/api/src/assets/emails/reset-password.html new file mode 100755 index 0000000000..af6ed7f235 --- /dev/null +++ b/packages/server/api/src/assets/emails/reset-password.html @@ -0,0 +1,658 @@ + + + + + + + + + + + + + + + Reset your {{platformName}} password + + + + + + + +
+ +
+ +
+  ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌  +
+ + + + + + + + + diff --git a/packages/server/api/src/assets/emails/verify-email.html b/packages/server/api/src/assets/emails/verify-email.html new file mode 100755 index 0000000000..d61276ba71 --- /dev/null +++ b/packages/server/api/src/assets/emails/verify-email.html @@ -0,0 +1,650 @@ + + + + + + + + + + + + + + + Set up your {{platformName}} account + + + + + + + +
+ +
+ +
+  ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌  +
+ + + + + + + + + diff --git a/packages/backend/src/assets/etc/resolv.conf b/packages/server/api/src/assets/etc/resolv.conf old mode 100644 new mode 100755 similarity index 100% rename from packages/backend/src/assets/etc/resolv.conf rename to packages/server/api/src/assets/etc/resolv.conf diff --git a/packages/server/api/src/assets/invalid-code.js b/packages/server/api/src/assets/invalid-code.js new file mode 100755 index 0000000000..7f432ced39 --- /dev/null +++ b/packages/server/api/src/assets/invalid-code.js @@ -0,0 +1,3 @@ +exports.code = async (params) => { + throw new Error('${ERROR_MESSAGE}'); +}; diff --git a/packages/backend/src/assets/isolate b/packages/server/api/src/assets/isolate similarity index 100% rename from packages/backend/src/assets/isolate rename to packages/server/api/src/assets/isolate diff --git a/packages/backend/src/assets/isolate-arm b/packages/server/api/src/assets/isolate-arm similarity index 100% rename from packages/backend/src/assets/isolate-arm rename to packages/server/api/src/assets/isolate-arm diff --git a/packages/backend/src/main.ts b/packages/server/api/src/main.ts similarity index 77% rename from packages/backend/src/main.ts rename to packages/server/api/src/main.ts index 0b866d3358..1bb1505bb2 100644 --- a/packages/backend/src/main.ts +++ b/packages/server/api/src/main.ts @@ -1,12 +1,10 @@ -import { system } from './app/helper/system/system' -import { SystemProp } from './app/helper/system/system-prop' import { databaseConnection } from './app/database/database-connection' -import { logger } from './app/helper/logger' import { ApEnvironment } from '@activepieces/shared' import { seedDevData } from './app/database/seeds/dev-seeds' import { setupApp } from './app/app' import { FastifyInstance } from 'fastify' import { enforceLimits } from './app/ee/helper/license-validator' +import { SystemProp, logger, system } from 'server-shared' const start = async (app: FastifyInstance): Promise => { try { @@ -23,20 +21,27 @@ const start = async (app: FastifyInstance): Promise => { / ____ \\ | |____ | | _| |_ \\ / | |____ | | _| |_ | |____ | |____ | |____ ____) | /_/ \\_\\ \\_____| |_| |_____| \\/ |______| |_| |_____| |______| \\_____| |______| |_____/ -The application started on ${system.get(SystemProp.FRONTEND_URL)}, as specified by the AP_FRONTEND_URL variables. +The application started on ${system.get( + SystemProp.FRONTEND_URL, + )}, as specified by the AP_FRONTEND_URL variables. `) const environemnt = system.get(SystemProp.ENVIRONMENT) const piecesSource = system.getOrThrow(SystemProp.PIECES_SOURCE) const pieces = process.env.AP_DEV_PIECES - logger.warn(`[WARNING]: Pieces will be loaded from source type ${piecesSource}`) + logger.warn( + `[WARNING]: Pieces will be loaded from source type ${piecesSource}`, + ) if (environemnt === ApEnvironment.DEVELOPMENT) { - logger.warn(`[WARNING]: The application is running in ${environemnt} mode.`) - logger.warn(`[WARNING]: This is only shows pieces specified in AP_DEV_PIECES ${pieces} environment variable.`) + logger.warn( + `[WARNING]: The application is running in ${environemnt} mode.`, + ) + logger.warn( + `[WARNING]: This is only shows pieces specified in AP_DEV_PIECES ${pieces} environment variable.`, + ) } await enforceLimits() - } catch (err) { logger.error(err) @@ -70,7 +75,6 @@ const stop = async (app: FastifyInstance): Promise => { } const main = async (): Promise => { - setupTimeZone() await databaseConnection.initialize() await databaseConnection.runMigrations() @@ -78,17 +82,14 @@ const main = async (): Promise => { const app = await setupApp() process.on('SIGINT', () => { - stop(app) - .catch((e) => logger.error(e, '[Main#stop]')) + stop(app).catch((e) => logger.error(e, '[Main#stop]')) }) process.on('SIGTERM', () => { - stop(app) - .catch((e) => logger.error(e, '[Main#stop]')) + stop(app).catch((e) => logger.error(e, '[Main#stop]')) }) await start(app) } -main() - .catch((e) => logger.error(e, '[Main#main]')) +main().catch((e) => logger.error(e, '[Main#main]')) diff --git a/packages/backend/test/helpers/auth.ts b/packages/server/api/test/helpers/auth.ts similarity index 92% rename from packages/backend/test/helpers/auth.ts rename to packages/server/api/test/helpers/auth.ts index 50b5031b65..ecd7250454 100644 --- a/packages/backend/test/helpers/auth.ts +++ b/packages/server/api/test/helpers/auth.ts @@ -2,7 +2,10 @@ import { SigningKeyId } from '@activepieces/ee-shared' import { Principal, PrincipalType, apId } from '@activepieces/shared' import { faker } from '@faker-js/faker' import jwt, { Algorithm, JwtPayload, SignOptions } from 'jsonwebtoken' -import { ExternalPrincipal, ExternalTokenPayload } from '../../src/app/ee/managed-authn/lib/external-token-extractor' +import { + ExternalPrincipal, + ExternalTokenPayload, +} from '../../src/app/ee/managed-authn/lib/external-token-extractor' const generateToken = ({ payload, @@ -18,14 +21,12 @@ const generateToken = ({ issuer, } - return jwt.sign( - payload, - key, - options, - ) + return jwt.sign(payload, key, options) } -export const generateMockToken = async (principal?: Partial): Promise => { +export const generateMockToken = async ( + principal?: Partial, +): Promise => { const mockPrincipal: Principal = { id: principal?.id ?? apId(), type: principal?.type ?? faker.helpers.enumValue(PrincipalType), @@ -92,7 +93,9 @@ GsXpDpzyyhR2ZjY3b+bLfTT9YOyGIxBp4hqA3Rcc6c7l31lAAsDxtfWfXeoMLt5T CEri0OurQ6fh4y87TK4JFbSTPEDkrPh4STPH7TtroBM/rn7Zj4+1Ur1RlgI= -----END RSA PRIVATE KEY-----` -export const generateMockExternalToken = (params?: Partial): GenerateMockExternalTokenReturn => { +export const generateMockExternalToken = ( + params?: Partial, +): GenerateMockExternalTokenReturn => { const mockExternalTokenPayload: ExternalTokenPayload = { externalUserId: params?.externalUserId ?? apId(), externalProjectId: params?.externalProjectId ?? apId(), diff --git a/packages/backend/test/helpers/mocks/authn.ts b/packages/server/api/test/helpers/mocks/authn.ts similarity index 78% rename from packages/backend/test/helpers/mocks/authn.ts rename to packages/server/api/test/helpers/mocks/authn.ts index a7509f066f..9499a882cd 100644 --- a/packages/backend/test/helpers/mocks/authn.ts +++ b/packages/server/api/test/helpers/mocks/authn.ts @@ -1,7 +1,9 @@ import { faker } from '@faker-js/faker' import { SignInRequest, SignUpRequest } from '@activepieces/shared' -export const createMockSignUpRequest = (signUpRequest?: Partial): SignUpRequest => { +export const createMockSignUpRequest = ( + signUpRequest?: Partial, +): SignUpRequest => { return { email: signUpRequest?.email ?? faker.internet.email(), password: signUpRequest?.password ?? faker.internet.password(), @@ -13,7 +15,9 @@ export const createMockSignUpRequest = (signUpRequest?: Partial): } } -export const createMockSignInRequest = (signInRequest?: Partial): SignInRequest => { +export const createMockSignInRequest = ( + signInRequest?: Partial, +): SignInRequest => { return { email: signInRequest?.email ?? faker.internet.email(), password: signInRequest?.password ?? faker.internet.password(), diff --git a/packages/backend/test/helpers/mocks/index.ts b/packages/server/api/test/helpers/mocks/index.ts similarity index 83% rename from packages/backend/test/helpers/mocks/index.ts rename to packages/server/api/test/helpers/mocks/index.ts index 09c403f1b0..6ff5af7d53 100644 --- a/packages/backend/test/helpers/mocks/index.ts +++ b/packages/server/api/test/helpers/mocks/index.ts @@ -1,5 +1,42 @@ -import { KeyAlgorithm, SigningKey, Platform, OAuthApp, FilteredPieceBehavior, CustomDomain, CustomDomainStatus, OtpModel, OtpType, OtpState, ProjectMember, ApiKey, ProjectMemberRole, ProjectMemberStatus, GitRepo, ApplicationEvent, ApplicationEventName } from '@activepieces/ee-shared' -import { UserStatus, User, apId, Project, NotificationStatus, ProjectType, PieceType, PackageType, Flow, FlowStatus, FlowVersion, TriggerType, FlowVersionState, FlowTemplate, TemplateType, FlowRun, ExecutionOutputStatus, RunEnvironment } from '@activepieces/shared' +import { + KeyAlgorithm, + SigningKey, + Platform, + OAuthApp, + FilteredPieceBehavior, + CustomDomain, + CustomDomainStatus, + OtpModel, + OtpType, + OtpState, + ProjectMember, + ApiKey, + ProjectMemberRole, + ProjectMemberStatus, + GitRepo, + ApplicationEvent, + ApplicationEventName, +} from '@activepieces/ee-shared' +import { + UserStatus, + User, + apId, + Project, + NotificationStatus, + ProjectType, + PieceType, + PackageType, + Flow, + FlowStatus, + FlowVersion, + TriggerType, + FlowVersionState, + FlowTemplate, + TemplateType, + FlowRun, + ExecutionOutputStatus, + RunEnvironment, +} from '@activepieces/shared' import { faker } from '@faker-js/faker' import { PieceMetadataSchema } from '../../../src/app/pieces/piece-metadata-entity' import bcrypt from 'bcrypt' @@ -20,7 +57,9 @@ export const createMockUser = (user?: Partial): User => { lastName: user?.lastName ?? faker.person.lastName(), trackEvents: user?.trackEvents ?? faker.datatype.boolean(), newsLetter: user?.newsLetter ?? faker.datatype.boolean(), - password: user?.password ? bcrypt.hashSync(user.password, 10) : faker.internet.password(), + password: user?.password + ? bcrypt.hashSync(user.password, 10) + : faker.internet.password(), status: user?.status ?? faker.helpers.enumValue(UserStatus), imageUrl: user?.imageUrl, title: user?.title, @@ -30,7 +69,9 @@ export const createMockUser = (user?: Partial): User => { } } -export const createMockOAuthApp = (oAuthApp?: Partial): OAuthAppWithEncryptedSecret => { +export const createMockOAuthApp = ( + oAuthApp?: Partial, +): OAuthAppWithEncryptedSecret => { return { id: oAuthApp?.id ?? apId(), created: oAuthApp?.created ?? faker.date.recent().toISOString(), @@ -42,7 +83,9 @@ export const createMockOAuthApp = (oAuthApp?: Partial): OAuthAppWithEn } } -export const createMockTemplate = (template?: Partial): FlowTemplate => { +export const createMockTemplate = ( + template?: Partial, +): FlowTemplate => { return { name: template?.name ?? faker.lorem.word(), description: template?.description ?? faker.lorem.sentence(), @@ -66,7 +109,8 @@ export const createMockProject = (project?: Partial): Project => { updated: project?.updated ?? faker.date.recent().toISOString(), ownerId: project?.ownerId ?? apId(), displayName: project?.displayName ?? faker.lorem.word(), - notifyStatus: project?.notifyStatus ?? faker.helpers.enumValue(NotificationStatus), + notifyStatus: + project?.notifyStatus ?? faker.helpers.enumValue(NotificationStatus), type: project?.type ?? faker.helpers.enumValue(ProjectType), platformId: project?.platformId ?? apId(), externalId: project?.externalId ?? apId(), @@ -103,7 +147,9 @@ export const createMockPlatform = (platform?: Partial): Platform => { favIconUrl: platform?.favIconUrl ?? faker.image.urlPlaceholder(), filteredPieceNames: platform?.filteredPieceNames ?? [], ssoEnabled: platform?.ssoEnabled ?? faker.datatype.boolean(), - filteredPieceBehavior: platform?.filteredPieceBehavior ?? faker.helpers.enumValue(FilteredPieceBehavior), + filteredPieceBehavior: + platform?.filteredPieceBehavior ?? + faker.helpers.enumValue(FilteredPieceBehavior), smtpHost: platform?.smtpHost ?? faker.internet.domainName(), smtpPort: platform?.smtpPort ?? faker.internet.port(), smtpUser: platform?.smtpUser ?? faker.internet.userName(), @@ -119,7 +165,9 @@ export const createMockPlatform = (platform?: Partial): Platform => { } } -export const createMockPlatformWithOwner = (params?: CreateMockPlatformWithOwnerParams): CreateMockPlatformWithOwnerReturn => { +export const createMockPlatformWithOwner = ( + params?: CreateMockPlatformWithOwnerParams, +): CreateMockPlatformWithOwnerReturn => { const mockOwnerId = params?.owner?.id ?? apId() const mockPlatformId = params?.platform?.id ?? apId() @@ -141,7 +189,9 @@ export const createMockPlatformWithOwner = (params?: CreateMockPlatformWithOwner } } -export const createMockProjectMember = (projectMember?: Partial): ProjectMember => { +export const createMockProjectMember = ( + projectMember?: Partial, +): ProjectMember => { return { id: projectMember?.id ?? apId(), created: projectMember?.created ?? faker.date.recent().toISOString(), @@ -150,11 +200,11 @@ export const createMockProjectMember = (projectMember?: Partial): email: projectMember?.email ?? faker.internet.email(), projectId: projectMember?.projectId ?? apId(), role: projectMember?.role ?? faker.helpers.enumValue(ProjectMemberRole), - status: projectMember?.status ?? faker.helpers.enumValue(ProjectMemberStatus), + status: + projectMember?.status ?? faker.helpers.enumValue(ProjectMemberStatus), } } - const MOCK_SIGNING_KEY_PUBLIC_KEY = `-----BEGIN RSA PUBLIC KEY----- MIICCgKCAgEAlnd5vGP/1bzcndN/yRD+ZTd6tuemxaJd+12bOZ2QCXcTM03AKSp3 NE5QMyIi13PXMg+z1uPowfivPJ4iVTMaW1U00O7JlUduGR0VrG0BCJlfEf852V71 @@ -169,7 +219,9 @@ j9mmntXsa/leIwBVspiEOHYZwJOe5+goSd8K1VIQJxC1DVBxB2eHxMvuo3eyJ0HE DlebIeZy4zrE1LPgRic1kfdemyxvuN3iwZnPGiY79nL1ZNDM3M4ApSMCAwEAAQ== -----END RSA PUBLIC KEY-----` -export const createMockApiKey = (apiKey?: Partial>): ApiKey & { value: string } => { +export const createMockApiKey = ( + apiKey?: Partial>, +): ApiKey & { value: string } => { const { secretHashed, secretTruncated, secret } = generateApiKey() return { id: apiKey?.id ?? apId(), @@ -183,7 +235,9 @@ export const createMockApiKey = (apiKey?: Partial { +export const setupMockApiKeyServiceAccount = ( + params?: SetupMockApiKeyServiceAccountParams, +): SetupMockApiKeyServiceAccountReturn => { const { mockOwner, mockPlatform } = createMockPlatformWithOwner({ owner: params?.owner, platform: params?.platform, @@ -201,7 +255,9 @@ export const setupMockApiKeyServiceAccount = (params?: SetupMockApiKeyServiceAcc } } -export const createMockSigningKey = (signingKey?: Partial): SigningKey => { +export const createMockSigningKey = ( + signingKey?: Partial, +): SigningKey => { return { id: signingKey?.id ?? apId(), created: signingKey?.created ?? faker.date.recent().toISOString(), @@ -214,20 +270,25 @@ export const createMockSigningKey = (signingKey?: Partial): SigningK } } -export const createProjectMember = (projectMember: Partial): ProjectMember => { +export const createProjectMember = ( + projectMember: Partial, +): ProjectMember => { return { id: projectMember.id ?? apId(), email: projectMember.email ?? faker.internet.email(), platformId: projectMember.platformId ?? apId(), projectId: projectMember.projectId ?? apId(), role: projectMember.role ?? faker.helpers.enumValue(ProjectMember.Role), - status: projectMember.status ?? faker.helpers.enumValue(ProjectMember.Status), + status: + projectMember.status ?? faker.helpers.enumValue(ProjectMember.Status), created: projectMember.created ?? faker.date.recent().toISOString(), updated: projectMember.updated ?? faker.date.recent().toISOString(), } } -export const createMockPieceMetadata = (pieceMetadata?: Partial>): Omit => { +export const createMockPieceMetadata = ( + pieceMetadata?: Partial>, +): Omit => { return { id: pieceMetadata?.id ?? apId(), created: pieceMetadata?.created ?? faker.date.recent().toISOString(), @@ -246,7 +307,8 @@ export const createMockPieceMetadata = (pieceMetadata?: Partial) => { } } -export const createMockCustomDomain = (customDomain?: Partial): CustomDomain => { +export const createMockCustomDomain = ( + customDomain?: Partial, +): CustomDomain => { return { id: customDomain?.id ?? apId(), created: customDomain?.created ?? faker.date.recent().toISOString(), @@ -284,10 +348,15 @@ export const createMockOtp = (otp?: Partial): OtpModel => { return { id: otp?.id ?? apId(), created: otp?.created ?? faker.date.recent().toISOString(), - updated: otp?.updated ?? faker.date.between({ from: twentyMinutesAgo.toDate(), to: now.toDate() }).toISOString(), + updated: + otp?.updated ?? + faker.date + .between({ from: twentyMinutesAgo.toDate(), to: now.toDate() }) + .toISOString(), type: otp?.type ?? faker.helpers.enumValue(OtpType), userId: otp?.userId ?? apId(), - value: otp?.value ?? faker.number.int({ min: 100000, max: 999999 }).toString(), + value: + otp?.value ?? faker.number.int({ min: 100000, max: 999999 }).toString(), state: otp?.state ?? faker.helpers.enumValue(OtpState), } } @@ -307,7 +376,8 @@ export const createMockFlowRun = (flowRun?: Partial): FlowRun => { status: flowRun?.status ?? faker.helpers.enumValue(ExecutionOutputStatus), startTime: flowRun?.startTime ?? faker.date.recent().toISOString(), finishTime: flowRun?.finishTime ?? faker.date.recent().toISOString(), - environment: flowRun?.environment ?? faker.helpers.enumValue(RunEnvironment), + environment: + flowRun?.environment ?? faker.helpers.enumValue(RunEnvironment), } } @@ -324,7 +394,9 @@ export const createMockFlow = (flow?: Partial): Flow => { } } -export const createMockFlowVersion = (flowVersion?: Partial): FlowVersion => { +export const createMockFlowVersion = ( + flowVersion?: Partial, +): FlowVersion => { const emptyTrigger = { type: TriggerType.EMPTY, name: 'trigger', diff --git a/packages/backend/test/integration/ce/authentication/authentication.test.ts b/packages/server/api/test/integration/ce/authentication/authentication.test.ts similarity index 95% rename from packages/backend/test/integration/ce/authentication/authentication.test.ts rename to packages/server/api/test/integration/ce/authentication/authentication.test.ts index 7a892fe3f8..e3d7fec055 100644 --- a/packages/backend/test/integration/ce/authentication/authentication.test.ts +++ b/packages/server/api/test/integration/ce/authentication/authentication.test.ts @@ -2,7 +2,10 @@ import { FastifyInstance } from 'fastify' import { StatusCodes } from 'http-status-codes' import { setupApp } from '../../../../src/app/app' import { databaseConnection } from '../../../../src/app/database/database-connection' -import { createMockSignInRequest, createMockSignUpRequest } from '../../../helpers/mocks/authn' +import { + createMockSignInRequest, + createMockSignUpRequest, +} from '../../../helpers/mocks/authn' import { createMockProject, createMockUser } from '../../../helpers/mocks' import { ApFlagId, ProjectType, UserStatus } from '@activepieces/shared' import { faker } from '@faker-js/faker' @@ -57,7 +60,6 @@ describe('Authentication API', () => { expect(responseBody?.projectId).toHaveLength(21) expect(responseBody?.token).toBeDefined() }) - it('Fails if USER_CREATED flag is set, and sign-up is disabled', async () => { // arrange @@ -93,9 +95,11 @@ describe('Authentication API', () => { expect(response?.statusCode).toBe(StatusCodes.OK) const responseBody = response?.json() - const project = await databaseConnection.getRepository('project').findOneBy({ - id: responseBody.projectId, - }) + const project = await databaseConnection + .getRepository('project') + .findOneBy({ + id: responseBody.projectId, + }) expect(project?.ownerId).toBe(responseBody.id) expect(project?.displayName).toBe(`${responseBody.firstName}'s Project`) @@ -190,6 +194,5 @@ describe('Authentication API', () => { const responseBody = response?.json() expect(responseBody?.code).toBe('INVALID_CREDENTIALS') }) - }) }) diff --git a/packages/backend/test/integration/ce/authentication/password-hasher.test.ts b/packages/server/api/test/integration/ce/authentication/password-hasher.test.ts similarity index 77% rename from packages/backend/test/integration/ce/authentication/password-hasher.test.ts rename to packages/server/api/test/integration/ce/authentication/password-hasher.test.ts index 33237815b3..58c34df064 100644 --- a/packages/backend/test/integration/ce/authentication/password-hasher.test.ts +++ b/packages/server/api/test/integration/ce/authentication/password-hasher.test.ts @@ -7,7 +7,6 @@ describe('Password Hasher', () => { const plainTextPassword = 'password123' describe('hash', () => { - it('should not produce the same hash for the same password', async () => { const hashedPassword1 = await bcrypt.hash(plainTextPassword, 10) const hashedPassword2 = await bcrypt.hash(plainTextPassword, 10) @@ -32,18 +31,23 @@ describe('Password Hasher', () => { }) }) - describe('compare', () => { it('should return true for identical bcrypt passwords', async () => { const hashedPassword = await bcrypt.hash(plainTextPassword, 10) - const result = await passwordHasher.compare(plainTextPassword, hashedPassword) + const result = await passwordHasher.compare( + plainTextPassword, + hashedPassword, + ) expect(result).toBe(true) }) it('should return false for different bcrypt passwords', async () => { const hashedPassword = await bcrypt.hash(plainTextPassword, 10) const differentPassword = 'differentPassword' - const result = await passwordHasher.compare(differentPassword, hashedPassword) + const result = await passwordHasher.compare( + differentPassword, + hashedPassword, + ) expect(result).toBe(false) }) @@ -66,20 +70,25 @@ describe('Password Hasher', () => { describe('compare - Scrypt', () => { const plainTextPassword = 'BusyBeaver$LOL99' - const salt = 'sPtDhWcd1MfdAw==' - const hashedPassword = 'iu1iqj6i6g9D7aBiE/Qdqv88GNnV/Ea67JK1kfLmzNgxsyCL8mhUxxI5VIHM9D+62xGHuZgjrfEBF+17wxyFIQ==' - + const salt = 'sPtDhWcd1MfdAw==' + const hashedPassword = + 'iu1iqj6i6g9D7aBiE/Qdqv88GNnV/Ea67JK1kfLmzNgxsyCL8mhUxxI5VIHM9D+62xGHuZgjrfEBF+17wxyFIQ==' + it('should return true for identical scrypt passwords', async () => { - const result = await passwordHasher.compare(plainTextPassword, `$scrypt$${hashedPassword}${SCRYPT_SEPERATOR}${salt}`) + const result = await passwordHasher.compare( + plainTextPassword, + `$scrypt$${hashedPassword}${SCRYPT_SEPERATOR}${salt}`, + ) expect(result).toBe(true) }) - it('should return false for different scrypt passwords', async () => { const differentPassword = 'differentPassword' - const result = await passwordHasher.compare(differentPassword, `$scrypt$${hashedPassword}${SCRYPT_SEPERATOR}${salt}`) + const result = await passwordHasher.compare( + differentPassword, + `$scrypt$${hashedPassword}${SCRYPT_SEPERATOR}${salt}`, + ) expect(result).toBe(false) }) - }) }) diff --git a/packages/backend/test/integration/ce/flows/flow-run/list-flow-runs.test.ts b/packages/server/api/test/integration/ce/flows/flow-run/list-flow-runs.test.ts similarity index 98% rename from packages/backend/test/integration/ce/flows/flow-run/list-flow-runs.test.ts rename to packages/server/api/test/integration/ce/flows/flow-run/list-flow-runs.test.ts index f463597e5f..84cb31c654 100644 --- a/packages/backend/test/integration/ce/flows/flow-run/list-flow-runs.test.ts +++ b/packages/server/api/test/integration/ce/flows/flow-run/list-flow-runs.test.ts @@ -18,7 +18,7 @@ afterAll(async () => { describe('List flow runs endpoint', () => { it('should return 200', async () => { - // arrange + // arrange const testToken = await generateMockToken({ type: PrincipalType.USER, }) diff --git a/packages/backend/test/integration/ce/flows/flow-worker.test.ts b/packages/server/api/test/integration/ce/flows/flow-worker.test.ts similarity index 67% rename from packages/backend/test/integration/ce/flows/flow-worker.test.ts rename to packages/server/api/test/integration/ce/flows/flow-worker.test.ts index 38c3fac72d..ace026270d 100644 --- a/packages/backend/test/integration/ce/flows/flow-worker.test.ts +++ b/packages/server/api/test/integration/ce/flows/flow-worker.test.ts @@ -1,10 +1,24 @@ -import { ActionType, ExecutionOutputStatus, ExecutionType, FlowStatus, FlowVersionState, RunEnvironment, TriggerType } from '@activepieces/shared' +import { + ActionType, + ExecutionOutputStatus, + ExecutionType, + FlowStatus, + FlowVersionState, + RunEnvironment, + TriggerType, +} from '@activepieces/shared' import { FastifyInstance } from 'fastify' import { databaseConnection } from '../../../../src/app/database/database-connection' import { setupApp } from '../../../../src/app/app' -import { createMockFlow, createMockFlowRun, createMockFlowVersion, createMockProject, createMockUser } from '../../../helpers/mocks' +import { + createMockFlow, + createMockFlowRun, + createMockFlowVersion, + createMockProject, + createMockUser, +} from '../../../helpers/mocks' import { flowWorker } from '../../../../src/app/workers/flow-worker/flow-worker' -import { fileCompressor } from '../../../../src/app/file/utils/file-compressor' +import { fileCompressor } from 'server-shared' let app: FastifyInstance | null = null @@ -19,7 +33,6 @@ afterAll(async () => { }) describe('flow execution', () => { - it('should execute simple flow with code and data mapper', async () => { const mockUser = createMockUser() await databaseConnection.getRepository('user').save([mockUser]) @@ -27,7 +40,10 @@ describe('flow execution', () => { const mockProject = createMockProject({ ownerId: mockUser.id }) await databaseConnection.getRepository('project').save([mockProject]) - const mockFlow = createMockFlow({ projectId: mockProject.id, status: FlowStatus.ENABLED }) + const mockFlow = createMockFlow({ + projectId: mockProject.id, + status: FlowStatus.ENABLED, + }) await databaseConnection.getRepository('flow').save([mockFlow]) const mockFlowVersion = createMockFlowVersion({ @@ -49,7 +65,7 @@ describe('flow execution', () => { settings: { inputUiInfo: {}, input: { - 'key': '{{ 1 + 2 }}', + key: '{{ 1 + 2 }}', }, sourceCode: { packageJson: '{}', @@ -73,7 +89,7 @@ describe('flow execution', () => { actionName: 'advanced_mapping', input: { mapping: { - 'key': '{{ 1 + 2 }}', + key: '{{ 1 + 2 }}', }, }, }, @@ -83,8 +99,9 @@ describe('flow execution', () => { }, }, }) - await databaseConnection.getRepository('flow_version').save([mockFlowVersion]) - + await databaseConnection + .getRepository('flow_version') + .save([mockFlowVersion]) const mockFlowRun = createMockFlowRun({ flowVersionId: mockFlowVersion.id, @@ -99,57 +116,59 @@ describe('flow execution', () => { projectId: mockProject.id, environment: RunEnvironment.PRODUCTION, runId: mockFlowRun.id, - payload: { - - }, + payload: {}, executionType: ExecutionType.BEGIN, }) - const flowRun = await databaseConnection.getRepository('flow_run').findOneByOrFail({ - id: mockFlowRun.id, - }) + const flowRun = await databaseConnection + .getRepository('flow_run') + .findOneByOrFail({ + id: mockFlowRun.id, + }) expect(flowRun.status).toEqual(ExecutionOutputStatus.SUCCEEDED) - - const file = await databaseConnection.getRepository('file').findOneByOrFail({ - id: flowRun.logsFileId, - }) + + const file = await databaseConnection + .getRepository('file') + .findOneByOrFail({ + id: flowRun.logsFileId, + }) const decompressedData = await fileCompressor.decompress({ data: file.data, compression: file.compression, }) - expect(JSON.parse(decompressedData.toString('utf-8')).executionState).toEqual( { - 'steps': { - 'webhook': { - 'type': 'WEBHOOK', - 'status': 'SUCCEEDED', - 'input': {}, - 'output': {}, + expect( + JSON.parse(decompressedData.toString('utf-8')).executionState, + ).toEqual({ + steps: { + webhook: { + type: 'WEBHOOK', + status: 'SUCCEEDED', + input: {}, + output: {}, }, - 'echo_step': { - 'type': 'CODE', - 'status': 'SUCCEEDED', - 'input': { - 'key': 3, + echo_step: { + type: 'CODE', + status: 'SUCCEEDED', + input: { + key: 3, }, - 'output': { - 'key': 3, + output: { + key: 3, }, }, - 'datamapper': { - 'type': 'PIECE', - 'status': 'SUCCEEDED', - 'input': { - 'mapping': { - 'key': 3, + datamapper: { + type: 'PIECE', + status: 'SUCCEEDED', + input: { + mapping: { + key: 3, }, }, - 'output': { - 'key': 3, + output: { + key: 3, }, }, }, }) - }, 60000) - -}) \ No newline at end of file +}) diff --git a/packages/backend/test/integration/ce/flows/flow.test.ts b/packages/server/api/test/integration/ce/flows/flow.test.ts similarity index 80% rename from packages/backend/test/integration/ce/flows/flow.test.ts rename to packages/server/api/test/integration/ce/flows/flow.test.ts index af4a5e2a0b..25e35c64f4 100644 --- a/packages/backend/test/integration/ce/flows/flow.test.ts +++ b/packages/server/api/test/integration/ce/flows/flow.test.ts @@ -1,10 +1,20 @@ import { databaseConnection } from '../../../../src/app/database/database-connection' import { setupApp } from '../../../../src/app/app' import { generateMockToken } from '../../../helpers/auth' -import { createMockUser, createMockProject, createMockFlow, createMockFlowVersion } from '../../../helpers/mocks' +import { + createMockUser, + createMockProject, + createMockFlow, + createMockFlowVersion, +} from '../../../helpers/mocks' import { StatusCodes } from 'http-status-codes' import { FastifyInstance } from 'fastify' -import { FlowOperationType, FlowStatus, FlowVersionState, PrincipalType } from '@activepieces/shared' +import { + FlowOperationType, + FlowStatus, + FlowVersionState, + PrincipalType, +} from '@activepieces/shared' let app: FastifyInstance | null = null @@ -20,7 +30,6 @@ afterAll(async () => { describe('Flow API', () => { describe('Create Flow endpoint', () => { - it('Adds an empty flow', async () => { // arrange const mockUser = createMockUser() @@ -29,7 +38,10 @@ describe('Flow API', () => { const mockProject = createMockProject({ ownerId: mockUser.id }) await databaseConnection.getRepository('project').save([mockProject]) - const mockToken = await generateMockToken({ type: PrincipalType.USER, projectId: mockProject.id }) + const mockToken = await generateMockToken({ + type: PrincipalType.USER, + projectId: mockProject.id, + }) const mockCreateFlowRequest = { displayName: 'test flow', @@ -90,17 +102,28 @@ describe('Flow API', () => { const mockProject = createMockProject({ ownerId: mockUser.id }) await databaseConnection.getRepository('project').save([mockProject]) - const mockFlow = createMockFlow({ projectId: mockProject.id, status: FlowStatus.DISABLED }) + const mockFlow = createMockFlow({ + projectId: mockProject.id, + status: FlowStatus.DISABLED, + }) await databaseConnection.getRepository('flow').save([mockFlow]) - const mockFlowVersion = createMockFlowVersion({ flowId: mockFlow.id, updatedBy: mockUser.id }) - await databaseConnection.getRepository('flow_version').save([mockFlowVersion]) + const mockFlowVersion = createMockFlowVersion({ + flowId: mockFlow.id, + updatedBy: mockUser.id, + }) + await databaseConnection + .getRepository('flow_version') + .save([mockFlowVersion]) await databaseConnection.getRepository('flow').update(mockFlow.id, { publishedVersionId: mockFlowVersion.id, }) - const mockToken = await generateMockToken({ type: PrincipalType.USER, projectId: mockProject.id }) + const mockToken = await generateMockToken({ + type: PrincipalType.USER, + projectId: mockProject.id, + }) const mockUpdateFlowStatusRequest = { type: FlowOperationType.CHANGE_STATUS, @@ -145,17 +168,28 @@ describe('Flow API', () => { const mockProject = createMockProject({ ownerId: mockUser.id }) await databaseConnection.getRepository('project').save([mockProject]) - const mockFlow = createMockFlow({ projectId: mockProject.id, status: FlowStatus.ENABLED }) + const mockFlow = createMockFlow({ + projectId: mockProject.id, + status: FlowStatus.ENABLED, + }) await databaseConnection.getRepository('flow').save([mockFlow]) - const mockFlowVersion = createMockFlowVersion({ flowId: mockFlow.id, updatedBy: mockUser.id }) - await databaseConnection.getRepository('flow_version').save([mockFlowVersion]) + const mockFlowVersion = createMockFlowVersion({ + flowId: mockFlow.id, + updatedBy: mockUser.id, + }) + await databaseConnection + .getRepository('flow_version') + .save([mockFlowVersion]) await databaseConnection.getRepository('flow').update(mockFlow.id, { publishedVersionId: mockFlowVersion.id, }) - const mockToken = await generateMockToken({ type: PrincipalType.USER, projectId: mockProject.id }) + const mockToken = await generateMockToken({ + type: PrincipalType.USER, + projectId: mockProject.id, + }) const mockUpdateFlowStatusRequest = { type: FlowOperationType.CHANGE_STATUS, @@ -202,7 +236,10 @@ describe('Flow API', () => { const mockProject = createMockProject({ ownerId: mockUser.id }) await databaseConnection.getRepository('project').save([mockProject]) - const mockFlow = createMockFlow({ projectId: mockProject.id, status: FlowStatus.DISABLED }) + const mockFlow = createMockFlow({ + projectId: mockProject.id, + status: FlowStatus.DISABLED, + }) await databaseConnection.getRepository('flow').save([mockFlow]) const mockFlowVersion = createMockFlowVersion({ @@ -210,7 +247,9 @@ describe('Flow API', () => { updatedBy: mockUser.id, state: FlowVersionState.DRAFT, }) - await databaseConnection.getRepository('flow_version').save([mockFlowVersion]) + await databaseConnection + .getRepository('flow_version') + .save([mockFlowVersion]) const mockToken = await generateMockToken({ id: mockUser.id, @@ -260,15 +299,32 @@ describe('Flow API', () => { const mockProject = createMockProject({ ownerId: mockUser.id }) await databaseConnection.getRepository('project').save([mockProject]) - const mockEnabledFlow = createMockFlow({ projectId: mockProject.id, status: FlowStatus.ENABLED }) - const mockDisabledFlow = createMockFlow({ projectId: mockProject.id, status: FlowStatus.DISABLED }) - await databaseConnection.getRepository('flow').save([mockEnabledFlow, mockDisabledFlow]) + const mockEnabledFlow = createMockFlow({ + projectId: mockProject.id, + status: FlowStatus.ENABLED, + }) + const mockDisabledFlow = createMockFlow({ + projectId: mockProject.id, + status: FlowStatus.DISABLED, + }) + await databaseConnection + .getRepository('flow') + .save([mockEnabledFlow, mockDisabledFlow]) - const mockEnabledFlowVersion = createMockFlowVersion({ flowId: mockEnabledFlow.id }) - const mockDisabledFlowVersion = createMockFlowVersion({ flowId: mockDisabledFlow.id }) - await databaseConnection.getRepository('flow_version').save([mockEnabledFlowVersion, mockDisabledFlowVersion]) + const mockEnabledFlowVersion = createMockFlowVersion({ + flowId: mockEnabledFlow.id, + }) + const mockDisabledFlowVersion = createMockFlowVersion({ + flowId: mockDisabledFlow.id, + }) + await databaseConnection + .getRepository('flow_version') + .save([mockEnabledFlowVersion, mockDisabledFlowVersion]) - const mockToken = await generateMockToken({ type: PrincipalType.USER, projectId: mockProject.id }) + const mockToken = await generateMockToken({ + type: PrincipalType.USER, + projectId: mockProject.id, + }) // act const response = await app?.inject({ @@ -303,9 +359,14 @@ describe('Flow API', () => { await databaseConnection.getRepository('flow').save([mockFlow]) const mockFlowVersion = createMockFlowVersion({ flowId: mockFlow.id }) - await databaseConnection.getRepository('flow_version').save([mockFlowVersion]) + await databaseConnection + .getRepository('flow_version') + .save([mockFlowVersion]) - const mockToken = await generateMockToken({ type: PrincipalType.USER, projectId: mockProject.id }) + const mockToken = await generateMockToken({ + type: PrincipalType.USER, + projectId: mockProject.id, + }) // act const response = await app?.inject({ @@ -339,7 +400,10 @@ describe('Flow API', () => { const mockFlow = createMockFlow({ projectId: mockProject.id }) await databaseConnection.getRepository('flow').save([mockFlow]) - const mockToken = await generateMockToken({ type: PrincipalType.USER, projectId: mockProject.id }) + const mockToken = await generateMockToken({ + type: PrincipalType.USER, + projectId: mockProject.id, + }) // act const response = await app?.inject({ diff --git a/packages/backend/test/integration/ce/flows/project-worker.test.ts b/packages/server/api/test/integration/ce/flows/project-worker.test.ts similarity index 91% rename from packages/backend/test/integration/ce/flows/project-worker.test.ts rename to packages/server/api/test/integration/ce/flows/project-worker.test.ts index 558727d397..228ed485ae 100644 --- a/packages/backend/test/integration/ce/flows/project-worker.test.ts +++ b/packages/server/api/test/integration/ce/flows/project-worker.test.ts @@ -28,7 +28,10 @@ describe('Project Worker API', () => { const mockProject = createMockProject({ ownerId: mockUser.id }) await databaseConnection.getRepository('project').save([mockProject]) - const mockToken = await generateMockToken({ type: PrincipalType.WORKER, projectId: mockProject.id }) + const mockToken = await generateMockToken({ + type: PrincipalType.WORKER, + projectId: mockProject.id, + }) // act const response = await app?.inject({ diff --git a/packages/backend/test/integration/cloud/api-key/api-key.test.ts b/packages/server/api/test/integration/cloud/api-key/api-key.test.ts similarity index 88% rename from packages/backend/test/integration/cloud/api-key/api-key.test.ts rename to packages/server/api/test/integration/cloud/api-key/api-key.test.ts index 469b738a74..73ba3c8281 100644 --- a/packages/backend/test/integration/cloud/api-key/api-key.test.ts +++ b/packages/server/api/test/integration/cloud/api-key/api-key.test.ts @@ -1,7 +1,11 @@ import { databaseConnection } from '../../../../src/app/database/database-connection' import { setupApp } from '../../../../src/app/app' import { generateMockToken } from '../../../helpers/auth' -import { createMockUser, createMockPlatform, createMockApiKey } from '../../../helpers/mocks' +import { + createMockUser, + createMockPlatform, + createMockApiKey, +} from '../../../helpers/mocks' import { StatusCodes } from 'http-status-codes' import { FastifyInstance } from 'fastify' import { PlatformRole, PrincipalType, apId } from '@activepieces/shared' @@ -60,7 +64,6 @@ describe('API Key API', () => { expect(responseBody.value).toContain('sk-') }) - it('Fails if platform is not found', async () => { // arrange const nonExistentPlatformId = apId() @@ -88,21 +91,22 @@ describe('API Key API', () => { // assert expect(response?.statusCode).toBe(StatusCodes.INTERNAL_SERVER_ERROR) }) - - }) - describe('Delete API Key endpoint', () => { it('Fail if non owner', async () => { // arrange const mockUser = createMockUser() const mockUserTwo = createMockUser() - await databaseConnection.getRepository('user').save([mockUser, mockUserTwo]) + await databaseConnection + .getRepository('user') + .save([mockUser, mockUserTwo]) const mockPlatform = createMockPlatform({ ownerId: mockUser.id }) const mockPlatform2 = createMockPlatform({ ownerId: mockUserTwo.id }) - await databaseConnection.getRepository('platform').save([mockPlatform, mockPlatform2]) + await databaseConnection + .getRepository('platform') + .save([mockPlatform, mockPlatform2]) const mockApiKey = createMockApiKey({ platformId: mockPlatform.id, @@ -130,17 +134,20 @@ describe('API Key API', () => { }) }) - describe('List API Keys endpoint', () => { it('Filters Signing Keys by platform', async () => { // arrange const mockUserOne = createMockUser() const mockUserTwo = createMockUser() - await databaseConnection.getRepository('user').save([mockUserOne, mockUserTwo]) + await databaseConnection + .getRepository('user') + .save([mockUserOne, mockUserTwo]) const mockPlatformOne = createMockPlatform({ ownerId: mockUserOne.id }) const mockPlatformTwo = createMockPlatform({ ownerId: mockUserTwo.id }) - await databaseConnection.getRepository('platform').save([mockPlatformOne, mockPlatformTwo]) + await databaseConnection + .getRepository('platform') + .save([mockPlatformOne, mockPlatformTwo]) const mockKeyOne = createMockApiKey({ platformId: mockPlatformOne.id, @@ -150,7 +157,9 @@ describe('API Key API', () => { platformId: mockPlatformTwo.id, }) - await databaseConnection.getRepository('api_key').save([mockKeyOne, mockKeyTwo]) + await databaseConnection + .getRepository('api_key') + .save([mockKeyOne, mockKeyTwo]) const testToken = await generateMockToken({ type: PrincipalType.USER, diff --git a/packages/backend/test/integration/cloud/app-sumo/app-sumo.test.ts b/packages/server/api/test/integration/cloud/app-sumo/app-sumo.test.ts similarity index 90% rename from packages/backend/test/integration/cloud/app-sumo/app-sumo.test.ts rename to packages/server/api/test/integration/cloud/app-sumo/app-sumo.test.ts index e175f60332..62e2bfd7cd 100644 --- a/packages/backend/test/integration/cloud/app-sumo/app-sumo.test.ts +++ b/packages/server/api/test/integration/cloud/app-sumo/app-sumo.test.ts @@ -45,7 +45,9 @@ describe('AppSumo API', () => { const responseBody = response?.json() expect(responseBody?.message).toBe('success') - expect(responseBody?.redirect_url).toBe(`https://cloud.activepieces.com/sign-up?email=${mockEmail}`) + expect(responseBody?.redirect_url).toBe( + `https://cloud.activepieces.com/sign-up?email=${mockEmail}`, + ) }) }) }) diff --git a/packages/backend/test/integration/cloud/audit-event/audit-event.test.ts b/packages/server/api/test/integration/cloud/audit-event/audit-event.test.ts similarity index 69% rename from packages/backend/test/integration/cloud/audit-event/audit-event.test.ts rename to packages/server/api/test/integration/cloud/audit-event/audit-event.test.ts index 52287b42d9..c3129d537a 100644 --- a/packages/backend/test/integration/cloud/audit-event/audit-event.test.ts +++ b/packages/server/api/test/integration/cloud/audit-event/audit-event.test.ts @@ -1,7 +1,12 @@ import { databaseConnection } from '../../../../src/app/database/database-connection' import { setupApp } from '../../../../src/app/app' import { generateMockToken } from '../../../helpers/auth' -import { createMockUser, createMockPlatform, createAuditEvent, createMockProject } from '../../../helpers/mocks' +import { + createMockUser, + createMockPlatform, + createAuditEvent, + createMockProject, +} from '../../../helpers/mocks' import { StatusCodes } from 'http-status-codes' import { FastifyInstance } from 'fastify' import { PlatformRole, PrincipalType } from '@activepieces/shared' @@ -19,17 +24,22 @@ afterAll(async () => { }) describe('Audit Event API', () => { - describe('List Audit event API', () => { it('should list audit events', async () => { // arrange const mockUser1 = createMockUser() await databaseConnection.getRepository('user').save(mockUser1) - const mockPlatform1 = createMockPlatform({ ownerId: mockUser1.id, auditLogEnabled: true }) + const mockPlatform1 = createMockPlatform({ + ownerId: mockUser1.id, + auditLogEnabled: true, + }) await databaseConnection.getRepository('platform').save(mockPlatform1) - const mockProject1 = createMockProject({ platformId: mockPlatform1.id, ownerId: mockUser1.id }) + const mockProject1 = createMockProject({ + platformId: mockPlatform1.id, + ownerId: mockUser1.id, + }) await databaseConnection.getRepository('project').save(mockProject1) const mockUser2 = createMockUser() @@ -38,7 +48,10 @@ describe('Audit Event API', () => { const mockPlatform2 = createMockPlatform({ ownerId: mockUser2.id }) await databaseConnection.getRepository('platform').save(mockPlatform2) - const mockProject2 = createMockProject({ platformId: mockPlatform2.id, ownerId: mockUser2.id }) + const mockProject2 = createMockProject({ + platformId: mockPlatform2.id, + ownerId: mockUser2.id, + }) await databaseConnection.getRepository('project').save(mockProject2) const testToken1 = await generateMockToken({ @@ -48,16 +61,32 @@ describe('Audit Event API', () => { }) const mockAuditEvents1 = [ - createAuditEvent({ platformId: mockPlatform1.id, userId: mockUser1.id }), - createAuditEvent({ platformId: mockPlatform1.id, userId: mockUser1.id }), + createAuditEvent({ + platformId: mockPlatform1.id, + userId: mockUser1.id, + }), + createAuditEvent({ + platformId: mockPlatform1.id, + userId: mockUser1.id, + }), ] - await databaseConnection.getRepository('audit_event').save(mockAuditEvents1) + await databaseConnection + .getRepository('audit_event') + .save(mockAuditEvents1) const mockAuditEvents2 = [ - createAuditEvent({ platformId: mockPlatform2.id, userId: mockUser2.id }), - createAuditEvent({ platformId: mockPlatform2.id, userId: mockUser2.id }), + createAuditEvent({ + platformId: mockPlatform2.id, + userId: mockUser2.id, + }), + createAuditEvent({ + platformId: mockPlatform2.id, + userId: mockUser2.id, + }), ] - await databaseConnection.getRepository('audit_event').save(mockAuditEvents2) + await databaseConnection + .getRepository('audit_event') + .save(mockAuditEvents2) // act const response1 = await app?.inject({ @@ -89,7 +118,10 @@ describe('Audit Event API', () => { const mockPlatform1 = createMockPlatform({ ownerId: mockUser1.id }) await databaseConnection.getRepository('platform').save(mockPlatform1) - const mockProject1 = createMockProject({ platformId: mockPlatform1.id, ownerId: mockUser1.id }) + const mockProject1 = createMockProject({ + platformId: mockPlatform1.id, + ownerId: mockUser1.id, + }) await databaseConnection.getRepository('project').save(mockProject1) const testToken1 = await generateMockToken({ diff --git a/packages/backend/test/integration/cloud/authn/cloud-authn.test.ts b/packages/server/api/test/integration/cloud/authn/cloud-authn.test.ts similarity index 77% rename from packages/backend/test/integration/cloud/authn/cloud-authn.test.ts rename to packages/server/api/test/integration/cloud/authn/cloud-authn.test.ts index a1e9c5467d..80b811f756 100644 --- a/packages/backend/test/integration/cloud/authn/cloud-authn.test.ts +++ b/packages/server/api/test/integration/cloud/authn/cloud-authn.test.ts @@ -2,13 +2,35 @@ import { FastifyInstance } from 'fastify' import { StatusCodes } from 'http-status-codes' import { setupApp } from '../../../../src/app/app' import { databaseConnection } from '../../../../src/app/database/database-connection' -import { createMockSignInRequest, createMockSignUpRequest } from '../../../helpers/mocks/authn' -import { CLOUD_PLATFORM_ID, createMockCustomDomain, createMockPlatform, createMockProject, createMockUser, createProjectMember } from '../../../helpers/mocks' -import { ApFlagId, ProjectType, User, UserStatus, apId } from '@activepieces/shared' +import { + createMockSignInRequest, + createMockSignUpRequest, +} from '../../../helpers/mocks/authn' +import { + CLOUD_PLATFORM_ID, + createMockCustomDomain, + createMockPlatform, + createMockProject, + createMockUser, + createProjectMember, +} from '../../../helpers/mocks' +import { + ApFlagId, + ProjectType, + User, + UserStatus, + apId, +} from '@activepieces/shared' import { faker } from '@faker-js/faker' import { emailService } from '../../../../src/app/ee/helper/email/email-service' import { stripeHelper } from '../../../../src/app/ee/billing/billing/stripe-helper' -import { CustomDomain, OtpType, Platform, ProjectMemberRole, ProjectMemberStatus } from '@activepieces/ee-shared' +import { + CustomDomain, + OtpType, + Platform, + ProjectMemberRole, + ProjectMemberStatus, +} from '@activepieces/ee-shared' import { decodeToken } from '../../../helpers/auth' let app: FastifyInstance | null = null @@ -20,7 +42,9 @@ beforeAll(async () => { beforeEach(async () => { emailService.sendOtpEmail = jest.fn() - stripeHelper.getOrCreateCustomer = jest.fn().mockResolvedValue(faker.string.alphanumeric()) + stripeHelper.getOrCreateCustomer = jest + .fn() + .mockResolvedValue(faker.string.alphanumeric()) await databaseConnection.getRepository('flag').delete({}) }) @@ -32,17 +56,22 @@ afterAll(async () => { describe('Authentication API', () => { describe('Sign up Endpoint', () => { - it('Add new user if the domain is allowed', async () => { // arrange - const { mockPlatform, mockUser, mockCustomDomain } = await createMockPlatformAndDomain() + const { mockPlatform, mockUser, mockCustomDomain } = + await createMockPlatformAndDomain() const mockSignUpRequest = createMockSignUpRequest() - await databaseConnection.getRepository('platform').update(mockPlatform.id, { - enforceAllowedAuthDomains: true, - allowedAuthDomains: [mockSignUpRequest.email.split('@')[1]], - }) + await databaseConnection + .getRepository('platform') + .update(mockPlatform.id, { + enforceAllowedAuthDomains: true, + allowedAuthDomains: [mockSignUpRequest.email.split('@')[1]], + }) - const mockProject = createMockProject({ ownerId: mockUser.id, platformId: mockPlatform.id }) + const mockProject = createMockProject({ + ownerId: mockUser.id, + platformId: mockPlatform.id, + }) await databaseConnection.getRepository('project').save(mockProject) const mockProjectMember = createProjectMember({ @@ -52,7 +81,9 @@ describe('Authentication API', () => { status: ProjectMemberStatus.ACTIVE, role: ProjectMemberRole.ADMIN, }) - await databaseConnection.getRepository('project_member').save(mockProjectMember) + await databaseConnection + .getRepository('project_member') + .save(mockProjectMember) // act const response = await app?.inject({ @@ -70,12 +101,15 @@ describe('Authentication API', () => { }) it('Fails If the domain is not allowed', async () => { // arrange - const { mockPlatform, mockCustomDomain } = await createMockPlatformAndDomain() - await databaseConnection.getRepository('platform').update(mockPlatform.id, { - enforceAllowedAuthDomains: true, - allowedAuthDomains: [], - ssoEnabled: true, - }) + const { mockPlatform, mockCustomDomain } = + await createMockPlatformAndDomain() + await databaseConnection + .getRepository('platform') + .update(mockPlatform.id, { + enforceAllowedAuthDomains: true, + allowedAuthDomains: [], + ssoEnabled: true, + }) const mockSignUpRequest = createMockSignUpRequest() // act @@ -96,8 +130,8 @@ describe('Authentication API', () => { }) it('Adds new user', async () => { - - const { mockPlatform, mockCustomDomain } = await createMockPlatformAndDomain(CLOUD_PLATFORM_ID) + const { mockPlatform, mockCustomDomain } = + await createMockPlatformAndDomain(CLOUD_PLATFORM_ID) // arrange const mockSignUpRequest = createMockSignUpRequest() @@ -136,7 +170,8 @@ describe('Authentication API', () => { it('Sends a verification email', async () => { // arrange const mockSignUpRequest = createMockSignUpRequest() - const { mockCustomDomain, mockPlatform } = await createMockPlatformAndDomain(CLOUD_PLATFORM_ID) + const { mockCustomDomain, mockPlatform } = + await createMockPlatformAndDomain(CLOUD_PLATFORM_ID) // act const response = await app?.inject({ method: 'POST', @@ -165,8 +200,15 @@ describe('Authentication API', () => { it('auto verify invited users to continue platform sign up', async () => { // arrange - const { mockUser: mockPlatformOwner, mockPlatform, mockCustomDomain } = await createMockPlatformAndDomain() - const mockProject = createMockProject({ ownerId: mockPlatformOwner.id, platformId: mockPlatform.id }) + const { + mockUser: mockPlatformOwner, + mockPlatform, + mockCustomDomain, + } = await createMockPlatformAndDomain() + const mockProject = createMockProject({ + ownerId: mockPlatformOwner.id, + platformId: mockPlatform.id, + }) await databaseConnection.getRepository('project').save(mockProject) const mockedUpEmail = faker.internet.email() @@ -177,10 +219,13 @@ describe('Authentication API', () => { status: ProjectMemberStatus.ACTIVE, role: ProjectMemberRole.ADMIN, }) - await databaseConnection.getRepository('project_member').save(mockProjectMember) + await databaseConnection + .getRepository('project_member') + .save(mockProjectMember) - - const mockSignUpRequest = createMockSignUpRequest({ email: mockedUpEmail }) + const mockSignUpRequest = createMockSignUpRequest({ + email: mockedUpEmail, + }) // act const response = await app?.inject({ @@ -207,7 +252,9 @@ describe('Authentication API', () => { const { mockCustomDomain } = await createMockPlatformAndDomain() const mockedUpEmail = faker.internet.email() - const mockSignUpRequest = createMockSignUpRequest({ email: mockedUpEmail }) + const mockSignUpRequest = createMockSignUpRequest({ + email: mockedUpEmail, + }) // act const response = await app?.inject({ @@ -228,14 +275,20 @@ describe('Authentication API', () => { it('Adds tasks for referrals', async () => { // arrange - const { mockCustomDomain, mockPlatform } = await createMockPlatformAndDomain(CLOUD_PLATFORM_ID) + const { mockCustomDomain, mockPlatform } = + await createMockPlatformAndDomain(CLOUD_PLATFORM_ID) const mockReferringUser = createMockUser({ platformId: mockPlatform.id }) await databaseConnection.getRepository('user').save(mockReferringUser) - const mockProject = createMockProject({ ownerId: mockReferringUser.id, platformId: mockPlatform.id }) + const mockProject = createMockProject({ + ownerId: mockReferringUser.id, + platformId: mockPlatform.id, + }) await databaseConnection.getRepository('project').save(mockProject) - const mockSignUpRequest = createMockSignUpRequest({ referringUserId: mockReferringUser.id }) + const mockSignUpRequest = createMockSignUpRequest({ + referringUserId: mockReferringUser.id, + }) // act const response = await app?.inject({ @@ -251,23 +304,28 @@ describe('Authentication API', () => { expect(response?.statusCode).toBe(StatusCodes.OK) const responseBody = response?.json() - const referral = await databaseConnection.getRepository('referal').findOneBy({ - referredUserId: responseBody?.id, - }) + const referral = await databaseConnection + .getRepository('referal') + .findOneBy({ + referredUserId: responseBody?.id, + }) expect(referral?.referringUserId).toBe(mockReferringUser.id) - const referringUserPlan = await databaseConnection.getRepository('project_plan').findOneBy({ - projectId: mockProject.id, - }) + const referringUserPlan = await databaseConnection + .getRepository('project_plan') + .findOneBy({ + projectId: mockProject.id, + }) expect(referringUserPlan?.tasks).toBe(1500) - const referredUserPlan = await databaseConnection.getRepository('project_plan').findOneBy({ - projectId: responseBody?.projectId, - }) + const referredUserPlan = await databaseConnection + .getRepository('project_plan') + .findOneBy({ + projectId: responseBody?.projectId, + }) expect(referredUserPlan?.tasks).toBe(1500) }) - it('Fails if USER_CREATED flag is set, and sign-up is disabled', async () => { // arrange const mockSignUpRequest = createMockSignUpRequest() @@ -288,8 +346,8 @@ describe('Authentication API', () => { }) it('Creates new project for cloud user', async () => { - - const { mockPlatform, mockCustomDomain } = await createMockPlatformAndDomain(CLOUD_PLATFORM_ID) + const { mockPlatform, mockCustomDomain } = + await createMockPlatformAndDomain(CLOUD_PLATFORM_ID) // arrange const mockSignUpRequest = createMockSignUpRequest() @@ -303,30 +361,29 @@ describe('Authentication API', () => { body: mockSignUpRequest, }) - // assert expect(response?.statusCode).toBe(StatusCodes.OK) const responseBody = response?.json() - const project = await databaseConnection.getRepository('project').findOneBy({ - id: responseBody.projectId, - }) + const project = await databaseConnection + .getRepository('project') + .findOneBy({ + id: responseBody.projectId, + }) expect(project?.ownerId).toBe(responseBody.id) expect(project?.displayName).toBe(`${responseBody.firstName}'s Project`) expect(project?.type).toBe(ProjectType.PLATFORM_MANAGED) expect(project?.platformId).toBe(mockPlatform.id) }) - }) describe('Sign in Endpoint', () => { - it('Fails If the email auth is not enabled', async () => { // arrange const mockPlatformId = faker.string.nanoid() const mockPlatformDomain = faker.internet.domainName() - + const rawPassword = faker.internet.password() const mockUser = createMockUser({ email: faker.internet.email(), @@ -336,25 +393,34 @@ describe('Authentication API', () => { platformId: mockPlatformId, }) await databaseConnection.getRepository('user').save(mockUser) - - const mockPlatform = createMockPlatform({ id: mockPlatformId, ownerId: mockUser.id, emailAuthEnabled: false, ssoEnabled: true }) + + const mockPlatform = createMockPlatform({ + id: mockPlatformId, + ownerId: mockUser.id, + emailAuthEnabled: false, + ssoEnabled: true, + }) await databaseConnection.getRepository('platform').save(mockPlatform) - - const mockCustomDomain = createMockCustomDomain({ platformId: mockPlatformId, domain: mockPlatformDomain }) - await databaseConnection.getRepository('custom_domain').save(mockCustomDomain) - + + const mockCustomDomain = createMockCustomDomain({ + platformId: mockPlatformId, + domain: mockPlatformDomain, + }) + await databaseConnection + .getRepository('custom_domain') + .save(mockCustomDomain) + const mockProject = createMockProject({ ownerId: mockUser.id, platformId: mockPlatformId, }) await databaseConnection.getRepository('project').save(mockProject) - - + const mockSignInRequest = createMockSignInRequest({ email: mockUser.email, password: rawPassword, }) - + // act const response = await app?.inject({ method: 'POST', @@ -366,7 +432,7 @@ describe('Authentication API', () => { }) expect(response?.statusCode).toBe(StatusCodes.FORBIDDEN) const responseBody = response?.json() - + expect(responseBody?.code).toBe('EMAIL_AUTH_DISABLED') }) @@ -385,11 +451,22 @@ describe('Authentication API', () => { }) await databaseConnection.getRepository('user').save(mockUser) - const mockPlatform = createMockPlatform({ id: mockPlatformId, ownerId: mockUser.id, allowedAuthDomains: [mockPlatformDomain], enforceAllowedAuthDomains: true, ssoEnabled: true }) + const mockPlatform = createMockPlatform({ + id: mockPlatformId, + ownerId: mockUser.id, + allowedAuthDomains: [mockPlatformDomain], + enforceAllowedAuthDomains: true, + ssoEnabled: true, + }) await databaseConnection.getRepository('platform').save(mockPlatform) - const mockCustomDomain = createMockCustomDomain({ platformId: mockPlatformId, domain: mockPlatformDomain }) - await databaseConnection.getRepository('custom_domain').save(mockCustomDomain) + const mockCustomDomain = createMockCustomDomain({ + platformId: mockPlatformId, + domain: mockPlatformDomain, + }) + await databaseConnection + .getRepository('custom_domain') + .save(mockCustomDomain) const mockProject = createMockProject({ ownerId: mockUser.id, @@ -397,7 +474,6 @@ describe('Authentication API', () => { }) await databaseConnection.getRepository('project').save(mockProject) - const mockSignInRequest = createMockSignInRequest({ email: mockUser.email, password: rawPassword, @@ -484,11 +560,19 @@ describe('Authentication API', () => { }) await databaseConnection.getRepository('user').save(mockUser) - const mockPlatform = createMockPlatform({ id: mockPlatformId, ownerId: mockUser.id }) + const mockPlatform = createMockPlatform({ + id: mockPlatformId, + ownerId: mockUser.id, + }) await databaseConnection.getRepository('platform').save(mockPlatform) - const mockCustomDomain = createMockCustomDomain({ platformId: mockPlatformId, domain: mockPlatformDomain }) - await databaseConnection.getRepository('custom_domain').save(mockCustomDomain) + const mockCustomDomain = createMockCustomDomain({ + platformId: mockPlatformId, + domain: mockPlatformDomain, + }) + await databaseConnection + .getRepository('custom_domain') + .save(mockCustomDomain) const mockProject = createMockProject({ ownerId: mockUser.id, @@ -537,11 +621,19 @@ describe('Authentication API', () => { }) await databaseConnection.getRepository('user').save(mockUser) - const mockPlatform = createMockPlatform({ id: mockPlatformId, ownerId: mockUser.id }) + const mockPlatform = createMockPlatform({ + id: mockPlatformId, + ownerId: mockUser.id, + }) await databaseConnection.getRepository('platform').save(mockPlatform) - const mockCustomDomain = createMockCustomDomain({ platformId: mockPlatformId, domain: mockPlatformDomain }) - await databaseConnection.getRepository('custom_domain').save(mockCustomDomain) + const mockCustomDomain = createMockCustomDomain({ + platformId: mockPlatformId, + domain: mockPlatformDomain, + }) + await databaseConnection + .getRepository('custom_domain') + .save(mockCustomDomain) const mockSignInRequest = createMockSignInRequest({ email: mockEmail, @@ -564,7 +656,9 @@ describe('Authentication API', () => { expect(responseBody?.code).toBe('ENTITY_NOT_FOUND') expect(responseBody?.params?.entityType).toBe('project') - expect(responseBody?.params?.message).toBe(`no projects found for the user=${mockUser.id}`) + expect(responseBody?.params?.message).toBe( + `no projects found for the user=${mockUser.id}`, + ) }) it('Fails if password doesn\'t match', async () => { @@ -643,14 +737,27 @@ describe('Authentication API', () => { }) }) -async function createMockPlatformAndDomain(platformId?: string): Promise<{ mockUser: User, mockPlatform: Platform, mockCustomDomain: CustomDomain }> { +async function createMockPlatformAndDomain( + platformId?: string, +): Promise<{ + mockUser: User + mockPlatform: Platform + mockCustomDomain: CustomDomain + }> { const mockUser = createMockUser() await databaseConnection.getRepository('user').save(mockUser) - const mockPlatform = createMockPlatform({ ownerId: mockUser.id, id: platformId ?? apId() }) + const mockPlatform = createMockPlatform({ + ownerId: mockUser.id, + id: platformId ?? apId(), + }) await databaseConnection.getRepository('platform').save(mockPlatform) - const mockCustomDomain = createMockCustomDomain({ platformId: mockPlatform.id }) - await databaseConnection.getRepository('custom_domain').save(mockCustomDomain) + const mockCustomDomain = createMockCustomDomain({ + platformId: mockPlatform.id, + }) + await databaseConnection + .getRepository('custom_domain') + .save(mockCustomDomain) return { mockUser, mockPlatform, mockCustomDomain } -} \ No newline at end of file +} diff --git a/packages/backend/test/integration/cloud/authn/enterprise-local-authn.test.ts b/packages/server/api/test/integration/cloud/authn/enterprise-local-authn.test.ts similarity index 89% rename from packages/backend/test/integration/cloud/authn/enterprise-local-authn.test.ts rename to packages/server/api/test/integration/cloud/authn/enterprise-local-authn.test.ts index 2ffe450af6..72e9b0d575 100644 --- a/packages/backend/test/integration/cloud/authn/enterprise-local-authn.test.ts +++ b/packages/server/api/test/integration/cloud/authn/enterprise-local-authn.test.ts @@ -51,10 +51,14 @@ describe('Enterprise Local Authn API', () => { expect(response?.statusCode).toBe(StatusCodes.OK) expect(response?.body).toBe('') - const user = await databaseConnection.getRepository('user').findOneBy({ id: mockUser.id }) + const user = await databaseConnection + .getRepository('user') + .findOneBy({ id: mockUser.id }) expect(user?.status).toBe(UserStatus.ACTIVE) expect(user?.verified).toBe(true) - const otp = await databaseConnection.getRepository('otp').findOneBy({ id: mockOtp.id }) + const otp = await databaseConnection + .getRepository('otp') + .findOneBy({ id: mockOtp.id }) expect(otp?.state).toBe(OtpState.CONFIRMED) }) @@ -92,10 +96,11 @@ describe('Enterprise Local Authn API', () => { const responseBody = response?.json() expect(responseBody?.code).toBe('INVALID_OTP') - const user = await databaseConnection.getRepository('user').findOneBy({ id: mockUser.id }) + const user = await databaseConnection + .getRepository('user') + .findOneBy({ id: mockUser.id }) expect(user?.status).toBe(UserStatus.ACTIVE) expect(user?.verified).toBe(false) - }) it('Fails if OTP has expired', async () => { @@ -130,10 +135,11 @@ describe('Enterprise Local Authn API', () => { const responseBody = response?.json() expect(responseBody?.code).toBe('INVALID_OTP') - const user = await databaseConnection.getRepository('user').findOneBy({ id: mockUser.id }) + const user = await databaseConnection + .getRepository('user') + .findOneBy({ id: mockUser.id }) expect(user?.status).toBe(UserStatus.ACTIVE) expect(user?.verified).toBe(false) - }) it('Fails if OTP was confirmed before', async () => { @@ -167,7 +173,9 @@ describe('Enterprise Local Authn API', () => { const responseBody = response?.json() expect(responseBody?.code).toBe('INVALID_OTP') - const user = await databaseConnection.getRepository('user').findOneBy({ id: mockUser.id }) + const user = await databaseConnection + .getRepository('user') + .findOneBy({ id: mockUser.id }) expect(user?.verified).toBe(false) }) }) @@ -201,7 +209,9 @@ describe('Enterprise Local Authn API', () => { expect(response?.statusCode).toBe(StatusCodes.OK) expect(response?.body).toBe('') - const user = await databaseConnection.getRepository('user').findOneBy({ id: mockUser.id }) + const user = await databaseConnection + .getRepository('user') + .findOneBy({ id: mockUser.id }) expect(user?.password).not.toBe(mockUser.password) }) @@ -236,7 +246,9 @@ describe('Enterprise Local Authn API', () => { const responseBody = response?.json() expect(responseBody?.code).toBe('INVALID_OTP') - const user = await databaseConnection.getRepository('user').findOneBy({ id: mockUser.id }) + const user = await databaseConnection + .getRepository('user') + .findOneBy({ id: mockUser.id }) expect(user?.password).toBe(mockUser.password) }) }) diff --git a/packages/backend/test/integration/cloud/core/security.test.ts b/packages/server/api/test/integration/cloud/core/security.test.ts similarity index 64% rename from packages/backend/test/integration/cloud/core/security.test.ts rename to packages/server/api/test/integration/cloud/core/security.test.ts index f81b2b8be6..ac28406852 100644 --- a/packages/backend/test/integration/cloud/core/security.test.ts +++ b/packages/server/api/test/integration/cloud/core/security.test.ts @@ -2,8 +2,22 @@ import { FastifyInstance, FastifyRequest } from 'fastify' import { databaseConnection } from '../../../../src/app/database/database-connection' import { setupApp } from '../../../../src/app/app' import { securityHandlerChain } from '../../../../src/app/core/security/security-handler-chain' -import { ActivepiecesError, EndpointScope, ErrorCode, PlatformRole, Principal, PrincipalType, ProjectType, apId } from '@activepieces/shared' -import { createMockFlow, createMockPlatformWithOwner, createMockProject, setupMockApiKeyServiceAccount } from '../../../helpers/mocks' +import { + ActivepiecesError, + EndpointScope, + ErrorCode, + PlatformRole, + Principal, + PrincipalType, + ProjectType, + apId, +} from '@activepieces/shared' +import { + createMockFlow, + createMockPlatformWithOwner, + createMockProject, + setupMockApiKeyServiceAccount, +} from '../../../helpers/mocks' import { generateMockToken } from '../../../helpers/auth' let app: FastifyInstance | null = null @@ -40,11 +54,13 @@ describe('API Security', () => { // assert await expect(result).resolves.toBeUndefined() - expect(mockRequest.principal).toEqual(expect.objectContaining({ - id: expect.stringMatching(/SUPER_USER_.{21}/), - type: PrincipalType.SUPER_USER, - projectId: expect.stringMatching(/SUPER_USER_.{21}/), - })) + expect(mockRequest.principal).toEqual( + expect.objectContaining({ + id: expect.stringMatching(/SUPER_USER_.{21}/), + type: PrincipalType.SUPER_USER, + projectId: expect.stringMatching(/SUPER_USER_.{21}/), + }), + ) }) it('Fails if provided API key is invalid', async () => { @@ -63,11 +79,13 @@ describe('API Security', () => { const result = securityHandlerChain(mockRequest) // assert - return result.catch(e => { - expect(e).toEqual(new ActivepiecesError({ - code: ErrorCode.INVALID_API_KEY, - params: {}, - })) + return result.catch((e) => { + expect(e).toEqual( + new ActivepiecesError({ + code: ErrorCode.INVALID_API_KEY, + params: {}, + }), + ) }) }) }) @@ -75,7 +93,8 @@ describe('API Security', () => { describe('Platform API Key Authentication', () => { it('Authenticates service principals', async () => { // arrange - const { mockOwner, mockPlatform, mockApiKey } = setupMockApiKeyServiceAccount() + const { mockOwner, mockPlatform, mockApiKey } = + setupMockApiKeyServiceAccount() await databaseConnection.getRepository('user').save([mockOwner]) await databaseConnection.getRepository('platform').save([mockPlatform]) @@ -99,22 +118,28 @@ describe('API Security', () => { // assert await expect(result).resolves.toBeUndefined() - expect(mockRequest.principal).toEqual(expect.objectContaining({ - id: mockApiKey.id, - type: PrincipalType.SERVICE, - projectId: expect.stringMatching(/ANONYMOUS_.{21}/), - projectType: ProjectType.PLATFORM_MANAGED, - platform: { - id: mockPlatform.id, - role: PlatformRole.OWNER, - }, - })) + expect(mockRequest.principal).toEqual( + expect.objectContaining({ + id: mockApiKey.id, + type: PrincipalType.SERVICE, + projectId: expect.stringMatching(/ANONYMOUS_.{21}/), + projectType: ProjectType.PLATFORM_MANAGED, + platform: { + id: mockPlatform.id, + role: PlatformRole.OWNER, + }, + }), + ) }) it('Gets projectId from body if endpoint scope is PROJECT', async () => { // arrange - const { mockOwner, mockPlatform, mockApiKey } = setupMockApiKeyServiceAccount() - const mockProject = createMockProject({ ownerId: mockOwner.id, platformId: mockPlatform.id }) + const { mockOwner, mockPlatform, mockApiKey } = + setupMockApiKeyServiceAccount() + const mockProject = createMockProject({ + ownerId: mockOwner.id, + platformId: mockPlatform.id, + }) await databaseConnection.getRepository('user').save([mockOwner]) await databaseConnection.getRepository('platform').save([mockPlatform]) @@ -142,22 +167,28 @@ describe('API Security', () => { // assert await expect(result).resolves.toBeUndefined() - expect(mockRequest.principal).toEqual(expect.objectContaining({ - id: mockApiKey.id, - type: PrincipalType.SERVICE, - projectId: mockProject.id, - projectType: ProjectType.PLATFORM_MANAGED, - platform: { - id: mockPlatform.id, - role: PlatformRole.OWNER, - }, - })) + expect(mockRequest.principal).toEqual( + expect.objectContaining({ + id: mockApiKey.id, + type: PrincipalType.SERVICE, + projectId: mockProject.id, + projectType: ProjectType.PLATFORM_MANAGED, + platform: { + id: mockPlatform.id, + role: PlatformRole.OWNER, + }, + }), + ) }) it('Gets projectId from query if endpoint scope is PROJECT', async () => { // arrange - const { mockOwner, mockPlatform, mockApiKey } = setupMockApiKeyServiceAccount() - const mockProject = createMockProject({ ownerId: mockOwner.id, platformId: mockPlatform.id }) + const { mockOwner, mockPlatform, mockApiKey } = + setupMockApiKeyServiceAccount() + const mockProject = createMockProject({ + ownerId: mockOwner.id, + platformId: mockPlatform.id, + }) await databaseConnection.getRepository('user').save([mockOwner]) await databaseConnection.getRepository('platform').save([mockPlatform]) @@ -185,22 +216,28 @@ describe('API Security', () => { // assert await expect(result).resolves.toBeUndefined() - expect(mockRequest.principal).toEqual(expect.objectContaining({ - id: mockApiKey.id, - type: PrincipalType.SERVICE, - projectId: mockProject.id, - projectType: ProjectType.PLATFORM_MANAGED, - platform: { - id: mockPlatform.id, - role: PlatformRole.OWNER, - }, - })) + expect(mockRequest.principal).toEqual( + expect.objectContaining({ + id: mockApiKey.id, + type: PrincipalType.SERVICE, + projectId: mockProject.id, + projectType: ProjectType.PLATFORM_MANAGED, + platform: { + id: mockPlatform.id, + role: PlatformRole.OWNER, + }, + }), + ) }) it('extracts projectId from resource if endpoint scope is PROJECT', async () => { // arrange - const { mockOwner, mockPlatform, mockApiKey } = setupMockApiKeyServiceAccount() - const mockProject = createMockProject({ ownerId: mockOwner.id, platformId: mockPlatform.id }) + const { mockOwner, mockPlatform, mockApiKey } = + setupMockApiKeyServiceAccount() + const mockProject = createMockProject({ + ownerId: mockOwner.id, + platformId: mockPlatform.id, + }) const mockFlow = createMockFlow({ projectId: mockProject.id }) await databaseConnection.getRepository('user').save([mockOwner]) @@ -230,28 +267,41 @@ describe('API Security', () => { // assert await expect(result).resolves.toBeUndefined() - expect(mockRequest.principal).toEqual(expect.objectContaining({ - id: mockApiKey.id, - type: PrincipalType.SERVICE, - projectId: mockProject.id, - projectType: ProjectType.PLATFORM_MANAGED, - platform: { - id: mockPlatform.id, - role: PlatformRole.OWNER, - }, - })) + expect(mockRequest.principal).toEqual( + expect.objectContaining({ + id: mockApiKey.id, + type: PrincipalType.SERVICE, + projectId: mockProject.id, + projectType: ProjectType.PLATFORM_MANAGED, + platform: { + id: mockPlatform.id, + role: PlatformRole.OWNER, + }, + }), + ) }) it('Fails if API key and project don\'t belong to same platform if endpoint scope is PROJECT', async () => { // arrange - const { mockOwner, mockPlatform, mockApiKey } = setupMockApiKeyServiceAccount() - const { mockOwner: mockOtherOwner, mockPlatform: mockOtherPlatform } = createMockPlatformWithOwner() - const mockOtherProject = createMockProject({ ownerId: mockOtherOwner.id, platformId: mockOtherPlatform.id }) + const { mockOwner, mockPlatform, mockApiKey } = + setupMockApiKeyServiceAccount() + const { mockOwner: mockOtherOwner, mockPlatform: mockOtherPlatform } = + createMockPlatformWithOwner() + const mockOtherProject = createMockProject({ + ownerId: mockOtherOwner.id, + platformId: mockOtherPlatform.id, + }) - await databaseConnection.getRepository('user').save([mockOwner, mockOtherOwner]) - await databaseConnection.getRepository('platform').save([mockPlatform, mockOtherPlatform]) + await databaseConnection + .getRepository('user') + .save([mockOwner, mockOtherOwner]) + await databaseConnection + .getRepository('platform') + .save([mockPlatform, mockOtherPlatform]) await databaseConnection.getRepository('api_key').save([mockApiKey]) - await databaseConnection.getRepository('project').save([mockOtherProject]) + await databaseConnection + .getRepository('project') + .save([mockOtherProject]) const mockRequest = { method: 'GET', @@ -272,17 +322,20 @@ describe('API Security', () => { const result = securityHandlerChain(mockRequest) // assert - await expect(result).rejects.toEqual(new ActivepiecesError({ - code: ErrorCode.AUTHORIZATION, - params: { - message: 'invalid project id', - }, - })) + await expect(result).rejects.toEqual( + new ActivepiecesError({ + code: ErrorCode.AUTHORIZATION, + params: { + message: 'invalid project id', + }, + }), + ) }) it('Fails if no projectId is extracted from request or resource and endpoint scope is PROJECT', async () => { // arrange - const { mockOwner, mockPlatform, mockApiKey } = setupMockApiKeyServiceAccount() + const { mockOwner, mockPlatform, mockApiKey } = + setupMockApiKeyServiceAccount() await databaseConnection.getRepository('user').save([mockOwner]) await databaseConnection.getRepository('platform').save([mockPlatform]) @@ -304,18 +357,21 @@ describe('API Security', () => { const result = securityHandlerChain(mockRequest) // assert - await expect(result).rejects.toEqual(new ActivepiecesError({ - code: ErrorCode.AUTHORIZATION, - params: { - message: 'invalid project id', - }, - })) + await expect(result).rejects.toEqual( + new ActivepiecesError({ + code: ErrorCode.AUTHORIZATION, + params: { + message: 'invalid project id', + }, + }), + ) }) it('Fails if project with extracted id doesn\'t exist and endpoint scope is PROJECT', async () => { // arrange const mockNonExistentProjectId = apId() - const { mockOwner, mockPlatform, mockApiKey } = setupMockApiKeyServiceAccount() + const { mockOwner, mockPlatform, mockApiKey } = + setupMockApiKeyServiceAccount() await databaseConnection.getRepository('user').save([mockOwner]) await databaseConnection.getRepository('platform').save([mockPlatform]) @@ -340,12 +396,14 @@ describe('API Security', () => { const result = securityHandlerChain(mockRequest) // assert - await expect(result).rejects.toEqual(new ActivepiecesError({ - code: ErrorCode.AUTHORIZATION, - params: { - message: 'invalid project id', - }, - })) + await expect(result).rejects.toEqual( + new ActivepiecesError({ + code: ErrorCode.AUTHORIZATION, + params: { + message: 'invalid project id', + }, + }), + ) }) it('Fails if API key doesn\'t exist', async () => { @@ -368,17 +426,20 @@ describe('API Security', () => { const result = securityHandlerChain(mockRequest) // assert - await expect(result).rejects.toEqual(new ActivepiecesError({ - code: ErrorCode.INVALID_BEARER_TOKEN, - params: { - message: 'invalid access token', - }, - })) + await expect(result).rejects.toEqual( + new ActivepiecesError({ + code: ErrorCode.INVALID_BEARER_TOKEN, + params: { + message: 'invalid access token', + }, + }), + ) }) it('Fails if route doesn\'t allow SERVICE principals', async () => { // arrange - const { mockOwner, mockPlatform, mockApiKey } = setupMockApiKeyServiceAccount() + const { mockOwner, mockPlatform, mockApiKey } = + setupMockApiKeyServiceAccount() await databaseConnection.getRepository('user').save([mockOwner]) await databaseConnection.getRepository('platform').save([mockPlatform]) @@ -400,12 +461,14 @@ describe('API Security', () => { const result = securityHandlerChain(mockRequest) // assert - await expect(result).rejects.toEqual(new ActivepiecesError({ - code: ErrorCode.AUTHORIZATION, - params: { - message: 'invalid route for principal type', - }, - })) + await expect(result).rejects.toEqual( + new ActivepiecesError({ + code: ErrorCode.AUTHORIZATION, + params: { + message: 'invalid route for principal type', + }, + }), + ) }) }) @@ -440,21 +503,25 @@ describe('API Security', () => { // assert await expect(result).resolves.toBeUndefined() - expect(mockRequest.principal).toEqual(expect.objectContaining({ - id: mockPrincipal.id, - type: PrincipalType.USER, - projectId: mockPrincipal.projectId, - projectType: ProjectType.PLATFORM_MANAGED, - platform: { - id: mockPrincipal.platform?.id, - role: PlatformRole.OWNER, - }, - })) + expect(mockRequest.principal).toEqual( + expect.objectContaining({ + id: mockPrincipal.id, + type: PrincipalType.USER, + projectId: mockPrincipal.projectId, + projectType: ProjectType.PLATFORM_MANAGED, + platform: { + id: mockPrincipal.platform?.id, + role: PlatformRole.OWNER, + }, + }), + ) }) it('Fails if route disallows USER principal type', async () => { // arrange - const mockAccessToken = await generateMockToken({ type: PrincipalType.USER }) + const mockAccessToken = await generateMockToken({ + type: PrincipalType.USER, + }) const mockRequest = { method: 'GET', @@ -471,19 +538,23 @@ describe('API Security', () => { const result = securityHandlerChain(mockRequest) // assert - await expect(result).rejects.toEqual(new ActivepiecesError({ - code: ErrorCode.AUTHORIZATION, - params: { - message: 'invalid route for principal type', - }, - })) + await expect(result).rejects.toEqual( + new ActivepiecesError({ + code: ErrorCode.AUTHORIZATION, + params: { + message: 'invalid route for principal type', + }, + }), + ) }) it('Fails if projectId in query doesn\'t match principal projectId', async () => { // arrange const mockProjectId = apId() const mockOtherProjectId = apId() - const mockAccessToken = await generateMockToken({ projectId: mockProjectId }) + const mockAccessToken = await generateMockToken({ + projectId: mockProjectId, + }) const mockRequest = { method: 'GET', @@ -501,19 +572,23 @@ describe('API Security', () => { const result = securityHandlerChain(mockRequest) // assert - await expect(result).rejects.toEqual(new ActivepiecesError({ - code: ErrorCode.AUTHORIZATION, - params: { - message: 'invalid project id', - }, - })) + await expect(result).rejects.toEqual( + new ActivepiecesError({ + code: ErrorCode.AUTHORIZATION, + params: { + message: 'invalid project id', + }, + }), + ) }) it('Fails if projectId in body doesn\'t match principal projectId', async () => { // arrange const mockProjectId = apId() const mockOtherProjectId = apId() - const mockAccessToken = await generateMockToken({ projectId: mockProjectId }) + const mockAccessToken = await generateMockToken({ + projectId: mockProjectId, + }) const mockRequest = { method: 'GET', @@ -531,12 +606,14 @@ describe('API Security', () => { const result = securityHandlerChain(mockRequest) // assert - await expect(result).rejects.toEqual(new ActivepiecesError({ - code: ErrorCode.AUTHORIZATION, - params: { - message: 'invalid project id', - }, - })) + await expect(result).rejects.toEqual( + new ActivepiecesError({ + code: ErrorCode.AUTHORIZATION, + params: { + message: 'invalid project id', + }, + }), + ) }) }) @@ -558,12 +635,14 @@ describe('API Security', () => { // assert await expect(result).resolves.toBeUndefined() - expect(mockRequest.principal).toEqual(expect.objectContaining({ - id: expect.stringMatching(/ANONYMOUS_.{21}/), - type: PrincipalType.UNKNOWN, - projectId: expect.stringMatching(/ANONYMOUS_.{21}/), - projectType: ProjectType.STANDALONE, - })) + expect(mockRequest.principal).toEqual( + expect.objectContaining({ + id: expect.stringMatching(/ANONYMOUS_.{21}/), + type: PrincipalType.UNKNOWN, + projectId: expect.stringMatching(/ANONYMOUS_.{21}/), + projectType: ProjectType.STANDALONE, + }), + ) expect(mockRequest.principal).not.toHaveProperty('platform') }) @@ -583,12 +662,14 @@ describe('API Security', () => { const result = securityHandlerChain(mockRequest) // assert - await expect(result).rejects.toEqual(new ActivepiecesError({ - code: ErrorCode.AUTHORIZATION, - params: { - message: 'invalid route for principal type', - }, - })) + await expect(result).rejects.toEqual( + new ActivepiecesError({ + code: ErrorCode.AUTHORIZATION, + params: { + message: 'invalid route for principal type', + }, + }), + ) }) }) }) diff --git a/packages/backend/test/integration/cloud/custom-domain/custom-domain.test.ts b/packages/server/api/test/integration/cloud/custom-domain/custom-domain.test.ts similarity index 84% rename from packages/backend/test/integration/cloud/custom-domain/custom-domain.test.ts rename to packages/server/api/test/integration/cloud/custom-domain/custom-domain.test.ts index dc11beed1e..26b90c3b52 100644 --- a/packages/backend/test/integration/cloud/custom-domain/custom-domain.test.ts +++ b/packages/server/api/test/integration/cloud/custom-domain/custom-domain.test.ts @@ -1,7 +1,11 @@ import { databaseConnection } from '../../../../src/app/database/database-connection' import { setupApp } from '../../../../src/app/app' import { generateMockToken } from '../../../helpers/auth' -import { createMockUser, createMockPlatform, createMockCustomDomain } from '../../../helpers/mocks' +import { + createMockUser, + createMockPlatform, + createMockCustomDomain, +} from '../../../helpers/mocks' import { StatusCodes } from 'http-status-codes' import { FastifyInstance } from 'fastify' import { faker } from '@faker-js/faker' @@ -88,7 +92,6 @@ describe('Custom Domain API', () => { }) }) - describe('List Custom Domain API', () => { it('should list custom domains', async () => { // arrange @@ -110,17 +113,29 @@ describe('Custom Domain API', () => { platform: { id: mockPlatform1.id, role: PlatformRole.OWNER }, }) - const mockCustomDomains1 = [ - createMockCustomDomain({ platformId: mockPlatform1.id, domain: faker.internet.domainName() }), - createMockCustomDomain({ platformId: mockPlatform1.id, domain: faker.internet.domainName() }), + createMockCustomDomain({ + platformId: mockPlatform1.id, + domain: faker.internet.domainName(), + }), + createMockCustomDomain({ + platformId: mockPlatform1.id, + domain: faker.internet.domainName(), + }), ] - await databaseConnection.getRepository('custom_domain').save(mockCustomDomains1) + await databaseConnection + .getRepository('custom_domain') + .save(mockCustomDomains1) const mockCustomDomains2 = [ - createMockCustomDomain({ platformId: mockPlatform2.id, domain: faker.internet.domainName() }), + createMockCustomDomain({ + platformId: mockPlatform2.id, + domain: faker.internet.domainName(), + }), ] - await databaseConnection.getRepository('custom_domain').save(mockCustomDomains2) + await databaseConnection + .getRepository('custom_domain') + .save(mockCustomDomains2) // act const response1 = await app?.inject({ @@ -137,12 +152,10 @@ describe('Custom Domain API', () => { expect(responseBody1.data).toHaveLength(mockCustomDomains1.length) expect(responseBody1?.data).toEqual( - expect.arrayContaining( - [ - expect.objectContaining({ id: mockCustomDomains1[0].id }), - expect.objectContaining({ id: mockCustomDomains1[1].id }), - ], - ), + expect.arrayContaining([ + expect.objectContaining({ id: mockCustomDomains1[0].id }), + expect.objectContaining({ id: mockCustomDomains1[1].id }), + ]), ) }) }) @@ -166,7 +179,9 @@ describe('Custom Domain API', () => { platformId: mockPlatform.id, domain: faker.internet.domainName(), }) - await databaseConnection.getRepository('custom_domain').save(customDomain) + await databaseConnection + .getRepository('custom_domain') + .save(customDomain) // act const response = await app?.inject({ @@ -200,7 +215,9 @@ describe('Custom Domain API', () => { platformId: mockPlatform.id, domain: faker.internet.domainName(), }) - await databaseConnection.getRepository('custom_domain').save(customDomain) + await databaseConnection + .getRepository('custom_domain') + .save(customDomain) // act const response = await app?.inject({ @@ -215,7 +232,4 @@ describe('Custom Domain API', () => { expect(response?.statusCode).toBe(StatusCodes.FORBIDDEN) }) }) - - - }) diff --git a/packages/backend/test/integration/cloud/flow-templates/flow-templates.test.ts b/packages/server/api/test/integration/cloud/flow-templates/flow-templates.test.ts similarity index 77% rename from packages/backend/test/integration/cloud/flow-templates/flow-templates.test.ts rename to packages/server/api/test/integration/cloud/flow-templates/flow-templates.test.ts index 0969785701..19f01c17ec 100644 --- a/packages/backend/test/integration/cloud/flow-templates/flow-templates.test.ts +++ b/packages/server/api/test/integration/cloud/flow-templates/flow-templates.test.ts @@ -1,10 +1,21 @@ import { databaseConnection } from '../../../../src/app/database/database-connection' import { setupApp } from '../../../../src/app/app' import { generateMockToken } from '../../../helpers/auth' -import { createMockUser, createMockPlatform, createMockTemplate, createMockProject, CLOUD_PLATFORM_ID } from '../../../helpers/mocks' +import { + createMockUser, + createMockPlatform, + createMockTemplate, + createMockProject, + CLOUD_PLATFORM_ID, +} from '../../../helpers/mocks' import { StatusCodes } from 'http-status-codes' import { FastifyInstance } from 'fastify' -import { PlatformRole, PrincipalType, TemplateType, apId } from '@activepieces/shared' +import { + PlatformRole, + PrincipalType, + TemplateType, + apId, +} from '@activepieces/shared' let app: FastifyInstance | null = null @@ -22,7 +33,8 @@ describe('Flow Templates', () => { describe('List Flow Templates', () => { it('should list platform templates only', async () => { // arrange - const { mockPlatform, mockUser, mockPlatformTemplate } = await createMockPlatformTemplate({ platformId: apId() }) + const { mockPlatform, mockUser, mockPlatformTemplate } = + await createMockPlatformTemplate({ platformId: apId() }) const testToken = await generateMockToken({ type: PrincipalType.USER, @@ -47,8 +59,12 @@ describe('Flow Templates', () => { it('should list cloud platform template for anonymous users', async () => { // arrange - const { mockPlatformTemplate } = await createMockPlatformTemplate({ platformId: CLOUD_PLATFORM_ID }) - const _randomPlatformTemplate = await createMockPlatformTemplate({ platformId: apId() }) + const { mockPlatformTemplate } = await createMockPlatformTemplate({ + platformId: CLOUD_PLATFORM_ID, + }) + const _randomPlatformTemplate = await createMockPlatformTemplate({ + platformId: apId(), + }) const response = await app?.inject({ method: 'GET', @@ -63,12 +79,11 @@ describe('Flow Templates', () => { }) }) - describe('Delete Flow Template', () => { - it('should not be able delete platform template as member', async () => { // arrange - const { mockPlatform, mockPlatformTemplate } = await createMockPlatformTemplate({ platformId: apId() }) + const { mockPlatform, mockPlatformTemplate } = + await createMockPlatformTemplate({ platformId: apId() }) const mockUser2 = createMockUser({ platformId: mockPlatform.id }) const testToken = await generateMockToken({ type: PrincipalType.USER, @@ -88,10 +103,10 @@ describe('Flow Templates', () => { expect(response?.statusCode).toBe(StatusCodes.FORBIDDEN) }) - it('should be able delete platform template as owner', async () => { // arrange - const { mockPlatform, mockUser, mockPlatformTemplate } = await createMockPlatformTemplate({ platformId: apId() }) + const { mockPlatform, mockUser, mockPlatformTemplate } = + await createMockPlatformTemplate({ platformId: apId() }) const testToken = await generateMockToken({ type: PrincipalType.USER, @@ -113,7 +128,9 @@ describe('Flow Templates', () => { it('should not delete platform template when not authenticated', async () => { // arrange - const { mockPlatformTemplate } = await createMockPlatformTemplate({ platformId: CLOUD_PLATFORM_ID }) + const { mockPlatformTemplate } = await createMockPlatformTemplate({ + platformId: CLOUD_PLATFORM_ID, + }) const response = await app?.inject({ method: 'DELETE', @@ -124,22 +141,36 @@ describe('Flow Templates', () => { expect(response?.statusCode).toBe(StatusCodes.FORBIDDEN) }) }) - }) - -async function createMockPlatformTemplate({ platformId }: { platformId: string }) { +async function createMockPlatformTemplate({ + platformId, +}: { + platformId: string +}) { const mockUser = createMockUser() await databaseConnection.getRepository('user').save(mockUser) - const mockPlatform = createMockPlatform({ id: platformId, ownerId: mockUser.id }) + const mockPlatform = createMockPlatform({ + id: platformId, + ownerId: mockUser.id, + }) await databaseConnection.getRepository('platform').save(mockPlatform) - const mockProject = createMockProject({ ownerId: mockUser.id, platformId: mockPlatform.id }) + const mockProject = createMockProject({ + ownerId: mockUser.id, + platformId: mockPlatform.id, + }) await databaseConnection.getRepository('project').save(mockProject) - const mockPlatformTemplate = createMockTemplate({ platformId: mockPlatform.id, projectId: mockProject.id, type: TemplateType.PLATFORM }) - await databaseConnection.getRepository('flow_template').save(mockPlatformTemplate) + const mockPlatformTemplate = createMockTemplate({ + platformId: mockPlatform.id, + projectId: mockProject.id, + type: TemplateType.PLATFORM, + }) + await databaseConnection + .getRepository('flow_template') + .save(mockPlatformTemplate) return { mockUser, mockPlatform, mockProject, mockPlatformTemplate } } diff --git a/packages/backend/test/integration/cloud/git-repos/git-repos.test.ts b/packages/server/api/test/integration/cloud/git-repos/git-repos.test.ts similarity index 88% rename from packages/backend/test/integration/cloud/git-repos/git-repos.test.ts rename to packages/server/api/test/integration/cloud/git-repos/git-repos.test.ts index d668bdeef3..42a2e63915 100644 --- a/packages/backend/test/integration/cloud/git-repos/git-repos.test.ts +++ b/packages/server/api/test/integration/cloud/git-repos/git-repos.test.ts @@ -4,7 +4,11 @@ import { FastifyInstance } from 'fastify' import { StatusCodes } from 'http-status-codes' import { faker } from '@faker-js/faker' import { PrincipalType } from '@activepieces/shared' -import { createMockUser, createMockProject, createMockGitRepo } from '../../../helpers/mocks' +import { + createMockUser, + createMockProject, + createMockGitRepo, +} from '../../../helpers/mocks' import { generateMockToken } from '../../../helpers/auth' let app: FastifyInstance | null = null @@ -22,15 +26,17 @@ afterAll(async () => { describe('Git API', () => { describe('Create API', () => { it('should not allow create git repo for other projects', async () => { - const mockUser = createMockUser() const mockUser2 = createMockUser() - await databaseConnection.getRepository('user').save([mockUser, mockUser2]) + await databaseConnection + .getRepository('user') + .save([mockUser, mockUser2]) const mockProject = createMockProject({ ownerId: mockUser.id }) const mockProject2 = createMockProject({ ownerId: mockUser2.id }) - await databaseConnection.getRepository('project').save([mockProject, mockProject2]) - + await databaseConnection + .getRepository('project') + .save([mockProject, mockProject2]) const request = { projectId: mockProject2.id, @@ -57,7 +63,6 @@ describe('Git API', () => { }) it('should create a git repo', async () => { - const mockUser = createMockUser() await databaseConnection.getRepository('user').save(mockUser) @@ -99,23 +104,22 @@ describe('Git API', () => { }) describe('Delete API', () => { - - it('should delete a git repo', async () => { + it('should delete a git repo', async () => { const mockUser = createMockUser() await databaseConnection.getRepository('user').save(mockUser) - + const mockProject = createMockProject({ ownerId: mockUser.id }) await databaseConnection.getRepository('project').save(mockProject) - + const mockGitRepo = createMockGitRepo({ projectId: mockProject.id }) await databaseConnection.getRepository('git_repo').save(mockGitRepo) - + const token = await generateMockToken({ id: mockUser.id, projectId: mockProject.id, type: PrincipalType.USER, }) - + const response = await app?.inject({ method: 'DELETE', url: '/v1/git-repos/' + mockGitRepo.id, @@ -126,17 +130,20 @@ describe('Git API', () => { expect(response?.statusCode).toBe(StatusCodes.NO_CONTENT) }) it('should not allow delete git repo for other projects', async () => { - const mockUser = createMockUser() await databaseConnection.getRepository('user').save(mockUser) const mockProject = createMockProject({ ownerId: mockUser.id }) const mockProject2 = createMockProject({ ownerId: mockUser.id }) - await databaseConnection.getRepository('project').save([mockProject, mockProject2]) + await databaseConnection + .getRepository('project') + .save([mockProject, mockProject2]) const mockGitRepo = createMockGitRepo({ projectId: mockProject.id }) const mockGitRepo2 = createMockGitRepo({ projectId: mockProject2.id }) - await databaseConnection.getRepository('git_repo').save([mockGitRepo, mockGitRepo2]) + await databaseConnection + .getRepository('git_repo') + .save([mockGitRepo, mockGitRepo2]) const token = await generateMockToken({ id: mockUser.id, @@ -153,26 +160,25 @@ describe('Git API', () => { }) expect(response?.statusCode).toBe(StatusCodes.NOT_FOUND) - }) - }) describe('List API', () => { - - it('should list a git repo', async () => { - const mockUser = createMockUser() await databaseConnection.getRepository('user').save(mockUser) const mockProject = createMockProject({ ownerId: mockUser.id }) const mockProject2 = createMockProject({ ownerId: mockUser.id }) - await databaseConnection.getRepository('project').save([mockProject, mockProject2]) + await databaseConnection + .getRepository('project') + .save([mockProject, mockProject2]) const mockGitRepo = createMockGitRepo({ projectId: mockProject.id }) const mockGitRepo2 = createMockGitRepo({ projectId: mockProject2.id }) - await databaseConnection.getRepository('git_repo').save([mockGitRepo, mockGitRepo2]) + await databaseConnection + .getRepository('git_repo') + .save([mockGitRepo, mockGitRepo2]) const token = await generateMockToken({ id: mockUser.id, @@ -203,6 +209,4 @@ describe('Git API', () => { expect(gitRepo.projectId).toBe(mockProject.id) }) }) - - }) diff --git a/packages/backend/test/integration/cloud/managed-authn/external-token.test.ts b/packages/server/api/test/integration/cloud/managed-authn/external-token.test.ts similarity index 80% rename from packages/backend/test/integration/cloud/managed-authn/external-token.test.ts rename to packages/server/api/test/integration/cloud/managed-authn/external-token.test.ts index 740ba22924..145f48370a 100644 --- a/packages/backend/test/integration/cloud/managed-authn/external-token.test.ts +++ b/packages/server/api/test/integration/cloud/managed-authn/external-token.test.ts @@ -1,6 +1,11 @@ import { databaseConnection } from '../../../../src/app/database/database-connection' import { setupApp } from '../../../../src/app/app' -import { createMockUser, createMockPlatform, createMockSigningKey, createMockProject } from '../../../helpers/mocks' +import { + createMockUser, + createMockPlatform, + createMockSigningKey, + createMockProject, +} from '../../../helpers/mocks' import { FastifyInstance } from 'fastify' import { StatusCodes } from 'http-status-codes' import { generateMockExternalToken } from '../../../helpers/auth' @@ -16,7 +21,9 @@ beforeAll(async () => { }) beforeEach(async () => { - stripeHelper.getOrCreateCustomer = jest.fn().mockResolvedValue(faker.string.alphanumeric()) + stripeHelper.getOrCreateCustomer = jest + .fn() + .mockResolvedValue(faker.string.alphanumeric()) }) afterAll(async () => { @@ -38,12 +45,15 @@ describe('Managed Authentication API', () => { platformId: mockPlatform.id, generatedBy: mockUser.id, }) - await databaseConnection.getRepository('signing_key').save(mockSigningKey) - - const { mockExternalToken, mockExternalTokenPayload } = generateMockExternalToken({ - platformId: mockPlatform.id, - signingKeyId: mockSigningKey.id, - }) + await databaseConnection + .getRepository('signing_key') + .save(mockSigningKey) + + const { mockExternalToken, mockExternalTokenPayload } = + generateMockExternalToken({ + platformId: mockPlatform.id, + signingKeyId: mockSigningKey.id, + }) // act const response = await app?.inject({ @@ -68,7 +78,9 @@ describe('Managed Authentication API', () => { expect(responseBody?.password).toBeUndefined() expect(responseBody?.status).toBe('ACTIVE') expect(responseBody?.verified).toBe(true) - expect(responseBody?.externalId).toBe(mockExternalTokenPayload.externalUserId) + expect(responseBody?.externalId).toBe( + mockExternalTokenPayload.externalUserId, + ) expect(responseBody?.platformId).toBe(mockPlatform.id) expect(responseBody?.projectId).toHaveLength(21) expect(responseBody?.token).toBeDefined() @@ -86,12 +98,15 @@ describe('Managed Authentication API', () => { platformId: mockPlatform.id, generatedBy: mockUser.id, }) - await databaseConnection.getRepository('signing_key').save(mockSigningKey) - - const { mockExternalToken, mockExternalTokenPayload } = generateMockExternalToken({ - platformId: mockPlatform.id, - signingKeyId: mockSigningKey.id, - }) + await databaseConnection + .getRepository('signing_key') + .save(mockSigningKey) + + const { mockExternalToken, mockExternalTokenPayload } = + generateMockExternalToken({ + platformId: mockPlatform.id, + signingKeyId: mockSigningKey.id, + }) // act const response = await app?.inject({ @@ -107,15 +122,21 @@ describe('Managed Authentication API', () => { expect(response?.statusCode).toBe(StatusCodes.OK) - const generatedProject = await databaseConnection.getRepository('project').findOneBy({ - id: responseBody?.projectId, - }) + const generatedProject = await databaseConnection + .getRepository('project') + .findOneBy({ + id: responseBody?.projectId, + }) - expect(generatedProject?.displayName).toBe(mockExternalTokenPayload.externalProjectId) + expect(generatedProject?.displayName).toBe( + mockExternalTokenPayload.externalProjectId, + ) expect(generatedProject?.ownerId).toBe(mockPlatform.ownerId) expect(generatedProject?.type).toBe('PLATFORM_MANAGED') expect(generatedProject?.platformId).toBe(mockPlatform.id) - expect(generatedProject?.externalId).toBe(mockExternalTokenPayload.externalProjectId) + expect(generatedProject?.externalId).toBe( + mockExternalTokenPayload.externalProjectId, + ) }) it('Adds new user as a member in new project', async () => { @@ -130,7 +151,9 @@ describe('Managed Authentication API', () => { platformId: mockPlatform.id, generatedBy: mockUser.id, }) - await databaseConnection.getRepository('signing_key').save(mockSigningKey) + await databaseConnection + .getRepository('signing_key') + .save(mockSigningKey) const mockedEmail = faker.internet.email() const { mockExternalToken } = generateMockExternalToken({ @@ -153,11 +176,13 @@ describe('Managed Authentication API', () => { expect(response?.statusCode).toBe(StatusCodes.OK) - const generatedProjectMember = await databaseConnection.getRepository('project_member').findOneBy({ - email: mockedEmail, - platformId: mockPlatform.id, - projectId: responseBody?.projectId, - }) + const generatedProjectMember = await databaseConnection + .getRepository('project_member') + .findOneBy({ + email: mockedEmail, + platformId: mockPlatform.id, + projectId: responseBody?.projectId, + }) expect(generatedProjectMember?.projectId).toBe(responseBody?.projectId) expect(generatedProjectMember?.email).toBe(mockedEmail) @@ -178,7 +203,9 @@ describe('Managed Authentication API', () => { platformId: mockPlatform.id, generatedBy: mockUser.id, }) - await databaseConnection.getRepository('signing_key').save(mockSigningKey) + await databaseConnection + .getRepository('signing_key') + .save(mockSigningKey) const mockExternalProjectId = apId() @@ -217,19 +244,24 @@ describe('Managed Authentication API', () => { const mockPlatformOwner = createMockUser() await databaseConnection.getRepository('user').save(mockPlatformOwner) - const mockPlatform = createMockPlatform({ ownerId: mockPlatformOwner.id }) + const mockPlatform = createMockPlatform({ + ownerId: mockPlatformOwner.id, + }) await databaseConnection.getRepository('platform').save(mockPlatform) const mockSigningKey = createMockSigningKey({ platformId: mockPlatform.id, generatedBy: mockPlatformOwner.id, }) - await databaseConnection.getRepository('signing_key').save(mockSigningKey) - - const { mockExternalToken, mockExternalTokenPayload } = generateMockExternalToken({ - platformId: mockPlatform.id, - signingKeyId: mockSigningKey.id, - }) + await databaseConnection + .getRepository('signing_key') + .save(mockSigningKey) + + const { mockExternalToken, mockExternalTokenPayload } = + generateMockExternalToken({ + platformId: mockPlatform.id, + signingKeyId: mockSigningKey.id, + }) const mockUser = createMockUser({ externalId: mockExternalTokenPayload.externalUserId, @@ -289,9 +321,9 @@ describe('Managed Authentication API', () => { const responseBody = response?.json() expect(response?.statusCode).toBe(StatusCodes.UNAUTHORIZED) - expect(responseBody?.params?.message).toBe(`signing key not found signingKeyId=${nonExistentSigningKeyId}`) + expect(responseBody?.params?.message).toBe( + `signing key not found signingKeyId=${nonExistentSigningKeyId}`, + ) }) - }) - }) diff --git a/packages/backend/test/integration/cloud/oauth-app/oauth-app.test.ts b/packages/server/api/test/integration/cloud/oauth-app/oauth-app.test.ts similarity index 88% rename from packages/backend/test/integration/cloud/oauth-app/oauth-app.test.ts rename to packages/server/api/test/integration/cloud/oauth-app/oauth-app.test.ts index fd9e38d76e..761ce01dc9 100644 --- a/packages/backend/test/integration/cloud/oauth-app/oauth-app.test.ts +++ b/packages/server/api/test/integration/cloud/oauth-app/oauth-app.test.ts @@ -1,7 +1,11 @@ import { databaseConnection } from '../../../../src/app/database/database-connection' import { setupApp } from '../../../../src/app/app' import { generateMockToken } from '../../../helpers/auth' -import { createMockUser, createMockPlatform, createMockOAuthApp } from '../../../helpers/mocks' +import { + createMockUser, + createMockPlatform, + createMockOAuthApp, +} from '../../../helpers/mocks' import { StatusCodes } from 'http-status-codes' import { FastifyInstance } from 'fastify' import { faker } from '@faker-js/faker' @@ -117,11 +121,15 @@ describe('OAuth App API', () => { // arrange const mockUser = createMockUser() const mockUserTwo = createMockUser() - await databaseConnection.getRepository('user').save([mockUser, mockUserTwo]) + await databaseConnection + .getRepository('user') + .save([mockUser, mockUserTwo]) const mockPlatform = createMockPlatform({ ownerId: mockUser.id }) const mockPlatformTwo = createMockPlatform({ ownerId: mockUserTwo.id }) - await databaseConnection.getRepository('platform').save([mockPlatform, mockPlatformTwo]) + await databaseConnection + .getRepository('platform') + .save([mockPlatform, mockPlatformTwo]) const mockOAuthApp = createMockOAuthApp({ platformId: mockPlatform.id, @@ -144,7 +152,6 @@ describe('OAuth App API', () => { }, }) - expect(response?.statusCode).toBe(StatusCodes.NOT_FOUND) }) @@ -177,7 +184,6 @@ describe('OAuth App API', () => { }, }) - expect(response?.statusCode).toBe(StatusCodes.OK) }) }) @@ -187,11 +193,15 @@ describe('OAuth App API', () => { // arrange const mockUserOne = createMockUser() const mockUserTwo = createMockUser() - await databaseConnection.getRepository('user').save([mockUserOne, mockUserTwo]) + await databaseConnection + .getRepository('user') + .save([mockUserOne, mockUserTwo]) const mockPlatformOne = createMockPlatform({ ownerId: mockUserOne.id }) const mockPlatformTwo = createMockPlatform({ ownerId: mockUserTwo.id }) - await databaseConnection.getRepository('platform').save([mockPlatformOne, mockPlatformTwo]) + await databaseConnection + .getRepository('platform') + .save([mockPlatformOne, mockPlatformTwo]) const mockOAuthAppsOne = createMockOAuthApp({ platformId: mockPlatformOne.id, @@ -201,7 +211,9 @@ describe('OAuth App API', () => { platformId: mockPlatformTwo.id, }) - await databaseConnection.getRepository('oauth_app').save([mockOAuthAppsOne, mockOAuthAppsTwo]) + await databaseConnection + .getRepository('oauth_app') + .save([mockOAuthAppsOne, mockOAuthAppsTwo]) const testToken = await generateMockToken({ type: PrincipalType.USER, @@ -230,11 +242,15 @@ describe('OAuth App API', () => { // arrange const mockUserOne = createMockUser() const mockUserTwo = createMockUser() - await databaseConnection.getRepository('user').save([mockUserOne, mockUserTwo]) + await databaseConnection + .getRepository('user') + .save([mockUserOne, mockUserTwo]) const mockPlatformOne = createMockPlatform({ ownerId: mockUserOne.id }) const mockPlatformTwo = createMockPlatform({ ownerId: mockUserTwo.id }) - await databaseConnection.getRepository('platform').save([mockPlatformOne, mockPlatformTwo]) + await databaseConnection + .getRepository('platform') + .save([mockPlatformOne, mockPlatformTwo]) const mockOAuthAppsOne = createMockOAuthApp({ platformId: mockPlatformOne.id, @@ -244,7 +260,9 @@ describe('OAuth App API', () => { platformId: mockPlatformTwo.id, }) - await databaseConnection.getRepository('oauth_app').save([mockOAuthAppsOne, mockOAuthAppsTwo]) + await databaseConnection + .getRepository('oauth_app') + .save([mockOAuthAppsOne, mockOAuthAppsTwo]) const testToken = await generateMockToken({ type: PrincipalType.USER, @@ -269,6 +287,4 @@ describe('OAuth App API', () => { expect(responseBody.data[0].clientSecret).toBeUndefined() }) }) - - }) diff --git a/packages/backend/test/integration/cloud/otp/otp.test.ts b/packages/server/api/test/integration/cloud/otp/otp.test.ts similarity index 99% rename from packages/backend/test/integration/cloud/otp/otp.test.ts rename to packages/server/api/test/integration/cloud/otp/otp.test.ts index abc398b463..08b9c1d605 100644 --- a/packages/backend/test/integration/cloud/otp/otp.test.ts +++ b/packages/server/api/test/integration/cloud/otp/otp.test.ts @@ -42,7 +42,6 @@ describe('OTP API', () => { // assert expect(response?.statusCode).toBe(StatusCodes.NO_CONTENT) - }) it('Sends OTP to user', async () => { diff --git a/packages/backend/test/integration/cloud/piece-metadata/piece-metadata.test.ts b/packages/server/api/test/integration/cloud/piece-metadata/piece-metadata.test.ts similarity index 75% rename from packages/backend/test/integration/cloud/piece-metadata/piece-metadata.test.ts rename to packages/server/api/test/integration/cloud/piece-metadata/piece-metadata.test.ts index c01f5f938b..4946594051 100644 --- a/packages/backend/test/integration/cloud/piece-metadata/piece-metadata.test.ts +++ b/packages/server/api/test/integration/cloud/piece-metadata/piece-metadata.test.ts @@ -1,11 +1,22 @@ import { databaseConnection } from '../../../../src/app/database/database-connection' import { setupApp } from '../../../../src/app/app' import { generateMockToken } from '../../../helpers/auth' -import { createMockPieceMetadata, createMockPlatform, createMockProject, createMockUser } from '../../../helpers/mocks' +import { + createMockPieceMetadata, + createMockPlatform, + createMockProject, + createMockUser, +} from '../../../helpers/mocks' import { StatusCodes } from 'http-status-codes' import { FastifyInstance } from 'fastify' import { FilteredPieceBehavior } from '@activepieces/ee-shared' -import { PieceType, PlatformRole, PrincipalType, ProjectType, apId } from '@activepieces/shared' +import { + PieceType, + PlatformRole, + PrincipalType, + ProjectType, + apId, +} from '@activepieces/shared' let app: FastifyInstance | null = null @@ -24,13 +35,16 @@ afterAll(async () => { }) describe('Piece Metadata API', () => { - - describe('Get Piece metadata', () => { it('Should return metadata when authenticated', async () => { // arrange - const mockPieceMetadata = createMockPieceMetadata({ name: '@activepieces/a', pieceType: PieceType.OFFICIAL }) - await databaseConnection.getRepository('piece_metadata').save(mockPieceMetadata) + const mockPieceMetadata = createMockPieceMetadata({ + name: '@activepieces/a', + pieceType: PieceType.OFFICIAL, + }) + await databaseConnection + .getRepository('piece_metadata') + .save(mockPieceMetadata) const mockUser = createMockUser() await databaseConnection.getRepository('user').save([mockUser]) @@ -72,11 +86,14 @@ describe('Piece Metadata API', () => { }) it('Should return metadata when not authenticated', async () => { - - // arrange - const mockPieceMetadata = createMockPieceMetadata({ name: '@activepieces/a', pieceType: PieceType.OFFICIAL }) - await databaseConnection.getRepository('piece_metadata').save(mockPieceMetadata) + const mockPieceMetadata = createMockPieceMetadata({ + name: '@activepieces/a', + pieceType: PieceType.OFFICIAL, + }) + await databaseConnection + .getRepository('piece_metadata') + .save(mockPieceMetadata) const testToken = await generateMockToken({ projectId: apId(), @@ -107,8 +124,12 @@ describe('Piece Metadata API', () => { expect(responseBody.displayName).toBe(mockPieceMetadata.displayName) expect(responseBody.id).toBe(mockPieceMetadata.id) expect(responseBody.logoUrl).toBe(mockPieceMetadata.logoUrl) - expect(responseBody.maximumSupportedRelease).toBe(mockPieceMetadata.maximumSupportedRelease) - expect(responseBody.minimumSupportedRelease).toBe(mockPieceMetadata.minimumSupportedRelease) + expect(responseBody.maximumSupportedRelease).toBe( + mockPieceMetadata.maximumSupportedRelease, + ) + expect(responseBody.minimumSupportedRelease).toBe( + mockPieceMetadata.minimumSupportedRelease, + ) expect(responseBody.packageType).toBe(mockPieceMetadata.packageType) expect(responseBody.pieceType).toBe(mockPieceMetadata.pieceType) expect(responseBody.platformId).toBe(mockPieceMetadata.platformId) @@ -118,7 +139,6 @@ describe('Piece Metadata API', () => { }) describe('List Piece Metadata endpoint', () => { it('Should list platform and project pieces', async () => { - const mockUser = createMockUser() await databaseConnection.getRepository('user').save([mockUser]) @@ -139,14 +159,39 @@ describe('Piece Metadata API', () => { type: ProjectType.PLATFORM_MANAGED, ownerId: mockUser.id, }) - await databaseConnection.getRepository('project').save([mockProject, mockProject2]) + await databaseConnection + .getRepository('project') + .save([mockProject, mockProject2]) // arrange - const mockPieceMetadataA = createMockPieceMetadata({ name: 'a', pieceType: PieceType.CUSTOM, projectId: mockProject.id }) - const mockPieceMetadataB = createMockPieceMetadata({ name: 'b', pieceType: PieceType.OFFICIAL }) - const mockPieceMetadataC = createMockPieceMetadata({ name: 'c', pieceType: PieceType.CUSTOM, projectId: mockProject2.id, platformId: mockPlatform.id }) - const mockPieceMetadataD = createMockPieceMetadata({ name: 'd', pieceType: PieceType.CUSTOM, platformId: mockPlatform.id }) - await databaseConnection.getRepository('piece_metadata').save([mockPieceMetadataA, mockPieceMetadataB, mockPieceMetadataC, mockPieceMetadataD]) + const mockPieceMetadataA = createMockPieceMetadata({ + name: 'a', + pieceType: PieceType.CUSTOM, + projectId: mockProject.id, + }) + const mockPieceMetadataB = createMockPieceMetadata({ + name: 'b', + pieceType: PieceType.OFFICIAL, + }) + const mockPieceMetadataC = createMockPieceMetadata({ + name: 'c', + pieceType: PieceType.CUSTOM, + projectId: mockProject2.id, + platformId: mockPlatform.id, + }) + const mockPieceMetadataD = createMockPieceMetadata({ + name: 'd', + pieceType: PieceType.CUSTOM, + platformId: mockPlatform.id, + }) + await databaseConnection + .getRepository('piece_metadata') + .save([ + mockPieceMetadataA, + mockPieceMetadataB, + mockPieceMetadataC, + mockPieceMetadataD, + ]) const testToken = await generateMockToken({ type: PrincipalType.USER, @@ -178,7 +223,6 @@ describe('Piece Metadata API', () => { }) it('Should list project pieces', async () => { - const mockUser = createMockUser() await databaseConnection.getRepository('user').save([mockUser]) @@ -188,13 +232,28 @@ describe('Piece Metadata API', () => { const mockProject2 = createMockProject({ ownerId: mockUser.id, }) - await databaseConnection.getRepository('project').save([mockProject, mockProject2]) + await databaseConnection + .getRepository('project') + .save([mockProject, mockProject2]) // arrange - const mockPieceMetadataA = createMockPieceMetadata({ name: 'a', pieceType: PieceType.CUSTOM, projectId: mockProject.id }) - const mockPieceMetadataB = createMockPieceMetadata({ name: 'b', pieceType: PieceType.OFFICIAL }) - const mockPieceMetadataC = createMockPieceMetadata({ name: 'c', pieceType: PieceType.CUSTOM, projectId: mockProject2.id }) - await databaseConnection.getRepository('piece_metadata').save([mockPieceMetadataA, mockPieceMetadataB, mockPieceMetadataC]) + const mockPieceMetadataA = createMockPieceMetadata({ + name: 'a', + pieceType: PieceType.CUSTOM, + projectId: mockProject.id, + }) + const mockPieceMetadataB = createMockPieceMetadata({ + name: 'b', + pieceType: PieceType.OFFICIAL, + }) + const mockPieceMetadataC = createMockPieceMetadata({ + name: 'c', + pieceType: PieceType.CUSTOM, + projectId: mockProject2.id, + }) + await databaseConnection + .getRepository('piece_metadata') + .save([mockPieceMetadataA, mockPieceMetadataB, mockPieceMetadataC]) const testToken = await generateMockToken({ type: PrincipalType.USER, @@ -222,9 +281,17 @@ describe('Piece Metadata API', () => { it('Sorts by piece name', async () => { // arrange - const mockPieceMetadataA = createMockPieceMetadata({ name: 'a', pieceType: PieceType.OFFICIAL }) - const mockPieceMetadataB = createMockPieceMetadata({ name: 'b', pieceType: PieceType.OFFICIAL }) - await databaseConnection.getRepository('piece_metadata').save([mockPieceMetadataA, mockPieceMetadataB]) + const mockPieceMetadataA = createMockPieceMetadata({ + name: 'a', + pieceType: PieceType.OFFICIAL, + }) + const mockPieceMetadataB = createMockPieceMetadata({ + name: 'b', + pieceType: PieceType.OFFICIAL, + }) + await databaseConnection + .getRepository('piece_metadata') + .save([mockPieceMetadataA, mockPieceMetadataB]) const testToken = await generateMockToken() @@ -259,9 +326,17 @@ describe('Piece Metadata API', () => { await databaseConnection.getRepository('platform').save([mockPlatform]) - const mockPieceMetadataA = createMockPieceMetadata({ name: 'a', pieceType: PieceType.OFFICIAL }) - const mockPieceMetadataB = createMockPieceMetadata({ name: 'b', pieceType: PieceType.OFFICIAL }) - await databaseConnection.getRepository('piece_metadata').save([mockPieceMetadataA, mockPieceMetadataB]) + const mockPieceMetadataA = createMockPieceMetadata({ + name: 'a', + pieceType: PieceType.OFFICIAL, + }) + const mockPieceMetadataB = createMockPieceMetadata({ + name: 'b', + pieceType: PieceType.OFFICIAL, + }) + await databaseConnection + .getRepository('piece_metadata') + .save([mockPieceMetadataA, mockPieceMetadataB]) const testToken = await generateMockToken({ type: PrincipalType.USER, @@ -301,9 +376,17 @@ describe('Piece Metadata API', () => { await databaseConnection.getRepository('platform').save([mockPlatform]) - const mockPieceMetadataA = createMockPieceMetadata({ name: 'a', pieceType: PieceType.OFFICIAL }) - const mockPieceMetadataB = createMockPieceMetadata({ name: 'b', pieceType: PieceType.OFFICIAL }) - await databaseConnection.getRepository('piece_metadata').save([mockPieceMetadataA, mockPieceMetadataB]) + const mockPieceMetadataA = createMockPieceMetadata({ + name: 'a', + pieceType: PieceType.OFFICIAL, + }) + const mockPieceMetadataB = createMockPieceMetadata({ + name: 'b', + pieceType: PieceType.OFFICIAL, + }) + await databaseConnection + .getRepository('piece_metadata') + .save([mockPieceMetadataA, mockPieceMetadataB]) const testToken = await generateMockToken({ type: PrincipalType.USER, diff --git a/packages/backend/test/integration/cloud/platform/admin-platform.test.ts b/packages/server/api/test/integration/cloud/platform/admin-platform.test.ts similarity index 88% rename from packages/backend/test/integration/cloud/platform/admin-platform.test.ts rename to packages/server/api/test/integration/cloud/platform/admin-platform.test.ts index ed6f418e46..9ae5a571b5 100644 --- a/packages/backend/test/integration/cloud/platform/admin-platform.test.ts +++ b/packages/server/api/test/integration/cloud/platform/admin-platform.test.ts @@ -21,7 +21,7 @@ afterAll(async () => { describe('admin add platform endpoint', () => { it('creates a new platform', async () => { - // arrange + // arrange const mockUser = createMockUser() await databaseConnection.getRepository('user').save(mockUser) @@ -62,9 +62,15 @@ describe('admin add platform endpoint', () => { expect(responseBody.ownerId).toBe(mockUser.id) expect(responseBody.name).toBe(mockPlatformName) expect(responseBody.primaryColor).toBe('#6e41e2') - expect(responseBody.logoIconUrl).toBe('https://cdn.activepieces.com/brand/logo.svg') - expect(responseBody.fullLogoUrl).toBe('https://cdn.activepieces.com/brand/full-logo.png') - expect(responseBody.favIconUrl).toBe('https://cdn.activepieces.com/brand/favicon.ico') + expect(responseBody.logoIconUrl).toBe( + 'https://cdn.activepieces.com/brand/logo.svg', + ) + expect(responseBody.fullLogoUrl).toBe( + 'https://cdn.activepieces.com/brand/full-logo.png', + ) + expect(responseBody.favIconUrl).toBe( + 'https://cdn.activepieces.com/brand/favicon.ico', + ) expect(responseBody.filteredPieceNames).toStrictEqual([]) expect(responseBody.filteredPieceBehavior).toBe('BLOCKED') expect(responseBody.smtpHost).toBeNull() @@ -84,7 +90,7 @@ describe('admin add platform endpoint', () => { }) it('updates project to be platform-managed', async () => { - // arrange + // arrange const mockUser = createMockUser() await databaseConnection.getRepository('user').save(mockUser) @@ -107,9 +113,11 @@ describe('admin add platform endpoint', () => { }, }) - const updatedMockProject = await databaseConnection.getRepository('project').findOneBy({ - id: mockProject.id, - }) + const updatedMockProject = await databaseConnection + .getRepository('project') + .findOneBy({ + id: mockProject.id, + }) // assert const mockPlatform = addPlatformResponse?.json() @@ -124,7 +132,7 @@ describe('admin add platform endpoint', () => { }) it('adds owner to newly created platform', async () => { - // arrange + // arrange const mockUser = createMockUser() await databaseConnection.getRepository('user').save(mockUser) @@ -152,7 +160,9 @@ describe('admin add platform endpoint', () => { const responseBody = response?.json() const newlyCreatedPlatformId = responseBody.id - const user = await databaseConnection.getRepository('user').findOneByOrFail({ id: mockUser.id }) + const user = await databaseConnection + .getRepository('user') + .findOneByOrFail({ id: mockUser.id }) expect(user.platformId).toBe(newlyCreatedPlatformId) }) }) diff --git a/packages/backend/test/integration/cloud/platform/platform.test.ts b/packages/server/api/test/integration/cloud/platform/platform.test.ts similarity index 90% rename from packages/backend/test/integration/cloud/platform/platform.test.ts rename to packages/server/api/test/integration/cloud/platform/platform.test.ts index 0f192d814f..9b2d6cebb2 100644 --- a/packages/backend/test/integration/cloud/platform/platform.test.ts +++ b/packages/server/api/test/integration/cloud/platform/platform.test.ts @@ -4,8 +4,16 @@ import { generateMockToken } from '../../../helpers/auth' import { createMockUser, createMockPlatform } from '../../../helpers/mocks' import { StatusCodes } from 'http-status-codes' import { FastifyInstance } from 'fastify' -import { LocalesEnum, PlatformRole, PrincipalType, apId } from '@activepieces/shared' -import { FilteredPieceBehavior, UpdatePlatformRequestBody } from '@activepieces/ee-shared' +import { + LocalesEnum, + PlatformRole, + PrincipalType, + apId, +} from '@activepieces/shared' +import { + FilteredPieceBehavior, + UpdatePlatformRequestBody, +} from '@activepieces/ee-shared' let app: FastifyInstance | null = null @@ -25,10 +33,15 @@ describe('Platform API', () => { // arrange const mockUser = createMockUser() await databaseConnection.getRepository('user').save(mockUser) - const mockPlatform = createMockPlatform({ ownerId: mockUser.id, embeddingEnabled: true }) + const mockPlatform = createMockPlatform({ + ownerId: mockUser.id, + embeddingEnabled: true, + }) await databaseConnection.getRepository('platform').save(mockPlatform) const testToken = await generateMockToken({ - type: PrincipalType.USER, id: mockUser.id, platform: { id: mockPlatform.id, role: PlatformRole.OWNER }, + type: PrincipalType.USER, + id: mockUser.id, + platform: { id: mockPlatform.id, role: PlatformRole.OWNER }, }) const requestBody: UpdatePlatformRequestBody = { name: 'updated name', @@ -70,8 +83,12 @@ describe('Platform API', () => { expect(responseBody.id).toBe(mockPlatform.id) expect(responseBody.created).toBeDefined() expect(responseBody.updated).toBeDefined() - expect(responseBody.enforceAllowedAuthDomains).toBe(requestBody.enforceAllowedAuthDomains) - expect(responseBody.allowedAuthDomains).toEqual(requestBody.allowedAuthDomains) + expect(responseBody.enforceAllowedAuthDomains).toBe( + requestBody.enforceAllowedAuthDomains, + ) + expect(responseBody.allowedAuthDomains).toEqual( + requestBody.allowedAuthDomains, + ) expect(responseBody.ownerId).toBe(mockUser.id) expect(responseBody.emailAuthEnabled).toBe(requestBody.emailAuthEnabled) expect(responseBody.name).toBe('updated name') @@ -79,7 +96,9 @@ describe('Platform API', () => { expect(responseBody.logoIconUrl).toBe('updated logo icon url') expect(responseBody.fullLogoUrl).toBe('updated full logo url') expect(responseBody.favIconUrl).toBe('updated fav icon url') - expect(responseBody.filteredPieceNames).toStrictEqual(['updated filtered piece names']) + expect(responseBody.filteredPieceNames).toStrictEqual([ + 'updated filtered piece names', + ]) expect(responseBody.filteredPieceBehavior).toBe('ALLOWED') expect(responseBody.emailAuthEnabled).toBe(false) expect(responseBody.smtpHost).toBe('updated smtp host') @@ -90,7 +109,9 @@ describe('Platform API', () => { expect(responseBody.smtpSenderEmail).toBe('updated smtp sender email') expect(responseBody.smtpUseSSL).toBe(true) expect(responseBody.privacyPolicyUrl).toBe('updated privacy policy url') - expect(responseBody.termsOfServiceUrl).toBe('updated terms of service url') + expect(responseBody.termsOfServiceUrl).toBe( + 'updated terms of service url', + ) expect(responseBody.cloudAuthEnabled).toBe(false) expect(responseBody.embeddingEnabled).toBe(true) expect(responseBody.defaultLocale).toBe(LocalesEnum.ENGLISH) @@ -105,7 +126,8 @@ describe('Platform API', () => { await databaseConnection.getRepository('platform').save(mockPlatform) const testToken = await generateMockToken({ - type: PrincipalType.USER, id: 'random-user-id', + type: PrincipalType.USER, + id: 'random-user-id', }) // act @@ -255,7 +277,9 @@ describe('Platform API', () => { expect(response?.statusCode).toBe(StatusCodes.INTERNAL_SERVER_ERROR) const responseBody = response?.json() - expect(responseBody?.message).toBe('userPlatformId and paramId should be equal') + expect(responseBody?.message).toBe( + 'userPlatformId and paramId should be equal', + ) }) it('fails if platform doesn\'t exist', async () => { diff --git a/packages/backend/test/integration/cloud/project-members/project-members.test.ts b/packages/server/api/test/integration/cloud/project-members/project-members.test.ts similarity index 88% rename from packages/backend/test/integration/cloud/project-members/project-members.test.ts rename to packages/server/api/test/integration/cloud/project-members/project-members.test.ts index e07f06ccc4..66b9b5e877 100644 --- a/packages/backend/test/integration/cloud/project-members/project-members.test.ts +++ b/packages/server/api/test/integration/cloud/project-members/project-members.test.ts @@ -2,14 +2,26 @@ import { FastifyInstance } from 'fastify' import { StatusCodes } from 'http-status-codes' import { setupApp } from '../../../../src/app/app' import { databaseConnection } from '../../../../src/app/database/database-connection' -import { createMockApiKey, createMockPlatform, createMockProject, createMockProjectMember, createMockUser } from '../../../helpers/mocks' +import { + createMockApiKey, + createMockPlatform, + createMockProject, + createMockProjectMember, + createMockUser, +} from '../../../helpers/mocks' import { generateMockToken } from '../../../helpers/auth' import { stripeHelper } from '../../../../src/app/ee/billing/billing/stripe-helper' import { emailService } from '../../../../src/app/ee/helper/email/email-service' import { faker } from '@faker-js/faker' import { PlatformRole, Project, User } from '@activepieces/shared' import { PrincipalType } from '@activepieces/shared' -import { AddProjectMemberRequestBody, ApiKeyResponseWithValue, Platform, ProjectMemberRole, ProjectMemberStatus } from '@activepieces/ee-shared' +import { + AddProjectMemberRequestBody, + ApiKeyResponseWithValue, + Platform, + ProjectMemberRole, + ProjectMemberStatus, +} from '@activepieces/ee-shared' let app: FastifyInstance | null = null @@ -19,7 +31,9 @@ beforeAll(async () => { }) beforeEach(async () => { - stripeHelper.getOrCreateCustomer = jest.fn().mockResolvedValue(faker.string.uuid()) + stripeHelper.getOrCreateCustomer = jest + .fn() + .mockResolvedValue(faker.string.uuid()) emailService.sendInvitation = jest.fn() }) @@ -30,7 +44,6 @@ afterAll(async () => { describe('Project Member API', () => { describe('Invite member to project Endpoint', () => { - it('Adds new invited user from api for random project', async () => { const { mockApiKey } = await createBasicEnvironment() const { mockProject: mockProject2 } = await createBasicEnvironment() @@ -54,7 +67,6 @@ describe('Project Member API', () => { expect(response?.statusCode).toBe(StatusCodes.FORBIDDEN) }) - it('Adds new invited user from api', async () => { const { mockApiKey, mockProject } = await createBasicEnvironment() const mockInviteProjectMemberRequest: AddProjectMemberRequestBody = { @@ -74,7 +86,6 @@ describe('Project Member API', () => { expect(response?.statusCode).toBe(StatusCodes.CREATED) }) - it('Adds new invited user', async () => { const { mockUserToken, mockProject } = await createBasicEnvironment() @@ -101,10 +112,12 @@ describe('Project Member API', () => { expect(emailService.sendInvitation).toBeCalledTimes(1) - const projectMember = await databaseConnection.getRepository('project_member').findOneBy({ - email: randomEmail, - projectId: mockProject.id, - }) + const projectMember = await databaseConnection + .getRepository('project_member') + .findOneBy({ + email: randomEmail, + projectId: mockProject.id, + }) expect(projectMember?.status).toBe('PENDING') }) @@ -192,7 +205,9 @@ describe('Project Member API', () => { projectId: mockProject.id, email: randomEmail, }) - await databaseConnection.getRepository('project_member').save(mockProjectMember) + await databaseConnection + .getRepository('project_member') + .save(mockProjectMember) // act const response = await app?.inject({ @@ -217,7 +232,9 @@ describe('Project Member API', () => { projectId: mockProject2.id, email: randomEmail, }) - await databaseConnection.getRepository('project_member').save(mockProjectMember) + await databaseConnection + .getRepository('project_member') + .save(mockProjectMember) // act const response = await app?.inject({ @@ -241,7 +258,9 @@ describe('Project Member API', () => { projectId: mockProject.id, email: randomEmail, }) - await databaseConnection.getRepository('project_member').save(mockProjectMember) + await databaseConnection + .getRepository('project_member') + .save(mockProjectMember) // act const response = await app?.inject({ @@ -262,7 +281,9 @@ describe('Project Member API', () => { projectId: mockProject.id, email: randomEmail, }) - await databaseConnection.getRepository('project_member').save(mockProjectMember) + await databaseConnection + .getRepository('project_member') + .save(mockProjectMember) // act const response = await app?.inject({ @@ -284,7 +305,9 @@ describe('Project Member API', () => { projectId: mockProject2.id, email: randomEmail, }) - await databaseConnection.getRepository('project_member').save(mockProjectMember) + await databaseConnection + .getRepository('project_member') + .save(mockProjectMember) // act const response = await app?.inject({ @@ -299,7 +322,15 @@ describe('Project Member API', () => { }) }) -async function createBasicEnvironment(embeddingEnabled = false): Promise<{ mockUser: User, mockPlatform: Platform, mockProject: Project, mockApiKey: ApiKeyResponseWithValue, mockUserToken: string }> { +async function createBasicEnvironment( + embeddingEnabled = false, +): Promise<{ + mockUser: User + mockPlatform: Platform + mockProject: Project + mockApiKey: ApiKeyResponseWithValue + mockUserToken: string + }> { const mockUser = createMockUser() await databaseConnection.getRepository('user').save(mockUser) @@ -335,6 +366,5 @@ async function createBasicEnvironment(embeddingEnabled = false): Promise<{ mockU mockProject, mockApiKey, mockUserToken, - } } diff --git a/packages/backend/test/integration/cloud/project/project.test.ts b/packages/server/api/test/integration/cloud/project/project.test.ts similarity index 86% rename from packages/backend/test/integration/cloud/project/project.test.ts rename to packages/server/api/test/integration/cloud/project/project.test.ts index 2c42dc4c09..ca9f5c0f6d 100644 --- a/packages/backend/test/integration/cloud/project/project.test.ts +++ b/packages/server/api/test/integration/cloud/project/project.test.ts @@ -1,12 +1,28 @@ import { databaseConnection } from '../../../../src/app/database/database-connection' import { setupApp } from '../../../../src/app/app' import { generateMockToken } from '../../../helpers/auth' -import { createMockUser, createMockPlatform, createMockProject, createMockApiKey } from '../../../helpers/mocks' +import { + createMockUser, + createMockPlatform, + createMockProject, + createMockApiKey, +} from '../../../helpers/mocks' import { StatusCodes } from 'http-status-codes' import { FastifyInstance } from 'fastify' -import { NotificationStatus, PlatformRole, PrincipalType, Project, ProjectType, User } from '@activepieces/shared' +import { + NotificationStatus, + PlatformRole, + PrincipalType, + Project, + ProjectType, + User, +} from '@activepieces/shared' import { faker } from '@faker-js/faker' -import { ApiKeyResponseWithValue, Platform, UpdateProjectPlatformRequest } from '@activepieces/ee-shared' +import { + ApiKeyResponseWithValue, + Platform, + UpdateProjectPlatformRequest, +} from '@activepieces/ee-shared' import { stripeHelper } from '../../../../src/app/ee/billing/billing/stripe-helper' let app: FastifyInstance | null = null @@ -22,7 +38,9 @@ afterAll(async () => { }) beforeEach(async () => { - stripeHelper.getOrCreateCustomer = jest.fn().mockResolvedValue(faker.string.uuid()) + stripeHelper.getOrCreateCustomer = jest + .fn() + .mockResolvedValue(faker.string.uuid()) }) describe('Project API', () => { @@ -95,12 +113,13 @@ describe('Project API', () => { }) }) - describe('List Projects by api key', () => { it('it should list platform project', async () => { const mockUser = createMockUser() const mockUser2 = createMockUser() - await databaseConnection.getRepository('user').save([mockUser, mockUser2]) + await databaseConnection + .getRepository('user') + .save([mockUser, mockUser2]) const mockPlatform = createMockPlatform({ ownerId: mockUser.id, @@ -108,7 +127,9 @@ describe('Project API', () => { const mockPlatform2 = createMockPlatform({ ownerId: mockUser2.id, }) - await databaseConnection.getRepository('platform').save([mockPlatform, mockPlatform2]) + await databaseConnection + .getRepository('platform') + .save([mockPlatform, mockPlatform2]) const mockProject = createMockProject({ ownerId: mockUser.id, @@ -118,7 +139,9 @@ describe('Project API', () => { ownerId: mockUser2.id, platformId: mockPlatform2.id, }) - await databaseConnection.getRepository('project').save([mockProject, mockProject2]) + await databaseConnection + .getRepository('project') + .save([mockProject, mockProject2]) const apiKey = createMockApiKey({ platformId: mockPlatform.id, @@ -142,11 +165,12 @@ describe('Project API', () => { }) describe('List Projects by user', () => { - it('it should list owned projects', async () => { const mockUser = createMockUser() const mockUser2 = createMockUser() - await databaseConnection.getRepository('user').save([mockUser, mockUser2]) + await databaseConnection + .getRepository('user') + .save([mockUser, mockUser2]) const mockPlatform = createMockPlatform({ ownerId: mockUser.id, @@ -163,10 +187,9 @@ describe('Project API', () => { const mockProject3 = createMockProject({ ownerId: mockUser2.id, }) - await databaseConnection.getRepository('project').save([mockProject, mockProject2, mockProject3]) - - - + await databaseConnection + .getRepository('project') + .save([mockProject, mockProject2, mockProject3]) const testToken = await generateMockToken({ type: PrincipalType.USER, @@ -189,7 +212,6 @@ describe('Project API', () => { expect(responseBody.data[0].id).toEqual(mockProject.id) expect(responseBody.data[1].id).toEqual(mockProject2.id) }) - }) describe('Update Project', () => { @@ -210,8 +232,6 @@ describe('Project API', () => { const tasks = faker.number.int({ min: 1, max: 100000 }) const teamMembers = faker.number.int({ min: 1, max: 100 }) - - const request: UpdateProjectPlatformRequest = { displayName: faker.animal.bird(), notifyStatus: NotificationStatus.NEVER, @@ -263,7 +283,8 @@ describe('Project API', () => { }) it('it should update project as platform owner with api key', async () => { - const { mockProject, mockApiKey } = await createProjectAndPlatformAndApiKey() + const { mockProject, mockApiKey } = + await createProjectAndPlatformAndApiKey() const tasks = faker.number.int({ min: 1, max: 100000 }) const teamMembers = faker.number.int({ min: 1, max: 100 }) const request = { @@ -286,13 +307,16 @@ describe('Project API', () => { }) it('it should update project as platform owner', async () => { - const { mockProject, mockPlatform, mockUser } = await createProjectAndPlatformAndApiKey() + const { mockProject, mockPlatform, mockUser } = + await createProjectAndPlatformAndApiKey() const mockProjectTwo = createMockProject({ ownerId: mockUser.id, type: ProjectType.PLATFORM_MANAGED, platformId: mockPlatform.id, }) - await databaseConnection.getRepository('project').save([mockProject, mockProjectTwo]) + await databaseConnection + .getRepository('project') + .save([mockProject, mockProjectTwo]) const testToken = await generateMockToken({ type: PrincipalType.USER, @@ -301,8 +325,6 @@ describe('Project API', () => { platform: { id: mockPlatform.id, role: PlatformRole.OWNER }, }) - - const tasks = faker.number.int({ min: 1, max: 100000 }) const teamMembers = faker.number.int({ min: 1, max: 100 }) const request: UpdateProjectPlatformRequest = { @@ -336,9 +358,13 @@ describe('Project API', () => { const memberUser = createMockUser() const platfornOwnerUser = createMockUser() - await databaseConnection.getRepository('user').save([memberUser, platfornOwnerUser]) + await databaseConnection + .getRepository('user') + .save([memberUser, platfornOwnerUser]) - const mockPlatform = createMockPlatform({ ownerId: platfornOwnerUser.id }) + const mockPlatform = createMockPlatform({ + ownerId: platfornOwnerUser.id, + }) await databaseConnection.getRepository('platform').save(mockPlatform) const mockProject = createMockProject({ @@ -349,7 +375,9 @@ describe('Project API', () => { ownerId: platfornOwnerUser.id, platformId: mockPlatform.id, }) - await databaseConnection.getRepository('project').save([mockProject, mockProjectTwo]) + await databaseConnection + .getRepository('project') + .save([mockProject, mockProjectTwo]) const testToken = await generateMockToken({ type: PrincipalType.USER, @@ -373,11 +401,14 @@ describe('Project API', () => { expect(response?.statusCode).toBe(StatusCodes.FORBIDDEN) }) }) - - }) -async function createProjectAndPlatformAndApiKey(): Promise<{ mockApiKey: ApiKeyResponseWithValue, mockPlatform: Platform, mockProject: Project, mockUser: User }> { +async function createProjectAndPlatformAndApiKey(): Promise<{ + mockApiKey: ApiKeyResponseWithValue + mockPlatform: Platform + mockProject: Project + mockUser: User +}> { const mockUser = createMockUser() await databaseConnection.getRepository('user').save(mockUser) @@ -403,4 +434,4 @@ async function createProjectAndPlatformAndApiKey(): Promise<{ mockApiKey: ApiKey mockProject, mockUser, } -} \ No newline at end of file +} diff --git a/packages/backend/test/integration/cloud/signing-key/signing-key.test.ts b/packages/server/api/test/integration/cloud/signing-key/signing-key.test.ts similarity index 88% rename from packages/backend/test/integration/cloud/signing-key/signing-key.test.ts rename to packages/server/api/test/integration/cloud/signing-key/signing-key.test.ts index 1e315a3f1f..2e52874f54 100644 --- a/packages/backend/test/integration/cloud/signing-key/signing-key.test.ts +++ b/packages/server/api/test/integration/cloud/signing-key/signing-key.test.ts @@ -1,7 +1,11 @@ import { databaseConnection } from '../../../../src/app/database/database-connection' import { setupApp } from '../../../../src/app/app' import { generateMockToken } from '../../../helpers/auth' -import { createMockUser, createMockPlatform, createMockSigningKey } from '../../../helpers/mocks' +import { + createMockUser, + createMockPlatform, + createMockSigningKey, +} from '../../../helpers/mocks' import { StatusCodes } from 'http-status-codes' import { FastifyInstance } from 'fastify' import { PlatformRole, PrincipalType, apId } from '@activepieces/shared' @@ -101,7 +105,9 @@ describe('Signing Key API', () => { generatedBy: mockUser.id, }) - await databaseConnection.getRepository('signing_key').save(mockSigningKey) + await databaseConnection + .getRepository('signing_key') + .save(mockSigningKey) const testToken = await generateMockToken({ type: PrincipalType.USER, @@ -140,7 +146,9 @@ describe('Signing Key API', () => { generatedBy: mockUser.id, }) - await databaseConnection.getRepository('signing_key').save(mockSigningKey) + await databaseConnection + .getRepository('signing_key') + .save(mockSigningKey) const testToken = await generateMockToken({ type: PrincipalType.USER, @@ -174,18 +182,24 @@ describe('Signing Key API', () => { // arrange const mockUser = createMockUser() const mockUserTwo = createMockUser() - await databaseConnection.getRepository('user').save([mockUser, mockUserTwo]) + await databaseConnection + .getRepository('user') + .save([mockUser, mockUserTwo]) const mockPlatform = createMockPlatform({ ownerId: mockUser.id }) const mockPlatformTwo = createMockPlatform({ ownerId: mockUserTwo.id }) - await databaseConnection.getRepository('platform').save([mockPlatform, mockPlatformTwo]) + await databaseConnection + .getRepository('platform') + .save([mockPlatform, mockPlatformTwo]) const mockSigningKey = createMockSigningKey({ platformId: mockPlatform.id, generatedBy: mockUser.id, }) - await databaseConnection.getRepository('signing_key').save(mockSigningKey) + await databaseConnection + .getRepository('signing_key') + .save(mockSigningKey) const testToken = await generateMockToken({ type: PrincipalType.USER, @@ -212,11 +226,15 @@ describe('Signing Key API', () => { // arrange const mockUserOne = createMockUser() const mockUserTwo = createMockUser() - await databaseConnection.getRepository('user').save([mockUserOne, mockUserTwo]) + await databaseConnection + .getRepository('user') + .save([mockUserOne, mockUserTwo]) const mockPlatformOne = createMockPlatform({ ownerId: mockUserOne.id }) const mockPlatformTwo = createMockPlatform({ ownerId: mockUserTwo.id }) - await databaseConnection.getRepository('platform').save([mockPlatformOne, mockPlatformTwo]) + await databaseConnection + .getRepository('platform') + .save([mockPlatformOne, mockPlatformTwo]) const mockSigningKeyOne = createMockSigningKey({ platformId: mockPlatformOne.id, @@ -228,7 +246,9 @@ describe('Signing Key API', () => { generatedBy: mockUserTwo.id, }) - await databaseConnection.getRepository('signing_key').save([mockSigningKeyOne, mockSigningKeyTwo]) + await databaseConnection + .getRepository('signing_key') + .save([mockSigningKeyOne, mockSigningKeyTwo]) const testToken = await generateMockToken({ type: PrincipalType.USER, diff --git a/packages/backend/test/integration/cloud/user/enterprise-user.test.ts b/packages/server/api/test/integration/cloud/user/enterprise-user.test.ts similarity index 88% rename from packages/backend/test/integration/cloud/user/enterprise-user.test.ts rename to packages/server/api/test/integration/cloud/user/enterprise-user.test.ts index 8e8190a80c..c990857a5b 100644 --- a/packages/backend/test/integration/cloud/user/enterprise-user.test.ts +++ b/packages/server/api/test/integration/cloud/user/enterprise-user.test.ts @@ -1,10 +1,19 @@ import { databaseConnection } from '../../../../src/app/database/database-connection' import { setupApp } from '../../../../src/app/app' import { generateMockToken } from '../../../helpers/auth' -import { createMockPlatformWithOwner, createMockUser, setupMockApiKeyServiceAccount } from '../../../helpers/mocks' +import { + createMockPlatformWithOwner, + createMockUser, + setupMockApiKeyServiceAccount, +} from '../../../helpers/mocks' import { StatusCodes } from 'http-status-codes' import { FastifyInstance } from 'fastify' -import { PlatformRole, PrincipalType, UserStatus, apId } from '@activepieces/shared' +import { + PlatformRole, + PrincipalType, + UserStatus, + apId, +} from '@activepieces/shared' let app: FastifyInstance | null = null @@ -22,11 +31,17 @@ describe('Enterprise User API', () => { describe('List users endpoint', () => { it('Returns a list of users', async () => { // arrange - const { mockOwner: mockOwnerOne, mockPlatform: mockPlatformOne } = createMockPlatformWithOwner() - const { mockOwner: mockOwnerTwo, mockPlatform: mockPlatformTwo } = createMockPlatformWithOwner() - - await databaseConnection.getRepository('user').save([mockOwnerOne, mockOwnerTwo]) - await databaseConnection.getRepository('platform').save([mockPlatformOne, mockPlatformTwo]) + const { mockOwner: mockOwnerOne, mockPlatform: mockPlatformOne } = + createMockPlatformWithOwner() + const { mockOwner: mockOwnerTwo, mockPlatform: mockPlatformTwo } = + createMockPlatformWithOwner() + + await databaseConnection + .getRepository('user') + .save([mockOwnerOne, mockOwnerTwo]) + await databaseConnection + .getRepository('platform') + .save([mockPlatformOne, mockPlatformTwo]) const testToken = await generateMockToken({ id: mockOwnerOne.id, @@ -61,7 +76,8 @@ describe('Enterprise User API', () => { it('Allows service accounts', async () => { // arrange - const { mockOwner, mockPlatform, mockApiKey } = setupMockApiKeyServiceAccount() + const { mockOwner, mockPlatform, mockApiKey } = + setupMockApiKeyServiceAccount() await databaseConnection.getRepository('user').save([mockOwner]) await databaseConnection.getRepository('platform').save([mockPlatform]) @@ -126,7 +142,9 @@ describe('Enterprise User API', () => { status: UserStatus.ACTIVE, }) - await databaseConnection.getRepository('user').save([mockOwner, mockUser]) + await databaseConnection + .getRepository('user') + .save([mockOwner, mockUser]) await databaseConnection.getRepository('platform').save([mockPlatform]) const testToken = await generateMockToken({ @@ -158,7 +176,7 @@ describe('Enterprise User API', () => { expect(responseJson.password).toBeUndefined() expect(responseJson.status).toBe(UserStatus.INACTIVE) }) - + it('Fails if user doesn\'t exist', async () => { // arrange const nonExistentUserId = apId() @@ -185,19 +203,21 @@ describe('Enterprise User API', () => { // assert expect(response?.statusCode).toBe(StatusCodes.NOT_FOUND) - }) it('Allows service accounts to activate', async () => { // arrange - const { mockOwner, mockPlatform, mockApiKey } = setupMockApiKeyServiceAccount() + const { mockOwner, mockPlatform, mockApiKey } = + setupMockApiKeyServiceAccount() const mockUser = createMockUser({ platformId: mockPlatform.id, status: UserStatus.INACTIVE, }) - await databaseConnection.getRepository('user').save([mockOwner, mockUser]) + await databaseConnection + .getRepository('user') + .save([mockOwner, mockUser]) await databaseConnection.getRepository('platform').save([mockPlatform]) await databaseConnection.getRepository('api_key').save([mockApiKey]) @@ -216,7 +236,6 @@ describe('Enterprise User API', () => { // assert expect(response?.statusCode).toBe(StatusCodes.OK) - const responseJson = response?.json() expect(responseJson.id).toBe(mockUser.id) expect(responseJson.password).toBeUndefined() diff --git a/packages/backend/test/integration/ee/authn/ee-authn.test.ts b/packages/server/api/test/integration/ee/authn/ee-authn.test.ts similarity index 84% rename from packages/backend/test/integration/ee/authn/ee-authn.test.ts rename to packages/server/api/test/integration/ee/authn/ee-authn.test.ts index 3ee4576b66..d661acd4f5 100644 --- a/packages/backend/test/integration/ee/authn/ee-authn.test.ts +++ b/packages/server/api/test/integration/ee/authn/ee-authn.test.ts @@ -6,7 +6,11 @@ import { createMockSignUpRequest } from '../../../helpers/mocks/authn' import { faker } from '@faker-js/faker' import { emailService } from '../../../../src/app/ee/helper/email/email-service' import { stripeHelper } from '../../../../src/app/ee/billing/billing/stripe-helper' -import { createMockCustomDomain, createMockPlatform, createMockUser } from '../../../../test/helpers/mocks' +import { + createMockCustomDomain, + createMockPlatform, + createMockUser, +} from '../../../../test/helpers/mocks' let app: FastifyInstance | null = null @@ -17,7 +21,9 @@ beforeAll(async () => { beforeEach(async () => { emailService.sendOtpEmail = jest.fn() - stripeHelper.getOrCreateCustomer = jest.fn().mockResolvedValue(faker.string.alphanumeric()) + stripeHelper.getOrCreateCustomer = jest + .fn() + .mockResolvedValue(faker.string.alphanumeric()) await databaseConnection.getRepository('flag').delete({}) }) @@ -60,22 +66,27 @@ describe('Authentication API', () => { expect(responseBody?.projectId).toHaveLength(21) expect(responseBody?.token).toBeDefined() }) - }) - it('fails to sign up invited user platform if no project exist', async () => { - // arrange + // arrange const mockPlatformId = faker.string.nanoid(21) const mockPlatformOwner = createMockUser({ platformId: mockPlatformId }) await databaseConnection.getRepository('user').save([mockPlatformOwner]) - const mockPlatform = createMockPlatform({ id: mockPlatformId, ownerId: mockPlatformOwner.id }) + const mockPlatform = createMockPlatform({ + id: mockPlatformId, + ownerId: mockPlatformOwner.id, + }) await databaseConnection.getRepository('platform').save(mockPlatform) - const mockCustomDomain = createMockCustomDomain({ platformId: mockPlatform.id }) - await databaseConnection.getRepository('custom_domain').save(mockCustomDomain) + const mockCustomDomain = createMockCustomDomain({ + platformId: mockPlatform.id, + }) + await databaseConnection + .getRepository('custom_domain') + .save(mockCustomDomain) const mockedUpEmail = faker.internet.email() const mockSignUpRequest = createMockSignUpRequest({ email: mockedUpEmail }) diff --git a/packages/backend/tsconfig.app.json b/packages/server/api/tsconfig.app.json similarity index 65% rename from packages/backend/tsconfig.app.json rename to packages/server/api/tsconfig.app.json index 349e58ac65..cf31f14422 100644 --- a/packages/backend/tsconfig.app.json +++ b/packages/server/api/tsconfig.app.json @@ -1,13 +1,10 @@ { "extends": "./tsconfig.json", "compilerOptions": { - "outDir": "../../dist/out-tsc", + "outDir": "../../../dist/out-tsc", "module": "CommonJS", "types": ["node"] }, "exclude": ["jest.config.ts", "src/**/*.spec.ts", "src/**/*.test.ts"], - "include": [ - "src/**/*.ts", - "types/**/*.d.ts" - ] + "include": ["src/**/*.ts", "types/**/*.d.ts"] } diff --git a/packages/backend/tsconfig.json b/packages/server/api/tsconfig.json similarity index 89% rename from packages/backend/tsconfig.json rename to packages/server/api/tsconfig.json index 0294db1054..9009109a23 100644 --- a/packages/backend/tsconfig.json +++ b/packages/server/api/tsconfig.json @@ -1,5 +1,5 @@ { - "extends": "../../tsconfig.base.json", + "extends": "../../../tsconfig.base.json", "files": [], "include": [], "references": [ diff --git a/packages/backend/tsconfig.spec.json b/packages/server/api/tsconfig.spec.json similarity index 88% rename from packages/backend/tsconfig.spec.json rename to packages/server/api/tsconfig.spec.json index 17fa567885..a225f685f8 100644 --- a/packages/backend/tsconfig.spec.json +++ b/packages/server/api/tsconfig.spec.json @@ -1,7 +1,7 @@ { "extends": "./tsconfig.json", "compilerOptions": { - "outDir": "../../dist/out-tsc", + "outDir": "../../../dist/out-tsc", "module": "commonjs", "types": ["jest", "node"] }, diff --git a/packages/backend/types/fastify.d.ts b/packages/server/api/types/fastify.d.ts similarity index 99% rename from packages/backend/types/fastify.d.ts rename to packages/server/api/types/fastify.d.ts index 08c0d7fae2..70ae9ee04d 100644 --- a/packages/backend/types/fastify.d.ts +++ b/packages/server/api/types/fastify.d.ts @@ -2,7 +2,6 @@ import fastify from 'fastify' import { EndpointScope, Principal, PrincipalType } from '@activepieces/shared' - declare module 'fastify' { // eslint-disable-next-line @typescript-eslint/consistent-type-definitions export interface FastifyRequest { diff --git a/packages/server/api/types/redis-lock.d.ts b/packages/server/api/types/redis-lock.d.ts new file mode 100644 index 0000000000..e773a81989 --- /dev/null +++ b/packages/server/api/types/redis-lock.d.ts @@ -0,0 +1,7 @@ +declare module 'redis-lock' { + function redisLock( + client: unknown, + retryDelay: number + ): (lockId: string) => Promise<() => Promise> + export default redisLock +} diff --git a/packages/backend/webpack.config.js b/packages/server/api/webpack.config.js similarity index 100% rename from packages/backend/webpack.config.js rename to packages/server/api/webpack.config.js diff --git a/packages/server/shared/.eslintrc.json b/packages/server/shared/.eslintrc.json new file mode 100644 index 0000000000..3230caf3d2 --- /dev/null +++ b/packages/server/shared/.eslintrc.json @@ -0,0 +1,25 @@ +{ + "extends": ["../../../.eslintrc.json"], + "ignorePatterns": ["!**/*"], + "overrides": [ + { + "files": ["*.ts", "*.tsx", "*.js", "*.jsx"], + "rules": {} + }, + { + "files": ["*.ts", "*.tsx"], + "rules": {} + }, + { + "files": ["*.js", "*.jsx"], + "rules": {} + }, + { + "files": ["*.json"], + "parser": "jsonc-eslint-parser", + "rules": { + "@nx/dependency-checks": "error" + } + } + ] +} diff --git a/packages/server/shared/README.md b/packages/server/shared/README.md new file mode 100644 index 0000000000..88ea696ae3 --- /dev/null +++ b/packages/server/shared/README.md @@ -0,0 +1,7 @@ +# server-shared + +This library was generated with [Nx](https://nx.dev). + +## Building + +Run `nx build server-shared` to build the library. diff --git a/packages/server/shared/package.json b/packages/server/shared/package.json new file mode 100644 index 0000000000..ee669d69e3 --- /dev/null +++ b/packages/server/shared/package.json @@ -0,0 +1,14 @@ +{ + "name": "server-shared", + "version": "0.0.1", + "dependencies": { + "tslib": "^2.3.0", + "@sentry/node": "7.64.0", + "pino": "8.18.0", + "pino-loki": "2.1.3", + "@activepieces/shared": "*" + }, + "type": "commonjs", + "main": "./src/index.js", + "typings": "./src/index.d.ts" +} diff --git a/packages/server/shared/project.json b/packages/server/shared/project.json new file mode 100644 index 0000000000..dd790e623d --- /dev/null +++ b/packages/server/shared/project.json @@ -0,0 +1,31 @@ +{ + "name": "server-shared", + "$schema": "../../../node_modules/nx/schemas/project-schema.json", + "sourceRoot": "packages/server/shared/src", + "projectType": "library", + "targets": { + "build": { + "executor": "@nx/js:tsc", + "outputs": ["{options.outputPath}"], + "options": { + "outputPath": "dist/packages/server/shared", + "main": "packages/server/shared/src/index.ts", + "tsConfig": "packages/server/shared/tsconfig.lib.json", + "assets": ["packages/server/shared/*.md"], + "buildableProjectDepsInPackageJsonType": "dependencies", + "updateBuildableProjectDepsInPackageJson": true + } + }, + "lint": { + "executor": "@nx/eslint:lint", + "outputs": ["{options.outputFile}"], + "options": { + "lintFilePatterns": [ + "packages/server/shared/**/*.ts", + "packages/server/shared/package.json" + ] + } + } + }, + "tags": [] +} diff --git a/packages/server/shared/src/index.ts b/packages/server/shared/src/index.ts new file mode 100644 index 0000000000..4d3bba983d --- /dev/null +++ b/packages/server/shared/src/index.ts @@ -0,0 +1,8 @@ +export * from './lib/file-compressor' +export * from './lib/file-system' +export * from './lib/package-manager' +export * from './lib/system/system' +export * from './lib/system/system-prop' +export * from './lib/promise-handler' +export * from './lib/logger' +export * from './lib/exception-handler' \ No newline at end of file diff --git a/packages/server/shared/src/lib/exception-handler.ts b/packages/server/shared/src/lib/exception-handler.ts new file mode 100644 index 0000000000..1f8c8e6de4 --- /dev/null +++ b/packages/server/shared/src/lib/exception-handler.ts @@ -0,0 +1,69 @@ +import * as Sentry from '@sentry/node' +import { logger } from './logger' +import { SystemProp } from './system/system-prop' +import { system } from './system/system' + +const sentryDsn = system.get(SystemProp.SENTRY_DSN) + +export const initilizeSentry = () => { + if (sentryDsn) { + logger.info('Initializing Sentry') + Sentry.init({ + dsn: sentryDsn, + tracesSampleRate: 0.2, + }) + } +} + +export const exceptionHandler = { + handle: (e: unknown): void => { + logger.error(e) + if (sentryDsn) { + Sentry.captureException(e) + } + }, +} + + + +const ENRICH_ERROR_CONTEXT = + system.getBoolean(SystemProp.ENRICH_ERROR_CONTEXT) ?? false + + +export const enrichErrorContext = ({ + error, + key, + value, +}: EnrichErrorContextParams): unknown => { + if (!ENRICH_ERROR_CONTEXT) { + return error + } + + if (error instanceof Error) { + if ('context' in error && error.context instanceof Object) { + const enrichedError = Object.assign(error, { + ...error.context, + [key]: value, + }) + + return enrichedError + } + else { + const enrichedError = Object.assign(error, { + context: { + [key]: value, + }, + }) + + return enrichedError + } + } + + return error +} + +type EnrichErrorContextParams = { + error: unknown + key: string + value: unknown +} diff --git a/packages/backend/src/app/helper/exec.ts b/packages/server/shared/src/lib/exec.ts similarity index 100% rename from packages/backend/src/app/helper/exec.ts rename to packages/server/shared/src/lib/exec.ts diff --git a/packages/backend/src/app/file/utils/file-compressor.ts b/packages/server/shared/src/lib/file-compressor.ts similarity index 100% rename from packages/backend/src/app/file/utils/file-compressor.ts rename to packages/server/shared/src/lib/file-compressor.ts diff --git a/packages/backend/src/app/helper/file-system.ts b/packages/server/shared/src/lib/file-system.ts similarity index 100% rename from packages/backend/src/app/helper/file-system.ts rename to packages/server/shared/src/lib/file-system.ts diff --git a/packages/backend/src/app/helper/logger.ts b/packages/server/shared/src/lib/logger.ts similarity index 68% rename from packages/backend/src/app/helper/logger.ts rename to packages/server/shared/src/lib/logger.ts index 189992e794..e4526523bc 100644 --- a/packages/backend/src/app/helper/logger.ts +++ b/packages/server/shared/src/lib/logger.ts @@ -2,13 +2,6 @@ import pino, { Logger, Level } from 'pino' import 'pino-loki' import { system } from './system/system' import { SystemProp } from './system/system-prop' -import { exceptionHandler } from './exception-handler' - -export const captureException = (error: unknown): void => { - logger.error(error) - exceptionHandler.handle(error) - .catch((e) => logger.error(e, '[Logger#captureException] exceptionHandler.handle')) -} const lokiUrl = system.get(SystemProp.LOKI_URL) const lokiUsername = system.get(SystemProp.LOKI_USERNAME) @@ -32,11 +25,13 @@ const initLogger = (): Logger => { }) } - const targets = [{ - target: 'pino/file', - level, - options: {}, - }] + const targets = [ + { + target: 'pino/file', + level, + options: {}, + }, + ] if (lokiUrl) { targets.push({ @@ -46,10 +41,13 @@ const initLogger = (): Logger => { batching: true, interval: 5, host: lokiUrl, - basicAuth: lokiPassword && lokiPassword ? { - username: lokiUsername, - password: lokiPassword, - } : undefined, + basicAuth: + lokiPassword && lokiPassword + ? { + username: lokiUsername, + password: lokiPassword, + } + : undefined, }, }) } diff --git a/packages/backend/src/app/helper/package-manager.ts b/packages/server/shared/src/lib/package-manager.ts similarity index 83% rename from packages/backend/src/app/helper/package-manager.ts rename to packages/server/shared/src/lib/package-manager.ts index acd6cc0cb3..9a6de5dcb4 100644 --- a/packages/backend/src/app/helper/package-manager.ts +++ b/packages/server/shared/src/lib/package-manager.ts @@ -1,9 +1,9 @@ -import { enrichErrorContext } from './error-handler' -import { exec } from './exec' -import { logger } from './logger' import { isEmpty } from '@activepieces/shared' import fs from 'fs/promises' import fsPath from 'path' +import { logger } from './logger' +import { exec } from './exec' +import { enrichErrorContext } from './exception-handler' type PackageManagerOutput = { stdout: string @@ -16,17 +16,21 @@ type Command = CoreCommand | ExecCommand export type PackageInfo = { /** - * name or alias - */ + * name or alias + */ alias: string /** - * where to get the package from, could be an npm tag, a local path, or a tarball. - */ + * where to get the package from, could be an npm tag, a local path, or a tarball. + */ spec: string } -const runCommand = async (path: string, command: Command, ...args: string[]): Promise => { +const runCommand = async ( + path: string, + command: Command, + ...args: string[] +): Promise => { try { logger.debug({ path, command, args }, '[PackageManager#execute]') @@ -63,7 +67,7 @@ export const packageManager = { '--config.auto-install-peers=true', ] - const dependencyArgs = dependencies.map(d => `${d.alias}@${d.spec}`) + const dependencyArgs = dependencies.map((d) => `${d.alias}@${d.spec}`) return runCommand(path, 'add', ...dependencyArgs, ...config) }, @@ -75,25 +79,27 @@ export const packageManager = { return runCommand(path, command) }, - async link({ path, linkPath, packageName }: LinkParams): Promise { + async link({ + path, + linkPath, + packageName, + }: LinkParams): Promise { const config = [ '--config.lockfile=false', '--config.auto-install-peers=true', ] - const result = await runCommand(path, 'link', linkPath, ...config) const nodeModules = fsPath.join(path, 'node_modules', packageName) await replaceRelativeSystemLinkWithAbsolute(nodeModules) return result }, - } const replaceRelativeSystemLinkWithAbsolute = async (filePath: string) => { try { - // Inside the isolate sandbox, the relative path is not valid + // Inside the isolate sandbox, the relative path is not valid const stats = await fs.stat(filePath) diff --git a/packages/backend/src/app/helper/promise-handler.ts b/packages/server/shared/src/lib/promise-handler.ts similarity index 80% rename from packages/backend/src/app/helper/promise-handler.ts rename to packages/server/shared/src/lib/promise-handler.ts index a3fbdc8c00..4111d71f1d 100644 --- a/packages/backend/src/app/helper/promise-handler.ts +++ b/packages/server/shared/src/lib/promise-handler.ts @@ -1,4 +1,4 @@ -import { logger } from './logger' +import { logger } from "./logger" export function rejectedPromiseHandler(promise: Promise) { promise.catch((error) => { diff --git a/packages/server/shared/src/lib/system/system-prop.ts b/packages/server/shared/src/lib/system/system-prop.ts new file mode 100644 index 0000000000..e550993af9 --- /dev/null +++ b/packages/server/shared/src/lib/system/system-prop.ts @@ -0,0 +1,80 @@ +export enum SystemProp { + API_KEY = 'API_KEY', + APP_WEBHOOK_SECRETS = 'APP_WEBHOOK_SECRETS', + API_RATE_LIMIT_AUTHN_ENABLED = 'API_RATE_LIMIT_AUTHN_ENABLED', + API_RATE_LIMIT_AUTHN_MAX = 'API_RATE_LIMIT_AUTHN_MAX', + API_RATE_LIMIT_AUTHN_WINDOW = 'API_RATE_LIMIT_AUTHN_WINDOW', + CACHE_PATH = 'CACHE_PATH', + CLIENT_REAL_IP_HEADER = 'CLIENT_REAL_IP_HEADER', + CLOUD_AUTH_ENABLED = 'CLOUD_AUTH_ENABLED', + CODE_SANDBOX_TYPE = 'CODE_SANDBOX_TYPE', + CONFIG_PATH = 'CONFIG_PATH', + DB_TYPE = 'DB_TYPE', + EDITION = 'EDITION', + ENCRYPTION_KEY = 'ENCRYPTION_KEY', + ENGINE_EXECUTABLE_PATH = 'ENGINE_EXECUTABLE_PATH', + ENRICH_ERROR_CONTEXT = 'ENRICH_ERROR_CONTEXT', + ENVIRONMENT = 'ENVIRONMENT', + EXECUTION_MODE = 'EXECUTION_MODE', + FLOW_WORKER_CONCURRENCY = 'FLOW_WORKER_CONCURRENCY', + FRONTEND_URL = 'FRONTEND_URL', + JWT_SECRET = 'JWT_SECRET', + LICENSE_KEY = 'LICENSE_KEY', + LOG_LEVEL = 'LOG_LEVEL', + LOG_PRETTY = 'LOG_PRETTY', + LOKI_PASSWORD = 'LOKI_PASSWORD', + LOKI_URL = 'LOKI_URL', + LOKI_USERNAME = 'LOKI_USERNAME', + NOTIFICATION_URL = 'NOTIFICATION_URL', + OPENAI_API_KEY = 'OPENAI_API_KEY', + OPENAI_API_BASE_URL = 'OPENAI_API_BASE_URL', + PIECES_SOURCE = 'PIECES_SOURCE', + POSTGRES_URL = 'POSTGRES_URL', + POSTGRES_DATABASE = 'POSTGRES_DATABASE', + POSTGRES_HOST = 'POSTGRES_HOST', + POSTGRES_PASSWORD = 'POSTGRES_PASSWORD', + POSTGRES_PORT = 'POSTGRES_PORT', + POSTGRES_SSL_CA = 'POSTGRES_SSL_CA', + POSTGRES_USERNAME = 'POSTGRES_USERNAME', + POSTGRES_USE_SSL = 'POSTGRES_USE_SSL', + QUEUE_MODE = 'QUEUE_MODE', + QUEUE_UI_ENABLED = 'QUEUE_UI_ENABLED', + QUEUE_UI_PASSWORD = 'QUEUE_UI_PASSWORD', + QUEUE_UI_USERNAME = 'QUEUE_UI_USERNAME', + REDIS_DB = 'REDIS_DB', + REDIS_HOST = 'REDIS_HOST', + REDIS_PASSWORD = 'REDIS_PASSWORD', + REDIS_PORT = 'REDIS_PORT', + REDIS_URL = 'REDIS_URL', + REDIS_USER = 'REDIS_USER', + REDIS_USE_SSL = 'REDIS_USE_SSL', + SANDBOX_MEMORY_LIMIT = 'SANDBOX_MEMORY_LIMIT', + SANDBOX_RUN_TIME_SECONDS = 'SANDBOX_RUN_TIME_SECONDS', + SIGN_UP_ENABLED = 'SIGN_UP_ENABLED', + SMTP_HOST = 'SMTP_HOST', + SMTP_PASSWORD = 'SMTP_PASSWORD', + SMTP_PORT = 'SMTP_PORT', + SMTP_USERNAME = 'SMTP_USERNAME', + SMTP_SENDER_NAME = 'SMTP_SENDER_NAME', + SMTP_SENDER_EMAIL = 'SMTP_SENDER_EMAIL', + SMTP_USE_SSL = 'SMTP_USE_SSL', + STATS_ENABLED = 'STATS_ENABLED', + TELEMETRY_ENABLED = 'TELEMETRY_ENABLED', + TEMPLATES_SOURCE_URL = 'TEMPLATES_SOURCE_URL', + TRIGGER_DEFAULT_POLL_INTERVAL = 'TRIGGER_DEFAULT_POLL_INTERVAL', + WEBHOOK_TIMEOUT_SECONDS = 'WEBHOOK_TIMEOUT_SECONDS', + WEBHOOK_URL = 'WEBHOOK_URL', + + // ENTERPRISE ONLY + APPSUMO_TOKEN = 'APPSUMO_TOKEN', + BILLING_SETTINGS = 'BILLING_SETTINGS', + FIREBASE_ADMIN_CREDENTIALS = 'FIREBASE_ADMIN_CREDENTIALS', + FIREBASE_HASH_PARAMETERS = 'FIREBASE_HASH_PARAMETERS', + PACKAGE_ARCHIVE_PATH = 'PACKAGE_ARCHIVE_PATH', + SENTRY_DSN = 'SENTRY_DSN', + STRIPE_SECRET_KEY = 'STRIPE_SECRET_KEY', + STRIPE_WEBHOOK_SECRET = 'STRIPE_WEBHOOK_SECRET', + + // CLOUD_ONLY + CLOUD_PLATFORM_ID = 'CLOUD_PLATFORM_ID', +} diff --git a/packages/server/shared/src/lib/system/system.ts b/packages/server/shared/src/lib/system/system.ts new file mode 100644 index 0000000000..5bbe0a0d2a --- /dev/null +++ b/packages/server/shared/src/lib/system/system.ts @@ -0,0 +1,113 @@ +import { + ActivepiecesError, + CodeSandboxType, + ErrorCode, + isNil, +} from '@activepieces/shared'; +import path from 'path'; +import os from 'os'; +import { SystemProp } from './system-prop'; + +export enum PiecesSource { + CLOUD_AND_DB = 'CLOUD_AND_DB', + DB = 'DB', + FILE = 'FILE', +} + +export enum QueueMode { + REDIS = 'REDIS', + MEMORY = 'MEMORY', +} + +export enum DatabaseType { + POSTGRES = 'POSTGRES', + SQLITE3 = 'SQLITE3', +} + +const systemPropDefaultValues: Partial> = { + [SystemProp.API_RATE_LIMIT_AUTHN_ENABLED]: 'true', + [SystemProp.API_RATE_LIMIT_AUTHN_MAX]: '50', + [SystemProp.API_RATE_LIMIT_AUTHN_WINDOW]: '1 minute', + [SystemProp.CLIENT_REAL_IP_HEADER]: 'x-real-ip', + [SystemProp.CLOUD_AUTH_ENABLED]: 'true', + [SystemProp.CODE_SANDBOX_TYPE]: CodeSandboxType.NO_OP, + [SystemProp.CONFIG_PATH]: path.join(os.homedir(), '.activepieces'), + [SystemProp.DB_TYPE]: DatabaseType.POSTGRES, + [SystemProp.EDITION]: 'ce', + [SystemProp.ENGINE_EXECUTABLE_PATH]: 'dist/packages/engine/main.js', + [SystemProp.ENVIRONMENT]: 'prod', + [SystemProp.EXECUTION_MODE]: 'UNSANDBOXED', + [SystemProp.FLOW_WORKER_CONCURRENCY]: '10', + [SystemProp.LOG_LEVEL]: 'info', + [SystemProp.LOG_PRETTY]: 'false', + [SystemProp.PACKAGE_ARCHIVE_PATH]: 'dist/archives', + [SystemProp.PIECES_SOURCE]: PiecesSource.CLOUD_AND_DB, + [SystemProp.QUEUE_MODE]: QueueMode.REDIS, + [SystemProp.SANDBOX_MEMORY_LIMIT]: '131072', + [SystemProp.SANDBOX_RUN_TIME_SECONDS]: '600', + [SystemProp.SIGN_UP_ENABLED]: 'false', + [SystemProp.STATS_ENABLED]: 'false', + [SystemProp.TELEMETRY_ENABLED]: 'true', + [SystemProp.TEMPLATES_SOURCE_URL]: + 'https://cloud.activepieces.com/api/v1/flow-templates', + [SystemProp.TRIGGER_DEFAULT_POLL_INTERVAL]: '5', +}; + +export const system = { + get(prop: SystemProp): T | undefined { + return getEnvVar(prop) as T | undefined; + }, + + getNumber(prop: SystemProp): number | null { + const stringNumber = getEnvVar(prop); + + if (!stringNumber) { + return null; + } + + const parsedNumber = Number.parseInt(stringNumber, 10); + + if (Number.isNaN(parsedNumber)) { + return null; + } + + return parsedNumber; + }, + + getBoolean(prop: SystemProp): boolean | undefined { + const value = getEnvVar(prop); + + if (isNil(value)) { + return undefined; + } + return value === 'true'; + }, + + getOrThrow(prop: SystemProp): T { + const value = getEnvVar(prop) as T | undefined; + + if (value === undefined) { + throw new ActivepiecesError( + { + code: ErrorCode.SYSTEM_PROP_NOT_DEFINED, + params: { + prop, + }, + }, + `System property AP_${prop} is not defined, please check the documentation` + ); + } + + return value; + }, +}; + +const getEnvVar = (prop: SystemProp): string | undefined => { + return process.env[`AP_${prop}`] ?? systemPropDefaultValues[prop]; +}; + + +export enum ExecutionMode { + SANDBOXED = 'SANDBOXED', + UNSANDBOXED = 'UNSANDBOXED', +} diff --git a/packages/server/shared/tsconfig.json b/packages/server/shared/tsconfig.json new file mode 100644 index 0000000000..f2400abede --- /dev/null +++ b/packages/server/shared/tsconfig.json @@ -0,0 +1,19 @@ +{ + "extends": "../../../tsconfig.base.json", + "compilerOptions": { + "module": "commonjs", + "forceConsistentCasingInFileNames": true, + "strict": true, + "noImplicitOverride": true, + "noPropertyAccessFromIndexSignature": true, + "noImplicitReturns": true, + "noFallthroughCasesInSwitch": true + }, + "files": [], + "include": [], + "references": [ + { + "path": "./tsconfig.lib.json" + } + ] +} diff --git a/packages/server/shared/tsconfig.lib.json b/packages/server/shared/tsconfig.lib.json new file mode 100644 index 0000000000..4befa7f099 --- /dev/null +++ b/packages/server/shared/tsconfig.lib.json @@ -0,0 +1,10 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../../../dist/out-tsc", + "declaration": true, + "types": ["node"] + }, + "include": ["src/**/*.ts"], + "exclude": ["jest.config.ts", "src/**/*.spec.ts", "src/**/*.test.ts"] +} diff --git a/packages/server/worker/.eslintrc.json b/packages/server/worker/.eslintrc.json new file mode 100644 index 0000000000..3230caf3d2 --- /dev/null +++ b/packages/server/worker/.eslintrc.json @@ -0,0 +1,25 @@ +{ + "extends": ["../../../.eslintrc.json"], + "ignorePatterns": ["!**/*"], + "overrides": [ + { + "files": ["*.ts", "*.tsx", "*.js", "*.jsx"], + "rules": {} + }, + { + "files": ["*.ts", "*.tsx"], + "rules": {} + }, + { + "files": ["*.js", "*.jsx"], + "rules": {} + }, + { + "files": ["*.json"], + "parser": "jsonc-eslint-parser", + "rules": { + "@nx/dependency-checks": "error" + } + } + ] +} diff --git a/packages/server/worker/README.md b/packages/server/worker/README.md new file mode 100644 index 0000000000..5b2f74c553 --- /dev/null +++ b/packages/server/worker/README.md @@ -0,0 +1,7 @@ +# server-worker + +This library was generated with [Nx](https://nx.dev). + +## Building + +Run `nx build server-worker` to build the library. diff --git a/packages/server/worker/package.json b/packages/server/worker/package.json new file mode 100644 index 0000000000..866764582d --- /dev/null +++ b/packages/server/worker/package.json @@ -0,0 +1,14 @@ +{ + "name": "server-worker", + "version": "0.0.1", + "dependencies": { + "tslib": "^2.3.0", + "@activepieces/shared": "*", + "server-shared": "*", + "fs-extra": "11.2.0", + "async-mutex": "0.4.0" + }, + "type": "commonjs", + "main": "./src/index.js", + "typings": "./src/index.d.ts" +} diff --git a/packages/server/worker/project.json b/packages/server/worker/project.json new file mode 100644 index 0000000000..ee95a9e226 --- /dev/null +++ b/packages/server/worker/project.json @@ -0,0 +1,29 @@ +{ + "name": "server-worker", + "$schema": "../../../node_modules/nx/schemas/project-schema.json", + "sourceRoot": "packages/server/worker/src", + "projectType": "library", + "targets": { + "build": { + "executor": "@nx/js:tsc", + "outputs": ["{options.outputPath}"], + "options": { + "outputPath": "dist/packages/server/worker", + "main": "packages/server/worker/src/index.ts", + "tsConfig": "packages/server/worker/tsconfig.lib.json", + "assets": ["packages/server/worker/*.md"] + } + }, + "lint": { + "executor": "@nx/eslint:lint", + "outputs": ["{options.outputFile}"], + "options": { + "lintFilePatterns": [ + "packages/server/worker/**/*.ts", + "packages/server/worker/package.json" + ] + } + } + }, + "tags": [] +} diff --git a/packages/server/worker/src/index.ts b/packages/server/worker/src/index.ts new file mode 100644 index 0000000000..7873d02b45 --- /dev/null +++ b/packages/server/worker/src/index.ts @@ -0,0 +1,5 @@ +export * from './lib/sandbox/sandbox-manager' +export * from './lib/sandbox' +export * from './lib/log-serializer' +export * from './lib/code-worker/code-builder' +export * from './lib/engine/engine-installer' \ No newline at end of file diff --git a/packages/backend/src/app/workers/code-worker/code-builder.ts b/packages/server/worker/src/lib/code-worker/code-builder.ts old mode 100755 new mode 100644 similarity index 73% rename from packages/backend/src/app/workers/code-worker/code-builder.ts rename to packages/server/worker/src/lib/code-worker/code-builder.ts index deb0073010..cc26566ae4 --- a/packages/backend/src/app/workers/code-worker/code-builder.ts +++ b/packages/server/worker/src/lib/code-worker/code-builder.ts @@ -1,7 +1,6 @@ import fs from 'node:fs/promises' -import { PackageInfo, packageManager } from '../../helper/package-manager' import { SourceCode } from '@activepieces/shared' -import { logger } from '../../helper/logger' +import { PackageInfo, logger, packageManager } from 'server-shared' const TS_CONFIG_CONTENT = ` { @@ -24,13 +23,23 @@ const TS_CONFIG_CONTENT = ` } ` -const INVALID_ARTIFACT_TEMPLATE_PATH = './packages/backend/src/assets/invalid-code.js' +const INVALID_ARTIFACT_TEMPLATE_PATH = + './packages/server/api/src/assets/invalid-code.js' const INVALID_ARTIFACT_ERROR_PLACEHOLDER = '${ERROR_MESSAGE}' export const codeBuilder = { - async processCodeStep({ sourceCode, sourceCodeId, buildPath }: ProcessCodeStepParams): Promise { - logger.debug({ name: 'CodeBuilder#processCodeStep', sourceCode, sourceCodeId, buildPath }) + async processCodeStep({ + sourceCode, + sourceCodeId, + buildPath, + }: ProcessCodeStepParams): Promise { + logger.debug({ + name: 'CodeBuilder#processCodeStep', + sourceCode, + sourceCodeId, + buildPath, + }) const codePath = `${buildPath}/codes/${sourceCodeId}` @@ -64,7 +73,10 @@ const createBuildDirectory = async (path: string): Promise => { await fs.mkdir(path, { recursive: true }) } -const installDependencies = async ({ path, packageJson }: InstallDependenciesParams): Promise => { +const installDependencies = async ({ + path, + packageJson, +}: InstallDependenciesParams): Promise => { await fs.writeFile(`${path}/package.json`, packageJson, 'utf8') const dependencies: PackageInfo[] = [ @@ -88,7 +100,10 @@ const installDependencies = async ({ path, packageJson }: InstallDependenciesPar }) } -const compileCode = async ({ path, code }: CompileCodeParams): Promise => { +const compileCode = async ({ + path, + code, +}: CompileCodeParams): Promise => { await fs.writeFile(`${path}/tsconfig.json`, TS_CONFIG_CONTENT, 'utf8') await fs.writeFile(`${path}/index.ts`, code, 'utf8') @@ -98,10 +113,18 @@ const compileCode = async ({ path, code }: CompileCodeParams): Promise => }) } -const handleCompilationError = async ({ codePath, error }: HandleCompilationErrorParams): Promise => { - const invalidArtifactTemplate = await fs.readFile(INVALID_ARTIFACT_TEMPLATE_PATH, 'utf8') +const handleCompilationError = async ({ + codePath, + error, +}: HandleCompilationErrorParams): Promise => { + const invalidArtifactTemplate = await fs.readFile( + INVALID_ARTIFACT_TEMPLATE_PATH, + 'utf8', + ) - const errorMessage = `Compilation Error:\n${error.stdout ?? error.message ?? 'error building code'}` + const errorMessage = `Compilation Error:\n${ + error['stdout'] ?? error['message'] ?? 'error building code' + }` const escapedErrorMessage = errorMessage.replace(/"/g, '\\"') const invalidArtifactContent = invalidArtifactTemplate.replace( diff --git a/packages/backend/src/app/workers/engine/engine-installer.ts b/packages/server/worker/src/lib/engine/engine-installer.ts similarity index 65% rename from packages/backend/src/app/workers/engine/engine-installer.ts rename to packages/server/worker/src/lib/engine/engine-installer.ts index a5332ef968..71ebbb99ff 100644 --- a/packages/backend/src/app/workers/engine/engine-installer.ts +++ b/packages/server/worker/src/lib/engine/engine-installer.ts @@ -1,9 +1,10 @@ import { copyFile } from 'node:fs/promises' -import { system } from '../../helper/system/system' -import { SystemProp } from '../../helper/system/system-prop' -import { logger } from '../../helper/logger' +import { SystemProp, system } from 'server-shared' +import { logger } from 'server-shared' -const engineExecutablePath = system.getOrThrow(SystemProp.ENGINE_EXECUTABLE_PATH) +const engineExecutablePath = system.getOrThrow( + SystemProp.ENGINE_EXECUTABLE_PATH, +) /** * Installs the engine executable to the given path diff --git a/packages/backend/src/app/flows/common/log-serializer.ts b/packages/server/worker/src/lib/log-serializer.ts similarity index 69% rename from packages/backend/src/app/flows/common/log-serializer.ts rename to packages/server/worker/src/lib/log-serializer.ts index 3ba3aad341..1e471ff0d0 100644 --- a/packages/backend/src/app/flows/common/log-serializer.ts +++ b/packages/server/worker/src/lib/log-serializer.ts @@ -1,6 +1,5 @@ import { ExecutionOutput, FileCompression } from '@activepieces/shared' -import { fileCompressor } from '../../file/utils/file-compressor' -import { logger } from '../../helper/logger' +import { logger, fileCompressor } from 'server-shared' export const logSerializer = { async serialize(log: ExecutionOutput): Promise { @@ -12,10 +11,13 @@ export const logSerializer = { compression: FileCompression.GZIP, }) - logger.debug({ - 'binaryLog.byteLength': binaryLog.byteLength, - 'compressedLog.byteLength': compressedLog.byteLength, - }, '[logSerializer#serialize]') + logger.debug( + { + 'binaryLog.byteLength': binaryLog.byteLength, + 'compressedLog.byteLength': compressedLog.byteLength, + }, + '[logSerializer#serialize]', + ) return compressedLog }, diff --git a/packages/backend/src/app/workers/sandbox/abstract-sandbox.ts b/packages/server/worker/src/lib/sandbox/abstract-sandbox.ts similarity index 75% rename from packages/backend/src/app/workers/sandbox/abstract-sandbox.ts rename to packages/server/worker/src/lib/sandbox/abstract-sandbox.ts index d361585ee7..5ea0ad620a 100644 --- a/packages/backend/src/app/workers/sandbox/abstract-sandbox.ts +++ b/packages/server/worker/src/lib/sandbox/abstract-sandbox.ts @@ -1,13 +1,11 @@ import { readFile } from 'node:fs/promises' import process from 'node:process' -import { system } from '../../helper/system/system' -import { SystemProp } from '../../helper/system/system-prop' -import { logger } from '../../helper/logger' +import { logger, SystemProp, fileExists, system } from 'server-shared' import { EngineResponse, EngineResponseStatus } from '@activepieces/shared' -import { fileExists } from '../../helper/file-system' export abstract class AbstractSandbox { - protected static readonly sandboxRunTimeSeconds = system.getNumber(SystemProp.SANDBOX_RUN_TIME_SECONDS) ?? 600 + protected static readonly sandboxRunTimeSeconds = + system.getNumber(SystemProp.SANDBOX_RUN_TIME_SECONDS) ?? 600 protected static readonly nodeExecutablePath = process.execPath public readonly boxId: number @@ -24,12 +22,20 @@ export abstract class AbstractSandbox { } public abstract recreate(): Promise - public abstract runOperation(operation: string): Promise + public abstract runOperation( + operation: string + ): Promise public abstract getSandboxFolderPath(): string protected abstract setupCache(): Promise - public async assignCache({ cacheKey, cachePath }: AssignCacheParams): Promise { - logger.debug({ boxId: this.boxId, cacheKey, cachePath }, '[AbstractSandbox#assignCache]') + public async assignCache({ + cacheKey, + cachePath, + }: AssignCacheParams): Promise { + logger.debug( + { boxId: this.boxId, cacheKey, cachePath }, + '[AbstractSandbox#assignCache]', + ) this._cacheKey = cacheKey this._cachePath = cachePath @@ -50,7 +56,6 @@ export abstract class AbstractSandbox { return result } - protected async parseFunctionOutput(): Promise> { const outputFile = this.getSandboxFilePath('output.json') @@ -58,7 +63,9 @@ export abstract class AbstractSandbox { throw new Error(`Output file not found in ${outputFile}`) } - const output = JSON.parse(await readFile(outputFile, { encoding: 'utf-8' })) + const output = JSON.parse( + await readFile(outputFile, { encoding: 'utf-8' }), + ) logger.trace(output, '[Sandbox#parseFunctionOutput] output') return output } diff --git a/packages/backend/src/app/workers/sandbox/file-sandbox.ts b/packages/server/worker/src/lib/sandbox/file-sandbox.ts similarity index 77% rename from packages/backend/src/app/workers/sandbox/file-sandbox.ts rename to packages/server/worker/src/lib/sandbox/file-sandbox.ts index 9dbf6ed886..d68ce18d3d 100644 --- a/packages/backend/src/app/workers/sandbox/file-sandbox.ts +++ b/packages/server/worker/src/lib/sandbox/file-sandbox.ts @@ -2,10 +2,13 @@ import { rmdir, mkdir, readFile, writeFile, cp } from 'node:fs/promises' import fs from 'fs-extra' import path from 'node:path' import { spawn } from 'node:child_process' -import { AbstractSandbox, ExecuteSandboxResult, SandboxCtorParams } from './abstract-sandbox' -import { logger } from '../../helper/logger' -import { system } from '../../helper/system/system' -import { SystemProp } from '../../helper/system/system-prop' +import { + AbstractSandbox, + ExecuteSandboxResult, + SandboxCtorParams, +} from './abstract-sandbox' +import { logger } from 'server-shared' +import { SystemProp, system } from 'server-shared' import { EngineResponseStatus } from '@activepieces/shared' export class FileSandbox extends AbstractSandbox { @@ -22,13 +25,18 @@ export class FileSandbox extends AbstractSandbox { await rmdir(sandboxFolderPath, { recursive: true }) } catch (e) { - logger.debug(e, `[Sandbox#recreateCleanup] rmdir failure ${sandboxFolderPath}`) + logger.debug( + e, + `[Sandbox#recreateCleanup] rmdir failure ${sandboxFolderPath}`, + ) } await mkdir(sandboxFolderPath, { recursive: true }) } - public override async runOperation(operation: string): Promise { + public override async runOperation( + operation: string, + ): Promise { const startTime = Date.now() const pieceSource = system.getOrThrow(SystemProp.PIECES_SOURCE) const codeSandboxType = system.get(SystemProp.CODE_SANDBOX_TYPE) @@ -58,8 +66,14 @@ export class FileSandbox extends AbstractSandbox { timeInSeconds: (Date.now() - startTime) / 1000, verdict: result.verdict, output: engineResponse?.response, - standardOutput: await readFile(this.getSandboxFilePath('_standardOutput.txt'), { encoding: 'utf-8' }), - standardError: await readFile(this.getSandboxFilePath('_standardError.txt'), { encoding: 'utf-8' }), + standardOutput: await readFile( + this.getSandboxFilePath('_standardOutput.txt'), + { encoding: 'utf-8' }, + ), + standardError: await readFile( + this.getSandboxFilePath('_standardError.txt'), + { encoding: 'utf-8' }, + ), } } @@ -69,19 +83,30 @@ export class FileSandbox extends AbstractSandbox { } protected override async setupCache(): Promise { - logger.debug({ boxId: this.boxId, cacheKey: this._cacheKey, cachePath: this._cachePath }, '[FileSandbox#setupCache]') + logger.debug( + { + boxId: this.boxId, + cacheKey: this._cacheKey, + cachePath: this._cachePath, + }, + '[FileSandbox#setupCache]', + ) if (this._cachePath) { if (process.platform === 'win32') { await fs.copy(this._cachePath, this.getSandboxFolderPath()) } else { - await cp(this._cachePath, this.getSandboxFolderPath(), { recursive: true }) + await cp(this._cachePath, this.getSandboxFolderPath(), { + recursive: true, + }) } } } - private async runUnsafeCommand(cmd: string): Promise<{ verdict: EngineResponseStatus }> { + private async runUnsafeCommand( + cmd: string, + ): Promise<{ verdict: EngineResponseStatus }> { logger.info(`sandbox, command: ${cmd}`) const standardOutputPath = this.getSandboxFilePath('_standardOutput.txt') diff --git a/packages/backend/src/app/workers/sandbox/index.ts b/packages/server/worker/src/lib/sandbox/index.ts similarity index 63% rename from packages/backend/src/app/workers/sandbox/index.ts rename to packages/server/worker/src/lib/sandbox/index.ts index 2ce78fe2bd..8fa4c0996e 100644 --- a/packages/backend/src/app/workers/sandbox/index.ts +++ b/packages/server/worker/src/lib/sandbox/index.ts @@ -1,10 +1,11 @@ -import { ExecutionMode, system } from '../../helper/system/system' -import { SystemProp } from '../../helper/system/system-prop' +import { ExecutionMode, SystemProp, system } from 'server-shared' import { FileSandbox } from './file-sandbox' import { IsolateSandbox } from './isolate-sandbox' const getSandbox = () => { - const executionMode = system.getOrThrow(SystemProp.EXECUTION_MODE) + const executionMode = system.getOrThrow( + SystemProp.EXECUTION_MODE, + ) const sandbox = { [ExecutionMode.SANDBOXED]: IsolateSandbox, diff --git a/packages/backend/src/app/workers/sandbox/isolate-sandbox.ts b/packages/server/worker/src/lib/sandbox/isolate-sandbox.ts similarity index 68% rename from packages/backend/src/app/workers/sandbox/isolate-sandbox.ts rename to packages/server/worker/src/lib/sandbox/isolate-sandbox.ts index ae38014024..96a712b5f3 100644 --- a/packages/backend/src/app/workers/sandbox/isolate-sandbox.ts +++ b/packages/server/worker/src/lib/sandbox/isolate-sandbox.ts @@ -2,18 +2,24 @@ import { readFile } from 'node:fs/promises' import { arch, cwd } from 'node:process' import path from 'node:path' import { exec } from 'node:child_process' -import { ExecuteSandboxResult, AbstractSandbox, SandboxCtorParams } from './abstract-sandbox' -import { EngineResponseStatus, assertNotNullOrUndefined } from '@activepieces/shared' -import { logger } from '../../helper/logger' -import { PiecesSource, system } from '../../helper/system/system' -import { SystemProp } from '../../helper/system/system-prop' +import { + ExecuteSandboxResult, + AbstractSandbox, + SandboxCtorParams, +} from './abstract-sandbox' +import { + EngineResponseStatus, + assertNotNullOrUndefined, +} from '@activepieces/shared' +import { logger } from 'server-shared' +import { PiecesSource, SystemProp, system } from 'server-shared' const getIsolateExecutableName = (): string => { const defaultName = 'isolate' const executableNameMap: Partial> = { - 'arm': 'isolate-arm', - 'arm64': 'isolate-arm', + arm: 'isolate-arm', + arm64: 'isolate-arm', } return executableNameMap[arch] ?? defaultName @@ -34,7 +40,9 @@ export class IsolateSandbox extends AbstractSandbox { await IsolateSandbox.runIsolate(`--box-id=${this.boxId} --init`) } - public override async runOperation(operation: string): Promise { + public override async runOperation( + operation: string, + ): Promise { const metaFile = this.getSandboxFilePath('meta.txt') let timeInSeconds @@ -72,20 +80,29 @@ export class IsolateSandbox extends AbstractSandbox { output = engineResponse.response verdict = engineResponse.status const metaResult = await this.parseMetaFile() - timeInSeconds = Number.parseFloat(metaResult.time as string) + timeInSeconds = Number.parseFloat(metaResult['time'] as string) } catch (e) { const metaResult = await this.parseMetaFile() - timeInSeconds = Number.parseFloat(metaResult.time as string) - verdict = metaResult.status == 'TO' ? EngineResponseStatus.TIMEOUT : EngineResponseStatus.ERROR + timeInSeconds = Number.parseFloat(metaResult['time'] as string) + verdict = + metaResult['status'] == 'TO' + ? EngineResponseStatus.TIMEOUT + : EngineResponseStatus.ERROR } const result = { timeInSeconds, verdict, output, - standardOutput: await readFile(this.getSandboxFilePath('_standardOutput.txt'), { encoding: 'utf-8' }), - standardError: await readFile(this.getSandboxFilePath('_standardError.txt'), { encoding: 'utf-8' }), + standardOutput: await readFile( + this.getSandboxFilePath('_standardOutput.txt'), + { encoding: 'utf-8' }, + ), + standardError: await readFile( + this.getSandboxFilePath('_standardError.txt'), + { encoding: 'utf-8' }, + ), } logger.trace(result, '[IsolateSandbox#runCommandLine] result') @@ -98,12 +115,19 @@ export class IsolateSandbox extends AbstractSandbox { } protected override async setupCache(): Promise { - logger.debug({ boxId: this.boxId, cacheKey: this._cacheKey, cachePath: this._cachePath }, '[IsolateSandbox#setupCache]') + logger.debug( + { + boxId: this.boxId, + cacheKey: this._cacheKey, + cachePath: this._cachePath, + }, + '[IsolateSandbox#setupCache]', + ) } private static runIsolate(cmd: string): Promise { const currentDir = cwd() - const fullCmd = `${currentDir}/packages/backend/src/assets/${this.isolateExecutableName} ${cmd}` + const fullCmd = `${currentDir}/packages/server/api/src/assets/${this.isolateExecutableName} ${cmd}` logger.info(`sandbox, command: ${fullCmd}`) @@ -123,10 +147,10 @@ export class IsolateSandbox extends AbstractSandbox { } /** - * Creates the arguments for the isolate command to bind the required directories - */ + * Creates the arguments for the isolate command to bind the required directories + */ private getDirsToBindArgs(): string[] { - const etcDir = path.resolve('./packages/backend/src/assets/etc/') + const etcDir = path.resolve('./packages/server/api/src/assets/etc/') const cachePath = this._cachePath assertNotNullOrUndefined(cachePath, 'cachePath') @@ -136,15 +160,26 @@ export class IsolateSandbox extends AbstractSandbox { `--dir=${IsolateSandbox.cacheBindPath}=${path.resolve(cachePath)}`, ] - const piecesSource = system.getOrThrow(SystemProp.PIECES_SOURCE) + const piecesSource = system.getOrThrow( + SystemProp.PIECES_SOURCE, + ) if (piecesSource === PiecesSource.FILE) { const basePath = path.resolve(__dirname.split('/dist')[0]) dirsToBind.push( - `--dir=${path.join(basePath, '.pnpm')}=/${path.join(basePath, '.pnpm')}:maybe`, - `--dir=${path.join(basePath, 'dist')}=/${path.join(basePath, 'dist')}:maybe`, - `--dir=${path.join(basePath, 'node_modules')}=/${path.join(basePath, 'node_modules')}:maybe`, + `--dir=${path.join(basePath, '.pnpm')}=/${path.join( + basePath, + '.pnpm', + )}:maybe`, + `--dir=${path.join(basePath, 'dist')}=/${path.join( + basePath, + 'dist', + )}:maybe`, + `--dir=${path.join(basePath, 'node_modules')}=/${path.join( + basePath, + 'node_modules', + )}:maybe`, ) } diff --git a/packages/backend/src/app/workers/sandbox/sandbox-manager.ts b/packages/server/worker/src/lib/sandbox/sandbox-manager.ts similarity index 83% rename from packages/backend/src/app/workers/sandbox/sandbox-manager.ts rename to packages/server/worker/src/lib/sandbox/sandbox-manager.ts index 69b9594fb4..bb209d19d3 100644 --- a/packages/backend/src/app/workers/sandbox/sandbox-manager.ts +++ b/packages/server/worker/src/lib/sandbox/sandbox-manager.ts @@ -1,11 +1,13 @@ import { Mutex } from 'async-mutex' -import { Sandbox } from '.' import { isNil } from '@activepieces/shared' -import { logger } from '../../helper/logger' +import { logger } from 'server-shared' +import { Sandbox } from '.' const SANDBOX_LIMIT = 1000 -const sandboxes: Sandbox[] = new Array(SANDBOX_LIMIT).fill(null).map((_, i) => new Sandbox({ boxId: i })) +const sandboxes: Sandbox[] = new Array(SANDBOX_LIMIT) + .fill(null) + .map((_, i) => new Sandbox({ boxId: i })) const lock: Mutex = new Mutex() @@ -42,7 +44,9 @@ export const sandboxManager = { const sandbox = sandboxes[sandboxId] if (isNil(sandbox)) { - throw new Error(`[SandboxManager#release] sandbox not found id=${sandboxId}`) + throw new Error( + `[SandboxManager#release] sandbox not found id=${sandboxId}`, + ) } sandbox.inUse = false diff --git a/packages/server/worker/tsconfig.json b/packages/server/worker/tsconfig.json new file mode 100644 index 0000000000..f2400abede --- /dev/null +++ b/packages/server/worker/tsconfig.json @@ -0,0 +1,19 @@ +{ + "extends": "../../../tsconfig.base.json", + "compilerOptions": { + "module": "commonjs", + "forceConsistentCasingInFileNames": true, + "strict": true, + "noImplicitOverride": true, + "noPropertyAccessFromIndexSignature": true, + "noImplicitReturns": true, + "noFallthroughCasesInSwitch": true + }, + "files": [], + "include": [], + "references": [ + { + "path": "./tsconfig.lib.json" + } + ] +} diff --git a/packages/server/worker/tsconfig.lib.json b/packages/server/worker/tsconfig.lib.json new file mode 100644 index 0000000000..4befa7f099 --- /dev/null +++ b/packages/server/worker/tsconfig.lib.json @@ -0,0 +1,10 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../../../dist/out-tsc", + "declaration": true, + "types": ["node"] + }, + "include": ["src/**/*.ts"], + "exclude": ["jest.config.ts", "src/**/*.spec.ts", "src/**/*.test.ts"] +} diff --git a/packages/shared/.eslintrc.json b/packages/shared/.eslintrc.json index 2119da96d5..939273c891 100644 --- a/packages/shared/.eslintrc.json +++ b/packages/shared/.eslintrc.json @@ -1,6 +1,6 @@ { "extends": [ - "../backend/.eslintrc.json" + "../server/api/.eslintrc.json" ], "overrides": [ { diff --git a/tools/scripts/pieces/turbowatch.ts b/tools/scripts/pieces/turbowatch.ts index dbe22dfaea..68d716f5f6 100644 --- a/tools/scripts/pieces/turbowatch.ts +++ b/tools/scripts/pieces/turbowatch.ts @@ -6,7 +6,7 @@ import { findPieceDirectoryInSource } from '../utils/piece-script-utils'; import path from 'path'; import { assertNotNullOrUndefined } from '../../../packages/shared/src'; -config({ path: 'packages/backend/.env' }); +config({ path: 'packages/server/api/.env' }); const packages = process.env.AP_DEV_PIECES?.split(',') || []; diff --git a/tsconfig.base.json b/tsconfig.base.json index dcf048073d..653652e53b 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -572,6 +572,8 @@ "packages/ui/feature-templates/src/index.ts" ], "@ee/*": ["packages/ee/*"], + "server-shared": ["packages/server/shared/src/index.ts"], + "server-worker": ["packages/server/worker/src/index.ts"], "ui-feature-flow-builder": [ "packages/ui/feature-flow-builder/src/index.ts" ],