From 9c0d7c027884630ec7d372f56a6f47cae5eb15ee Mon Sep 17 00:00:00 2001 From: Sam Rose Date: Mon, 24 Feb 2025 14:47:53 +0000 Subject: [PATCH 01/46] Fix bug with branches when no conditions are set. --- .../src/automations/tests/branching.spec.ts | 26 ++++++++++++++++++- packages/server/src/threads/automation.ts | 2 ++ packages/types/src/sdk/search.ts | 3 ++- 3 files changed, 29 insertions(+), 2 deletions(-) diff --git a/packages/server/src/automations/tests/branching.spec.ts b/packages/server/src/automations/tests/branching.spec.ts index bf9b9ce3f8..70aa4cbaa7 100644 --- a/packages/server/src/automations/tests/branching.spec.ts +++ b/packages/server/src/automations/tests/branching.spec.ts @@ -1,5 +1,10 @@ import * as automation from "../index" -import { Table, AutomationStatus } from "@budibase/types" +import { + Table, + AutomationStatus, + AutomationStepStatus, + EmptyFilterOption, +} from "@budibase/types" import { createAutomationBuilder } from "./utilities/AutomationTestBuilder" import TestConfiguration from "../../tests/utilities/TestConfiguration" @@ -280,4 +285,23 @@ describe("Branching automations", () => { expect(results.steps[2].outputs.message).toContain("Special user") }) + + it("should not fail with empty conditions", async () => { + const results = await createAutomationBuilder(config) + .onAppAction() + .branch({ + specialBranch: { + steps: stepBuilder => stepBuilder.serverLog({ text: "Hello!" }), + condition: { + onEmptyFilter: EmptyFilterOption.RETURN_NONE, + }, + }, + }) + .test({ fields: { test_trigger: true } }) + + expect(results.steps[0].outputs.success).toEqual(false) + expect(results.steps[0].outputs.status).toEqual( + AutomationStatus.NO_CONDITION_MET + ) + }) }) diff --git a/packages/server/src/threads/automation.ts b/packages/server/src/threads/automation.ts index 762da1cbc1..def2ab4201 100644 --- a/packages/server/src/threads/automation.ts +++ b/packages/server/src/threads/automation.ts @@ -367,6 +367,8 @@ class Orchestrator { if (e.errno === "ETIME") { span?.addTags({ timedOut: true }) console.warn(`Automation execution timed out after ${timeout}ms`) + } else { + throw e } } diff --git a/packages/types/src/sdk/search.ts b/packages/types/src/sdk/search.ts index 992e9961d4..99c3658fa8 100644 --- a/packages/types/src/sdk/search.ts +++ b/packages/types/src/sdk/search.ts @@ -3,6 +3,7 @@ import { Row, DocumentType, Table, Datasource } from "../documents" import { SortOrder, SortType } from "../api" import { Knex } from "knex" import { Aggregation } from "./row" +import _ from "lodash" export enum BasicOperator { EQUAL = "equal", @@ -83,7 +84,7 @@ type RangeFilter = Record< type LogicalFilter = { conditions: SearchFilters[] } export function isLogicalFilter(filter: any): filter is LogicalFilter { - return "conditions" in filter + return _.isPlainObject(filter) && "conditions" in filter } export type AnySearchFilter = BasicFilter | ArrayFilter | RangeFilter From 68b72acb717249059bad54360794a521c8519e8d Mon Sep 17 00:00:00 2001 From: Sam Rose Date: Mon, 24 Feb 2025 15:06:12 +0000 Subject: [PATCH 02/46] Fix lint. --- packages/server/src/automations/tests/branching.spec.ts | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/packages/server/src/automations/tests/branching.spec.ts b/packages/server/src/automations/tests/branching.spec.ts index 70aa4cbaa7..4572871c44 100644 --- a/packages/server/src/automations/tests/branching.spec.ts +++ b/packages/server/src/automations/tests/branching.spec.ts @@ -1,10 +1,5 @@ import * as automation from "../index" -import { - Table, - AutomationStatus, - AutomationStepStatus, - EmptyFilterOption, -} from "@budibase/types" +import { Table, AutomationStatus, EmptyFilterOption } from "@budibase/types" import { createAutomationBuilder } from "./utilities/AutomationTestBuilder" import TestConfiguration from "../../tests/utilities/TestConfiguration" From a959a26d60a4fae91e939382ed447b991577c49d Mon Sep 17 00:00:00 2001 From: Sam Rose Date: Mon, 24 Feb 2025 16:15:59 +0000 Subject: [PATCH 03/46] Support filtering relationships by _id --- .../src/api/routes/tests/search.spec.ts | 22 +++++++++++++++++++ .../server/src/sdk/app/rows/queryUtils.ts | 7 +++--- 2 files changed, 25 insertions(+), 4 deletions(-) diff --git a/packages/server/src/api/routes/tests/search.spec.ts b/packages/server/src/api/routes/tests/search.spec.ts index ee372914d7..ba2b3f0acf 100644 --- a/packages/server/src/api/routes/tests/search.spec.ts +++ b/packages/server/src/api/routes/tests/search.spec.ts @@ -3553,6 +3553,28 @@ if (descriptions.length) { limit: 1, }).toContainExactly([row]) }) + + it("can filter by the related _id", async () => { + await expectSearch({ + query: { + equal: { "rel._id": row.rel[0]._id }, + }, + }).toContainExactly([row]) + + await expectSearch({ + query: { + equal: { "rel._id": row.rel[1]._id }, + }, + }).toContainExactly([row]) + }) + + it("can filter by the related _id and find nothing", async () => { + await expectSearch({ + query: { + equal: { "rel._id": "rel_none" }, + }, + }).toFindNothing() + }) }) !isInternal && diff --git a/packages/server/src/sdk/app/rows/queryUtils.ts b/packages/server/src/sdk/app/rows/queryUtils.ts index ddd32870be..12e724b5d8 100644 --- a/packages/server/src/sdk/app/rows/queryUtils.ts +++ b/packages/server/src/sdk/app/rows/queryUtils.ts @@ -69,7 +69,8 @@ export const getQueryableFields = async ( fromTables: string[], opts?: { noRelationships?: boolean } ): Promise => { - const result = [] + // Querying by _id is always allowed, even if it's never part of the schema + const result = ["_id"] for (const field of Object.keys(table.schema).filter( f => allowedFields.includes(f) && table.schema[f].visible !== false )) { @@ -113,9 +114,7 @@ export const getQueryableFields = async ( return result } - const result = [ - "_id", // Querying by _id is always allowed, even if it's never part of the schema - ] + const result = [] if (fields == null) { fields = Object.keys(table.schema) From a88530438c8be7e5ebed22e09c748ed315c12c55 Mon Sep 17 00:00:00 2001 From: Sam Rose Date: Mon, 24 Feb 2025 16:36:08 +0000 Subject: [PATCH 04/46] Remove view enrichment unit test, covered by integration tests. --- .../src/sdk/app/tables/tests/tables.spec.ts | 108 ------------------ 1 file changed, 108 deletions(-) delete mode 100644 packages/server/src/sdk/app/tables/tests/tables.spec.ts diff --git a/packages/server/src/sdk/app/tables/tests/tables.spec.ts b/packages/server/src/sdk/app/tables/tests/tables.spec.ts deleted file mode 100644 index 41ac808f5c..0000000000 --- a/packages/server/src/sdk/app/tables/tests/tables.spec.ts +++ /dev/null @@ -1,108 +0,0 @@ -import { - FieldType, - INTERNAL_TABLE_SOURCE_ID, - Table, - TableSourceType, - ViewV2, -} from "@budibase/types" -import { generator } from "@budibase/backend-core/tests" -import sdk from "../../.." - -jest.mock("../../views", () => ({ - ...jest.requireActual("../../views"), - enrichSchema: jest.fn().mockImplementation(v => ({ ...v, mocked: true })), -})) - -describe("table sdk", () => { - describe("enrichViewSchemas", () => { - const basicTable: Table = { - _id: generator.guid(), - name: "TestTable", - type: "table", - sourceId: INTERNAL_TABLE_SOURCE_ID, - sourceType: TableSourceType.INTERNAL, - schema: { - name: { - type: FieldType.STRING, - name: "name", - visible: true, - width: 80, - order: 2, - constraints: { - type: "string", - }, - }, - description: { - type: FieldType.STRING, - name: "description", - visible: true, - width: 200, - constraints: { - type: "string", - }, - }, - id: { - type: FieldType.NUMBER, - name: "id", - visible: true, - order: 1, - constraints: { - type: "number", - }, - }, - hiddenField: { - type: FieldType.STRING, - name: "hiddenField", - visible: false, - constraints: { - type: "string", - }, - }, - }, - } - - it("should fetch the default schema if not overriden", async () => { - const tableId = basicTable._id! - function getTable() { - const view: ViewV2 = { - version: 2, - id: generator.guid(), - name: generator.guid(), - tableId, - } - return view - } - const view1 = getTable() - const view2 = getTable() - const view3 = getTable() - const res = await sdk.tables.enrichViewSchemas({ - ...basicTable, - views: { - [view1.name]: view1, - [view2.name]: view2, - [view3.name]: view3, - }, - }) - - expect(sdk.views.enrichSchema).toHaveBeenCalledTimes(3) - - expect(res).toEqual({ - ...basicTable, - views: { - [view1.name]: { - ...view1, - mocked: true, - }, - [view2.name]: { - ...view2, - mocked: true, - }, - [view3.name]: { - ...view3, - mocked: true, - }, - }, - }) - }) - }) -}) From 1dc52cfa75ea8ab9ce98539fa088bfc93acac792 Mon Sep 17 00:00:00 2001 From: Sam Rose Date: Mon, 24 Feb 2025 17:19:02 +0000 Subject: [PATCH 05/46] Improve typing around nodemailer. --- .../server/src/utilities/workerRequests.ts | 40 ++-- packages/types/src/api/web/global/email.ts | 6 +- .../documents/app/automation/automation.ts | 8 +- packages/worker/package.json | 1 + .../src/api/controllers/global/email.ts | 7 +- packages/worker/src/utilities/email.ts | 7 +- yarn.lock | 194 +++++++++++++----- 7 files changed, 184 insertions(+), 79 deletions(-) diff --git a/packages/server/src/utilities/workerRequests.ts b/packages/server/src/utilities/workerRequests.ts index 0f487d9f31..dd1493b82f 100644 --- a/packages/server/src/utilities/workerRequests.ts +++ b/packages/server/src/utilities/workerRequests.ts @@ -8,7 +8,15 @@ import { logging, env as coreEnv, } from "@budibase/backend-core" -import { Ctx, User, EmailInvite, EmailAttachment } from "@budibase/types" +import { + Ctx, + User, + EmailInvite, + EmailAttachment, + SendEmailResponse, + SendEmailRequest, + EmailTemplatePurpose, +} from "@budibase/types" interface Request { ctx?: Ctx @@ -110,25 +118,23 @@ export async function sendSmtpEmail({ invite?: EmailInvite }) { // tenant ID will be set in header + const request: SendEmailRequest = { + email: to, + from, + contents, + subject, + cc, + bcc, + purpose: EmailTemplatePurpose.CUSTOM, + automation, + invite, + attachments, + } const response = await fetch( checkSlashesInUrl(env.WORKER_URL + `/api/global/email/send`), - createRequest({ - method: "POST", - body: { - email: to, - from, - contents, - subject, - cc, - bcc, - purpose: "custom", - automation, - invite, - attachments, - }, - }) + createRequest({ method: "POST", body: request }) ) - return checkResponse(response, "send email") + return (await checkResponse(response, "send email")) as SendEmailResponse } export async function removeAppFromUserRoles(ctx: Ctx, appId: string) { diff --git a/packages/types/src/api/web/global/email.ts b/packages/types/src/api/web/global/email.ts index a0ca0e8485..13b22a939c 100644 --- a/packages/types/src/api/web/global/email.ts +++ b/packages/types/src/api/web/global/email.ts @@ -12,13 +12,13 @@ export enum EmailTemplatePurpose { export interface SendEmailRequest { workspaceId?: string email: string - userId: string + userId?: string purpose: EmailTemplatePurpose contents?: string from?: string subject: string - cc?: boolean - bcc?: boolean + cc?: string + bcc?: string automation?: boolean invite?: EmailInvite attachments?: EmailAttachment[] diff --git a/packages/types/src/documents/app/automation/automation.ts b/packages/types/src/documents/app/automation/automation.ts index d5ef35d059..cfe2ba5147 100644 --- a/packages/types/src/documents/app/automation/automation.ts +++ b/packages/types/src/documents/app/automation/automation.ts @@ -1,10 +1,10 @@ import { Document } from "../../document" import { User } from "../../global" -import { ReadStream } from "fs" import { Row } from "../row" import { Table } from "../table" import { AutomationStep, AutomationTrigger } from "./schema" import { ContextEmitter } from "../../../sdk" +import { Readable } from "stream" export enum AutomationIOType { OBJECT = "object", @@ -108,8 +108,8 @@ export interface SendEmailOpts { subject: string // info Pass in a structure of information to be stored alongside the invitation. info?: any - cc?: boolean - bcc?: boolean + cc?: string + bcc?: string automation?: boolean invite?: EmailInvite attachments?: EmailAttachment[] @@ -269,7 +269,7 @@ export type AutomationAttachment = { export type AutomationAttachmentContent = { filename: string - content: ReadStream | NodeJS.ReadableStream + content: Readable } export type BucketedContent = AutomationAttachmentContent & { diff --git a/packages/worker/package.json b/packages/worker/package.json index 53d14dacee..ee7cf03779 100644 --- a/packages/worker/package.json +++ b/packages/worker/package.json @@ -85,6 +85,7 @@ "@types/koa__router": "12.0.4", "@types/lodash": "4.14.200", "@types/node-fetch": "2.6.4", + "@types/nodemailer": "^6.4.17", "@types/server-destroy": "1.0.1", "@types/supertest": "2.0.14", "@types/uuid": "8.3.4", diff --git a/packages/worker/src/api/controllers/global/email.ts b/packages/worker/src/api/controllers/global/email.ts index ad0fc3fa32..ed2d9b5125 100644 --- a/packages/worker/src/api/controllers/global/email.ts +++ b/packages/worker/src/api/controllers/global/email.ts @@ -24,10 +24,13 @@ export async function sendEmail( invite, attachments, } = ctx.request.body - let user: any + let user: User | undefined = undefined if (userId) { const db = tenancy.getGlobalDB() - user = await db.get(userId) + user = await db.tryGet(userId) + } + if (!user) { + ctx.throw(404, "User not found.") } const response = await sendEmailFn(email, purpose, { workspaceId, diff --git a/packages/worker/src/utilities/email.ts b/packages/worker/src/utilities/email.ts index fa9dd7a6fa..a2b9c3bfc2 100644 --- a/packages/worker/src/utilities/email.ts +++ b/packages/worker/src/utilities/email.ts @@ -13,7 +13,8 @@ import { configs, cache, objectStore } from "@budibase/backend-core" import ical from "ical-generator" import _ from "lodash" -const nodemailer = require("nodemailer") +import nodemailer from "nodemailer" +import SMTPTransport from "nodemailer/lib/smtp-transport" const TEST_MODE = env.ENABLE_EMAIL_TEST_MODE && env.isDev() const TYPE = TemplateType.EMAIL @@ -26,7 +27,7 @@ const FULL_EMAIL_PURPOSES = [ ] function createSMTPTransport(config?: SMTPInnerConfig) { - let options: any + let options: SMTPTransport.Options let secure = config?.secure // default it if not specified if (secure == null) { @@ -161,7 +162,7 @@ export async function sendEmail( const code = await getLinkCode(purpose, email, opts.user, opts?.info) let context = await getSettingsTemplateContext(purpose, code) - let message: any = { + let message: Parameters[0] = { from: opts?.from || config?.from, html: await buildEmail(purpose, email, context, { user: opts?.user, diff --git a/yarn.lock b/yarn.lock index ceae41458c..8df30c905b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1457,7 +1457,7 @@ "@azure/abort-controller" "^2.0.0" tslib "^2.6.2" -"@azure/identity@4.2.1", "@azure/identity@^4.2.1": +"@azure/identity@^4.2.1": version "4.2.1" resolved "https://registry.yarnpkg.com/@azure/identity/-/identity-4.2.1.tgz#22b366201e989b7b41c0e1690e103bd579c31e4c" integrity sha512-U8hsyC9YPcEIzoaObJlRDvp7KiF0MGS7xcWbyJSVvXRkC/HXo1f0oYeBYmEvVgRfacw7GHf6D6yAoh9JHz6A5Q== @@ -2777,28 +2777,6 @@ pouchdb-promise "^6.0.4" through2 "^2.0.0" -"@budibase/pro@npm:@budibase/pro@latest": - version "3.4.12" - resolved "https://registry.yarnpkg.com/@budibase/pro/-/pro-3.4.12.tgz#60e630944de4e2de970a04179d8f0f57d48ce75e" - integrity sha512-msUBmcWxRDg+ugjZvd27XudERQqtQRdiARsO8MaDVTcp5ejIXgshEIVVshHOCj3hcbRblw9pXvBIMI53iTMUsA== - dependencies: - "@anthropic-ai/sdk" "^0.27.3" - "@budibase/backend-core" "*" - "@budibase/shared-core" "*" - "@budibase/string-templates" "*" - "@budibase/types" "*" - "@koa/router" "13.1.0" - bull "4.10.1" - dd-trace "5.26.0" - joi "17.6.0" - jsonwebtoken "9.0.2" - lru-cache "^7.14.1" - memorystream "^0.3.1" - node-fetch "2.6.7" - openai "4.59.0" - scim-patch "^0.8.1" - scim2-parse-filter "^0.2.8" - "@budibase/vm-browserify@^1.1.4": version "1.1.4" resolved "https://registry.yarnpkg.com/@budibase/vm-browserify/-/vm-browserify-1.1.4.tgz#eecb001bd9521cb7647e26fb4d2d29d0a4dce262" @@ -6768,6 +6746,13 @@ dependencies: undici-types "~6.19.2" +"@types/nodemailer@^6.4.17": + version "6.4.17" + resolved "https://registry.yarnpkg.com/@types/nodemailer/-/nodemailer-6.4.17.tgz#5c82a42aee16a3dd6ea31446a1bd6a447f1ac1a4" + integrity sha512-I9CCaIp6DTldEg7vyUTZi8+9Vo0hi1/T8gv3C89yk1rSAAzoKQ8H8ki/jBYJSFoH/BisgLP8tkZMlQ91CIquww== + dependencies: + "@types/node" "*" + "@types/normalize-package-data@^2.4.0": version "2.4.1" resolved "https://registry.yarnpkg.com/@types/normalize-package-data/-/normalize-package-data-2.4.1.tgz#d3357479a0fdfdd5907fe67e17e0a85c906e1301" @@ -8129,7 +8114,23 @@ aws4@^1.8.0: resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.13.2.tgz#0aa167216965ac9474ccfa83892cfb6b3e1e52ef" integrity sha512-lHe62zvbTB5eEABUVi/AwVh0ZKY9rMMDhmm+eeyuuUQbQ3+J+fONVQOZyj+DdrvD4BY33uYniyRJ4UJIaSKAfw== -axios@1.1.3, axios@1.7.7, axios@^0.21.1, axios@^1.0.0, axios@^1.1.3, axios@^1.4.0, axios@^1.6.2, axios@^1.6.8: +axios@1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/axios/-/axios-1.1.3.tgz#8274250dada2edf53814ed7db644b9c2866c1e35" + integrity sha512-00tXVRwKx/FZr/IDVFt4C+f9FYairX517WoGCL6dpOntqLkZofjhu43F/Xl44UOpqa+9sLFDrG/XAnFsUYgkDA== + dependencies: + follow-redirects "^1.15.0" + form-data "^4.0.0" + proxy-from-env "^1.1.0" + +axios@^0.21.1: + version "0.21.4" + resolved "https://registry.yarnpkg.com/axios/-/axios-0.21.4.tgz#c67b90dc0568e5c1cf2b0b858c43ba28e2eda575" + integrity sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg== + dependencies: + follow-redirects "^1.14.0" + +axios@^1.0.0, axios@^1.1.3, axios@^1.4.0, axios@^1.6.2, axios@^1.6.8: version "1.7.7" resolved "https://registry.yarnpkg.com/axios/-/axios-1.7.7.tgz#2f554296f9892a72ac8d8e4c5b79c14a91d0a47f" integrity sha512-S4kL7XrjgBmvdGut0sN3yJxqYzrDOnivkBiN0OFs6hLiUam3UPvswUo0kqGyhqUZGEOytHyumEdXsAkgCOUf3Q== @@ -11763,7 +11764,7 @@ fn.name@1.x.x: resolved "https://registry.yarnpkg.com/fn.name/-/fn.name-1.1.0.tgz#26cad8017967aea8731bc42961d04a3d5988accc" integrity sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw== -follow-redirects@^1.15.6: +follow-redirects@^1.14.0, follow-redirects@^1.15.0, follow-redirects@^1.15.6: version "1.15.9" resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.9.tgz#a604fa10e443bf98ca94228d9eebcc2e8a2c8ee1" integrity sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ== @@ -12378,10 +12379,22 @@ global@~4.4.0: min-document "^2.19.0" process "^0.11.10" -globals@15.13.0, globals@^11.1.0, globals@^13.19.0, globals@^14.0.0: - version "15.13.0" - resolved "https://registry.yarnpkg.com/globals/-/globals-15.13.0.tgz#bbec719d69aafef188ecd67954aae76a696010fc" - integrity sha512-49TewVEz0UxZjr1WYYsWpPrhyC/B/pA8Bq0fUmet2n+eR7yn0IvNzNaoBwnK6mdkzcN+se7Ez9zUgULTz2QH4g== +globals@^11.1.0: + version "11.12.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" + integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== + +globals@^13.19.0: + version "13.24.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-13.24.0.tgz#8432a19d78ce0c1e833949c36adb345400bb1171" + integrity sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ== + dependencies: + type-fest "^0.20.2" + +globals@^14.0.0: + version "14.0.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-14.0.0.tgz#898d7413c29babcf6bafe56fcadded858ada724e" + integrity sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ== globalthis@^1.0.1, globalthis@^1.0.4: version "1.0.4" @@ -12791,7 +12804,12 @@ http-assert@^1.3.0: deep-equal "~1.0.1" http-errors "~1.8.0" -http-cache-semantics@3.8.1, http-cache-semantics@4.1.1, http-cache-semantics@^4.0.0, http-cache-semantics@^4.1.0, http-cache-semantics@^4.1.1: +http-cache-semantics@3.8.1: + version "3.8.1" + resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-3.8.1.tgz#39b0e16add9b605bf0a9ef3d9daaf4843b4cacd2" + integrity sha512-5ai2iksyV8ZXmnZhHH4rWPoxxistEexSi5936zIQ1bnNTW5VnA85B6P/VpXiRM017IgRvb2kKo1a//y+0wSp3w== + +http-cache-semantics@^4.0.0, http-cache-semantics@^4.1.0, http-cache-semantics@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz#abe02fcb2985460bf0323be664436ec3476a6d5a" integrity sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ== @@ -13247,6 +13265,11 @@ is-boolean-object@^1.1.0: call-bind "^1.0.2" has-tostringtag "^1.0.0" +is-buffer@^1.1.5: + version "1.1.6" + resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" + integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w== + is-buffer@^2.0.5: version "2.0.5" resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-2.0.5.tgz#ebc252e400d22ff8d77fa09888821a24a658c191" @@ -13686,11 +13709,6 @@ isobject@^3.0.1: resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" integrity sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg== -isobject@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/isobject/-/isobject-4.0.0.tgz#3f1c9155e73b192022a80819bacd0343711697b0" - integrity sha512-S/2fF5wH8SJA/kmwr6HYhK/RI/OkhD84k8ntalo0iJjZikgq1XFvR5M8NPT1x5F7fBwCG3qHfnzeP/Vh/ZxCUA== - isolated-vm@^4.7.2: version "4.7.2" resolved "https://registry.yarnpkg.com/isolated-vm/-/isolated-vm-4.7.2.tgz#5670d5cce1d92004f9b825bec5b0b11fc7501b65" @@ -14570,7 +14588,14 @@ kill-port@^1.6.1: get-them-args "1.3.2" shell-exec "1.0.2" -kind-of@6.0.3, kind-of@^3.0.2, kind-of@^3.1.0, kind-of@^6.0.0, kind-of@^6.0.2, kind-of@^6.0.3: +kind-of@^3.0.2, kind-of@^3.1.0: + version "3.2.2" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64" + integrity sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ== + dependencies: + is-buffer "^1.1.5" + +kind-of@^6.0.0, kind-of@^6.0.2, kind-of@^6.0.3: version "6.0.3" resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd" integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw== @@ -15953,7 +15978,7 @@ msgpackr-extract@^3.0.2: "@msgpackr-extract/msgpackr-extract-linux-x64" "3.0.2" "@msgpackr-extract/msgpackr-extract-win32-x64" "3.0.2" -msgpackr@1.10.1, msgpackr@^1.5.2: +msgpackr@^1.5.2: version "1.10.1" resolved "https://registry.yarnpkg.com/msgpackr/-/msgpackr-1.10.1.tgz#51953bb4ce4f3494f0c4af3f484f01cfbb306555" integrity sha512-r5VRLv9qouXuLiIBrLpl2d5ZvPt8svdQTl5/vMvE4nzDMyEX4sgW5yWhuBBj5UmgwOTWj8CIdSXn5sAfsHAWIQ== @@ -16146,13 +16171,27 @@ node-domexception@1.0.0: resolved "https://registry.yarnpkg.com/node-domexception/-/node-domexception-1.0.0.tgz#6888db46a1f71c0b76b3f7555016b63fe64766e5" integrity sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ== -node-fetch@2.6.7, node-fetch@2.6.9, node-fetch@^2.6.0, node-fetch@^2.6.1, node-fetch@^2.6.7, node-fetch@^2.6.9: +node-fetch@2.6.7, node-fetch@^2.6.0, node-fetch@^2.6.1, node-fetch@^2.6.7: version "2.6.7" resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.7.tgz#24de9fba827e3b4ae44dc8b20256a379160052ad" integrity sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ== dependencies: whatwg-url "^5.0.0" +node-fetch@2.6.9: + version "2.6.9" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.9.tgz#7c7f744b5cc6eb5fd404e0c7a9fec630a55657e6" + integrity sha512-DJm/CJkZkRjKKj4Zi4BsKVZh3ValV5IR5s7LVZnW+6YMh0W1BfNA8XSs6DLMGYlId5F3KnA70uu2qepcR08Qqg== + dependencies: + whatwg-url "^5.0.0" + +node-fetch@^2.6.9: + version "2.7.0" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.7.0.tgz#d0f0fa6e3e2dc1d27efcd8ad99d550bda94d187d" + integrity sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A== + dependencies: + whatwg-url "^5.0.0" + node-forge@^1.3.1: version "1.3.1" resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-1.3.1.tgz#be8da2af243b2417d5f646a770663a92b7e9ded3" @@ -17181,7 +17220,15 @@ passport-strategy@1.x.x, passport-strategy@^1.0.0: resolved "https://registry.yarnpkg.com/passport-strategy/-/passport-strategy-1.0.0.tgz#b5539aa8fc225a3d1ad179476ddf236b440f52e4" integrity sha512-CB97UUvDKJde2V0KDWWB3lyf6PC3FaZP7YxZ2G8OAtn9p4HI9j9JLP9qjOGZFvyl8uwNT8qM+hGnz/n16NI7oA== -passport@0.6.0, passport@^0.4.0, passport@^0.6.0: +passport@^0.4.0: + version "0.4.1" + resolved "https://registry.yarnpkg.com/passport/-/passport-0.4.1.tgz#941446a21cb92fc688d97a0861c38ce9f738f270" + integrity sha512-IxXgZZs8d7uFSt3eqNjM9NQ3g3uQCW5avD8mRNoXV99Yig50vjuaez6dQK2qC0kVWPRTujxY0dWgGfT09adjYg== + dependencies: + passport-strategy "1.x.x" + pause "0.0.1" + +passport@^0.6.0: version "0.6.0" resolved "https://registry.yarnpkg.com/passport/-/passport-0.6.0.tgz#e869579fab465b5c0b291e841e6cc95c005fac9d" integrity sha512-0fe+p3ZnrWRW74fe8+SvCyf4a3Pb2/h7gFkQ8yTJpAO50gDzlfjZUZTO1k5Eg9kUct22OxHLqDZoKUWRHOh9ug== @@ -18166,6 +18213,13 @@ pseudomap@^1.0.2: resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3" integrity sha512-b/YwNhb8lk1Zz2+bXXpS/LK9OisiZZ1SNsSLxN1x2OXVEhW2Ckr/7mWE5vrC1ZTiJlD9g19jWszTmJsB+oEpFQ== +psl@^1.1.28: + version "1.15.0" + resolved "https://registry.yarnpkg.com/psl/-/psl-1.15.0.tgz#bdace31896f1d97cec6a79e8224898ce93d974c6" + integrity sha512-JZd3gMVBAVQkSs6HdNZo9Sdo0LNcQeMNP3CozBJb3JYC/QUYZTnKxP+f8oWRX4rHP5EurWxqAHTSwUCjlNKa1w== + dependencies: + punycode "^2.3.1" + psl@^1.1.33: version "1.9.0" resolved "https://registry.yarnpkg.com/psl/-/psl-1.9.0.tgz#d0df2a137f00794565fcaf3b2c00cd09f8d5a5a7" @@ -18199,6 +18253,11 @@ punycode@^2.1.0, punycode@^2.1.1, punycode@^2.3.0: resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.0.tgz#f67fa67c94da8f4d0cfff981aee4118064199b8f" integrity sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA== +punycode@^2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.1.tgz#027422e2faec0b25e1549c3e1bd8309b9133b6e5" + integrity sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg== + pupa@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/pupa/-/pupa-2.1.1.tgz#f5e8fd4afc2c5d97828faa523549ed8744a20d62" @@ -19030,6 +19089,11 @@ sax@1.2.1: resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.1.tgz#7b8e656190b228e81a66aea748480d828cd2d37a" integrity sha512-8I2a3LovHTOpm7NV5yOyO8IHqgVsfK4+UuySrXU8YXkSRX7k6hCV9b3HrkKCr3nMpgj+0bmocaJJWpvp1oc7ZA== +sax@>=0.1.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/sax/-/sax-1.4.1.tgz#44cc8988377f126304d3b3fc1010c733b929ef0f" + integrity sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg== + sax@>=0.6.0: version "1.2.4" resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" @@ -19102,13 +19166,28 @@ semver-diff@^3.1.1: dependencies: semver "^6.3.0" -"semver@2 || 3 || 4 || 5", semver@7.5.3, semver@^5.6.0, semver@^5.7.1, semver@^6.0.0, semver@^6.1.1, semver@^6.1.2, semver@^6.2.0, semver@^6.3.0, semver@^6.3.1, semver@^7.0.0, semver@^7.1.1, semver@^7.3.2, semver@^7.3.4, semver@^7.3.5, semver@^7.3.7, semver@^7.3.8, semver@^7.5.3, semver@^7.5.4, semver@^7.6.0, semver@^7.6.2: +"semver@2 || 3 || 4 || 5", semver@^5.6.0, semver@^5.7.1: + version "5.7.2" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.2.tgz#48d55db737c3287cd4835e17fa13feace1c41ef8" + integrity sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g== + +semver@7.5.3, semver@^7.0.0, semver@^7.1.1, semver@^7.3.2, semver@^7.3.4, semver@^7.3.5, semver@^7.3.7, semver@^7.3.8, semver@^7.5.3: version "7.5.3" resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.3.tgz#161ce8c2c6b4b3bdca6caadc9fa3317a4c4fe88e" integrity sha512-QBlUtyVk/5EeHbi7X0fw6liDZc7BBmEaSYn01fMU1OUYbf6GPsbTtd8WmnqbI20SeycoHSeiybkE/q1Q+qlThQ== dependencies: lru-cache "^6.0.0" +semver@^6.0.0, semver@^6.1.1, semver@^6.1.2, semver@^6.2.0, semver@^6.3.0, semver@^6.3.1: + version "6.3.1" + resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4" + integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== + +semver@^7.5.4, semver@^7.6.0, semver@^7.6.2: + version "7.7.1" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.7.1.tgz#abd5098d82b18c6c81f6074ff2647fd3e7220c9f" + integrity sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA== + seq-queue@^0.0.5: version "0.0.5" resolved "https://registry.yarnpkg.com/seq-queue/-/seq-queue-0.0.5.tgz#d56812e1c017a6e4e7c3e3a37a1da6d78dd3c93e" @@ -20590,7 +20669,7 @@ touch@^3.1.0: dependencies: nopt "~1.0.10" -tough-cookie@4.1.3, "tough-cookie@^2.3.3 || ^3.0.1 || ^4.0.0", tough-cookie@^4.0.0, tough-cookie@^4.1.2, tough-cookie@~2.5.0: +"tough-cookie@^2.3.3 || ^3.0.1 || ^4.0.0", tough-cookie@^4.0.0, tough-cookie@^4.1.2: version "4.1.3" resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-4.1.3.tgz#97b9adb0728b42280aa3d814b6b999b2ff0318bf" integrity sha512-aX/y5pVRkfRnfmuX+OdbSdXvPe6ieKX/G2s7e98f4poJHnqH3281gDPm/metm6E/WRamfx7WC4HUqkWHfQHprw== @@ -20600,6 +20679,14 @@ tough-cookie@4.1.3, "tough-cookie@^2.3.3 || ^3.0.1 || ^4.0.0", tough-cookie@^4.0 universalify "^0.2.0" url-parse "^1.5.3" +tough-cookie@~2.5.0: + version "2.5.0" + resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.5.0.tgz#cd9fb2a0aa1d5a12b473bd9fb96fa3dcff65ade2" + integrity sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g== + dependencies: + psl "^1.1.28" + punycode "^2.1.1" + tr46@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/tr46/-/tr46-2.1.0.tgz#fa87aa81ca5d5941da8cbf1f9b749dc969a4e240" @@ -21067,14 +21154,6 @@ unpipe@1.0.0: resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" integrity sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ== -unset-value@2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/unset-value/-/unset-value-2.0.1.tgz#57bed0c22d26f28d69acde5df9a11b77c74d2df3" - integrity sha512-2hvrBfjUE00PkqN+q0XP6yRAOGrR06uSiUoIQGZkc7GxvQ9H7v8quUPNtZjMg4uux69i8HWpIjLPUKwCuRGyNg== - dependencies: - has-value "^2.0.2" - isobject "^4.0.0" - untildify@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/untildify/-/untildify-4.0.0.tgz#2bc947b953652487e4600949fb091e3ae8cd919b" @@ -21778,7 +21857,14 @@ xml-parse-from-string@^1.0.0: resolved "https://registry.yarnpkg.com/xml-parse-from-string/-/xml-parse-from-string-1.0.1.tgz#a9029e929d3dbcded169f3c6e28238d95a5d5a28" integrity sha512-ErcKwJTF54uRzzNMXq2X5sMIy88zJvfN2DmdoQvy7PAFJ+tPRU6ydWuOKNMyfmOjdyBQTFREi60s0Y0SyI0G0g== -xml2js@0.1.x, xml2js@0.6.2, xml2js@^0.5.0: +xml2js@0.1.x: + version "0.1.14" + resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.1.14.tgz#5274e67f5a64c5f92974cd85139e0332adc6b90c" + integrity sha512-pbdws4PPPNc1HPluSUKamY4GWMk592K7qwcj6BExbVOhhubub8+pMda/ql68b6L3luZs/OGjGSB5goV7SnmgnA== + dependencies: + sax ">=0.1.1" + +xml2js@0.6.2: version "0.6.2" resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.6.2.tgz#dd0b630083aa09c161e25a4d0901e2b2a929b499" integrity sha512-T4rieHaC1EXcES0Kxxj4JWgaUQHDk+qwHcYOCFHfiwKz7tOVPLq7Hjq9dM1WCMhylqMEfP7hMcOIChvotiZegA== @@ -21786,6 +21872,14 @@ xml2js@0.1.x, xml2js@0.6.2, xml2js@^0.5.0: sax ">=0.6.0" xmlbuilder "~11.0.0" +xml2js@^0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.5.0.tgz#d9440631fbb2ed800203fad106f2724f62c493b7" + integrity sha512-drPFnkQJik/O+uPKpqSgr22mpuFHqKdbS835iAQrUC73L2F5WkboIRd63ai/2Yg6I1jzifPFKH2NTK+cfglkIA== + dependencies: + sax ">=0.6.0" + xmlbuilder "~11.0.0" + xmlbuilder@~11.0.0: version "11.0.1" resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-11.0.1.tgz#be9bae1c8a046e76b31127726347d0ad7002beb3" From 81c404f88d3fd14a1ed1a89f87bc36cbf7494d0a Mon Sep 17 00:00:00 2001 From: Sam Rose Date: Mon, 24 Feb 2025 17:27:27 +0000 Subject: [PATCH 06/46] Correctly type things that interact with nodemailer. --- .../tests/steps/sendSmtpEmail.spec.ts | 20 ++++++++++--------- packages/types/package.json | 1 + packages/types/src/api/web/global/email.ts | 3 ++- 3 files changed, 14 insertions(+), 10 deletions(-) diff --git a/packages/server/src/automations/tests/steps/sendSmtpEmail.spec.ts b/packages/server/src/automations/tests/steps/sendSmtpEmail.spec.ts index 7452239dfa..7aff612a97 100644 --- a/packages/server/src/automations/tests/steps/sendSmtpEmail.spec.ts +++ b/packages/server/src/automations/tests/steps/sendSmtpEmail.spec.ts @@ -1,3 +1,4 @@ +import { SendEmailResponse } from "@budibase/types" import TestConfiguration from "../../../tests/utilities/TestConfiguration" import * as workerRequests from "../../../utilities/workerRequests" @@ -5,17 +6,18 @@ jest.mock("../../../utilities/workerRequests", () => ({ sendSmtpEmail: jest.fn(), })) -function generateResponse(to: string, from: string) { +function generateResponse(to: string, from: string): SendEmailResponse { return { - success: true, - response: { - accepted: [to], - envelope: { - from: from, - to: [to], - }, - message: `Email sent to ${to}.`, + message: `Email sent to ${to}.`, + accepted: [to], + envelope: { + from: from, + to: [to], }, + messageId: "messageId", + pending: [], + rejected: [], + response: "response", } } diff --git a/packages/types/package.json b/packages/types/package.json index ee3c059bc9..a6e08ab84c 100644 --- a/packages/types/package.json +++ b/packages/types/package.json @@ -17,6 +17,7 @@ "@budibase/nano": "10.1.5", "@types/json-schema": "^7.0.15", "@types/koa": "2.13.4", + "@types/nodemailer": "^6.4.17", "@types/redlock": "4.0.7", "koa-useragent": "^4.1.0", "rimraf": "3.0.2", diff --git a/packages/types/src/api/web/global/email.ts b/packages/types/src/api/web/global/email.ts index 13b22a939c..3d2e007231 100644 --- a/packages/types/src/api/web/global/email.ts +++ b/packages/types/src/api/web/global/email.ts @@ -1,4 +1,5 @@ import { EmailAttachment, EmailInvite } from "../../../documents" +import SMTPTransport from "nodemailer/lib/smtp-transport" export enum EmailTemplatePurpose { CORE = "core", @@ -23,6 +24,6 @@ export interface SendEmailRequest { invite?: EmailInvite attachments?: EmailAttachment[] } -export interface SendEmailResponse extends Record { +export interface SendEmailResponse extends SMTPTransport.SentMessageInfo { message: string } From ce7b2e69ab187470e8f367b76e67c66314a88d2c Mon Sep 17 00:00:00 2001 From: Sam Rose Date: Mon, 24 Feb 2025 17:30:14 +0000 Subject: [PATCH 07/46] Update yarn.lock. --- yarn.lock | 187 +++++++++++++++--------------------------------------- 1 file changed, 50 insertions(+), 137 deletions(-) diff --git a/yarn.lock b/yarn.lock index 8df30c905b..5a51409fd9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1457,7 +1457,7 @@ "@azure/abort-controller" "^2.0.0" tslib "^2.6.2" -"@azure/identity@^4.2.1": +"@azure/identity@4.2.1", "@azure/identity@^4.2.1": version "4.2.1" resolved "https://registry.yarnpkg.com/@azure/identity/-/identity-4.2.1.tgz#22b366201e989b7b41c0e1690e103bd579c31e4c" integrity sha512-U8hsyC9YPcEIzoaObJlRDvp7KiF0MGS7xcWbyJSVvXRkC/HXo1f0oYeBYmEvVgRfacw7GHf6D6yAoh9JHz6A5Q== @@ -2777,6 +2777,28 @@ pouchdb-promise "^6.0.4" through2 "^2.0.0" +"@budibase/pro@npm:@budibase/pro@latest": + version "3.4.16" + resolved "https://registry.yarnpkg.com/@budibase/pro/-/pro-3.4.16.tgz#c482a400e27b7e89ca73092c4c81bdeac1d24581" + integrity sha512-8ECnqOh9jQ10KlQEwmKPFcoVGE+2gGgSybj+vbshwDp1zAW76doyMR2DMNjEatNpWVnpoMnTkDWtE9aqQ5v0vQ== + dependencies: + "@anthropic-ai/sdk" "^0.27.3" + "@budibase/backend-core" "*" + "@budibase/shared-core" "*" + "@budibase/string-templates" "*" + "@budibase/types" "*" + "@koa/router" "13.1.0" + bull "4.10.1" + dd-trace "5.26.0" + joi "17.6.0" + jsonwebtoken "9.0.2" + lru-cache "^7.14.1" + memorystream "^0.3.1" + node-fetch "2.6.7" + openai "4.59.0" + scim-patch "^0.8.1" + scim2-parse-filter "^0.2.8" + "@budibase/vm-browserify@^1.1.4": version "1.1.4" resolved "https://registry.yarnpkg.com/@budibase/vm-browserify/-/vm-browserify-1.1.4.tgz#eecb001bd9521cb7647e26fb4d2d29d0a4dce262" @@ -8114,23 +8136,7 @@ aws4@^1.8.0: resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.13.2.tgz#0aa167216965ac9474ccfa83892cfb6b3e1e52ef" integrity sha512-lHe62zvbTB5eEABUVi/AwVh0ZKY9rMMDhmm+eeyuuUQbQ3+J+fONVQOZyj+DdrvD4BY33uYniyRJ4UJIaSKAfw== -axios@1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/axios/-/axios-1.1.3.tgz#8274250dada2edf53814ed7db644b9c2866c1e35" - integrity sha512-00tXVRwKx/FZr/IDVFt4C+f9FYairX517WoGCL6dpOntqLkZofjhu43F/Xl44UOpqa+9sLFDrG/XAnFsUYgkDA== - dependencies: - follow-redirects "^1.15.0" - form-data "^4.0.0" - proxy-from-env "^1.1.0" - -axios@^0.21.1: - version "0.21.4" - resolved "https://registry.yarnpkg.com/axios/-/axios-0.21.4.tgz#c67b90dc0568e5c1cf2b0b858c43ba28e2eda575" - integrity sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg== - dependencies: - follow-redirects "^1.14.0" - -axios@^1.0.0, axios@^1.1.3, axios@^1.4.0, axios@^1.6.2, axios@^1.6.8: +axios@1.1.3, axios@1.7.7, axios@^0.21.1, axios@^1.0.0, axios@^1.1.3, axios@^1.4.0, axios@^1.6.2, axios@^1.6.8: version "1.7.7" resolved "https://registry.yarnpkg.com/axios/-/axios-1.7.7.tgz#2f554296f9892a72ac8d8e4c5b79c14a91d0a47f" integrity sha512-S4kL7XrjgBmvdGut0sN3yJxqYzrDOnivkBiN0OFs6hLiUam3UPvswUo0kqGyhqUZGEOytHyumEdXsAkgCOUf3Q== @@ -11764,7 +11770,7 @@ fn.name@1.x.x: resolved "https://registry.yarnpkg.com/fn.name/-/fn.name-1.1.0.tgz#26cad8017967aea8731bc42961d04a3d5988accc" integrity sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw== -follow-redirects@^1.14.0, follow-redirects@^1.15.0, follow-redirects@^1.15.6: +follow-redirects@^1.15.6: version "1.15.9" resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.9.tgz#a604fa10e443bf98ca94228d9eebcc2e8a2c8ee1" integrity sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ== @@ -12379,22 +12385,10 @@ global@~4.4.0: min-document "^2.19.0" process "^0.11.10" -globals@^11.1.0: - version "11.12.0" - resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" - integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== - -globals@^13.19.0: - version "13.24.0" - resolved "https://registry.yarnpkg.com/globals/-/globals-13.24.0.tgz#8432a19d78ce0c1e833949c36adb345400bb1171" - integrity sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ== - dependencies: - type-fest "^0.20.2" - -globals@^14.0.0: - version "14.0.0" - resolved "https://registry.yarnpkg.com/globals/-/globals-14.0.0.tgz#898d7413c29babcf6bafe56fcadded858ada724e" - integrity sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ== +globals@15.13.0, globals@^11.1.0, globals@^13.19.0, globals@^14.0.0: + version "15.13.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-15.13.0.tgz#bbec719d69aafef188ecd67954aae76a696010fc" + integrity sha512-49TewVEz0UxZjr1WYYsWpPrhyC/B/pA8Bq0fUmet2n+eR7yn0IvNzNaoBwnK6mdkzcN+se7Ez9zUgULTz2QH4g== globalthis@^1.0.1, globalthis@^1.0.4: version "1.0.4" @@ -12804,12 +12798,7 @@ http-assert@^1.3.0: deep-equal "~1.0.1" http-errors "~1.8.0" -http-cache-semantics@3.8.1: - version "3.8.1" - resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-3.8.1.tgz#39b0e16add9b605bf0a9ef3d9daaf4843b4cacd2" - integrity sha512-5ai2iksyV8ZXmnZhHH4rWPoxxistEexSi5936zIQ1bnNTW5VnA85B6P/VpXiRM017IgRvb2kKo1a//y+0wSp3w== - -http-cache-semantics@^4.0.0, http-cache-semantics@^4.1.0, http-cache-semantics@^4.1.1: +http-cache-semantics@3.8.1, http-cache-semantics@4.1.1, http-cache-semantics@^4.0.0, http-cache-semantics@^4.1.0, http-cache-semantics@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz#abe02fcb2985460bf0323be664436ec3476a6d5a" integrity sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ== @@ -13265,11 +13254,6 @@ is-boolean-object@^1.1.0: call-bind "^1.0.2" has-tostringtag "^1.0.0" -is-buffer@^1.1.5: - version "1.1.6" - resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" - integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w== - is-buffer@^2.0.5: version "2.0.5" resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-2.0.5.tgz#ebc252e400d22ff8d77fa09888821a24a658c191" @@ -13709,6 +13693,11 @@ isobject@^3.0.1: resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" integrity sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg== +isobject@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/isobject/-/isobject-4.0.0.tgz#3f1c9155e73b192022a80819bacd0343711697b0" + integrity sha512-S/2fF5wH8SJA/kmwr6HYhK/RI/OkhD84k8ntalo0iJjZikgq1XFvR5M8NPT1x5F7fBwCG3qHfnzeP/Vh/ZxCUA== + isolated-vm@^4.7.2: version "4.7.2" resolved "https://registry.yarnpkg.com/isolated-vm/-/isolated-vm-4.7.2.tgz#5670d5cce1d92004f9b825bec5b0b11fc7501b65" @@ -14588,14 +14577,7 @@ kill-port@^1.6.1: get-them-args "1.3.2" shell-exec "1.0.2" -kind-of@^3.0.2, kind-of@^3.1.0: - version "3.2.2" - resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64" - integrity sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ== - dependencies: - is-buffer "^1.1.5" - -kind-of@^6.0.0, kind-of@^6.0.2, kind-of@^6.0.3: +kind-of@6.0.3, kind-of@^3.0.2, kind-of@^3.1.0, kind-of@^6.0.0, kind-of@^6.0.2, kind-of@^6.0.3: version "6.0.3" resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd" integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw== @@ -15978,7 +15960,7 @@ msgpackr-extract@^3.0.2: "@msgpackr-extract/msgpackr-extract-linux-x64" "3.0.2" "@msgpackr-extract/msgpackr-extract-win32-x64" "3.0.2" -msgpackr@^1.5.2: +msgpackr@1.10.1, msgpackr@^1.5.2: version "1.10.1" resolved "https://registry.yarnpkg.com/msgpackr/-/msgpackr-1.10.1.tgz#51953bb4ce4f3494f0c4af3f484f01cfbb306555" integrity sha512-r5VRLv9qouXuLiIBrLpl2d5ZvPt8svdQTl5/vMvE4nzDMyEX4sgW5yWhuBBj5UmgwOTWj8CIdSXn5sAfsHAWIQ== @@ -16171,27 +16153,13 @@ node-domexception@1.0.0: resolved "https://registry.yarnpkg.com/node-domexception/-/node-domexception-1.0.0.tgz#6888db46a1f71c0b76b3f7555016b63fe64766e5" integrity sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ== -node-fetch@2.6.7, node-fetch@^2.6.0, node-fetch@^2.6.1, node-fetch@^2.6.7: +node-fetch@2.6.7, node-fetch@2.6.9, node-fetch@^2.6.0, node-fetch@^2.6.1, node-fetch@^2.6.7, node-fetch@^2.6.9: version "2.6.7" resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.7.tgz#24de9fba827e3b4ae44dc8b20256a379160052ad" integrity sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ== dependencies: whatwg-url "^5.0.0" -node-fetch@2.6.9: - version "2.6.9" - resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.9.tgz#7c7f744b5cc6eb5fd404e0c7a9fec630a55657e6" - integrity sha512-DJm/CJkZkRjKKj4Zi4BsKVZh3ValV5IR5s7LVZnW+6YMh0W1BfNA8XSs6DLMGYlId5F3KnA70uu2qepcR08Qqg== - dependencies: - whatwg-url "^5.0.0" - -node-fetch@^2.6.9: - version "2.7.0" - resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.7.0.tgz#d0f0fa6e3e2dc1d27efcd8ad99d550bda94d187d" - integrity sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A== - dependencies: - whatwg-url "^5.0.0" - node-forge@^1.3.1: version "1.3.1" resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-1.3.1.tgz#be8da2af243b2417d5f646a770663a92b7e9ded3" @@ -17220,15 +17188,7 @@ passport-strategy@1.x.x, passport-strategy@^1.0.0: resolved "https://registry.yarnpkg.com/passport-strategy/-/passport-strategy-1.0.0.tgz#b5539aa8fc225a3d1ad179476ddf236b440f52e4" integrity sha512-CB97UUvDKJde2V0KDWWB3lyf6PC3FaZP7YxZ2G8OAtn9p4HI9j9JLP9qjOGZFvyl8uwNT8qM+hGnz/n16NI7oA== -passport@^0.4.0: - version "0.4.1" - resolved "https://registry.yarnpkg.com/passport/-/passport-0.4.1.tgz#941446a21cb92fc688d97a0861c38ce9f738f270" - integrity sha512-IxXgZZs8d7uFSt3eqNjM9NQ3g3uQCW5avD8mRNoXV99Yig50vjuaez6dQK2qC0kVWPRTujxY0dWgGfT09adjYg== - dependencies: - passport-strategy "1.x.x" - pause "0.0.1" - -passport@^0.6.0: +passport@0.6.0, passport@^0.4.0, passport@^0.6.0: version "0.6.0" resolved "https://registry.yarnpkg.com/passport/-/passport-0.6.0.tgz#e869579fab465b5c0b291e841e6cc95c005fac9d" integrity sha512-0fe+p3ZnrWRW74fe8+SvCyf4a3Pb2/h7gFkQ8yTJpAO50gDzlfjZUZTO1k5Eg9kUct22OxHLqDZoKUWRHOh9ug== @@ -18213,13 +18173,6 @@ pseudomap@^1.0.2: resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3" integrity sha512-b/YwNhb8lk1Zz2+bXXpS/LK9OisiZZ1SNsSLxN1x2OXVEhW2Ckr/7mWE5vrC1ZTiJlD9g19jWszTmJsB+oEpFQ== -psl@^1.1.28: - version "1.15.0" - resolved "https://registry.yarnpkg.com/psl/-/psl-1.15.0.tgz#bdace31896f1d97cec6a79e8224898ce93d974c6" - integrity sha512-JZd3gMVBAVQkSs6HdNZo9Sdo0LNcQeMNP3CozBJb3JYC/QUYZTnKxP+f8oWRX4rHP5EurWxqAHTSwUCjlNKa1w== - dependencies: - punycode "^2.3.1" - psl@^1.1.33: version "1.9.0" resolved "https://registry.yarnpkg.com/psl/-/psl-1.9.0.tgz#d0df2a137f00794565fcaf3b2c00cd09f8d5a5a7" @@ -18253,11 +18206,6 @@ punycode@^2.1.0, punycode@^2.1.1, punycode@^2.3.0: resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.0.tgz#f67fa67c94da8f4d0cfff981aee4118064199b8f" integrity sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA== -punycode@^2.3.1: - version "2.3.1" - resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.1.tgz#027422e2faec0b25e1549c3e1bd8309b9133b6e5" - integrity sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg== - pupa@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/pupa/-/pupa-2.1.1.tgz#f5e8fd4afc2c5d97828faa523549ed8744a20d62" @@ -19089,11 +19037,6 @@ sax@1.2.1: resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.1.tgz#7b8e656190b228e81a66aea748480d828cd2d37a" integrity sha512-8I2a3LovHTOpm7NV5yOyO8IHqgVsfK4+UuySrXU8YXkSRX7k6hCV9b3HrkKCr3nMpgj+0bmocaJJWpvp1oc7ZA== -sax@>=0.1.1: - version "1.4.1" - resolved "https://registry.yarnpkg.com/sax/-/sax-1.4.1.tgz#44cc8988377f126304d3b3fc1010c733b929ef0f" - integrity sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg== - sax@>=0.6.0: version "1.2.4" resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" @@ -19166,28 +19109,13 @@ semver-diff@^3.1.1: dependencies: semver "^6.3.0" -"semver@2 || 3 || 4 || 5", semver@^5.6.0, semver@^5.7.1: - version "5.7.2" - resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.2.tgz#48d55db737c3287cd4835e17fa13feace1c41ef8" - integrity sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g== - -semver@7.5.3, semver@^7.0.0, semver@^7.1.1, semver@^7.3.2, semver@^7.3.4, semver@^7.3.5, semver@^7.3.7, semver@^7.3.8, semver@^7.5.3: +"semver@2 || 3 || 4 || 5", semver@7.5.3, semver@^5.6.0, semver@^5.7.1, semver@^6.0.0, semver@^6.1.1, semver@^6.1.2, semver@^6.2.0, semver@^6.3.0, semver@^6.3.1, semver@^7.0.0, semver@^7.1.1, semver@^7.3.2, semver@^7.3.4, semver@^7.3.5, semver@^7.3.7, semver@^7.3.8, semver@^7.5.3, semver@^7.5.4, semver@^7.6.0, semver@^7.6.2: version "7.5.3" resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.3.tgz#161ce8c2c6b4b3bdca6caadc9fa3317a4c4fe88e" integrity sha512-QBlUtyVk/5EeHbi7X0fw6liDZc7BBmEaSYn01fMU1OUYbf6GPsbTtd8WmnqbI20SeycoHSeiybkE/q1Q+qlThQ== dependencies: lru-cache "^6.0.0" -semver@^6.0.0, semver@^6.1.1, semver@^6.1.2, semver@^6.2.0, semver@^6.3.0, semver@^6.3.1: - version "6.3.1" - resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4" - integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== - -semver@^7.5.4, semver@^7.6.0, semver@^7.6.2: - version "7.7.1" - resolved "https://registry.yarnpkg.com/semver/-/semver-7.7.1.tgz#abd5098d82b18c6c81f6074ff2647fd3e7220c9f" - integrity sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA== - seq-queue@^0.0.5: version "0.0.5" resolved "https://registry.yarnpkg.com/seq-queue/-/seq-queue-0.0.5.tgz#d56812e1c017a6e4e7c3e3a37a1da6d78dd3c93e" @@ -20669,7 +20597,7 @@ touch@^3.1.0: dependencies: nopt "~1.0.10" -"tough-cookie@^2.3.3 || ^3.0.1 || ^4.0.0", tough-cookie@^4.0.0, tough-cookie@^4.1.2: +tough-cookie@4.1.3, "tough-cookie@^2.3.3 || ^3.0.1 || ^4.0.0", tough-cookie@^4.0.0, tough-cookie@^4.1.2, tough-cookie@~2.5.0: version "4.1.3" resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-4.1.3.tgz#97b9adb0728b42280aa3d814b6b999b2ff0318bf" integrity sha512-aX/y5pVRkfRnfmuX+OdbSdXvPe6ieKX/G2s7e98f4poJHnqH3281gDPm/metm6E/WRamfx7WC4HUqkWHfQHprw== @@ -20679,14 +20607,6 @@ touch@^3.1.0: universalify "^0.2.0" url-parse "^1.5.3" -tough-cookie@~2.5.0: - version "2.5.0" - resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.5.0.tgz#cd9fb2a0aa1d5a12b473bd9fb96fa3dcff65ade2" - integrity sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g== - dependencies: - psl "^1.1.28" - punycode "^2.1.1" - tr46@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/tr46/-/tr46-2.1.0.tgz#fa87aa81ca5d5941da8cbf1f9b749dc969a4e240" @@ -21154,6 +21074,14 @@ unpipe@1.0.0: resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" integrity sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ== +unset-value@2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/unset-value/-/unset-value-2.0.1.tgz#57bed0c22d26f28d69acde5df9a11b77c74d2df3" + integrity sha512-2hvrBfjUE00PkqN+q0XP6yRAOGrR06uSiUoIQGZkc7GxvQ9H7v8quUPNtZjMg4uux69i8HWpIjLPUKwCuRGyNg== + dependencies: + has-value "^2.0.2" + isobject "^4.0.0" + untildify@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/untildify/-/untildify-4.0.0.tgz#2bc947b953652487e4600949fb091e3ae8cd919b" @@ -21857,14 +21785,7 @@ xml-parse-from-string@^1.0.0: resolved "https://registry.yarnpkg.com/xml-parse-from-string/-/xml-parse-from-string-1.0.1.tgz#a9029e929d3dbcded169f3c6e28238d95a5d5a28" integrity sha512-ErcKwJTF54uRzzNMXq2X5sMIy88zJvfN2DmdoQvy7PAFJ+tPRU6ydWuOKNMyfmOjdyBQTFREi60s0Y0SyI0G0g== -xml2js@0.1.x: - version "0.1.14" - resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.1.14.tgz#5274e67f5a64c5f92974cd85139e0332adc6b90c" - integrity sha512-pbdws4PPPNc1HPluSUKamY4GWMk592K7qwcj6BExbVOhhubub8+pMda/ql68b6L3luZs/OGjGSB5goV7SnmgnA== - dependencies: - sax ">=0.1.1" - -xml2js@0.6.2: +xml2js@0.1.x, xml2js@0.6.2, xml2js@^0.5.0: version "0.6.2" resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.6.2.tgz#dd0b630083aa09c161e25a4d0901e2b2a929b499" integrity sha512-T4rieHaC1EXcES0Kxxj4JWgaUQHDk+qwHcYOCFHfiwKz7tOVPLq7Hjq9dM1WCMhylqMEfP7hMcOIChvotiZegA== @@ -21872,14 +21793,6 @@ xml2js@0.6.2: sax ">=0.6.0" xmlbuilder "~11.0.0" -xml2js@^0.5.0: - version "0.5.0" - resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.5.0.tgz#d9440631fbb2ed800203fad106f2724f62c493b7" - integrity sha512-drPFnkQJik/O+uPKpqSgr22mpuFHqKdbS835iAQrUC73L2F5WkboIRd63ai/2Yg6I1jzifPFKH2NTK+cfglkIA== - dependencies: - sax ">=0.6.0" - xmlbuilder "~11.0.0" - xmlbuilder@~11.0.0: version "11.0.1" resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-11.0.1.tgz#be9bae1c8a046e76b31127726347d0ad7002beb3" From e6fc3dbff42922285b197f271845528f73684225 Mon Sep 17 00:00:00 2001 From: Sam Rose Date: Tue, 25 Feb 2025 09:19:25 +0000 Subject: [PATCH 08/46] Fix queryUtils tests. --- .../src/sdk/app/rows/tests/queryUtils.spec.ts | 31 ++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/packages/server/src/sdk/app/rows/tests/queryUtils.spec.ts b/packages/server/src/sdk/app/rows/tests/queryUtils.spec.ts index f399801f1e..100581cb54 100644 --- a/packages/server/src/sdk/app/rows/tests/queryUtils.spec.ts +++ b/packages/server/src/sdk/app/rows/tests/queryUtils.spec.ts @@ -250,6 +250,8 @@ describe("query utils", () => { expect(result).toEqual([ "_id", "name", + "aux._id", + "auxTable._id", "aux.title", "auxTable.title", "aux.name", @@ -284,7 +286,14 @@ describe("query utils", () => { const result = await config.doInContext(config.appId, () => { return getQueryableFields(table) }) - expect(result).toEqual(["_id", "name", "aux.name", "auxTable.name"]) + expect(result).toEqual([ + "_id", + "name", + "aux._id", + "auxTable._id", + "aux.name", + "auxTable.name", + ]) }) it("excludes all relationship fields if hidden", async () => { @@ -387,10 +396,14 @@ describe("query utils", () => { "_id", "name", // aux1 primitive props + "aux1._id", + "aux1Table._id", "aux1.name", "aux1Table.name", // aux2 primitive props + "aux2._id", + "aux2Table._id", "aux2.title", "aux2Table.title", ]) @@ -405,14 +418,20 @@ describe("query utils", () => { "name", // aux2_1 primitive props + "aux2_1._id", + "aux2Table._id", "aux2_1.title", "aux2Table.title", // aux2_2 primitive props + "aux2_2._id", + "aux2Table._id", "aux2_2.title", "aux2Table.title", // table primitive props + "table._id", + "TestTable._id", "table.name", "TestTable.name", ]) @@ -427,14 +446,20 @@ describe("query utils", () => { "title", // aux1_1 primitive props + "aux1_1._id", + "aux1Table._id", "aux1_1.name", "aux1Table.name", // aux1_2 primitive props + "aux1_2._id", + "aux1Table._id", "aux1_2.name", "aux1Table.name", // table primitive props + "table._id", + "TestTable._id", "table.name", "TestTable.name", ]) @@ -481,6 +506,8 @@ describe("query utils", () => { "name", // deep 1 aux primitive props + "aux._id", + "auxTable._id", "aux.title", "auxTable.title", ]) @@ -495,6 +522,8 @@ describe("query utils", () => { "title", // deep 1 dependency primitive props + "table._id", + "TestTable._id", "table.name", "TestTable.name", ]) From 3aeead4a7bfb0513314566cc5530ed04bb942d46 Mon Sep 17 00:00:00 2001 From: Budibase Staging Release Bot <> Date: Tue, 25 Feb 2025 09:27:02 +0000 Subject: [PATCH 09/46] Bump version to 3.4.17 --- lerna.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lerna.json b/lerna.json index bb71d10f41..8ea860e3c4 100644 --- a/lerna.json +++ b/lerna.json @@ -1,6 +1,6 @@ { "$schema": "node_modules/lerna/schemas/lerna-schema.json", - "version": "3.4.16", + "version": "3.4.17", "npmClient": "yarn", "concurrency": 20, "command": { From 3c6e2ff2d784cd79fc42df2c9955ebdba1897e2c Mon Sep 17 00:00:00 2001 From: Sam Rose Date: Tue, 25 Feb 2025 09:54:10 +0000 Subject: [PATCH 10/46] Fix search tests. --- .../src/api/routes/tests/search.spec.ts | 41 ++++++++++--------- .../server/src/sdk/app/rows/queryUtils.ts | 11 +++-- 2 files changed, 30 insertions(+), 22 deletions(-) diff --git a/packages/server/src/api/routes/tests/search.spec.ts b/packages/server/src/api/routes/tests/search.spec.ts index ba2b3f0acf..76ce4a0243 100644 --- a/packages/server/src/api/routes/tests/search.spec.ts +++ b/packages/server/src/api/routes/tests/search.spec.ts @@ -3554,27 +3554,30 @@ if (descriptions.length) { }).toContainExactly([row]) }) - it("can filter by the related _id", async () => { - await expectSearch({ - query: { - equal: { "rel._id": row.rel[0]._id }, - }, - }).toContainExactly([row]) + isInternal && + describe("search by _id for relations", () => { + it("can filter by the related _id", async () => { + await expectSearch({ + query: { + equal: { "rel._id": row.rel[0]._id }, + }, + }).toContainExactly([row]) - await expectSearch({ - query: { - equal: { "rel._id": row.rel[1]._id }, - }, - }).toContainExactly([row]) - }) + await expectSearch({ + query: { + equal: { "rel._id": row.rel[1]._id }, + }, + }).toContainExactly([row]) + }) - it("can filter by the related _id and find nothing", async () => { - await expectSearch({ - query: { - equal: { "rel._id": "rel_none" }, - }, - }).toFindNothing() - }) + it("can filter by the related _id and find nothing", async () => { + await expectSearch({ + query: { + equal: { "rel._id": "rel_none" }, + }, + }).toFindNothing() + }) + }) }) !isInternal && diff --git a/packages/server/src/sdk/app/rows/queryUtils.ts b/packages/server/src/sdk/app/rows/queryUtils.ts index 12e724b5d8..629fb50545 100644 --- a/packages/server/src/sdk/app/rows/queryUtils.ts +++ b/packages/server/src/sdk/app/rows/queryUtils.ts @@ -7,6 +7,7 @@ import { } from "@budibase/types" import { cloneDeep } from "lodash/fp" import sdk from "../../../sdk" +import { isInternal } from "../tables/utils" export const removeInvalidFilters = ( filters: SearchFilters, @@ -69,8 +70,11 @@ export const getQueryableFields = async ( fromTables: string[], opts?: { noRelationships?: boolean } ): Promise => { - // Querying by _id is always allowed, even if it's never part of the schema - const result = ["_id"] + const result = [] + if (isInternal({ table })) { + result.push("_id") + } + for (const field of Object.keys(table.schema).filter( f => allowedFields.includes(f) && table.schema[f].visible !== false )) { @@ -114,7 +118,8 @@ export const getQueryableFields = async ( return result } - const result = [] + // Querying by _id is always allowed, even if it's never part of the schema + const result = ["_id"] if (fields == null) { fields = Object.keys(table.schema) From c93d413d67c04e57ab9936b8aa6bb2d30eeba7cb Mon Sep 17 00:00:00 2001 From: Sam Rose Date: Tue, 25 Feb 2025 11:03:04 +0000 Subject: [PATCH 11/46] Improve typing around plugins. --- packages/pro | 2 +- .../src/api/controllers/plugin/index.ts | 14 ++++--- packages/server/src/sdk/index.ts | 2 +- packages/server/src/sdk/plugins/index.ts | 42 +++++++++++++++++-- packages/server/src/sdk/plugins/plugins.ts | 41 ------------------ .../server/src/utilities/fileSystem/plugin.ts | 35 ++++++++-------- packages/server/src/watch.ts | 5 ++- packages/types/src/documents/global/plugin.ts | 26 ++++++++++-- 8 files changed, 92 insertions(+), 75 deletions(-) delete mode 100644 packages/server/src/sdk/plugins/plugins.ts diff --git a/packages/pro b/packages/pro index 45f5673d5e..219be3ef38 160000 --- a/packages/pro +++ b/packages/pro @@ -1 +1 @@ -Subproject commit 45f5673d5e5ab3c22deb6663cea2e31a628aa133 +Subproject commit 219be3ef380ac8cb16b34892f62117d31b50eec7 diff --git a/packages/server/src/api/controllers/plugin/index.ts b/packages/server/src/api/controllers/plugin/index.ts index 2a4d69b671..6f7cceca10 100644 --- a/packages/server/src/api/controllers/plugin/index.ts +++ b/packages/server/src/api/controllers/plugin/index.ts @@ -11,6 +11,7 @@ import { UploadPluginResponse, FetchPluginResponse, DeletePluginResponse, + PluginMetadata, } from "@budibase/types" import env from "../../../environment" import { clientAppSocket } from "../../../websockets" @@ -53,10 +54,11 @@ export async function create( const { source, url, headers, githubToken } = ctx.request.body try { - let metadata - let directory + let metadata: PluginMetadata + let directory: string + // Generating random name as a backup and needed for url - let name = "PLUGIN_" + Math.floor(100000 + Math.random() * 900000) + const name = "PLUGIN_" + Math.floor(100000 + Math.random() * 900000) switch (source) { case PluginSource.NPM: { @@ -81,12 +83,14 @@ export async function create( directory = directoryUrl break } + default: + ctx.throw(400, "Invalid source") } - pluginCore.validate(metadata?.schema) + pluginCore.validate(metadata.schema) // Only allow components in cloud - if (!env.SELF_HOSTED && metadata?.schema?.type !== PluginType.COMPONENT) { + if (!env.SELF_HOSTED && metadata.schema?.type !== PluginType.COMPONENT) { throw new Error( "Only component plugins are supported outside of self-host" ) diff --git a/packages/server/src/sdk/index.ts b/packages/server/src/sdk/index.ts index e3e88c25c4..6d6bf00ee0 100644 --- a/packages/server/src/sdk/index.ts +++ b/packages/server/src/sdk/index.ts @@ -7,7 +7,7 @@ import { default as queries } from "./app/queries" import { default as rows } from "./app/rows" import { default as links } from "./app/links" import { default as users } from "./users" -import { default as plugins } from "./plugins" +import * as plugins from "./plugins" import * as views from "./app/views" import * as permissions from "./app/permissions" import * as rowActions from "./app/rowActions" diff --git a/packages/server/src/sdk/plugins/index.ts b/packages/server/src/sdk/plugins/index.ts index 863cfa0db6..03dd2be256 100644 --- a/packages/server/src/sdk/plugins/index.ts +++ b/packages/server/src/sdk/plugins/index.ts @@ -1,5 +1,41 @@ -import * as plugins from "./plugins" +import { KoaFile, Plugin, PluginSource, PluginType } from "@budibase/types" +import { + db as dbCore, + objectStore, + plugins as pluginCore, + tenancy, +} from "@budibase/backend-core" +import { fileUpload } from "../../api/controllers/plugin/file" +import env from "../../environment" +import { clientAppSocket } from "../../websockets" +import { sdk as pro } from "@budibase/pro" -export default { - ...plugins, +export async function fetch(type?: PluginType): Promise { + const db = tenancy.getGlobalDB() + const response = await db.allDocs( + dbCore.getPluginParams(null, { + include_docs: true, + }) + ) + let plugins = response.rows.map((row: any) => row.doc) as Plugin[] + plugins = await objectStore.enrichPluginURLs(plugins) + if (type) { + return plugins.filter((plugin: Plugin) => plugin.schema?.type === type) + } else { + return plugins + } +} + +export async function processUploaded(plugin: KoaFile, source: PluginSource) { + const { metadata, directory } = await fileUpload(plugin) + pluginCore.validate(metadata.schema) + + // Only allow components in cloud + if (!env.SELF_HOSTED && metadata.schema?.type !== PluginType.COMPONENT) { + throw new Error("Only component plugins are supported outside of self-host") + } + + const doc = await pro.plugins.storePlugin(metadata, directory, source) + clientAppSocket?.emit("plugin-update", { name: doc.name, hash: doc.hash }) + return doc } diff --git a/packages/server/src/sdk/plugins/plugins.ts b/packages/server/src/sdk/plugins/plugins.ts deleted file mode 100644 index bff24dcef7..0000000000 --- a/packages/server/src/sdk/plugins/plugins.ts +++ /dev/null @@ -1,41 +0,0 @@ -import { KoaFile, Plugin, PluginSource, PluginType } from "@budibase/types" -import { - db as dbCore, - objectStore, - plugins as pluginCore, - tenancy, -} from "@budibase/backend-core" -import { fileUpload } from "../../api/controllers/plugin/file" -import env from "../../environment" -import { clientAppSocket } from "../../websockets" -import { sdk as pro } from "@budibase/pro" - -export async function fetch(type?: PluginType): Promise { - const db = tenancy.getGlobalDB() - const response = await db.allDocs( - dbCore.getPluginParams(null, { - include_docs: true, - }) - ) - let plugins = response.rows.map((row: any) => row.doc) as Plugin[] - plugins = await objectStore.enrichPluginURLs(plugins) - if (type) { - return plugins.filter((plugin: Plugin) => plugin.schema?.type === type) - } else { - return plugins - } -} - -export async function processUploaded(plugin: KoaFile, source?: PluginSource) { - const { metadata, directory } = await fileUpload(plugin) - pluginCore.validate(metadata?.schema) - - // Only allow components in cloud - if (!env.SELF_HOSTED && metadata?.schema?.type !== PluginType.COMPONENT) { - throw new Error("Only component plugins are supported outside of self-host") - } - - const doc = await pro.plugins.storePlugin(metadata, directory, source) - clientAppSocket?.emit("plugin-update", { name: doc.name, hash: doc.hash }) - return doc -} diff --git a/packages/server/src/utilities/fileSystem/plugin.ts b/packages/server/src/utilities/fileSystem/plugin.ts index 2949daef61..1c62e9c1e9 100644 --- a/packages/server/src/utilities/fileSystem/plugin.ts +++ b/packages/server/src/utilities/fileSystem/plugin.ts @@ -1,4 +1,4 @@ -import { Plugin } from "@budibase/types" +import { Plugin, PluginUpload } from "@budibase/types" import { budibaseTempDir } from "../budibaseDir" import fs from "fs" import { join } from "path" @@ -8,23 +8,22 @@ import stream from "stream" const DATASOURCE_PATH = join(budibaseTempDir(), "datasource") const AUTOMATION_PATH = join(budibaseTempDir(), "automation") -export const getPluginMetadata = async (path: string) => { - let metadata: any = {} +export const getPluginMetadata = async ( + path: string +): Promise => { + let pkg: any + let schema: any try { - const pkg = fs.readFileSync(join(path, "package.json"), "utf8") - const schema = fs.readFileSync(join(path, "schema.json"), "utf8") - - metadata.schema = JSON.parse(schema) - metadata.package = JSON.parse(pkg) - - if ( - !metadata.package.name || - !metadata.package.version || - !metadata.package.description - ) { - throw new Error( - "package.json is missing one of 'name', 'version' or 'description'." - ) + pkg = JSON.parse(fs.readFileSync(join(path, "pkg.json"), "utf8")) + schema = JSON.parse(fs.readFileSync(join(path, "schema.json"), "utf8")) + if (!pkg.name) { + throw new Error("package.json is missing 'name'.") + } + if (!pkg.version) { + throw new Error("package.json is missing 'version'.") + } + if (!pkg.description) { + throw new Error("package.json is missing 'description'.") } } catch (err: any) { throw new Error( @@ -32,7 +31,7 @@ export const getPluginMetadata = async (path: string) => { ) } - return { metadata, directory: path } + return { metadata: { package: pkg, schema }, directory: path } } async function getPluginImpl(path: string, plugin: Plugin) { diff --git a/packages/server/src/watch.ts b/packages/server/src/watch.ts index 8f3fe22023..16b8800887 100644 --- a/packages/server/src/watch.ts +++ b/packages/server/src/watch.ts @@ -3,7 +3,8 @@ import env from "./environment" import chokidar from "chokidar" import fs from "fs" import { constants, tenancy } from "@budibase/backend-core" -import pluginsSdk from "./sdk/plugins" +import { processUploaded } from "./sdk/plugins" +import { PluginSource } from "@budibase/types" export function watch() { const watchPath = path.join(env.PLUGINS_DIR, "./**/*.tar.gz") @@ -27,7 +28,7 @@ export function watch() { const split = path.split("/") const name = split[split.length - 1] console.log("Importing plugin:", path) - await pluginsSdk.processUploaded({ name, path }) + await processUploaded({ name, path }, PluginSource.FILE) } catch (err: any) { const message = err?.message ? err?.message : err console.error("Failed to import plugin:", message) diff --git a/packages/types/src/documents/global/plugin.ts b/packages/types/src/documents/global/plugin.ts index eeddc04e58..56611d2d24 100644 --- a/packages/types/src/documents/global/plugin.ts +++ b/packages/types/src/documents/global/plugin.ts @@ -24,10 +24,7 @@ export interface Plugin extends Document { source: PluginSource package: { [key: string]: any } hash: string - schema: { - type: PluginType - [key: string]: any - } + schema: PluginSchema iconFileName?: string // Populated on read jsUrl?: string @@ -36,3 +33,24 @@ export interface Plugin extends Document { } export const PLUGIN_TYPE_ARR = Object.values(PluginType) + +export interface PluginSchema { + type: PluginType + [key: string]: any +} + +interface Package { + name: string + version: string + description: string +} + +export interface PluginMetadata { + schema: PluginSchema + package: Package +} + +export interface PluginUpload { + metadata: PluginMetadata + directory: string +} From da8c5be6857c0190f3ec3c3cd99c51a994425ef0 Mon Sep 17 00:00:00 2001 From: Sam Rose Date: Tue, 25 Feb 2025 11:08:18 +0000 Subject: [PATCH 12/46] Fix queryUtils tests. --- packages/server/src/sdk/app/rows/queryUtils.ts | 2 +- packages/server/src/sdk/app/rows/tests/queryUtils.spec.ts | 4 ---- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/packages/server/src/sdk/app/rows/queryUtils.ts b/packages/server/src/sdk/app/rows/queryUtils.ts index 629fb50545..8ab50ea1b7 100644 --- a/packages/server/src/sdk/app/rows/queryUtils.ts +++ b/packages/server/src/sdk/app/rows/queryUtils.ts @@ -126,5 +126,5 @@ export const getQueryableFields = async ( } result.push(...(await extractTableFields(table, fields, [table._id!]))) - return result + return Array.from(new Set(result)) } diff --git a/packages/server/src/sdk/app/rows/tests/queryUtils.spec.ts b/packages/server/src/sdk/app/rows/tests/queryUtils.spec.ts index 100581cb54..26a8431446 100644 --- a/packages/server/src/sdk/app/rows/tests/queryUtils.spec.ts +++ b/packages/server/src/sdk/app/rows/tests/queryUtils.spec.ts @@ -425,9 +425,7 @@ describe("query utils", () => { // aux2_2 primitive props "aux2_2._id", - "aux2Table._id", "aux2_2.title", - "aux2Table.title", // table primitive props "table._id", @@ -453,9 +451,7 @@ describe("query utils", () => { // aux1_2 primitive props "aux1_2._id", - "aux1Table._id", "aux1_2.name", - "aux1Table.name", // table primitive props "table._id", From f4846736675ac9fe7cb549c75366931d57e62fa1 Mon Sep 17 00:00:00 2001 From: Sam Rose Date: Tue, 25 Feb 2025 12:43:05 +0000 Subject: [PATCH 13/46] Remove elasticsearch global mock, fix tests. --- .../__mocks__/@elastic/elasticsearch.ts | 24 ---- packages/server/datasource-sha.env | 1 + .../server/src/integrations/elasticsearch.ts | 42 ++++--- .../integrations/tests/elasticsearch.spec.ts | 119 +++++++++--------- .../integrations/tests/utils/elasticsearch.ts | 43 +++++++ .../src/integrations/tests/utils/images.ts | 1 + 6 files changed, 126 insertions(+), 104 deletions(-) delete mode 100644 packages/server/__mocks__/@elastic/elasticsearch.ts create mode 100644 packages/server/src/integrations/tests/utils/elasticsearch.ts diff --git a/packages/server/__mocks__/@elastic/elasticsearch.ts b/packages/server/__mocks__/@elastic/elasticsearch.ts deleted file mode 100644 index 5e13437f29..0000000000 --- a/packages/server/__mocks__/@elastic/elasticsearch.ts +++ /dev/null @@ -1,24 +0,0 @@ -const elastic: any = {} - -elastic.Client = function () { - this.index = jest.fn().mockResolvedValue({ body: [] }) - this.search = jest.fn().mockResolvedValue({ - body: { - hits: { - hits: [ - { - _source: { - name: "test", - }, - }, - ], - }, - }, - }) - this.update = jest.fn().mockResolvedValue({ body: [] }) - this.delete = jest.fn().mockResolvedValue({ body: [] }) - - this.close = jest.fn() -} - -module.exports = elastic diff --git a/packages/server/datasource-sha.env b/packages/server/datasource-sha.env index 61249d530c..383fb191f4 100644 --- a/packages/server/datasource-sha.env +++ b/packages/server/datasource-sha.env @@ -3,3 +3,4 @@ MYSQL_SHA=sha256:9de9d54fecee6253130e65154b930978b1fcc336bcc86dfd06e89b72a2588eb POSTGRES_SHA=sha256:bd0d8e485d1aca439d39e5ea99b931160bd28d862e74c786f7508e9d0053090e MONGODB_SHA=sha256:afa36bca12295b5f9dae68a493c706113922bdab520e901bd5d6c9d7247a1d8d MARIADB_SHA=sha256:e59ba8783bf7bc02a4779f103bb0d8751ac0e10f9471089709608377eded7aa8 +ELASTICSEARCH_SHA=sha256:9a6443f55243f6acbfeb4a112d15eb3b9aac74bf25e0e39fa19b3ddd3a6879d0 \ No newline at end of file diff --git a/packages/server/src/integrations/elasticsearch.ts b/packages/server/src/integrations/elasticsearch.ts index af03baaef1..10f9d1e697 100644 --- a/packages/server/src/integrations/elasticsearch.ts +++ b/packages/server/src/integrations/elasticsearch.ts @@ -10,7 +10,7 @@ import { import { Client, ClientOptions } from "@elastic/elasticsearch" import { HOST_ADDRESS } from "./utils" -interface ElasticsearchConfig { +export interface ElasticsearchConfig { url: string ssl?: boolean ca?: string @@ -99,9 +99,9 @@ const SCHEMA: Integration = { }, } -class ElasticSearchIntegration implements IntegrationBase { +export class ElasticSearchIntegration implements IntegrationBase { private config: ElasticsearchConfig - private client + private client: Client constructor(config: ElasticsearchConfig) { this.config = config @@ -132,20 +132,23 @@ class ElasticSearchIntegration implements IntegrationBase { } } - async create(query: { index: string; json: object }) { - const { index, json } = query + async create(query: { + index: string + json: object + extra?: Record + }) { + const { index, json, extra } = query try { const result = await this.client.index({ index, body: json, + ...extra, }) return result.body } catch (err) { console.error("Error writing to elasticsearch", err) throw err - } finally { - await this.client.close() } } @@ -160,41 +163,46 @@ class ElasticSearchIntegration implements IntegrationBase { } catch (err) { console.error("Error querying elasticsearch", err) throw err - } finally { - await this.client.close() } } - async update(query: { id: string; index: string; json: object }) { - const { id, index, json } = query + async update(query: { + id: string + index: string + json: object + extra?: Record + }) { + const { id, index, json, extra } = query try { const result = await this.client.update({ id, index, body: json, + ...extra, }) return result.body } catch (err) { console.error("Error querying elasticsearch", err) throw err - } finally { - await this.client.close() } } - async delete(query: { id: string; index: string }) { - const { id, index } = query + async delete(query: { + id: string + index: string + extra?: Record + }) { + const { id, index, extra } = query try { const result = await this.client.delete({ id, index, + ...extra, }) return result.body } catch (err) { console.error("Error deleting from elasticsearch", err) throw err - } finally { - await this.client.close() } } } diff --git a/packages/server/src/integrations/tests/elasticsearch.spec.ts b/packages/server/src/integrations/tests/elasticsearch.spec.ts index f8a1dd8013..da9c5600ad 100644 --- a/packages/server/src/integrations/tests/elasticsearch.spec.ts +++ b/packages/server/src/integrations/tests/elasticsearch.spec.ts @@ -1,83 +1,76 @@ -import { default as ElasticSearchIntegration } from "../elasticsearch" - -jest.mock("@elastic/elasticsearch") - -class TestConfiguration { - integration: any - - constructor(config: any = {}) { - this.integration = new ElasticSearchIntegration.integration(config) - } -} +import { Datasource } from "@budibase/types" +import { ElasticsearchConfig, ElasticSearchIntegration } from "../elasticsearch" +import * as elasticsearch from "../tests/utils/elasticsearch" +import { generator } from "@budibase/backend-core/tests" describe("Elasticsearch Integration", () => { - let config: any - let indexName = "Users" + let datasource: Datasource + let integration: ElasticSearchIntegration + + let index: string + + beforeAll(async () => { + datasource = await elasticsearch.getDatasource() + }) beforeEach(() => { - config = new TestConfiguration() + index = generator.guid() + integration = new ElasticSearchIntegration( + datasource.config! as ElasticsearchConfig + ) }) - it("calls the create method with the correct params", async () => { - const body = { - name: "Hello", - } - await config.integration.create({ - index: indexName, - json: body, + it("can create a record", async () => { + await integration.create({ + index, + json: { name: "Hello" }, + extra: { refresh: "true" }, }) - expect(config.integration.client.index).toHaveBeenCalledWith({ - index: indexName, - body, + const records = await integration.read({ + index, + json: { query: { match_all: {} } }, }) + expect(records).toEqual([{ name: "Hello" }]) }) - it("calls the read method with the correct params", async () => { - const body = { - query: { - term: { - name: "kimchy", - }, - }, - } - const response = await config.integration.read({ - index: indexName, - json: body, + it("can update a record", async () => { + const create = await integration.create({ + index, + json: { name: "Hello" }, + extra: { refresh: "true" }, }) - expect(config.integration.client.search).toHaveBeenCalledWith({ - index: indexName, - body, + + await integration.update({ + id: create._id, + index, + json: { doc: { name: "World" } }, + extra: { refresh: "true" }, }) - expect(response).toEqual(expect.any(Array)) + + const records = await integration.read({ + index, + json: { query: { match_all: {} } }, + }) + expect(records).toEqual([{ name: "World" }]) }) - it("calls the update method with the correct params", async () => { - const body = { - name: "updated", - } - - const response = await config.integration.update({ - id: "1234", - index: indexName, - json: body, + it("can delete a record", async () => { + const create = await integration.create({ + index, + json: { name: "Hello" }, + extra: { refresh: "true" }, }) - expect(config.integration.client.update).toHaveBeenCalledWith({ - id: "1234", - index: indexName, - body, + await integration.delete({ + id: create._id, + index, + extra: { refresh: "true" }, }) - expect(response).toEqual(expect.any(Array)) - }) - it("calls the delete method with the correct params", async () => { - const body = { - id: "1234", - } - - const response = await config.integration.delete(body) - - expect(config.integration.client.delete).toHaveBeenCalledWith(body) - expect(response).toEqual(expect.any(Array)) + const records = await integration.read({ + index, + json: { query: { match_all: {} } }, + }) + expect(records).toEqual([]) }) }) diff --git a/packages/server/src/integrations/tests/utils/elasticsearch.ts b/packages/server/src/integrations/tests/utils/elasticsearch.ts new file mode 100644 index 0000000000..a7229c3f60 --- /dev/null +++ b/packages/server/src/integrations/tests/utils/elasticsearch.ts @@ -0,0 +1,43 @@ +import { Datasource, SourceName } from "@budibase/types" +import { GenericContainer, Wait } from "testcontainers" +import { testContainerUtils } from "@budibase/backend-core/tests" +import { startContainer } from "." +import { ELASTICSEARCH_IMAGE } from "./images" +import { ElasticsearchConfig } from "../../elasticsearch" + +let ports: Promise + +export async function getDatasource(): Promise { + if (!ports) { + ports = startContainer( + new GenericContainer(ELASTICSEARCH_IMAGE) + .withExposedPorts(9200) + .withEnvironment({ + "discovery.type": "single-node", + "xpack.security.enabled": "false", + }) + .withWaitStrategy( + Wait.forHttp( + "/_cluster/health?wait_for_status=yellow&timeout=10s", + 9200 + ).withStartupTimeout(60000) + ) + .withTmpFs({ "/usr/share/elasticsearch/data": "rw" }) + ) + } + + const port = (await ports).find(x => x.container === 9200)?.host + if (!port) { + throw new Error("Elasticsearch port not found") + } + + const config: ElasticsearchConfig = { + url: `http://127.0.0.1:${port}`, + } + + return { + type: "datasource", + source: SourceName.ELASTICSEARCH, + config, + } +} diff --git a/packages/server/src/integrations/tests/utils/images.ts b/packages/server/src/integrations/tests/utils/images.ts index 00686412c6..c09b130ea5 100644 --- a/packages/server/src/integrations/tests/utils/images.ts +++ b/packages/server/src/integrations/tests/utils/images.ts @@ -12,3 +12,4 @@ export const POSTGRES_IMAGE = `postgres@${process.env.POSTGRES_SHA}` export const POSTGRES_LEGACY_IMAGE = `postgres:9.5.25` export const MONGODB_IMAGE = `mongo@${process.env.MONGODB_SHA}` export const MARIADB_IMAGE = `mariadb@${process.env.MARIADB_SHA}` +export const ELASTICSEARCH_IMAGE = `elasticsearch@${process.env.ELASTICSEARCH_SHA}` From 1c23509839517910e1b44a66bdb184ffd8f02c27 Mon Sep 17 00:00:00 2001 From: Sam Rose Date: Tue, 25 Feb 2025 14:58:52 +0000 Subject: [PATCH 14/46] Integrate Elasticsearch as a test datasource. --- .github/workflows/budibase_ci.yml | 15 +- .../src/api/routes/tests/datasource.spec.ts | 6 +- .../routes/tests/queries/generic-sql.spec.ts | 3 +- .../server/src/api/routes/tests/row.spec.ts | 7 +- .../src/api/routes/tests/search.spec.ts | 7 +- .../server/src/api/routes/tests/table.spec.ts | 7 +- .../src/api/routes/tests/viewV2.spec.ts | 7 +- .../tests/steps/executeQuery.spec.ts | 3 +- .../integrations/tests/elasticsearch.spec.ts | 141 +++++++++--------- .../src/integrations/tests/utils/index.ts | 56 +++++-- .../sdk/app/rows/search/tests/search.spec.ts | 7 +- 11 files changed, 145 insertions(+), 114 deletions(-) diff --git a/.github/workflows/budibase_ci.yml b/.github/workflows/budibase_ci.yml index e294e50e8d..6a9aa3e8d0 100644 --- a/.github/workflows/budibase_ci.yml +++ b/.github/workflows/budibase_ci.yml @@ -155,7 +155,18 @@ jobs: strategy: matrix: datasource: - [mssql, mysql, postgres, postgres_legacy, mongodb, mariadb, oracle, sqs, none] + [ + mssql, + mysql, + postgres, + postgres_legacy, + mongodb, + mariadb, + oracle, + sqs, + elasticsearch, + none, + ] steps: - name: Checkout repo uses: actions/checkout@v4 @@ -192,6 +203,8 @@ jobs: docker pull budibase/oracle-database:23.2-slim-faststart elif [ "${{ matrix.datasource }}" == "postgres_legacy" ]; then docker pull postgres:9.5.25 + elif [ "${{ matrix.datasource }}" == "elasticsearch" ]; then + docker pull elasticsearch@${{ steps.dotenv.outputs.ELASTICSEARCH_SHA }} fi docker pull minio/minio & docker pull redis & diff --git a/packages/server/src/api/routes/tests/datasource.spec.ts b/packages/server/src/api/routes/tests/datasource.spec.ts index 21e9effa77..12029c39c4 100644 --- a/packages/server/src/api/routes/tests/datasource.spec.ts +++ b/packages/server/src/api/routes/tests/datasource.spec.ts @@ -165,7 +165,8 @@ describe("/datasources", () => { }) const descriptions = datasourceDescribe({ - exclude: [DatabaseName.MONGODB, DatabaseName.SQS], + plus: true, + exclude: [DatabaseName.SQS], }) if (descriptions.length) { @@ -590,7 +591,8 @@ if (descriptions.length) { } const datasources = datasourceDescribe({ - exclude: [DatabaseName.MONGODB, DatabaseName.SQS, DatabaseName.ORACLE], + plus: true, + exclude: [DatabaseName.SQS, DatabaseName.ORACLE], }) if (datasources.length) { diff --git a/packages/server/src/api/routes/tests/queries/generic-sql.spec.ts b/packages/server/src/api/routes/tests/queries/generic-sql.spec.ts index 863f5b65e0..4a545b253e 100644 --- a/packages/server/src/api/routes/tests/queries/generic-sql.spec.ts +++ b/packages/server/src/api/routes/tests/queries/generic-sql.spec.ts @@ -9,7 +9,8 @@ import { Knex } from "knex" import { generator } from "@budibase/backend-core/tests" const descriptions = datasourceDescribe({ - exclude: [DatabaseName.MONGODB, DatabaseName.SQS], + plus: true, + exclude: [DatabaseName.SQS], }) if (descriptions.length) { diff --git a/packages/server/src/api/routes/tests/row.spec.ts b/packages/server/src/api/routes/tests/row.spec.ts index 87002670b7..b349a1df8a 100644 --- a/packages/server/src/api/routes/tests/row.spec.ts +++ b/packages/server/src/api/routes/tests/row.spec.ts @@ -1,9 +1,6 @@ import * as setup from "./utilities" -import { - DatabaseName, - datasourceDescribe, -} from "../../../integrations/tests/utils" +import { datasourceDescribe } from "../../../integrations/tests/utils" import tk from "timekeeper" import emitter from "../../../../src/events" @@ -80,7 +77,7 @@ function encodeJS(binding: string) { return `{{ js "${Buffer.from(binding).toString("base64")}"}}` } -const descriptions = datasourceDescribe({ exclude: [DatabaseName.MONGODB] }) +const descriptions = datasourceDescribe({ plus: true }) if (descriptions.length) { describe.each(descriptions)( diff --git a/packages/server/src/api/routes/tests/search.spec.ts b/packages/server/src/api/routes/tests/search.spec.ts index ee372914d7..a904c0c469 100644 --- a/packages/server/src/api/routes/tests/search.spec.ts +++ b/packages/server/src/api/routes/tests/search.spec.ts @@ -1,8 +1,5 @@ import { tableForDatasource } from "../../../tests/utilities/structures" -import { - DatabaseName, - datasourceDescribe, -} from "../../../integrations/tests/utils" +import { datasourceDescribe } from "../../../integrations/tests/utils" import { context, db as dbCore, @@ -60,7 +57,7 @@ jest.mock("@budibase/pro", () => ({ }, })) -const descriptions = datasourceDescribe({ exclude: [DatabaseName.MONGODB] }) +const descriptions = datasourceDescribe({ plus: true }) if (descriptions.length) { describe.each(descriptions)( diff --git a/packages/server/src/api/routes/tests/table.spec.ts b/packages/server/src/api/routes/tests/table.spec.ts index 2a7f039ff5..29b576d16a 100644 --- a/packages/server/src/api/routes/tests/table.spec.ts +++ b/packages/server/src/api/routes/tests/table.spec.ts @@ -28,17 +28,14 @@ import * as setup from "./utilities" import * as uuid from "uuid" import { generator } from "@budibase/backend-core/tests" -import { - DatabaseName, - datasourceDescribe, -} from "../../../integrations/tests/utils" +import { datasourceDescribe } from "../../../integrations/tests/utils" import { tableForDatasource } from "../../../tests/utilities/structures" import timekeeper from "timekeeper" const { basicTable } = setup.structures const ISO_REGEX_PATTERN = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z$/ -const descriptions = datasourceDescribe({ exclude: [DatabaseName.MONGODB] }) +const descriptions = datasourceDescribe({ plus: true }) if (descriptions.length) { describe.each(descriptions)( diff --git a/packages/server/src/api/routes/tests/viewV2.spec.ts b/packages/server/src/api/routes/tests/viewV2.spec.ts index 9531737d30..7eed1811d9 100644 --- a/packages/server/src/api/routes/tests/viewV2.spec.ts +++ b/packages/server/src/api/routes/tests/viewV2.spec.ts @@ -37,17 +37,14 @@ import { ViewV2Type, } from "@budibase/types" import { generator, mocks } from "@budibase/backend-core/tests" -import { - DatabaseName, - datasourceDescribe, -} from "../../../integrations/tests/utils" +import { datasourceDescribe } from "../../../integrations/tests/utils" import merge from "lodash/merge" import { quotas } from "@budibase/pro" import { context, db, events, roles, setEnv } from "@budibase/backend-core" import { mockChatGPTResponse } from "../../../tests/utilities/mocks/openai" import nock from "nock" -const descriptions = datasourceDescribe({ exclude: [DatabaseName.MONGODB] }) +const descriptions = datasourceDescribe({ plus: true }) if (descriptions.length) { describe.each(descriptions)( diff --git a/packages/server/src/automations/tests/steps/executeQuery.spec.ts b/packages/server/src/automations/tests/steps/executeQuery.spec.ts index dff3580b7e..a51d335902 100644 --- a/packages/server/src/automations/tests/steps/executeQuery.spec.ts +++ b/packages/server/src/automations/tests/steps/executeQuery.spec.ts @@ -9,7 +9,8 @@ import { generator } from "@budibase/backend-core/tests" import { createAutomationBuilder } from "../utilities/AutomationTestBuilder" const descriptions = datasourceDescribe({ - exclude: [DatabaseName.MONGODB, DatabaseName.SQS], + plus: true, + exclude: [DatabaseName.SQS], }) if (descriptions.length) { diff --git a/packages/server/src/integrations/tests/elasticsearch.spec.ts b/packages/server/src/integrations/tests/elasticsearch.spec.ts index da9c5600ad..14a272d610 100644 --- a/packages/server/src/integrations/tests/elasticsearch.spec.ts +++ b/packages/server/src/integrations/tests/elasticsearch.spec.ts @@ -2,75 +2,80 @@ import { Datasource } from "@budibase/types" import { ElasticsearchConfig, ElasticSearchIntegration } from "../elasticsearch" import * as elasticsearch from "../tests/utils/elasticsearch" import { generator } from "@budibase/backend-core/tests" +import { DatabaseName, datasourceDescribe } from "./utils" -describe("Elasticsearch Integration", () => { - let datasource: Datasource - let integration: ElasticSearchIntegration +const describes = datasourceDescribe({ only: [DatabaseName.ELASTICSEARCH] }) - let index: string +if (describes.length) { + describe.each(describes)("Elasticsearch Integration", () => { + let datasource: Datasource + let integration: ElasticSearchIntegration - beforeAll(async () => { - datasource = await elasticsearch.getDatasource() + let index: string + + beforeAll(async () => { + datasource = await elasticsearch.getDatasource() + }) + + beforeEach(() => { + index = generator.guid() + integration = new ElasticSearchIntegration( + datasource.config! as ElasticsearchConfig + ) + }) + + it("can create a record", async () => { + await integration.create({ + index, + json: { name: "Hello" }, + extra: { refresh: "true" }, + }) + const records = await integration.read({ + index, + json: { query: { match_all: {} } }, + }) + expect(records).toEqual([{ name: "Hello" }]) + }) + + it("can update a record", async () => { + const create = await integration.create({ + index, + json: { name: "Hello" }, + extra: { refresh: "true" }, + }) + + await integration.update({ + id: create._id, + index, + json: { doc: { name: "World" } }, + extra: { refresh: "true" }, + }) + + const records = await integration.read({ + index, + json: { query: { match_all: {} } }, + }) + expect(records).toEqual([{ name: "World" }]) + }) + + it("can delete a record", async () => { + const create = await integration.create({ + index, + json: { name: "Hello" }, + extra: { refresh: "true" }, + }) + + await integration.delete({ + id: create._id, + index, + extra: { refresh: "true" }, + }) + + const records = await integration.read({ + index, + json: { query: { match_all: {} } }, + }) + expect(records).toEqual([]) + }) }) - - beforeEach(() => { - index = generator.guid() - integration = new ElasticSearchIntegration( - datasource.config! as ElasticsearchConfig - ) - }) - - it("can create a record", async () => { - await integration.create({ - index, - json: { name: "Hello" }, - extra: { refresh: "true" }, - }) - const records = await integration.read({ - index, - json: { query: { match_all: {} } }, - }) - expect(records).toEqual([{ name: "Hello" }]) - }) - - it("can update a record", async () => { - const create = await integration.create({ - index, - json: { name: "Hello" }, - extra: { refresh: "true" }, - }) - - await integration.update({ - id: create._id, - index, - json: { doc: { name: "World" } }, - extra: { refresh: "true" }, - }) - - const records = await integration.read({ - index, - json: { query: { match_all: {} } }, - }) - expect(records).toEqual([{ name: "World" }]) - }) - - it("can delete a record", async () => { - const create = await integration.create({ - index, - json: { name: "Hello" }, - extra: { refresh: "true" }, - }) - - await integration.delete({ - id: create._id, - index, - extra: { refresh: "true" }, - }) - - const records = await integration.read({ - index, - json: { query: { match_all: {} } }, - }) - expect(records).toEqual([]) - }) -}) +} diff --git a/packages/server/src/integrations/tests/utils/index.ts b/packages/server/src/integrations/tests/utils/index.ts index 9e2c4f7e70..08777cab89 100644 --- a/packages/server/src/integrations/tests/utils/index.ts +++ b/packages/server/src/integrations/tests/utils/index.ts @@ -6,6 +6,7 @@ import * as mysql from "./mysql" import * as mssql from "./mssql" import * as mariadb from "./mariadb" import * as oracle from "./oracle" +import * as elasticsearch from "./elasticsearch" import { testContainerUtils } from "@budibase/backend-core/tests" import { Knex } from "knex" import TestConfiguration from "../../../tests/utilities/TestConfiguration" @@ -23,22 +24,32 @@ export enum DatabaseName { MARIADB = "mariadb", ORACLE = "oracle", SQS = "sqs", + ELASTICSEARCH = "elasticsearch", } +const DATASOURCE_PLUS = [ + DatabaseName.POSTGRES, + DatabaseName.POSTGRES_LEGACY, + DatabaseName.MYSQL, + DatabaseName.SQL_SERVER, + DatabaseName.MARIADB, + DatabaseName.ORACLE, + DatabaseName.SQS, +] + const providers: Record = { + // datasource_plus entries [DatabaseName.POSTGRES]: postgres.getDatasource, [DatabaseName.POSTGRES_LEGACY]: postgres.getLegacyDatasource, - [DatabaseName.MONGODB]: mongodb.getDatasource, [DatabaseName.MYSQL]: mysql.getDatasource, [DatabaseName.SQL_SERVER]: mssql.getDatasource, [DatabaseName.MARIADB]: mariadb.getDatasource, [DatabaseName.ORACLE]: oracle.getDatasource, [DatabaseName.SQS]: async () => undefined, -} -export interface DatasourceDescribeOpts { - only?: DatabaseName[] - exclude?: DatabaseName[] + // rest + [DatabaseName.ELASTICSEARCH]: elasticsearch.getDatasource, + [DatabaseName.MONGODB]: mongodb.getDatasource, } export interface DatasourceDescribeReturnPromise { @@ -103,6 +114,20 @@ function createDummyTest() { }) } +interface OnlyOpts { + only: DatabaseName[] +} + +interface PlusOpts { + plus: true + exclude?: DatabaseName[] +} + +export type DatasourceDescribeOpts = OnlyOpts | PlusOpts + +// If you ever want to rename this function, be mindful that you will also need +// to modify src/tests/filters/index.js to make sure that we're correctly +// filtering datasource/non-datasource tests in CI. export function datasourceDescribe(opts: DatasourceDescribeOpts) { // tests that call this need a lot longer timeouts jest.setTimeout(120000) @@ -111,17 +136,15 @@ export function datasourceDescribe(opts: DatasourceDescribeOpts) { createDummyTest() } - const { only, exclude } = opts - - if (only && exclude) { - throw new Error("you can only supply one of 'only' or 'exclude'") - } - - let databases = Object.values(DatabaseName) - if (only) { - databases = only - } else if (exclude) { - databases = databases.filter(db => !exclude.includes(db)) + let databases: DatabaseName[] = [] + if ("only" in opts) { + databases = opts.only + } else if ("plus" in opts) { + databases = Object.values(DatabaseName) + .filter(db => DATASOURCE_PLUS.includes(db)) + .filter(db => !opts.exclude?.includes(db)) + } else { + throw new Error("invalid options") } if (process.env.DATASOURCE) { @@ -156,6 +179,7 @@ export function datasourceDescribe(opts: DatasourceDescribeOpts) { isMSSQL: dbName === DatabaseName.SQL_SERVER, isOracle: dbName === DatabaseName.ORACLE, isMariaDB: dbName === DatabaseName.MARIADB, + isElasticsearch: dbName === DatabaseName.ELASTICSEARCH, })) } diff --git a/packages/server/src/sdk/app/rows/search/tests/search.spec.ts b/packages/server/src/sdk/app/rows/search/tests/search.spec.ts index b424c3707d..eaf495e25f 100644 --- a/packages/server/src/sdk/app/rows/search/tests/search.spec.ts +++ b/packages/server/src/sdk/app/rows/search/tests/search.spec.ts @@ -10,16 +10,13 @@ import { import { search } from "../../../../../sdk/app/rows/search" import { generator } from "@budibase/backend-core/tests" -import { - DatabaseName, - datasourceDescribe, -} from "../../../../../integrations/tests/utils" +import { datasourceDescribe } from "../../../../../integrations/tests/utils" import { tableForDatasource } from "../../../../../tests/utilities/structures" // These test cases are only for things that cannot be tested through the API // (e.g. limiting searches to returning specific fields). If it's possible to // test through the API, it should be done there instead. -const descriptions = datasourceDescribe({ exclude: [DatabaseName.MONGODB] }) +const descriptions = datasourceDescribe({ plus: true }) if (descriptions.length) { describe.each(descriptions)( From 48674833fcca04598f3549b580e1c511a3670541 Mon Sep 17 00:00:00 2001 From: Sam Rose Date: Tue, 25 Feb 2025 15:09:39 +0000 Subject: [PATCH 15/46] Correct use of dsProvider in elasticsearch.spec.ts. --- .../server/src/integrations/tests/elasticsearch.spec.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/server/src/integrations/tests/elasticsearch.spec.ts b/packages/server/src/integrations/tests/elasticsearch.spec.ts index 14a272d610..bcf8def1e9 100644 --- a/packages/server/src/integrations/tests/elasticsearch.spec.ts +++ b/packages/server/src/integrations/tests/elasticsearch.spec.ts @@ -1,20 +1,20 @@ import { Datasource } from "@budibase/types" import { ElasticsearchConfig, ElasticSearchIntegration } from "../elasticsearch" -import * as elasticsearch from "../tests/utils/elasticsearch" import { generator } from "@budibase/backend-core/tests" import { DatabaseName, datasourceDescribe } from "./utils" const describes = datasourceDescribe({ only: [DatabaseName.ELASTICSEARCH] }) if (describes.length) { - describe.each(describes)("Elasticsearch Integration", () => { + describe.each(describes)("Elasticsearch Integration", ({ dsProvider }) => { let datasource: Datasource let integration: ElasticSearchIntegration let index: string beforeAll(async () => { - datasource = await elasticsearch.getDatasource() + const ds = await dsProvider() + datasource = ds.datasource! }) beforeEach(() => { From 9f0da2a65a1252a9754afa2806d07fac30cd5e60 Mon Sep 17 00:00:00 2001 From: Sam Rose Date: Tue, 25 Feb 2025 15:12:35 +0000 Subject: [PATCH 16/46] Document elasticsearch container params. --- .../src/integrations/tests/utils/elasticsearch.ts | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/packages/server/src/integrations/tests/utils/elasticsearch.ts b/packages/server/src/integrations/tests/utils/elasticsearch.ts index a7229c3f60..a2ea22f73b 100644 --- a/packages/server/src/integrations/tests/utils/elasticsearch.ts +++ b/packages/server/src/integrations/tests/utils/elasticsearch.ts @@ -13,15 +13,26 @@ export async function getDatasource(): Promise { new GenericContainer(ELASTICSEARCH_IMAGE) .withExposedPorts(9200) .withEnvironment({ + // We need to set the discovery type to single-node to avoid the + // cluster waiting for other nodes to join before starting up. "discovery.type": "single-node", + // We disable security to avoid having to do any auth against the + // container, and to disable SSL. With SSL enabled it uses a self + // signed certificate that we'd have to ignore anyway. "xpack.security.enabled": "false", }) .withWaitStrategy( Wait.forHttp( + // Single node clusters never reach status green, so we wait for + // yellow instead. "/_cluster/health?wait_for_status=yellow&timeout=10s", 9200 ).withStartupTimeout(60000) ) + // We gave the container a tmpfs data directory. Without this, I found + // that the default data directory was very small and the container + // easily filled it up. This caused the cluster to go into a red status + // and stop responding to requests. .withTmpFs({ "/usr/share/elasticsearch/data": "rw" }) ) } From b23aee478da9ecdfbbd8d6d4fa0d359f242d651c Mon Sep 17 00:00:00 2001 From: Sam Rose Date: Tue, 25 Feb 2025 15:18:28 +0000 Subject: [PATCH 17/46] Fix plugin tests. --- packages/server/src/utilities/fileSystem/plugin.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/server/src/utilities/fileSystem/plugin.ts b/packages/server/src/utilities/fileSystem/plugin.ts index 1c62e9c1e9..15238637c1 100644 --- a/packages/server/src/utilities/fileSystem/plugin.ts +++ b/packages/server/src/utilities/fileSystem/plugin.ts @@ -14,7 +14,7 @@ export const getPluginMetadata = async ( let pkg: any let schema: any try { - pkg = JSON.parse(fs.readFileSync(join(path, "pkg.json"), "utf8")) + pkg = JSON.parse(fs.readFileSync(join(path, "package.json"), "utf8")) schema = JSON.parse(fs.readFileSync(join(path, "schema.json"), "utf8")) if (!pkg.name) { throw new Error("package.json is missing 'name'.") @@ -27,7 +27,8 @@ export const getPluginMetadata = async ( } } catch (err: any) { throw new Error( - `Unable to process schema.json/package.json in plugin. ${err.message}` + `Unable to process schema.json/package.json in plugin. ${err.message}`, + { cause: err } ) } From 3be31652524b9849e62b650cf1bd26ccf6769fa1 Mon Sep 17 00:00:00 2001 From: Sam Rose Date: Tue, 25 Feb 2025 15:22:32 +0000 Subject: [PATCH 18/46] Remove mocks from static.spec.ts --- .../src/api/routes/tests/static.spec.ts | 20 ++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/packages/server/src/api/routes/tests/static.spec.ts b/packages/server/src/api/routes/tests/static.spec.ts index 872085c382..6ec7b54a7f 100644 --- a/packages/server/src/api/routes/tests/static.spec.ts +++ b/packages/server/src/api/routes/tests/static.spec.ts @@ -1,11 +1,3 @@ -// Directly mock the AWS SDK -jest.mock("@aws-sdk/s3-request-presigner", () => ({ - getSignedUrl: jest.fn(() => { - return `http://example.com` - }), -})) -jest.mock("@aws-sdk/client-s3") - import { Datasource, SourceName } from "@budibase/types" import { setEnv } from "../../../environment" import { getRequest, getConfig, afterAll as _afterAll } from "./utilities" @@ -92,7 +84,17 @@ describe("/static", () => { .set(config.defaultHeaders()) .expect("Content-Type", /json/) .expect(200) - expect(res.body.signedUrl).toEqual("http://example.com") + + expect(res.body.signedUrl).toStartWith( + "https://foo.s3.eu-west-1.amazonaws.com/bar?" + ) + expect(res.body.signedUrl).toContain("X-Amz-Algorithm=AWS4-HMAC-SHA256") + expect(res.body.signedUrl).toContain("X-Amz-Credential=bb") + expect(res.body.signedUrl).toContain("X-Amz-Date=") + expect(res.body.signedUrl).toContain("X-Amz-Signature=") + expect(res.body.signedUrl).toContain("X-Amz-Expires=900") + expect(res.body.signedUrl).toContain("X-Amz-SignedHeaders=host") + expect(res.body.publicUrl).toEqual( `https://${bucket}.s3.eu-west-1.amazonaws.com/${key}` ) From 7a63890c1f94a13839a76370066c765b651afadd Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Tue, 25 Feb 2025 15:32:29 +0000 Subject: [PATCH 19/46] Adding zoom capabilities to QR-code reader to help with smaller qr codes. --- packages/client/manifest.json | 6 ++++++ packages/client/package.json | 2 +- .../client/src/components/app/forms/CodeScanner.svelte | 8 ++++++++ .../src/components/app/forms/CodeScannerField.svelte | 2 ++ yarn.lock | 8 ++++---- 5 files changed, 21 insertions(+), 5 deletions(-) diff --git a/packages/client/manifest.json b/packages/client/manifest.json index a2d29d3020..886ad49650 100644 --- a/packages/client/manifest.json +++ b/packages/client/manifest.json @@ -4492,6 +4492,12 @@ } ] }, + { + "type": "text", + "label": "Zoom level", + "key": "defaultZoom", + "defaultValue": "1" + }, { "type": "event", "label": "On change", diff --git a/packages/client/package.json b/packages/client/package.json index 72be403698..a7ea04fd0b 100644 --- a/packages/client/package.json +++ b/packages/client/package.json @@ -28,7 +28,7 @@ "apexcharts": "^3.48.0", "dayjs": "^1.10.8", "downloadjs": "1.4.7", - "html5-qrcode": "^2.2.1", + "html5-qrcode": "^2.3.8", "leaflet": "^1.7.1", "sanitize-html": "^2.13.0", "screenfull": "^6.0.1", diff --git a/packages/client/src/components/app/forms/CodeScanner.svelte b/packages/client/src/components/app/forms/CodeScanner.svelte index 008c0f5727..5c5d6ff73b 100644 --- a/packages/client/src/components/app/forms/CodeScanner.svelte +++ b/packages/client/src/components/app/forms/CodeScanner.svelte @@ -20,6 +20,7 @@ export let beepFrequency = 2637 export let customFrequency = 1046 export let preferredCamera = "environment" + export let defaultZoom = 1 export let validator const dispatch = createEventDispatcher() @@ -58,6 +59,13 @@ html5QrCode .start(cameraSetting, cameraConfig, onScanSuccess) .then(() => { + if (defaultZoom > 1) { + const cameraOptions = html5QrCode.getRunningTrackCameraCapabilities() + const zoom = cameraOptions.zoomFeature() + if (zoom.isSupported()) { + zoom.apply(defaultZoom) + } + } resolve({ initialised: true }) }) .catch(err => { diff --git a/packages/client/src/components/app/forms/CodeScannerField.svelte b/packages/client/src/components/app/forms/CodeScannerField.svelte index 7c9948554a..dd9e986804 100644 --- a/packages/client/src/components/app/forms/CodeScannerField.svelte +++ b/packages/client/src/components/app/forms/CodeScannerField.svelte @@ -17,6 +17,7 @@ export let beepFrequency export let customFrequency export let preferredCamera + export let defaultZoom export let helpText = null let fieldState @@ -56,6 +57,7 @@ {beepFrequency} {customFrequency} {preferredCamera} + {defaultZoom} validator={fieldState.validator} /> {/if} diff --git a/yarn.lock b/yarn.lock index ceae41458c..64810291c4 100644 --- a/yarn.lock +++ b/yarn.lock @@ -12768,10 +12768,10 @@ html-tag@^2.0.0: is-self-closing "^1.0.1" kind-of "^6.0.0" -html5-qrcode@^2.2.1: - version "2.3.7" - resolved "https://registry.yarnpkg.com/html5-qrcode/-/html5-qrcode-2.3.7.tgz#09ed2ca7473a47bd551088c15fcfcb7cb409a5be" - integrity sha512-Jmlok9Ynm49hgVXkdupWryf8o430proIFoQsRl1LmTg4Rq461W72omylR9yw9tsEMtswMEw3wacUM5y0agOBQA== +html5-qrcode@^2.3.8: + version "2.3.8" + resolved "https://registry.yarnpkg.com/html5-qrcode/-/html5-qrcode-2.3.8.tgz#0b0cdf7a9926cfd4be530e13a51db47592adfa0d" + integrity sha512-jsr4vafJhwoLVEDW3n1KvPnCCXWaQfRng0/EEYk1vNcQGcG/htAdhJX0be8YyqMoSz7+hZvOZSTAepsabiuhiQ== htmlparser2@^8.0.0: version "8.0.1" From a1670c309f53a95f3e890cdfd6298c3db08ab778 Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Tue, 25 Feb 2025 15:42:50 +0000 Subject: [PATCH 20/46] Linting. --- packages/client/src/components/app/forms/CodeScanner.svelte | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/client/src/components/app/forms/CodeScanner.svelte b/packages/client/src/components/app/forms/CodeScanner.svelte index 5c5d6ff73b..1a046d7168 100644 --- a/packages/client/src/components/app/forms/CodeScanner.svelte +++ b/packages/client/src/components/app/forms/CodeScanner.svelte @@ -60,7 +60,8 @@ .start(cameraSetting, cameraConfig, onScanSuccess) .then(() => { if (defaultZoom > 1) { - const cameraOptions = html5QrCode.getRunningTrackCameraCapabilities() + const cameraOptions = + html5QrCode.getRunningTrackCameraCapabilities() const zoom = cameraOptions.zoomFeature() if (zoom.isSupported()) { zoom.apply(defaultZoom) From eeb6f42681622cde92f294e81a21f9c69d3753b5 Mon Sep 17 00:00:00 2001 From: Dean Date: Tue, 25 Feb 2025 15:53:55 +0000 Subject: [PATCH 21/46] Fix for autocompletion evaluation in the builder --- .../builder/src/components/common/bindings/BindingPanel.svelte | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/builder/src/components/common/bindings/BindingPanel.svelte b/packages/builder/src/components/common/bindings/BindingPanel.svelte index 9ebbc91309..3715719565 100644 --- a/packages/builder/src/components/common/bindings/BindingPanel.svelte +++ b/packages/builder/src/components/common/bindings/BindingPanel.svelte @@ -90,7 +90,7 @@ $: requestEval(runtimeExpression, context, snippets) $: bindingHelpers = new BindingHelpers(getCaretPosition, insertAtPos) - $: bindingOptions = bindingsToCompletions(bindings, editorMode) + $: bindingOptions = bindingsToCompletions(enrichedBindings, editorMode) $: helperOptions = allowHelpers ? getHelperCompletions(editorMode) : [] $: snippetsOptions = usingJS && useSnippets && snippets?.length ? snippets : [] From daf317b0a72c96eb815e473ea8d283c63586def9 Mon Sep 17 00:00:00 2001 From: Budibase Staging Release Bot <> Date: Wed, 26 Feb 2025 13:19:59 +0000 Subject: [PATCH 22/46] Bump version to 3.4.18 --- lerna.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lerna.json b/lerna.json index 8ea860e3c4..055b8b5ca8 100644 --- a/lerna.json +++ b/lerna.json @@ -1,6 +1,6 @@ { "$schema": "node_modules/lerna/schemas/lerna-schema.json", - "version": "3.4.17", + "version": "3.4.18", "npmClient": "yarn", "concurrency": 20, "command": { From eefcfb3c0f22e7d20d58a02ee782262472b13e96 Mon Sep 17 00:00:00 2001 From: Christos Alexiou Date: Wed, 26 Feb 2025 15:43:26 +0200 Subject: [PATCH 23/46] Update before installing --- hosting/single/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hosting/single/Dockerfile b/hosting/single/Dockerfile index 1f449e7376..75b1a12d12 100644 --- a/hosting/single/Dockerfile +++ b/hosting/single/Dockerfile @@ -92,7 +92,7 @@ COPY hosting/single/ssh/sshd_config /etc/ COPY hosting/single/ssh/ssh_setup.sh /tmp # setup letsencrypt certificate -RUN apt-get install -y certbot python3-certbot-nginx +RUN apt-get update && apt-get install -y certbot python3-certbot-nginx COPY hosting/letsencrypt /app/letsencrypt RUN chmod +x /app/letsencrypt/certificate-request.sh /app/letsencrypt/certificate-renew.sh From 7b9cc6eea4263a2f4c716121230ae59864461d95 Mon Sep 17 00:00:00 2001 From: Budibase Staging Release Bot <> Date: Wed, 26 Feb 2025 14:11:40 +0000 Subject: [PATCH 24/46] Bump version to 3.4.19 --- lerna.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lerna.json b/lerna.json index 055b8b5ca8..03be6e46bc 100644 --- a/lerna.json +++ b/lerna.json @@ -1,6 +1,6 @@ { "$schema": "node_modules/lerna/schemas/lerna-schema.json", - "version": "3.4.18", + "version": "3.4.19", "npmClient": "yarn", "concurrency": 20, "command": { From 606c4475ad8f6aed56b64b14c7fa017cc0e7db39 Mon Sep 17 00:00:00 2001 From: Sam Rose Date: Wed, 26 Feb 2025 14:29:39 +0000 Subject: [PATCH 25/46] Revert "Improve types around `nodemailer`" --- .../tests/steps/sendSmtpEmail.spec.ts | 20 +++++----- .../server/src/utilities/workerRequests.ts | 40 ++++++++----------- packages/types/package.json | 1 - packages/types/src/api/web/global/email.ts | 9 ++--- .../documents/app/automation/automation.ts | 8 ++-- packages/worker/package.json | 1 - .../src/api/controllers/global/email.ts | 7 +--- packages/worker/src/utilities/email.ts | 7 ++-- yarn.lock | 13 ++---- 9 files changed, 42 insertions(+), 64 deletions(-) diff --git a/packages/server/src/automations/tests/steps/sendSmtpEmail.spec.ts b/packages/server/src/automations/tests/steps/sendSmtpEmail.spec.ts index 7aff612a97..7452239dfa 100644 --- a/packages/server/src/automations/tests/steps/sendSmtpEmail.spec.ts +++ b/packages/server/src/automations/tests/steps/sendSmtpEmail.spec.ts @@ -1,4 +1,3 @@ -import { SendEmailResponse } from "@budibase/types" import TestConfiguration from "../../../tests/utilities/TestConfiguration" import * as workerRequests from "../../../utilities/workerRequests" @@ -6,18 +5,17 @@ jest.mock("../../../utilities/workerRequests", () => ({ sendSmtpEmail: jest.fn(), })) -function generateResponse(to: string, from: string): SendEmailResponse { +function generateResponse(to: string, from: string) { return { - message: `Email sent to ${to}.`, - accepted: [to], - envelope: { - from: from, - to: [to], + success: true, + response: { + accepted: [to], + envelope: { + from: from, + to: [to], + }, + message: `Email sent to ${to}.`, }, - messageId: "messageId", - pending: [], - rejected: [], - response: "response", } } diff --git a/packages/server/src/utilities/workerRequests.ts b/packages/server/src/utilities/workerRequests.ts index dd1493b82f..0f487d9f31 100644 --- a/packages/server/src/utilities/workerRequests.ts +++ b/packages/server/src/utilities/workerRequests.ts @@ -8,15 +8,7 @@ import { logging, env as coreEnv, } from "@budibase/backend-core" -import { - Ctx, - User, - EmailInvite, - EmailAttachment, - SendEmailResponse, - SendEmailRequest, - EmailTemplatePurpose, -} from "@budibase/types" +import { Ctx, User, EmailInvite, EmailAttachment } from "@budibase/types" interface Request { ctx?: Ctx @@ -118,23 +110,25 @@ export async function sendSmtpEmail({ invite?: EmailInvite }) { // tenant ID will be set in header - const request: SendEmailRequest = { - email: to, - from, - contents, - subject, - cc, - bcc, - purpose: EmailTemplatePurpose.CUSTOM, - automation, - invite, - attachments, - } const response = await fetch( checkSlashesInUrl(env.WORKER_URL + `/api/global/email/send`), - createRequest({ method: "POST", body: request }) + createRequest({ + method: "POST", + body: { + email: to, + from, + contents, + subject, + cc, + bcc, + purpose: "custom", + automation, + invite, + attachments, + }, + }) ) - return (await checkResponse(response, "send email")) as SendEmailResponse + return checkResponse(response, "send email") } export async function removeAppFromUserRoles(ctx: Ctx, appId: string) { diff --git a/packages/types/package.json b/packages/types/package.json index a6e08ab84c..ee3c059bc9 100644 --- a/packages/types/package.json +++ b/packages/types/package.json @@ -17,7 +17,6 @@ "@budibase/nano": "10.1.5", "@types/json-schema": "^7.0.15", "@types/koa": "2.13.4", - "@types/nodemailer": "^6.4.17", "@types/redlock": "4.0.7", "koa-useragent": "^4.1.0", "rimraf": "3.0.2", diff --git a/packages/types/src/api/web/global/email.ts b/packages/types/src/api/web/global/email.ts index 3d2e007231..a0ca0e8485 100644 --- a/packages/types/src/api/web/global/email.ts +++ b/packages/types/src/api/web/global/email.ts @@ -1,5 +1,4 @@ import { EmailAttachment, EmailInvite } from "../../../documents" -import SMTPTransport from "nodemailer/lib/smtp-transport" export enum EmailTemplatePurpose { CORE = "core", @@ -13,17 +12,17 @@ export enum EmailTemplatePurpose { export interface SendEmailRequest { workspaceId?: string email: string - userId?: string + userId: string purpose: EmailTemplatePurpose contents?: string from?: string subject: string - cc?: string - bcc?: string + cc?: boolean + bcc?: boolean automation?: boolean invite?: EmailInvite attachments?: EmailAttachment[] } -export interface SendEmailResponse extends SMTPTransport.SentMessageInfo { +export interface SendEmailResponse extends Record { message: string } diff --git a/packages/types/src/documents/app/automation/automation.ts b/packages/types/src/documents/app/automation/automation.ts index cfe2ba5147..d5ef35d059 100644 --- a/packages/types/src/documents/app/automation/automation.ts +++ b/packages/types/src/documents/app/automation/automation.ts @@ -1,10 +1,10 @@ import { Document } from "../../document" import { User } from "../../global" +import { ReadStream } from "fs" import { Row } from "../row" import { Table } from "../table" import { AutomationStep, AutomationTrigger } from "./schema" import { ContextEmitter } from "../../../sdk" -import { Readable } from "stream" export enum AutomationIOType { OBJECT = "object", @@ -108,8 +108,8 @@ export interface SendEmailOpts { subject: string // info Pass in a structure of information to be stored alongside the invitation. info?: any - cc?: string - bcc?: string + cc?: boolean + bcc?: boolean automation?: boolean invite?: EmailInvite attachments?: EmailAttachment[] @@ -269,7 +269,7 @@ export type AutomationAttachment = { export type AutomationAttachmentContent = { filename: string - content: Readable + content: ReadStream | NodeJS.ReadableStream } export type BucketedContent = AutomationAttachmentContent & { diff --git a/packages/worker/package.json b/packages/worker/package.json index edaab50d78..28728272ca 100644 --- a/packages/worker/package.json +++ b/packages/worker/package.json @@ -86,7 +86,6 @@ "@types/koa__router": "12.0.4", "@types/lodash": "4.14.200", "@types/node-fetch": "2.6.4", - "@types/nodemailer": "^6.4.17", "@types/server-destroy": "1.0.1", "@types/supertest": "2.0.14", "@types/uuid": "8.3.4", diff --git a/packages/worker/src/api/controllers/global/email.ts b/packages/worker/src/api/controllers/global/email.ts index ed2d9b5125..ad0fc3fa32 100644 --- a/packages/worker/src/api/controllers/global/email.ts +++ b/packages/worker/src/api/controllers/global/email.ts @@ -24,13 +24,10 @@ export async function sendEmail( invite, attachments, } = ctx.request.body - let user: User | undefined = undefined + let user: any if (userId) { const db = tenancy.getGlobalDB() - user = await db.tryGet(userId) - } - if (!user) { - ctx.throw(404, "User not found.") + user = await db.get(userId) } const response = await sendEmailFn(email, purpose, { workspaceId, diff --git a/packages/worker/src/utilities/email.ts b/packages/worker/src/utilities/email.ts index a2b9c3bfc2..fa9dd7a6fa 100644 --- a/packages/worker/src/utilities/email.ts +++ b/packages/worker/src/utilities/email.ts @@ -13,8 +13,7 @@ import { configs, cache, objectStore } from "@budibase/backend-core" import ical from "ical-generator" import _ from "lodash" -import nodemailer from "nodemailer" -import SMTPTransport from "nodemailer/lib/smtp-transport" +const nodemailer = require("nodemailer") const TEST_MODE = env.ENABLE_EMAIL_TEST_MODE && env.isDev() const TYPE = TemplateType.EMAIL @@ -27,7 +26,7 @@ const FULL_EMAIL_PURPOSES = [ ] function createSMTPTransport(config?: SMTPInnerConfig) { - let options: SMTPTransport.Options + let options: any let secure = config?.secure // default it if not specified if (secure == null) { @@ -162,7 +161,7 @@ export async function sendEmail( const code = await getLinkCode(purpose, email, opts.user, opts?.info) let context = await getSettingsTemplateContext(purpose, code) - let message: Parameters[0] = { + let message: any = { from: opts?.from || config?.from, html: await buildEmail(purpose, email, context, { user: opts?.user, diff --git a/yarn.lock b/yarn.lock index 445e0abc18..48eaaf4ecd 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2785,9 +2785,9 @@ through2 "^2.0.0" "@budibase/pro@npm:@budibase/pro@latest": - version "3.4.16" - resolved "https://registry.yarnpkg.com/@budibase/pro/-/pro-3.4.16.tgz#c482a400e27b7e89ca73092c4c81bdeac1d24581" - integrity sha512-8ECnqOh9jQ10KlQEwmKPFcoVGE+2gGgSybj+vbshwDp1zAW76doyMR2DMNjEatNpWVnpoMnTkDWtE9aqQ5v0vQ== + version "3.4.12" + resolved "https://registry.yarnpkg.com/@budibase/pro/-/pro-3.4.12.tgz#60e630944de4e2de970a04179d8f0f57d48ce75e" + integrity sha512-msUBmcWxRDg+ugjZvd27XudERQqtQRdiARsO8MaDVTcp5ejIXgshEIVVshHOCj3hcbRblw9pXvBIMI53iTMUsA== dependencies: "@anthropic-ai/sdk" "^0.27.3" "@budibase/backend-core" "*" @@ -6775,13 +6775,6 @@ dependencies: undici-types "~6.19.2" -"@types/nodemailer@^6.4.17": - version "6.4.17" - resolved "https://registry.yarnpkg.com/@types/nodemailer/-/nodemailer-6.4.17.tgz#5c82a42aee16a3dd6ea31446a1bd6a447f1ac1a4" - integrity sha512-I9CCaIp6DTldEg7vyUTZi8+9Vo0hi1/T8gv3C89yk1rSAAzoKQ8H8ki/jBYJSFoH/BisgLP8tkZMlQ91CIquww== - dependencies: - "@types/node" "*" - "@types/normalize-package-data@^2.4.0": version "2.4.1" resolved "https://registry.yarnpkg.com/@types/normalize-package-data/-/normalize-package-data-2.4.1.tgz#d3357479a0fdfdd5907fe67e17e0a85c906e1301" From d6d32ceaadde4597554f786d6e98317df2674ddf Mon Sep 17 00:00:00 2001 From: Budibase Staging Release Bot <> Date: Wed, 26 Feb 2025 14:49:09 +0000 Subject: [PATCH 26/46] Bump version to 3.4.20 --- lerna.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lerna.json b/lerna.json index 03be6e46bc..b391c8e05c 100644 --- a/lerna.json +++ b/lerna.json @@ -1,6 +1,6 @@ { "$schema": "node_modules/lerna/schemas/lerna-schema.json", - "version": "3.4.19", + "version": "3.4.20", "npmClient": "yarn", "concurrency": 20, "command": { From 33f61a8da7e37f0759435a408e43515c7d9e6923 Mon Sep 17 00:00:00 2001 From: Sam Rose Date: Wed, 26 Feb 2025 14:53:36 +0000 Subject: [PATCH 27/46] Revert "Revert "Improve types around `nodemailer`"" --- .../tests/steps/sendSmtpEmail.spec.ts | 20 +++++----- .../server/src/utilities/workerRequests.ts | 40 +++++++++++-------- packages/types/package.json | 1 + packages/types/src/api/web/global/email.ts | 9 +++-- .../documents/app/automation/automation.ts | 8 ++-- packages/worker/package.json | 1 + .../src/api/controllers/global/email.ts | 7 +++- packages/worker/src/utilities/email.ts | 7 ++-- yarn.lock | 13 ++++-- 9 files changed, 64 insertions(+), 42 deletions(-) diff --git a/packages/server/src/automations/tests/steps/sendSmtpEmail.spec.ts b/packages/server/src/automations/tests/steps/sendSmtpEmail.spec.ts index 7452239dfa..7aff612a97 100644 --- a/packages/server/src/automations/tests/steps/sendSmtpEmail.spec.ts +++ b/packages/server/src/automations/tests/steps/sendSmtpEmail.spec.ts @@ -1,3 +1,4 @@ +import { SendEmailResponse } from "@budibase/types" import TestConfiguration from "../../../tests/utilities/TestConfiguration" import * as workerRequests from "../../../utilities/workerRequests" @@ -5,17 +6,18 @@ jest.mock("../../../utilities/workerRequests", () => ({ sendSmtpEmail: jest.fn(), })) -function generateResponse(to: string, from: string) { +function generateResponse(to: string, from: string): SendEmailResponse { return { - success: true, - response: { - accepted: [to], - envelope: { - from: from, - to: [to], - }, - message: `Email sent to ${to}.`, + message: `Email sent to ${to}.`, + accepted: [to], + envelope: { + from: from, + to: [to], }, + messageId: "messageId", + pending: [], + rejected: [], + response: "response", } } diff --git a/packages/server/src/utilities/workerRequests.ts b/packages/server/src/utilities/workerRequests.ts index 0f487d9f31..dd1493b82f 100644 --- a/packages/server/src/utilities/workerRequests.ts +++ b/packages/server/src/utilities/workerRequests.ts @@ -8,7 +8,15 @@ import { logging, env as coreEnv, } from "@budibase/backend-core" -import { Ctx, User, EmailInvite, EmailAttachment } from "@budibase/types" +import { + Ctx, + User, + EmailInvite, + EmailAttachment, + SendEmailResponse, + SendEmailRequest, + EmailTemplatePurpose, +} from "@budibase/types" interface Request { ctx?: Ctx @@ -110,25 +118,23 @@ export async function sendSmtpEmail({ invite?: EmailInvite }) { // tenant ID will be set in header + const request: SendEmailRequest = { + email: to, + from, + contents, + subject, + cc, + bcc, + purpose: EmailTemplatePurpose.CUSTOM, + automation, + invite, + attachments, + } const response = await fetch( checkSlashesInUrl(env.WORKER_URL + `/api/global/email/send`), - createRequest({ - method: "POST", - body: { - email: to, - from, - contents, - subject, - cc, - bcc, - purpose: "custom", - automation, - invite, - attachments, - }, - }) + createRequest({ method: "POST", body: request }) ) - return checkResponse(response, "send email") + return (await checkResponse(response, "send email")) as SendEmailResponse } export async function removeAppFromUserRoles(ctx: Ctx, appId: string) { diff --git a/packages/types/package.json b/packages/types/package.json index ee3c059bc9..a6e08ab84c 100644 --- a/packages/types/package.json +++ b/packages/types/package.json @@ -17,6 +17,7 @@ "@budibase/nano": "10.1.5", "@types/json-schema": "^7.0.15", "@types/koa": "2.13.4", + "@types/nodemailer": "^6.4.17", "@types/redlock": "4.0.7", "koa-useragent": "^4.1.0", "rimraf": "3.0.2", diff --git a/packages/types/src/api/web/global/email.ts b/packages/types/src/api/web/global/email.ts index a0ca0e8485..3d2e007231 100644 --- a/packages/types/src/api/web/global/email.ts +++ b/packages/types/src/api/web/global/email.ts @@ -1,4 +1,5 @@ import { EmailAttachment, EmailInvite } from "../../../documents" +import SMTPTransport from "nodemailer/lib/smtp-transport" export enum EmailTemplatePurpose { CORE = "core", @@ -12,17 +13,17 @@ export enum EmailTemplatePurpose { export interface SendEmailRequest { workspaceId?: string email: string - userId: string + userId?: string purpose: EmailTemplatePurpose contents?: string from?: string subject: string - cc?: boolean - bcc?: boolean + cc?: string + bcc?: string automation?: boolean invite?: EmailInvite attachments?: EmailAttachment[] } -export interface SendEmailResponse extends Record { +export interface SendEmailResponse extends SMTPTransport.SentMessageInfo { message: string } diff --git a/packages/types/src/documents/app/automation/automation.ts b/packages/types/src/documents/app/automation/automation.ts index d5ef35d059..cfe2ba5147 100644 --- a/packages/types/src/documents/app/automation/automation.ts +++ b/packages/types/src/documents/app/automation/automation.ts @@ -1,10 +1,10 @@ import { Document } from "../../document" import { User } from "../../global" -import { ReadStream } from "fs" import { Row } from "../row" import { Table } from "../table" import { AutomationStep, AutomationTrigger } from "./schema" import { ContextEmitter } from "../../../sdk" +import { Readable } from "stream" export enum AutomationIOType { OBJECT = "object", @@ -108,8 +108,8 @@ export interface SendEmailOpts { subject: string // info Pass in a structure of information to be stored alongside the invitation. info?: any - cc?: boolean - bcc?: boolean + cc?: string + bcc?: string automation?: boolean invite?: EmailInvite attachments?: EmailAttachment[] @@ -269,7 +269,7 @@ export type AutomationAttachment = { export type AutomationAttachmentContent = { filename: string - content: ReadStream | NodeJS.ReadableStream + content: Readable } export type BucketedContent = AutomationAttachmentContent & { diff --git a/packages/worker/package.json b/packages/worker/package.json index 28728272ca..edaab50d78 100644 --- a/packages/worker/package.json +++ b/packages/worker/package.json @@ -86,6 +86,7 @@ "@types/koa__router": "12.0.4", "@types/lodash": "4.14.200", "@types/node-fetch": "2.6.4", + "@types/nodemailer": "^6.4.17", "@types/server-destroy": "1.0.1", "@types/supertest": "2.0.14", "@types/uuid": "8.3.4", diff --git a/packages/worker/src/api/controllers/global/email.ts b/packages/worker/src/api/controllers/global/email.ts index ad0fc3fa32..ed2d9b5125 100644 --- a/packages/worker/src/api/controllers/global/email.ts +++ b/packages/worker/src/api/controllers/global/email.ts @@ -24,10 +24,13 @@ export async function sendEmail( invite, attachments, } = ctx.request.body - let user: any + let user: User | undefined = undefined if (userId) { const db = tenancy.getGlobalDB() - user = await db.get(userId) + user = await db.tryGet(userId) + } + if (!user) { + ctx.throw(404, "User not found.") } const response = await sendEmailFn(email, purpose, { workspaceId, diff --git a/packages/worker/src/utilities/email.ts b/packages/worker/src/utilities/email.ts index fa9dd7a6fa..a2b9c3bfc2 100644 --- a/packages/worker/src/utilities/email.ts +++ b/packages/worker/src/utilities/email.ts @@ -13,7 +13,8 @@ import { configs, cache, objectStore } from "@budibase/backend-core" import ical from "ical-generator" import _ from "lodash" -const nodemailer = require("nodemailer") +import nodemailer from "nodemailer" +import SMTPTransport from "nodemailer/lib/smtp-transport" const TEST_MODE = env.ENABLE_EMAIL_TEST_MODE && env.isDev() const TYPE = TemplateType.EMAIL @@ -26,7 +27,7 @@ const FULL_EMAIL_PURPOSES = [ ] function createSMTPTransport(config?: SMTPInnerConfig) { - let options: any + let options: SMTPTransport.Options let secure = config?.secure // default it if not specified if (secure == null) { @@ -161,7 +162,7 @@ export async function sendEmail( const code = await getLinkCode(purpose, email, opts.user, opts?.info) let context = await getSettingsTemplateContext(purpose, code) - let message: any = { + let message: Parameters[0] = { from: opts?.from || config?.from, html: await buildEmail(purpose, email, context, { user: opts?.user, diff --git a/yarn.lock b/yarn.lock index 48eaaf4ecd..445e0abc18 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2785,9 +2785,9 @@ through2 "^2.0.0" "@budibase/pro@npm:@budibase/pro@latest": - version "3.4.12" - resolved "https://registry.yarnpkg.com/@budibase/pro/-/pro-3.4.12.tgz#60e630944de4e2de970a04179d8f0f57d48ce75e" - integrity sha512-msUBmcWxRDg+ugjZvd27XudERQqtQRdiARsO8MaDVTcp5ejIXgshEIVVshHOCj3hcbRblw9pXvBIMI53iTMUsA== + version "3.4.16" + resolved "https://registry.yarnpkg.com/@budibase/pro/-/pro-3.4.16.tgz#c482a400e27b7e89ca73092c4c81bdeac1d24581" + integrity sha512-8ECnqOh9jQ10KlQEwmKPFcoVGE+2gGgSybj+vbshwDp1zAW76doyMR2DMNjEatNpWVnpoMnTkDWtE9aqQ5v0vQ== dependencies: "@anthropic-ai/sdk" "^0.27.3" "@budibase/backend-core" "*" @@ -6775,6 +6775,13 @@ dependencies: undici-types "~6.19.2" +"@types/nodemailer@^6.4.17": + version "6.4.17" + resolved "https://registry.yarnpkg.com/@types/nodemailer/-/nodemailer-6.4.17.tgz#5c82a42aee16a3dd6ea31446a1bd6a447f1ac1a4" + integrity sha512-I9CCaIp6DTldEg7vyUTZi8+9Vo0hi1/T8gv3C89yk1rSAAzoKQ8H8ki/jBYJSFoH/BisgLP8tkZMlQ91CIquww== + dependencies: + "@types/node" "*" + "@types/normalize-package-data@^2.4.0": version "2.4.1" resolved "https://registry.yarnpkg.com/@types/normalize-package-data/-/normalize-package-data-2.4.1.tgz#d3357479a0fdfdd5907fe67e17e0a85c906e1301" From 8dc635b894dab6a720019ba6857a13f9ca5ad9e8 Mon Sep 17 00:00:00 2001 From: Sam Rose Date: Wed, 26 Feb 2025 14:56:11 +0000 Subject: [PATCH 28/46] Attempt to fix the user check problem. --- .../documents/app/automation/automation.ts | 2 +- .../src/api/controllers/global/email.ts | 6 ++-- packages/worker/src/utilities/email.ts | 29 ++++++++----------- 3 files changed, 16 insertions(+), 21 deletions(-) diff --git a/packages/types/src/documents/app/automation/automation.ts b/packages/types/src/documents/app/automation/automation.ts index cfe2ba5147..dd85e1f3aa 100644 --- a/packages/types/src/documents/app/automation/automation.ts +++ b/packages/types/src/documents/app/automation/automation.ts @@ -99,7 +99,7 @@ export interface SendEmailOpts { // workspaceId If finer grain controls being used then this will lookup config for workspace. workspaceId?: string // user If sending to an existing user the object can be provided, this is used in the context. - user: User + user?: User // from If sending from an address that is not what is configured in the SMTP config. from?: string // contents If sending a custom email then can supply contents which will be added to it. diff --git a/packages/worker/src/api/controllers/global/email.ts b/packages/worker/src/api/controllers/global/email.ts index ed2d9b5125..674fe5955f 100644 --- a/packages/worker/src/api/controllers/global/email.ts +++ b/packages/worker/src/api/controllers/global/email.ts @@ -28,9 +28,9 @@ export async function sendEmail( if (userId) { const db = tenancy.getGlobalDB() user = await db.tryGet(userId) - } - if (!user) { - ctx.throw(404, "User not found.") + if (!user) { + ctx.throw(404, "User not found.") + } } const response = await sendEmailFn(email, purpose, { workspaceId, diff --git a/packages/worker/src/utilities/email.ts b/packages/worker/src/utilities/email.ts index a2b9c3bfc2..d3fac15860 100644 --- a/packages/worker/src/utilities/email.ts +++ b/packages/worker/src/utilities/email.ts @@ -60,22 +60,6 @@ function createSMTPTransport(config?: SMTPInnerConfig) { return nodemailer.createTransport(options) } -async function getLinkCode( - purpose: EmailTemplatePurpose, - email: string, - user: User, - info: any = null -) { - switch (purpose) { - case EmailTemplatePurpose.PASSWORD_RECOVERY: - return cache.passwordReset.createCode(user._id!, info) - case EmailTemplatePurpose.INVITATION: - return cache.invite.createCode(email, info) - default: - return null - } -} - /** * Builds an email using handlebars and the templates found in the system (default or otherwise). * @param purpose the purpose of the email being built, e.g. invitation, password reset. @@ -159,7 +143,18 @@ export async function sendEmail( } const transport = createSMTPTransport(config) // if there is a link code needed this will retrieve it - const code = await getLinkCode(purpose, email, opts.user, opts?.info) + let code: string | null = null + switch (purpose) { + case EmailTemplatePurpose.PASSWORD_RECOVERY: + if (!opts.user || !opts.user._id) { + throw "User must be provided for password recovery." + } + code = await cache.passwordReset.createCode(opts.user._id, opts.info) + break + case EmailTemplatePurpose.INVITATION: + code = await cache.invite.createCode(email, opts.info) + break + } let context = await getSettingsTemplateContext(purpose, code) let message: Parameters[0] = { From 06d00d69b2660ed98648161785453ef93cbea83c Mon Sep 17 00:00:00 2001 From: Sam Rose Date: Wed, 26 Feb 2025 15:23:49 +0000 Subject: [PATCH 29/46] Debug testcontainers. --- .github/workflows/budibase_ci.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/budibase_ci.yml b/.github/workflows/budibase_ci.yml index 6a9aa3e8d0..97cfe88804 100644 --- a/.github/workflows/budibase_ci.yml +++ b/.github/workflows/budibase_ci.yml @@ -235,6 +235,7 @@ jobs: - name: Test server env: DATASOURCE: ${{ matrix.datasource }} + DEBUG: testcontainers* run: | if ${{ env.ONLY_AFFECTED_TASKS }}; then AFFECTED=$(yarn --silent nx show projects --affected -t test --base=${{ env.NX_BASE_BRANCH }} -p @budibase/server) From f604aba7ba278915e65329858ad39607510c5ebe Mon Sep 17 00:00:00 2001 From: Sam Rose Date: Wed, 26 Feb 2025 15:41:09 +0000 Subject: [PATCH 30/46] Try ubuntu-latest --- .github/workflows/budibase_ci.yml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/.github/workflows/budibase_ci.yml b/.github/workflows/budibase_ci.yml index 97cfe88804..af3950a439 100644 --- a/.github/workflows/budibase_ci.yml +++ b/.github/workflows/budibase_ci.yml @@ -30,7 +30,7 @@ env: jobs: lint: - runs-on: ubuntu-22.04 + runs-on: ubuntu-latest steps: - name: Checkout repo uses: actions/checkout@v4 @@ -47,7 +47,7 @@ jobs: - run: yarn lint build: - runs-on: ubuntu-22.04 + runs-on: ubuntu-latest steps: - name: Checkout repo uses: actions/checkout@v4 @@ -76,7 +76,7 @@ jobs: fi helm-lint: - runs-on: ubuntu-22.04 + runs-on: ubuntu-latest steps: - name: Checkout repo uses: actions/checkout@v4 @@ -88,7 +88,7 @@ jobs: - run: cd charts/budibase && helm lint . test-libraries: - runs-on: ubuntu-22.04 + runs-on: ubuntu-latest steps: - name: Checkout repo uses: actions/checkout@v4 @@ -122,7 +122,7 @@ jobs: fi test-worker: - runs-on: ubuntu-22.04 + runs-on: ubuntu-latest steps: - name: Checkout repo uses: actions/checkout@v4 @@ -151,7 +151,7 @@ jobs: yarn test --verbose --reporters=default --reporters=github-actions test-server: - runs-on: ubuntu-22.04 + runs-on: ubuntu-latest strategy: matrix: datasource: @@ -254,7 +254,7 @@ jobs: yarn test --filter $FILTER --verbose --reporters=default --reporters=github-actions check-pro-submodule: - runs-on: ubuntu-22.04 + runs-on: ubuntu-latest if: inputs.run_as_oss != true && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'Budibase/budibase') steps: - name: Checkout repo and submodules @@ -313,7 +313,7 @@ jobs: fi check-lockfile: - runs-on: ubuntu-22.04 + runs-on: ubuntu-latest if: inputs.run_as_oss != true && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'Budibase/budibase') steps: - name: Checkout repo From 9076d847c19cb9f855101e38213e213c7e402738 Mon Sep 17 00:00:00 2001 From: Sam Rose Date: Wed, 26 Feb 2025 15:48:26 +0000 Subject: [PATCH 31/46] Update to mssql 2022 to see if that helps. --- .github/workflows/budibase_ci.yml | 16 ++++++++-------- packages/server/datasource-sha.env | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/.github/workflows/budibase_ci.yml b/.github/workflows/budibase_ci.yml index af3950a439..91c32359d2 100644 --- a/.github/workflows/budibase_ci.yml +++ b/.github/workflows/budibase_ci.yml @@ -30,7 +30,7 @@ env: jobs: lint: - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 steps: - name: Checkout repo uses: actions/checkout@v4 @@ -47,7 +47,7 @@ jobs: - run: yarn lint build: - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 steps: - name: Checkout repo uses: actions/checkout@v4 @@ -76,7 +76,7 @@ jobs: fi helm-lint: - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 steps: - name: Checkout repo uses: actions/checkout@v4 @@ -88,7 +88,7 @@ jobs: - run: cd charts/budibase && helm lint . test-libraries: - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 steps: - name: Checkout repo uses: actions/checkout@v4 @@ -122,7 +122,7 @@ jobs: fi test-worker: - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 steps: - name: Checkout repo uses: actions/checkout@v4 @@ -151,7 +151,7 @@ jobs: yarn test --verbose --reporters=default --reporters=github-actions test-server: - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 strategy: matrix: datasource: @@ -254,7 +254,7 @@ jobs: yarn test --filter $FILTER --verbose --reporters=default --reporters=github-actions check-pro-submodule: - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 if: inputs.run_as_oss != true && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'Budibase/budibase') steps: - name: Checkout repo and submodules @@ -313,7 +313,7 @@ jobs: fi check-lockfile: - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 if: inputs.run_as_oss != true && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'Budibase/budibase') steps: - name: Checkout repo diff --git a/packages/server/datasource-sha.env b/packages/server/datasource-sha.env index 383fb191f4..69750793ce 100644 --- a/packages/server/datasource-sha.env +++ b/packages/server/datasource-sha.env @@ -1,4 +1,4 @@ -MSSQL_SHA=sha256:3b913841850a4d57fcfcb798be06acc88ea0f2acc5418bc0c140a43e91c4a545 +MSSQL_SHA=sha256:d252932ef839c24c61c1139cc98f69c85ca774fa7c6bfaaa0015b7eb02b9dc87 MYSQL_SHA=sha256:9de9d54fecee6253130e65154b930978b1fcc336bcc86dfd06e89b72a2588ebe POSTGRES_SHA=sha256:bd0d8e485d1aca439d39e5ea99b931160bd28d862e74c786f7508e9d0053090e MONGODB_SHA=sha256:afa36bca12295b5f9dae68a493c706113922bdab520e901bd5d6c9d7247a1d8d From 82e32b3db84fa2562c332d4190476c8f13bea8b6 Mon Sep 17 00:00:00 2001 From: Sam Rose Date: Wed, 26 Feb 2025 15:56:32 +0000 Subject: [PATCH 32/46] Fix healthcheck. --- packages/server/src/integrations/tests/utils/mssql.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/server/src/integrations/tests/utils/mssql.ts b/packages/server/src/integrations/tests/utils/mssql.ts index 548631a987..d84fb5d12d 100644 --- a/packages/server/src/integrations/tests/utils/mssql.ts +++ b/packages/server/src/integrations/tests/utils/mssql.ts @@ -23,7 +23,7 @@ export async function getDatasource(): Promise { }) .withWaitStrategy( Wait.forSuccessfulCommand( - "/opt/mssql-tools/bin/sqlcmd -S localhost -U sa -P Password_123 -q 'SELECT 1'" + "/opt/mssql-tools18/bin/sqlcmd -S localhost -U sa -P Password_123 -q 'SELECT 1'" ).withStartupTimeout(20000) ) ) From a684c9f0490d20f5685201e10fcd903c64116170 Mon Sep 17 00:00:00 2001 From: Sam Rose Date: Wed, 26 Feb 2025 16:09:14 +0000 Subject: [PATCH 33/46] Fix self-signed cert error in tests. --- .github/workflows/budibase_ci.yml | 1 - packages/server/src/integrations/tests/utils/mssql.ts | 5 +++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/budibase_ci.yml b/.github/workflows/budibase_ci.yml index 91c32359d2..2e7851b338 100644 --- a/.github/workflows/budibase_ci.yml +++ b/.github/workflows/budibase_ci.yml @@ -235,7 +235,6 @@ jobs: - name: Test server env: DATASOURCE: ${{ matrix.datasource }} - DEBUG: testcontainers* run: | if ${{ env.ONLY_AFFECTED_TASKS }}; then AFFECTED=$(yarn --silent nx show projects --affected -t test --base=${{ env.NX_BASE_BRANCH }} -p @budibase/server) diff --git a/packages/server/src/integrations/tests/utils/mssql.ts b/packages/server/src/integrations/tests/utils/mssql.ts index d84fb5d12d..453c2b8bc8 100644 --- a/packages/server/src/integrations/tests/utils/mssql.ts +++ b/packages/server/src/integrations/tests/utils/mssql.ts @@ -23,7 +23,7 @@ export async function getDatasource(): Promise { }) .withWaitStrategy( Wait.forSuccessfulCommand( - "/opt/mssql-tools18/bin/sqlcmd -S localhost -U sa -P Password_123 -q 'SELECT 1'" + "/opt/mssql-tools18/bin/sqlcmd -C -S localhost -U sa -P Password_123 -q 'SELECT 1'" ).withStartupTimeout(20000) ) ) @@ -44,7 +44,8 @@ export async function getDatasource(): Promise { user: "sa", password: "Password_123", options: { - encrypt: false, + encrypt: true, + trustServerCertificate: true, }, }, } From 92b391e9ef514e60438a3067701d04ca46693ec3 Mon Sep 17 00:00:00 2001 From: Sam Rose Date: Wed, 26 Feb 2025 16:24:35 +0000 Subject: [PATCH 34/46] Fix lint. --- packages/worker/src/utilities/email.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/worker/src/utilities/email.ts b/packages/worker/src/utilities/email.ts index d3fac15860..94e86548c2 100644 --- a/packages/worker/src/utilities/email.ts +++ b/packages/worker/src/utilities/email.ts @@ -4,7 +4,6 @@ import { getTemplateByPurpose, EmailTemplates } from "../constants/templates" import { getSettingsTemplateContext } from "./templates" import { processString } from "@budibase/string-templates" import { - User, SendEmailOpts, SMTPInnerConfig, EmailTemplatePurpose, From 478d28285b68ef8dc405ea65fba8acccc08cc411 Mon Sep 17 00:00:00 2001 From: Sam Rose Date: Wed, 26 Feb 2025 17:55:54 +0000 Subject: [PATCH 35/46] Replace email mocks and real email sending with maildev. --- packages/worker/package.json | 2 + .../src/api/routes/global/tests/email.spec.ts | 94 ++- .../api/routes/global/tests/realEmail.spec.ts | 108 --- .../worker/src/tests/TestConfiguration.ts | 12 +- packages/worker/src/tests/mocks/email.ts | 156 +++- packages/worker/src/utilities/email.ts | 9 +- yarn.lock | 713 ++++++++++++++++-- 7 files changed, 876 insertions(+), 218 deletions(-) delete mode 100644 packages/worker/src/api/routes/global/tests/realEmail.spec.ts diff --git a/packages/worker/package.json b/packages/worker/package.json index edaab50d78..b67e8d4911 100644 --- a/packages/worker/package.json +++ b/packages/worker/package.json @@ -85,12 +85,14 @@ "@types/jsonwebtoken": "9.0.3", "@types/koa__router": "12.0.4", "@types/lodash": "4.14.200", + "@types/maildev": "^0.0.7", "@types/node-fetch": "2.6.4", "@types/nodemailer": "^6.4.17", "@types/server-destroy": "1.0.1", "@types/supertest": "2.0.14", "@types/uuid": "8.3.4", "jest": "29.7.0", + "maildev": "^2.2.1", "nock": "^13.5.4", "nodemon": "2.0.15", "rimraf": "3.0.2", diff --git a/packages/worker/src/api/routes/global/tests/email.spec.ts b/packages/worker/src/api/routes/global/tests/email.spec.ts index eb46c501d9..7bf56fabd3 100644 --- a/packages/worker/src/api/routes/global/tests/email.spec.ts +++ b/packages/worker/src/api/routes/global/tests/email.spec.ts @@ -1,33 +1,97 @@ -jest.mock("nodemailer") import { EmailTemplatePurpose } from "@budibase/types" -import { TestConfiguration, mocks } from "../../../../tests" - -const sendMailMock = mocks.email.mock() +import { TestConfiguration } from "../../../../tests" +import { + captureEmail, + deleteAllEmail, + getAttachment, + getUnusedPort, + Mailserver, + startMailserver, + stopMailserver, +} from "../../../../tests/mocks/email" +import { objectStore } from "@budibase/backend-core" describe("/api/global/email", () => { const config = new TestConfiguration() + let mailserver: Mailserver beforeAll(async () => { await config.beforeAll() + const port = await getUnusedPort() + mailserver = await startMailserver(config, { smtp: port }) }) afterAll(async () => { + await stopMailserver(mailserver) await config.afterAll() }) - it("should be able to send an email (with mocking)", async () => { - // initially configure settings - await config.saveSmtpConfig() - await config.saveSettingsConfig() + beforeEach(async () => { + await deleteAllEmail(mailserver) + }) - const res = await config.api.emails.sendEmail( - EmailTemplatePurpose.INVITATION + it.each([ + { + purpose: EmailTemplatePurpose.WELCOME, + expectedText: `Thanks for getting started with Budibase's Budibase platform.`, + }, + { + purpose: EmailTemplatePurpose.INVITATION, + expectedText: `Use the button below to set up your account and get started:`, + }, + { + purpose: EmailTemplatePurpose.PASSWORD_RECOVERY, + expectedText: `You recently requested to reset your password for your Budibase account in your Budibase platform`, + }, + ])("can send $purpose emails", async ({ purpose, expectedText }) => { + const email = await captureEmail(mailserver, async () => { + const res = await config.api.emails.sendEmail(purpose) + expect(res.body.message).toBeDefined() + expect(res.status).toBe(200) + }) + + expect(email.html).toContain(expectedText) + expect(email.html).not.toContain("Invalid binding") + }) + + it("should be able to send an email with an attachment", async () => { + let bucket = "testbucket" + let filename = "test.txt" + await objectStore.upload({ + bucket, + filename, + body: Buffer.from("test data"), + }) + let presignedUrl = await objectStore.getPresignedUrl( + bucket, + filename, + 60000 ) - expect(res.body.message).toBeDefined() - expect(sendMailMock).toHaveBeenCalled() - const emailCall = sendMailMock.mock.calls[0][0] - expect(emailCall.subject).toBe("Hello!") - expect(emailCall.html).not.toContain("Invalid binding") + let attachmentObject = { + url: presignedUrl, + filename, + } + + const email = await captureEmail(mailserver, async () => { + const res = await config.api.emails.sendEmail( + EmailTemplatePurpose.WELCOME, + [attachmentObject] + ) + expect(res.body.message).toBeDefined() + expect(res.status).toBe(200) + }) + + expect(email.html).toContain( + "Thanks for getting started with Budibase's Budibase platform." + ) + expect(email.html).not.toContain("Invalid binding") + + const attachment = await getAttachment( + mailserver, + email, + email.attachments[0] + ) + expect(attachment).toEqual("test data") }) }) diff --git a/packages/worker/src/api/routes/global/tests/realEmail.spec.ts b/packages/worker/src/api/routes/global/tests/realEmail.spec.ts deleted file mode 100644 index 479a1f0476..0000000000 --- a/packages/worker/src/api/routes/global/tests/realEmail.spec.ts +++ /dev/null @@ -1,108 +0,0 @@ -jest.unmock("node-fetch") -import { TestConfiguration } from "../../../../tests" -import { objectStore } from "@budibase/backend-core" -import { helpers } from "@budibase/shared-core" - -import tk from "timekeeper" -import { EmailAttachment, EmailTemplatePurpose } from "@budibase/types" - -const fetch = require("node-fetch") - -const nodemailer = require("nodemailer") - -// for the real email tests give them a long time to try complete/fail -jest.setTimeout(30000) - -describe("/api/global/email", () => { - const config = new TestConfiguration() - - beforeAll(async () => { - tk.reset() - await config.beforeAll() - }) - - afterAll(async () => { - await config.afterAll() - }) - - async function sendRealEmail( - purpose: string, - attachments?: EmailAttachment[] - ) { - let response, text - try { - await helpers.withTimeout(20000, () => config.saveEtherealSmtpConfig()) - await helpers.withTimeout(20000, () => config.saveSettingsConfig()) - let res - if (attachments) { - res = await config.api.emails - .sendEmail(purpose, attachments) - .timeout(20000) - } else { - res = await config.api.emails.sendEmail(purpose).timeout(20000) - } - // ethereal hiccup, can't test right now - if (res.status >= 300) { - return - } - expect(res.body.message).toBeDefined() - const testUrl = nodemailer.getTestMessageUrl(res.body) - expect(testUrl).toBeDefined() - response = await fetch(testUrl) - text = await response.text() - } catch (err: any) { - // ethereal hiccup, can't test right now - if (parseInt(err.status) >= 300 || (err && err.errno === "ETIME")) { - return - } else { - throw err - } - } - let toCheckFor - switch (purpose) { - case EmailTemplatePurpose.WELCOME: - toCheckFor = `Thanks for getting started with Budibase's Budibase platform.` - break - case EmailTemplatePurpose.INVITATION: - toCheckFor = `Use the button below to set up your account and get started:` - break - case EmailTemplatePurpose.PASSWORD_RECOVERY: - toCheckFor = `You recently requested to reset your password for your Budibase account in your Budibase platform` - break - } - expect(text).toContain(toCheckFor) - } - - it("should be able to send a welcome email", async () => { - await sendRealEmail(EmailTemplatePurpose.WELCOME) - }) - - it("should be able to send a invitation email", async () => { - await sendRealEmail(EmailTemplatePurpose.INVITATION) - }) - - it("should be able to send a password recovery email", async () => { - await sendRealEmail(EmailTemplatePurpose.PASSWORD_RECOVERY) - }) - - it("should be able to send an email with attachments", async () => { - let bucket = "testbucket" - let filename = "test.txt" - await objectStore.upload({ - bucket, - filename, - body: Buffer.from("test data"), - }) - let presignedUrl = await objectStore.getPresignedUrl( - bucket, - filename, - 60000 - ) - - let attachmentObject = { - url: presignedUrl, - filename, - } - await sendRealEmail(EmailTemplatePurpose.WELCOME, [attachmentObject]) - }) -}) diff --git a/packages/worker/src/tests/TestConfiguration.ts b/packages/worker/src/tests/TestConfiguration.ts index b4d5061db7..b49d4119df 100644 --- a/packages/worker/src/tests/TestConfiguration.ts +++ b/packages/worker/src/tests/TestConfiguration.ts @@ -32,6 +32,8 @@ import { AuthToken, SCIMConfig, ConfigType, + SMTPConfig, + SMTPInnerConfig, } from "@budibase/types" import API from "./api" import jwt, { Secret } from "jsonwebtoken" @@ -348,9 +350,15 @@ class TestConfiguration { // CONFIGS - SMTP - async saveSmtpConfig() { + async saveSmtpConfig(config?: SMTPInnerConfig) { await this.deleteConfig(Config.SMTP) - await this._req(structures.configs.smtp(), null, controllers.config.save) + + let smtpConfig: SMTPConfig = structures.configs.smtp() + if (config) { + smtpConfig = { type: ConfigType.SMTP, config } + } + + await this._req(smtpConfig, null, controllers.config.save) } async saveEtherealSmtpConfig() { diff --git a/packages/worker/src/tests/mocks/email.ts b/packages/worker/src/tests/mocks/email.ts index c16c58ddb5..67ea683ec2 100644 --- a/packages/worker/src/tests/mocks/email.ts +++ b/packages/worker/src/tests/mocks/email.ts @@ -1,10 +1,148 @@ -export function mock() { - // mock the email system - const sendMailMock = jest.fn() - const nodemailer = require("nodemailer") - nodemailer.createTransport.mockReturnValue({ - sendMail: sendMailMock, - verify: jest.fn(), - }) - return sendMailMock +import MailDev from "maildev" +import { promisify } from "util" +import TestConfiguration from "../TestConfiguration" + +export type Mailserver = InstanceType +export type MailserverConfig = ConstructorParameters[0] + +export interface Attachment { + checksum: string + contentId: string + contentType: string + fileName: string + generatedFileName: string + length: number + transferEncoding: string + transformed: boolean +} + +export interface Address { + address: string + args?: boolean + name?: string +} + +export interface Envelope { + from: Address + to: Address[] + host: string + remoteAddress: string +} + +export interface Email { + attachments: Attachment[] + calculatedBcc: string[] + date: string + envelope: Envelope + from: Address[] + headers: Record + html: string + id: string + messageId: string + priority: string + read: boolean + size: number + sizeHuman: string + source: string + time: Date + to: Address[] +} + +export function getUnusedPort(): Promise { + return new Promise((resolve, reject) => { + const server = require("net").createServer() + server.unref() + server.on("error", reject) + server.listen(0, () => { + const port = server.address().port + server.close(() => { + resolve(port) + }) + }) + }) +} + +export function waitForEmail( + mailserver: Mailserver, + timeoutMs = 5000 +): Promise { + let timeout: ReturnType + const timeoutPromise = new Promise((_, reject) => { + timeout = setTimeout(() => { + reject(new Error("Timed out waiting for email")) + }, timeoutMs) + }) + const mailPromise = new Promise(resolve => { + // @ts-expect-error - types are wrong + mailserver.once("new", email => { + resolve(email as Email) + clearTimeout(timeout) + }) + }) + return Promise.race([mailPromise, timeoutPromise]) +} + +export async function captureEmail( + mailserver: Mailserver, + f: () => Promise +): Promise { + const emailPromise = waitForEmail(mailserver) + await f() + return await emailPromise +} + +export async function startMailserver( + config: TestConfiguration, + opts?: MailserverConfig +): Promise { + if (!opts) { + opts = {} + } + if (!opts.smtp) { + opts.smtp = await getUnusedPort() + } + const mailserver = new MailDev(opts || {}) + await new Promise((resolve, reject) => { + mailserver.listen(err => { + if (err) { + return reject(err) + } + resolve(mailserver) + }) + }) + await config.saveSmtpConfig({ + host: "localhost", + port: opts.smtp, + secure: false, + from: "test@example.com", + }) + return mailserver +} + +export function deleteAllEmail(mailserver: Mailserver) { + return promisify(mailserver.deleteAllEmail).bind(mailserver)() +} + +export function stopMailserver(mailserver: Mailserver) { + return promisify(mailserver.close).bind(mailserver)() +} + +export function getAttachment( + mailserver: Mailserver, + email: Email, + attachment: Attachment +) { + return new Promise(resolve => { + // @ts-expect-error - types are wrong + mailserver.getEmailAttachment( + email.id, + attachment.generatedFileName, + (err: any, _contentType: string, stream: ReadableStream) => { + if (err) { + throw err + } + resolve(new Response(stream).text()) + } + ) + }) } diff --git a/packages/worker/src/utilities/email.ts b/packages/worker/src/utilities/email.ts index 94e86548c2..5461a18b82 100644 --- a/packages/worker/src/utilities/email.ts +++ b/packages/worker/src/utilities/email.ts @@ -7,6 +7,7 @@ import { SendEmailOpts, SMTPInnerConfig, EmailTemplatePurpose, + User, } from "@budibase/types" import { configs, cache, objectStore } from "@budibase/backend-core" import ical from "ical-generator" @@ -71,8 +72,8 @@ function createSMTPTransport(config?: SMTPInnerConfig) { async function buildEmail( purpose: EmailTemplatePurpose, email: string, - context: any, - { user, contents }: any = {} + context: Record, + { user, contents }: { user?: User; contents?: string } = {} ) { // this isn't a full email if (FULL_EMAIL_PURPOSES.indexOf(purpose) === -1) { @@ -90,8 +91,8 @@ async function buildEmail( throw "Unable to build email, missing base components" } - let name = user ? user.name : undefined - if (user && !name && user.firstName) { + let name: string | undefined + if (user && user.firstName) { name = user.lastName ? `${user.firstName} ${user.lastName}` : user.firstName } context = { diff --git a/yarn.lock b/yarn.lock index 445e0abc18..846a149495 100644 --- a/yarn.lock +++ b/yarn.lock @@ -82,6 +82,17 @@ call-me-maybe "^1.0.1" z-schema "^5.0.1" +"@asamuzakjp/css-color@^2.8.2": + version "2.8.3" + resolved "https://registry.yarnpkg.com/@asamuzakjp/css-color/-/css-color-2.8.3.tgz#665f0f5e8edb95d8f543847529e30fe5cc437ef7" + integrity sha512-GIc76d9UI1hCvOATjZPyHFmE5qhRccp3/zGfMPapK3jBi+yocEzp6BBB0UnfRYP9NP4FANqUZYb0hnfs3TM3hw== + dependencies: + "@csstools/css-calc" "^2.1.1" + "@csstools/css-color-parser" "^3.0.7" + "@csstools/css-parser-algorithms" "^3.0.4" + "@csstools/css-tokenizer" "^3.0.3" + lru-cache "^10.4.3" + "@aws-crypto/crc32@5.2.0": version "5.2.0" resolved "https://registry.yarnpkg.com/@aws-crypto/crc32/-/crc32-5.2.0.tgz#cfcc22570949c98c6689cfcbd2d693d36cdae2e1" @@ -1457,7 +1468,7 @@ "@azure/abort-controller" "^2.0.0" tslib "^2.6.2" -"@azure/identity@4.2.1", "@azure/identity@^4.2.1": +"@azure/identity@^4.2.1": version "4.2.1" resolved "https://registry.yarnpkg.com/@azure/identity/-/identity-4.2.1.tgz#22b366201e989b7b41c0e1690e103bd579c31e4c" integrity sha512-U8hsyC9YPcEIzoaObJlRDvp7KiF0MGS7xcWbyJSVvXRkC/HXo1f0oYeBYmEvVgRfacw7GHf6D6yAoh9JHz6A5Q== @@ -2784,28 +2795,6 @@ pouchdb-promise "^6.0.4" through2 "^2.0.0" -"@budibase/pro@npm:@budibase/pro@latest": - version "3.4.16" - resolved "https://registry.yarnpkg.com/@budibase/pro/-/pro-3.4.16.tgz#c482a400e27b7e89ca73092c4c81bdeac1d24581" - integrity sha512-8ECnqOh9jQ10KlQEwmKPFcoVGE+2gGgSybj+vbshwDp1zAW76doyMR2DMNjEatNpWVnpoMnTkDWtE9aqQ5v0vQ== - dependencies: - "@anthropic-ai/sdk" "^0.27.3" - "@budibase/backend-core" "*" - "@budibase/shared-core" "*" - "@budibase/string-templates" "*" - "@budibase/types" "*" - "@koa/router" "13.1.0" - bull "4.10.1" - dd-trace "5.26.0" - joi "17.6.0" - jsonwebtoken "9.0.2" - lru-cache "^7.14.1" - memorystream "^0.3.1" - node-fetch "2.6.7" - openai "4.59.0" - scim-patch "^0.8.1" - scim2-parse-filter "^0.2.8" - "@budibase/vm-browserify@^1.1.4": version "1.1.4" resolved "https://registry.yarnpkg.com/@budibase/vm-browserify/-/vm-browserify-1.1.4.tgz#eecb001bd9521cb7647e26fb4d2d29d0a4dce262" @@ -2957,6 +2946,34 @@ dependencies: "@jridgewell/trace-mapping" "0.3.9" +"@csstools/color-helpers@^5.0.2": + version "5.0.2" + resolved "https://registry.yarnpkg.com/@csstools/color-helpers/-/color-helpers-5.0.2.tgz#82592c9a7c2b83c293d9161894e2a6471feb97b8" + integrity sha512-JqWH1vsgdGcw2RR6VliXXdA0/59LttzlU8UlRT/iUUsEeWfYq8I+K0yhihEUTTHLRm1EXvpsCx3083EU15ecsA== + +"@csstools/css-calc@^2.1.1", "@csstools/css-calc@^2.1.2": + version "2.1.2" + resolved "https://registry.yarnpkg.com/@csstools/css-calc/-/css-calc-2.1.2.tgz#bffd55f002dab119b76d4023f95cd943e6c8c11e" + integrity sha512-TklMyb3uBB28b5uQdxjReG4L80NxAqgrECqLZFQbyLekwwlcDDS8r3f07DKqeo8C4926Br0gf/ZDe17Zv4wIuw== + +"@csstools/css-color-parser@^3.0.7": + version "3.0.8" + resolved "https://registry.yarnpkg.com/@csstools/css-color-parser/-/css-color-parser-3.0.8.tgz#5fe9322920851450bf5e065c2b0e731b9e165394" + integrity sha512-pdwotQjCCnRPuNi06jFuP68cykU1f3ZWExLe/8MQ1LOs8Xq+fTkYgd+2V8mWUWMrOn9iS2HftPVaMZDaXzGbhQ== + dependencies: + "@csstools/color-helpers" "^5.0.2" + "@csstools/css-calc" "^2.1.2" + +"@csstools/css-parser-algorithms@^3.0.4": + version "3.0.4" + resolved "https://registry.yarnpkg.com/@csstools/css-parser-algorithms/-/css-parser-algorithms-3.0.4.tgz#74426e93bd1c4dcab3e441f5cc7ba4fb35d94356" + integrity sha512-Up7rBoV77rv29d3uKHUIVubz1BTcgyUK72IvCQAbfbMv584xHcGKCKbWh7i8hPrRJ7qU4Y8IO3IY9m+iTB7P3A== + +"@csstools/css-tokenizer@^3.0.3": + version "3.0.3" + resolved "https://registry.yarnpkg.com/@csstools/css-tokenizer/-/css-tokenizer-3.0.3.tgz#a5502c8539265fecbd873c1e395a890339f119c2" + integrity sha512-UJnjoFsmxfKUdNYdWgOB0mWUypuLvAfQPH1+pyvRJs6euowbFkFC6P13w1l8mJyi3vxYMxc9kld5jZEGRQs6bw== + "@curlconverter/yargs-parser@^0.0.1": version "0.0.1" resolved "https://registry.yarnpkg.com/@curlconverter/yargs-parser/-/yargs-parser-0.0.1.tgz#62a360cea3d62b9b5805e61e8110cea98da8d140" @@ -6689,6 +6706,13 @@ resolved "https://registry.yarnpkg.com/@types/long/-/long-4.0.2.tgz#b74129719fc8d11c01868010082d483b7545591a" integrity sha512-MqTGEo5bj5t157U6fA/BiDynNkn0YknVdh48CMPkTSpFTVmvao5UQmm7uEF6xBEo7qIMAlY/JSleYaE6VOdpaA== +"@types/maildev@^0.0.7": + version "0.0.7" + resolved "https://registry.yarnpkg.com/@types/maildev/-/maildev-0.0.7.tgz#025e646776a170e63cc8631d09391ba7612ba6cf" + integrity sha512-8Xs2PFd7SA2tAojYuAISTcE+IrrZysfuDQcwiE/cDMbErw2OyAHbO1yiJyYODnmdb/7dUIH7uaTrqK8H+kPB5w== + dependencies: + "@types/node" "*" + "@types/marked@^4.0.7": version "4.0.8" resolved "https://registry.yarnpkg.com/@types/marked/-/marked-4.0.8.tgz#b316887ab3499d0a8f4c70b7bd8508f92d477955" @@ -7148,6 +7172,11 @@ resolved "https://registry.yarnpkg.com/@types/triple-beam/-/triple-beam-1.3.5.tgz#74fef9ffbaa198eb8b588be029f38b00299caa2c" integrity sha512-6WaYesThRMCl19iryMYP7/x2OVgCtbIVflDGFpWnb9irXI3UjYE4AzmYuiUKY1AJstGijoY+MgUszMgRxIYTYw== +"@types/trusted-types@^2.0.7": + version "2.0.7" + resolved "https://registry.yarnpkg.com/@types/trusted-types/-/trusted-types-2.0.7.tgz#baccb07a970b91707df3a3e8ba6896c57ead2d11" + integrity sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw== + "@types/tunnel@^0.0.3": version "0.0.3" resolved "https://registry.yarnpkg.com/@types/tunnel/-/tunnel-0.0.3.tgz#f109e730b072b3136347561fc558c9358bb8c6e9" @@ -7563,7 +7592,7 @@ abstract-leveldown@~6.2.1, abstract-leveldown@~6.2.3: level-supports "~1.0.0" xtend "~4.0.0" -accepts@^1.3.5, accepts@^1.3.7, accepts@~1.3.4: +accepts@^1.3.5, accepts@^1.3.7, accepts@~1.3.4, accepts@~1.3.8: version "1.3.8" resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.8.tgz#0bf0be125b67014adcb0b0921e62db7bffe16b2e" integrity sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw== @@ -7634,6 +7663,11 @@ add-stream@^1.0.0: resolved "https://registry.yarnpkg.com/add-stream/-/add-stream-1.0.0.tgz#6a7990437ca736d5e1288db92bd3266d5f5cb2aa" integrity sha512-qQLMr+8o0WC4FZGQTcJiKBVC59JylcPSrTtk6usvmIDFUOCKegapy1VHQwRbFMOFyb/inzUVqHs+eMYKDM1YeQ== +addressparser@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/addressparser/-/addressparser-1.0.1.tgz#47afbe1a2a9262191db6838e4fd1d39b40821746" + integrity sha512-aQX7AISOMM7HFE0iZ3+YnD07oIeJqWGVnJ+ZIKaBZAk03ftmVYVqsGas/rbXKR21n4D/hKCSHypvcyOkds/xzg== + agent-base@6, agent-base@^6.0.2: version "6.0.2" resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-6.0.2.tgz#49fff58577cfee3f37176feab4c22e00f86d7f77" @@ -7648,6 +7682,11 @@ agent-base@^7.0.2, agent-base@^7.1.0: dependencies: debug "^4.3.4" +agent-base@^7.1.2: + version "7.1.3" + resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-7.1.3.tgz#29435eb821bc4194633a5b89e5bc4703bafc25a1" + integrity sha512-jRR5wdylq8CkOe6hei19GGZnxM6rBGwFl3Bg0YItGDimvjGtAvdZk4Pu6Cl4u4Igsws4a1fd1Vq3ezrhn4KmFw== + agentkeepalive@^4.2.1: version "4.5.0" resolved "https://registry.yarnpkg.com/agentkeepalive/-/agentkeepalive-4.5.0.tgz#2673ad1389b3c418c5a20c5d7364f93ca04be923" @@ -7914,6 +7953,11 @@ array-differ@^3.0.0: resolved "https://registry.yarnpkg.com/array-differ/-/array-differ-3.0.0.tgz#3cbb3d0f316810eafcc47624734237d6aee4ae6b" integrity sha512-THtfYS6KtME/yIAhKjZ2ul7XI96lQGHRputJQHO80LAWQnuGP4iCIN8vdMRboGbIEYBwU33q8Tch1os2+X0kMg== +array-flatten@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" + integrity sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg== + array-ify@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/array-ify/-/array-ify-1.0.0.tgz#9e528762b4a9066ad163a6962a364418e9626ece" @@ -8143,7 +8187,23 @@ aws4@^1.8.0: resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.13.2.tgz#0aa167216965ac9474ccfa83892cfb6b3e1e52ef" integrity sha512-lHe62zvbTB5eEABUVi/AwVh0ZKY9rMMDhmm+eeyuuUQbQ3+J+fONVQOZyj+DdrvD4BY33uYniyRJ4UJIaSKAfw== -axios@1.1.3, axios@1.7.7, axios@^0.21.1, axios@^1.0.0, axios@^1.1.3, axios@^1.4.0, axios@^1.6.2, axios@^1.6.8: +axios@1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/axios/-/axios-1.1.3.tgz#8274250dada2edf53814ed7db644b9c2866c1e35" + integrity sha512-00tXVRwKx/FZr/IDVFt4C+f9FYairX517WoGCL6dpOntqLkZofjhu43F/Xl44UOpqa+9sLFDrG/XAnFsUYgkDA== + dependencies: + follow-redirects "^1.15.0" + form-data "^4.0.0" + proxy-from-env "^1.1.0" + +axios@^0.21.1: + version "0.21.4" + resolved "https://registry.yarnpkg.com/axios/-/axios-0.21.4.tgz#c67b90dc0568e5c1cf2b0b858c43ba28e2eda575" + integrity sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg== + dependencies: + follow-redirects "^1.14.0" + +axios@^1.0.0, axios@^1.1.3, axios@^1.4.0, axios@^1.6.2, axios@^1.6.8: version "1.7.7" resolved "https://registry.yarnpkg.com/axios/-/axios-1.7.7.tgz#2f554296f9892a72ac8d8e4c5b79c14a91d0a47f" integrity sha512-S4kL7XrjgBmvdGut0sN3yJxqYzrDOnivkBiN0OFs6hLiUam3UPvswUo0kqGyhqUZGEOytHyumEdXsAkgCOUf3Q== @@ -8319,6 +8379,11 @@ bare-path@^2.0.0, bare-path@^2.1.0: dependencies: bare-os "^2.1.0" +base32.js@0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/base32.js/-/base32.js-0.1.0.tgz#b582dec693c2f11e893cf064ee6ac5b6131a2202" + integrity sha512-n3TkB02ixgBOhTvANakDb4xaMXnYUVkNoRFJjQflcqMQhyEKxEHdj3E6N8t8sUQ0mjH/3/JxzlXuz3ul/J90pQ== + base62@^1.1.0: version "1.2.8" resolved "https://registry.yarnpkg.com/base62/-/base62-1.2.8.tgz#1264cb0fb848d875792877479dbe8bae6bae3428" @@ -8431,6 +8496,24 @@ bn.js@^5.2.1: resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-5.2.1.tgz#0bc527a6a0d18d0aa8d5b0538ce4a77dccfa7b70" integrity sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ== +body-parser@1.20.3: + version "1.20.3" + resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.20.3.tgz#1953431221c6fb5cd63c4b36d53fab0928e548c6" + integrity sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g== + dependencies: + bytes "3.1.2" + content-type "~1.0.5" + debug "2.6.9" + depd "2.0.0" + destroy "1.2.0" + http-errors "2.0.0" + iconv-lite "0.4.24" + on-finished "2.4.1" + qs "6.13.0" + raw-body "2.5.2" + type-is "~1.6.18" + unpipe "1.0.0" + boolean@^3.0.1: version "3.2.0" resolved "https://registry.yarnpkg.com/boolean/-/boolean-3.2.0.tgz#9e5294af4e98314494cbb17979fa54ca159f116b" @@ -9188,6 +9271,11 @@ commander@^11.0.0: resolved "https://registry.yarnpkg.com/commander/-/commander-11.1.0.tgz#62fdce76006a68e5c1ab3314dc92e800eb83d906" integrity sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ== +commander@^12.1.0: + version "12.1.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-12.1.0.tgz#01423b36f501259fdaac4d0e4d60c96c991585d3" + integrity sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA== + commander@^2.16.0, commander@^2.19.0, commander@^2.20.0, commander@^2.20.3, commander@^2.5.0, commander@^2.7.1, commander@^2.8.1: version "2.20.3" resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" @@ -9252,13 +9340,26 @@ compress-commons@^6.0.2: normalize-path "^3.0.0" readable-stream "^4.0.0" -compressible@^2.0.0: +compressible@^2.0.0, compressible@~2.0.18: version "2.0.18" resolved "https://registry.yarnpkg.com/compressible/-/compressible-2.0.18.tgz#af53cca6b070d4c3c0750fbd77286a6d7cc46fba" integrity sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg== dependencies: mime-db ">= 1.43.0 < 2" +compression@^1.7.4: + version "1.8.0" + resolved "https://registry.yarnpkg.com/compression/-/compression-1.8.0.tgz#09420efc96e11a0f44f3a558de59e321364180f7" + integrity sha512-k6WLKfunuqCYD3t6AsuPGvQWaKwuLLh2/xHNcX4qE+vIfDNXpSqnrhwA7O53R7WVQUnt8dVAIW+YHr7xTgOgGA== + dependencies: + bytes "3.1.2" + compressible "~2.0.18" + debug "2.6.9" + negotiator "~0.6.4" + on-headers "~1.0.2" + safe-buffer "5.2.1" + vary "~1.1.2" + concat-map@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" @@ -9332,14 +9433,14 @@ consolidate@^0.16.0: dependencies: bluebird "^3.7.2" -content-disposition@^0.5.2, content-disposition@^0.5.3, content-disposition@^0.5.4, content-disposition@~0.5.2: +content-disposition@0.5.4, content-disposition@^0.5.2, content-disposition@^0.5.3, content-disposition@^0.5.4, content-disposition@~0.5.2: version "0.5.4" resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.4.tgz#8b82b4efac82512a02bb0b1dcec9d2c5e8eb5bfe" integrity sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ== dependencies: safe-buffer "5.2.1" -content-type@^1.0.4: +content-type@^1.0.4, content-type@~1.0.4, content-type@~1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.5.tgz#8b773162656d1d1086784c8f23a54ce6d73d7918" integrity sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA== @@ -9427,6 +9528,16 @@ convert-source-map@^2.0.0: resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-2.0.0.tgz#4b560f649fc4e918dd0ab75cf4961e8bc882d82a" integrity sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg== +cookie-signature@1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c" + integrity sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ== + +cookie@0.7.1: + version "0.7.1" + resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.7.1.tgz#2f73c42142d5d5cf71310a74fc4ae61670e5dbc9" + integrity sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w== + cookie@^0.4.1: version "0.4.2" resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.2.tgz#0e41f24de5ecf317947c82fc789e06a884824432" @@ -9495,7 +9606,7 @@ correlation-id@4.0.0: dependencies: uuid "^8.3.1" -cors@~2.8.5: +cors@^2.8.5, cors@~2.8.5: version "2.8.5" resolved "https://registry.yarnpkg.com/cors/-/cors-2.8.5.tgz#eac11da51592dd86b9f06f6e7ac293b3df875d29" integrity sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g== @@ -9650,6 +9761,14 @@ cssstyle@^3.0.0: dependencies: rrweb-cssom "^0.6.0" +cssstyle@^4.0.1: + version "4.2.1" + resolved "https://registry.yarnpkg.com/cssstyle/-/cssstyle-4.2.1.tgz#5142782410fea95db66fb68147714a652a7c2381" + integrity sha512-9+vem03dMXG7gDmZ62uqmRiMRNtinIZ9ZyuF6BdxzfOD+FdN5hretzynkn0ReS2DO2GSw76RWHs0UmJPI2zUjw== + dependencies: + "@asamuzakjp/css-color" "^2.8.2" + rrweb-cssom "^0.8.0" + csvtojson@2.0.10: version "2.0.10" resolved "https://registry.yarnpkg.com/csvtojson/-/csvtojson-2.0.10.tgz#11e7242cc630da54efce7958a45f443210357574" @@ -9764,6 +9883,14 @@ data-urls@^4.0.0: whatwg-mimetype "^3.0.0" whatwg-url "^12.0.0" +data-urls@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/data-urls/-/data-urls-5.0.0.tgz#2f76906bce1824429ffecb6920f45a0b30f00dde" + integrity sha512-ZYP5VBHshaDAiVZxjbRVcFJpc+4xGgT0bK3vzy1HLN8jTO975HEbuYzZJcHoQEY5K1a0z8YayJkyVETa08eNTg== + dependencies: + whatwg-mimetype "^4.0.0" + whatwg-url "^14.0.0" + data-view-buffer@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/data-view-buffer/-/data-view-buffer-1.0.1.tgz#8ea6326efec17a2e42620696e671d7d5a8bc66b2" @@ -9849,6 +9976,13 @@ dd-trace@5.26.0: shell-quote "^1.8.1" tlhunter-sorted-set "^0.1.0" +debug@2.6.9: + version "2.6.9" + resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" + integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== + dependencies: + ms "2.0.0" + debug@4, debug@^4.0.0, debug@^4.0.1, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.3, debug@^4.3.4, debug@^4.3.5: version "4.4.0" resolved "https://registry.yarnpkg.com/debug/-/debug-4.4.0.tgz#2b3f2aea2ffeb776477460267377dc8710faba8a" @@ -10171,7 +10305,7 @@ dequal@^2.0.3: resolved "https://registry.yarnpkg.com/dequal/-/dequal-2.0.3.tgz#2644214f1997d39ed0ee0ece72335490a7ac67be" integrity sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA== -destroy@^1.0.4: +destroy@1.2.0, destroy@^1.0.4: version "1.2.0" resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.2.0.tgz#4803735509ad8be552934c67df614f94e66fa015" integrity sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg== @@ -10488,6 +10622,13 @@ domhandler@^5.0.1, domhandler@^5.0.2: dependencies: domelementtype "^2.3.0" +dompurify@^3.1.6: + version "3.2.4" + resolved "https://registry.yarnpkg.com/dompurify/-/dompurify-3.2.4.tgz#af5a5a11407524431456cf18836c55d13441cd8e" + integrity sha512-ysFSFEDVduQpyhzAob/kkuJjf5zWkZD8/A9ywSp1byueyuCfHamrCBa14/Oc2iiB0e51B+NpxSl5gmzn+Ms/mg== + optionalDependencies: + "@types/trusted-types" "^2.0.7" + domutils@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/domutils/-/domutils-3.0.1.tgz#696b3875238338cb186b6c0612bd4901c89a4f1c" @@ -10669,11 +10810,16 @@ enabled@2.0.x: resolved "https://registry.yarnpkg.com/enabled/-/enabled-2.0.0.tgz#f9dd92ec2d6f4bbc0d5d1e64e21d61cd4665e7c2" integrity sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ== -encodeurl@^1.0.2: +encodeurl@^1.0.2, encodeurl@~1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" integrity sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w== +encodeurl@~2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-2.0.0.tgz#7b8ea898077d7e409d3ac45474ea38eaf0857a58" + integrity sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg== + encoding-down@^6.3.0: version "6.3.0" resolved "https://registry.yarnpkg.com/encoding-down/-/encoding-down-6.3.0.tgz#b1c4eb0e1728c146ecaef8e32963c549e76d082b" @@ -10957,12 +11103,12 @@ escape-goat@^2.0.0: resolved "https://registry.yarnpkg.com/escape-goat/-/escape-goat-2.1.1.tgz#1b2dc77003676c457ec760b2dc68edb648188675" integrity sha512-8/uIhbG12Csjy2JEW7D9pHbreaVaS/OpN3ycnyvElTdwM5n6GY6W6e2IPemfvGZeUMqZ9A/3GqIZMgKnBhAw/Q== -escape-html@^1.0.3: +escape-html@^1.0.3, escape-html@~1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" integrity sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow== -escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5: +escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5, escape-string-regexp@~1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg== @@ -11291,6 +11437,11 @@ esutils@^2.0.2, esutils@^2.0.3: resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== +etag@~1.8.1: + version "1.8.1" + resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" + integrity sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg== + event-lite@^0.1.1: version "0.1.3" resolved "https://registry.yarnpkg.com/event-lite/-/event-lite-0.1.3.tgz#3dfe01144e808ac46448f0c19b4ab68e403a901d" @@ -11384,6 +11535,43 @@ express-useragent@^1.0.15: resolved "https://registry.yarnpkg.com/express-useragent/-/express-useragent-1.0.15.tgz#cefda5fa4904345d51d3368b117a8dd4124985d9" integrity sha512-eq5xMiYCYwFPoekffMjvEIk+NWdlQY9Y38OsTyl13IvA728vKT+q/CSERYWzcw93HGBJcIqMIsZC5CZGARPVdg== +express@^4.21.2: + version "4.21.2" + resolved "https://registry.yarnpkg.com/express/-/express-4.21.2.tgz#cf250e48362174ead6cea4a566abef0162c1ec32" + integrity sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA== + dependencies: + accepts "~1.3.8" + array-flatten "1.1.1" + body-parser "1.20.3" + content-disposition "0.5.4" + content-type "~1.0.4" + cookie "0.7.1" + cookie-signature "1.0.6" + debug "2.6.9" + depd "2.0.0" + encodeurl "~2.0.0" + escape-html "~1.0.3" + etag "~1.8.1" + finalhandler "1.3.1" + fresh "0.5.2" + http-errors "2.0.0" + merge-descriptors "1.0.3" + methods "~1.1.2" + on-finished "2.4.1" + parseurl "~1.3.3" + path-to-regexp "0.1.12" + proxy-addr "~2.0.7" + qs "6.13.0" + range-parser "~1.2.1" + safe-buffer "5.2.1" + send "0.19.0" + serve-static "1.16.2" + setprototypeof "1.2.0" + statuses "2.0.1" + type-is "~1.6.18" + utils-merge "1.0.1" + vary "~1.1.2" + ext-list@^2.0.0: version "2.2.2" resolved "https://registry.yarnpkg.com/ext-list/-/ext-list-2.2.2.tgz#0b98e64ed82f5acf0f2931babf69212ef52ddd37" @@ -11406,7 +11594,7 @@ extend-shallow@^2.0.1: dependencies: is-extendable "^0.1.0" -extend@^3.0.2, extend@~3.0.2: +extend@^3.0.2, extend@~3.0.0, extend@~3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g== @@ -11698,6 +11886,19 @@ filter-obj@^1.1.0: resolved "https://registry.yarnpkg.com/filter-obj/-/filter-obj-1.1.0.tgz#9b311112bc6c6127a16e016c6c5d7f19e0805c5b" integrity sha512-8rXg1ZnX7xzy2NGDVkBVaAy+lSlPNwad13BtgSlLuxfIslyt5Vg64U7tFcCt4WS1R0hvtnQybT/IyCkGZ3DpXQ== +finalhandler@1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.3.1.tgz#0c575f1d1d324ddd1da35ad7ece3df7d19088019" + integrity sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ== + dependencies: + debug "2.6.9" + encodeurl "~2.0.0" + escape-html "~1.0.3" + on-finished "2.4.1" + parseurl "~1.3.3" + statuses "2.0.1" + unpipe "~1.0.0" + find-free-port@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/find-free-port/-/find-free-port-2.0.0.tgz#4b22e5f6579eb1a38c41ac6bcb3efed1b6da9b1b" @@ -11784,7 +11985,7 @@ fn.name@1.x.x: resolved "https://registry.yarnpkg.com/fn.name/-/fn.name-1.1.0.tgz#26cad8017967aea8731bc42961d04a3d5988accc" integrity sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw== -follow-redirects@^1.15.6: +follow-redirects@^1.14.0, follow-redirects@^1.15.0, follow-redirects@^1.15.6: version "1.15.9" resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.9.tgz#a604fa10e443bf98ca94228d9eebcc2e8a2c8ee1" integrity sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ== @@ -11882,7 +12083,12 @@ formidable@^3.5.2: hexoid "^2.0.0" once "^1.4.0" -fresh@^0.5.2, fresh@~0.5.2: +forwarded@0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.2.0.tgz#2269936428aad4c15c7ebe9779a84bf0b2a81811" + integrity sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow== + +fresh@0.5.2, fresh@^0.5.2, fresh@~0.5.2: version "0.5.2" resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" integrity sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q== @@ -12399,10 +12605,22 @@ global@~4.4.0: min-document "^2.19.0" process "^0.11.10" -globals@15.13.0, globals@^11.1.0, globals@^13.19.0, globals@^14.0.0: - version "15.13.0" - resolved "https://registry.yarnpkg.com/globals/-/globals-15.13.0.tgz#bbec719d69aafef188ecd67954aae76a696010fc" - integrity sha512-49TewVEz0UxZjr1WYYsWpPrhyC/B/pA8Bq0fUmet2n+eR7yn0IvNzNaoBwnK6mdkzcN+se7Ez9zUgULTz2QH4g== +globals@^11.1.0: + version "11.12.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" + integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== + +globals@^13.19.0: + version "13.24.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-13.24.0.tgz#8432a19d78ce0c1e833949c36adb345400bb1171" + integrity sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ== + dependencies: + type-fest "^0.20.2" + +globals@^14.0.0: + version "14.0.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-14.0.0.tgz#898d7413c29babcf6bafe56fcadded858ada724e" + integrity sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ== globalthis@^1.0.1, globalthis@^1.0.4: version "1.0.4" @@ -12771,6 +12989,13 @@ html-encoding-sniffer@^3.0.0: dependencies: whatwg-encoding "^2.0.0" +html-encoding-sniffer@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/html-encoding-sniffer/-/html-encoding-sniffer-4.0.0.tgz#696df529a7cfd82446369dc5193e590a3735b448" + integrity sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ== + dependencies: + whatwg-encoding "^3.1.1" + html-entities@^2.5.2: version "2.5.2" resolved "https://registry.yarnpkg.com/html-entities/-/html-entities-2.5.2.tgz#201a3cf95d3a15be7099521620d19dfb4f65359f" @@ -12812,7 +13037,12 @@ http-assert@^1.3.0: deep-equal "~1.0.1" http-errors "~1.8.0" -http-cache-semantics@3.8.1, http-cache-semantics@4.1.1, http-cache-semantics@^4.0.0, http-cache-semantics@^4.1.0, http-cache-semantics@^4.1.1: +http-cache-semantics@3.8.1: + version "3.8.1" + resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-3.8.1.tgz#39b0e16add9b605bf0a9ef3d9daaf4843b4cacd2" + integrity sha512-5ai2iksyV8ZXmnZhHH4rWPoxxistEexSi5936zIQ1bnNTW5VnA85B6P/VpXiRM017IgRvb2kKo1a//y+0wSp3w== + +http-cache-semantics@^4.0.0, http-cache-semantics@^4.1.0, http-cache-semantics@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz#abe02fcb2985460bf0323be664436ec3476a6d5a" integrity sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ== @@ -12874,7 +13104,7 @@ http-proxy-agent@^5.0.0: agent-base "6" debug "4" -http-proxy-agent@^7.0.0: +http-proxy-agent@^7.0.0, http-proxy-agent@^7.0.2: version "7.0.2" resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz#9a8b1f246866c028509486585f62b8f2c18c270e" integrity sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig== @@ -12907,6 +13137,14 @@ https-proxy-agent@^7.0.0, https-proxy-agent@^7.0.1, https-proxy-agent@^7.0.2: agent-base "^7.0.2" debug "4" +https-proxy-agent@^7.0.5: + version "7.0.6" + resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz#da8dfeac7da130b05c2ba4b59c9b6cd66611a6b9" + integrity sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw== + dependencies: + agent-base "^7.1.2" + debug "4" + human-signals@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-2.1.0.tgz#dc91fcba42e4d06e4abaed33b3e7a3c02f514ea0" @@ -12938,6 +13176,13 @@ iconv-lite@0.4.24, iconv-lite@^0.4.24, iconv-lite@^0.4.5: dependencies: safer-buffer ">= 2.1.2 < 3" +iconv-lite@0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.5.0.tgz#59cdde0a2a297cc2aeb0c6445a195ee89f127550" + integrity sha512-NnEhI9hIEKHOzJ4f697DMz9IQEXr/MMJ5w64vN2/4Ai+wRnvV7SBrL0KLoRlwaKVghOc7LQ5YkPLuX146b6Ydw== + dependencies: + safer-buffer ">= 2.1.2 < 3" + iconv-lite@0.6.3, iconv-lite@^0.6.2, iconv-lite@^0.6.3: version "0.6.3" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.6.3.tgz#a52f80bf38da1952eb5c681790719871a1a72501" @@ -13220,6 +13465,16 @@ ip@^2.0.0: resolved "https://registry.yarnpkg.com/ip/-/ip-2.0.0.tgz#4cf4ab182fee2314c75ede1276f8c80b479936da" integrity sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ== +ipaddr.js@1.9.1: + version "1.9.1" + resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3" + integrity sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g== + +ipv6-normalize@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/ipv6-normalize/-/ipv6-normalize-1.0.1.tgz#1b3258290d365fa83239e89907dde4592e7620a8" + integrity sha512-Bm6H79i01DjgGTCWjUuCjJ6QDo1HB96PT/xCYuyJUP9WFbVDrLSbG4EZCvOCun2rNswZb0c3e4Jt/ws795esHA== + is-arguments@^1.0.4, is-arguments@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/is-arguments/-/is-arguments-1.1.1.tgz#15b3f88fda01f2a97fec84ca761a560f123efa9b" @@ -13268,6 +13523,11 @@ is-boolean-object@^1.1.0: call-bind "^1.0.2" has-tostringtag "^1.0.0" +is-buffer@^1.1.5: + version "1.1.6" + resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" + integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w== + is-buffer@^2.0.5: version "2.0.5" resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-2.0.5.tgz#ebc252e400d22ff8d77fa09888821a24a658c191" @@ -13707,11 +13967,6 @@ isobject@^3.0.1: resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" integrity sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg== -isobject@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/isobject/-/isobject-4.0.0.tgz#3f1c9155e73b192022a80819bacd0343711697b0" - integrity sha512-S/2fF5wH8SJA/kmwr6HYhK/RI/OkhD84k8ntalo0iJjZikgq1XFvR5M8NPT1x5F7fBwCG3qHfnzeP/Vh/ZxCUA== - isolated-vm@^4.7.2: version "4.7.2" resolved "https://registry.yarnpkg.com/isolated-vm/-/isolated-vm-4.7.2.tgz#5670d5cce1d92004f9b825bec5b0b11fc7501b65" @@ -14381,6 +14636,33 @@ jsdom@^21.1.1: ws "^8.13.0" xml-name-validator "^4.0.0" +jsdom@^24.1.1: + version "24.1.3" + resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-24.1.3.tgz#88e4a07cb9dd21067514a619e9f17b090a394a9f" + integrity sha512-MyL55p3Ut3cXbeBEG7Hcv0mVM8pp8PBNWxRqchZnSfAiES1v1mRnMeFfaHWIPULpwsYfvO+ZmMZz5tGCnjzDUQ== + dependencies: + cssstyle "^4.0.1" + data-urls "^5.0.0" + decimal.js "^10.4.3" + form-data "^4.0.0" + html-encoding-sniffer "^4.0.0" + http-proxy-agent "^7.0.2" + https-proxy-agent "^7.0.5" + is-potential-custom-element-name "^1.0.1" + nwsapi "^2.2.12" + parse5 "^7.1.2" + rrweb-cssom "^0.7.1" + saxes "^6.0.0" + symbol-tree "^3.2.4" + tough-cookie "^4.1.4" + w3c-xmlserializer "^5.0.0" + webidl-conversions "^7.0.0" + whatwg-encoding "^3.1.1" + whatwg-mimetype "^4.0.0" + whatwg-url "^14.0.0" + ws "^8.18.0" + xml-name-validator "^5.0.0" + jsesc@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-3.0.2.tgz#bb8b09a6597ba426425f2e4a07245c3d00b9343e" @@ -14591,7 +14873,14 @@ kill-port@^1.6.1: get-them-args "1.3.2" shell-exec "1.0.2" -kind-of@6.0.3, kind-of@^3.0.2, kind-of@^3.1.0, kind-of@^6.0.0, kind-of@^6.0.2, kind-of@^6.0.3: +kind-of@^3.0.2, kind-of@^3.1.0: + version "3.2.2" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64" + integrity sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ== + dependencies: + is-buffer "^1.1.5" + +kind-of@^6.0.0, kind-of@^6.0.2, kind-of@^6.0.3: version "6.0.3" resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd" integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw== @@ -15354,6 +15643,11 @@ lru-cache@^10.2.0: resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-10.2.0.tgz#0bd445ca57363465900f4d1f9bd8db343a4d95c3" integrity sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q== +lru-cache@^10.4.3: + version "10.4.3" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-10.4.3.tgz#410fc8a17b70e598013df257c2446b7f3383f119" + integrity sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ== + lru-cache@^4.1.5: version "4.1.5" resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.5.tgz#8bbe50ea85bed59bc9e33dcab8235ee9bcf443cd" @@ -15451,6 +15745,27 @@ magic-string@^0.30.11, magic-string@^0.30.3, magic-string@^0.30.4: dependencies: "@jridgewell/sourcemap-codec" "^1.5.0" +maildev@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/maildev/-/maildev-2.2.1.tgz#0a7ea8188bc6d9fea6bd08dbc63ecf4872acc67c" + integrity sha512-uNSJ4LpiNfCMw5KpWAM5x1UgOyG3ngeNwzBqw4/Wl18ECkJDyXBYpTH44HCG8LqAOFLkUiLl/1Ah5lrQhv3GzQ== + dependencies: + addressparser "1.0.1" + async "^3.2.3" + commander "^12.1.0" + compression "^1.7.4" + cors "^2.8.5" + dompurify "^3.1.6" + express "^4.21.2" + iconv-lite "0.5.0" + jsdom "^24.1.1" + mime "2.4.4" + nodemailer "^6.9.14" + smtp-server "^3.13.4" + socket.io "^4.7.5" + uue "3.1.2" + wildstring "1.0.9" + make-dir@4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-4.0.0.tgz#c3c2307a771277cd9638305f915c29ae741b614e" @@ -15606,6 +15921,11 @@ meow@^8.1.2: type-fest "^0.18.0" yargs-parser "^20.2.3" +merge-descriptors@1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.3.tgz#d80319a65f3c7935351e5cfdac8f9318504dbed5" + integrity sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ== + merge-descriptors@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" @@ -15621,7 +15941,7 @@ merge2@^1.3.0, merge2@^1.4.1: resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== -methods@^1.1.2: +methods@^1.1.2, methods@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" integrity sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w== @@ -15654,6 +15974,16 @@ mime-types@^2.1.12, mime-types@^2.1.18, mime-types@^2.1.24, mime-types@^2.1.29, dependencies: mime-db "1.52.0" +mime@1.6.0, mime@^1.3.4: + version "1.6.0" + resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" + integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== + +mime@2.4.4: + version "2.4.4" + resolved "https://registry.yarnpkg.com/mime/-/mime-2.4.4.tgz#bd7b91135fc6b01cde3e9bae33d659b63d8857e5" + integrity sha512-LRxmNwziLPT828z+4YkNzloCFC2YM4wrB99k+AV5ZbEyfGNWfG8SO1FUXLmLDBSo89NrJZ4DIWeLjy1CHGhMGA== + mime@2.6.0: version "2.6.0" resolved "https://registry.yarnpkg.com/mime/-/mime-2.6.0.tgz#a2a682a95cd4d0cb1d6257e28f83da7e35800367" @@ -15664,11 +15994,6 @@ mime@3, mime@^3.0.0: resolved "https://registry.yarnpkg.com/mime/-/mime-3.0.0.tgz#b374550dca3a0c18443b0c950a6a58f1931cf7a7" integrity sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A== -mime@^1.3.4: - version "1.6.0" - resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" - integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== - mimic-fn@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" @@ -15950,12 +16275,17 @@ mri@^1.1.0: resolved "https://registry.yarnpkg.com/mri/-/mri-1.2.0.tgz#6721480fec2a11a4889861115a48b6cbe7cc8f0b" integrity sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA== +ms@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" + integrity sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A== + ms@2.1.2: version "2.1.2" resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== -ms@^2.0.0, ms@^2.1.1, ms@^2.1.3: +ms@2.1.3, ms@^2.0.0, ms@^2.1.1, ms@^2.1.3: version "2.1.3" resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== @@ -15984,7 +16314,7 @@ msgpackr-extract@^3.0.2: "@msgpackr-extract/msgpackr-extract-linux-x64" "3.0.2" "@msgpackr-extract/msgpackr-extract-win32-x64" "3.0.2" -msgpackr@1.10.1, msgpackr@^1.5.2: +msgpackr@^1.5.2: version "1.10.1" resolved "https://registry.yarnpkg.com/msgpackr/-/msgpackr-1.10.1.tgz#51953bb4ce4f3494f0c4af3f484f01cfbb306555" integrity sha512-r5VRLv9qouXuLiIBrLpl2d5ZvPt8svdQTl5/vMvE4nzDMyEX4sgW5yWhuBBj5UmgwOTWj8CIdSXn5sAfsHAWIQ== @@ -16122,6 +16452,11 @@ negotiator@0.6.3, negotiator@^0.6.3: resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.3.tgz#58e323a72fedc0d6f9cd4d31fe49f51479590ccd" integrity sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg== +negotiator@~0.6.4: + version "0.6.4" + resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.4.tgz#777948e2452651c570b712dd01c23e262713fff7" + integrity sha512-myRT3DiWPHqho5PrJaIRyaMv2kgYf0mUVgBNOYMuCH5Ki1yEiQaf/ZJuQ62nvpc44wL5WDbTX7yGJi1Neevw8w== + neo-async@^2.6.2: version "2.6.2" resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.2.tgz#b4aafb93e3aeb2d8174ca53cf163ab7d7308305f" @@ -16177,13 +16512,27 @@ node-domexception@1.0.0: resolved "https://registry.yarnpkg.com/node-domexception/-/node-domexception-1.0.0.tgz#6888db46a1f71c0b76b3f7555016b63fe64766e5" integrity sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ== -node-fetch@2.6.7, node-fetch@2.6.9, node-fetch@^2.6.0, node-fetch@^2.6.1, node-fetch@^2.6.7, node-fetch@^2.6.9: +node-fetch@2.6.7, node-fetch@^2.6.0, node-fetch@^2.6.1, node-fetch@^2.6.7: version "2.6.7" resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.7.tgz#24de9fba827e3b4ae44dc8b20256a379160052ad" integrity sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ== dependencies: whatwg-url "^5.0.0" +node-fetch@2.6.9: + version "2.6.9" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.9.tgz#7c7f744b5cc6eb5fd404e0c7a9fec630a55657e6" + integrity sha512-DJm/CJkZkRjKKj4Zi4BsKVZh3ValV5IR5s7LVZnW+6YMh0W1BfNA8XSs6DLMGYlId5F3KnA70uu2qepcR08Qqg== + dependencies: + whatwg-url "^5.0.0" + +node-fetch@^2.6.9: + version "2.7.0" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.7.0.tgz#d0f0fa6e3e2dc1d27efcd8ad99d550bda94d187d" + integrity sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A== + dependencies: + whatwg-url "^5.0.0" + node-forge@^1.3.1: version "1.3.1" resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-1.3.1.tgz#be8da2af243b2417d5f646a770663a92b7e9ded3" @@ -16270,11 +16619,21 @@ node-source-walk@^5.0.0: dependencies: "@babel/parser" "^7.0.0" +nodemailer@6.9.15: + version "6.9.15" + resolved "https://registry.yarnpkg.com/nodemailer/-/nodemailer-6.9.15.tgz#57b79dc522be27e0e47ac16cc860aa0673e62e04" + integrity sha512-AHf04ySLC6CIfuRtRiEYtGEXgRfa6INgWGluDhnxTZhHSKvrBu7lc1VVchQ0d8nPc4cFaZoPq8vkyNoZr0TpGQ== + nodemailer@6.9.9: version "6.9.9" resolved "https://registry.yarnpkg.com/nodemailer/-/nodemailer-6.9.9.tgz#4549bfbf710cc6addec5064dd0f19874d24248d9" integrity sha512-dexTll8zqQoVJEZPwQAKzxxtFn0qTnjdQTchoU6Re9BUUGBJiOy3YMn/0ShTW6J5M0dfQ1NeDeRTTl4oIWgQMA== +nodemailer@^6.9.14: + version "6.10.0" + resolved "https://registry.yarnpkg.com/nodemailer/-/nodemailer-6.10.0.tgz#1f24c9de94ad79c6206f66d132776b6503003912" + integrity sha512-SQ3wZCExjeSatLE/HBaXS5vqUOQk6GtBdIIKxiFdmm01mOQZX/POJkO3SUX1wDiYcwUOJwT23scFSC9fY2H8IA== + nodemon@2.0.15: version "2.0.15" resolved "https://registry.yarnpkg.com/nodemon/-/nodemon-2.0.15.tgz#504516ce3b43d9dc9a955ccd9ec57550a31a8d4e" @@ -16505,6 +16864,11 @@ nwsapi@^2.2.0, nwsapi@^2.2.4: resolved "https://registry.yarnpkg.com/nwsapi/-/nwsapi-2.2.12.tgz#fb6af5c0ec35b27b4581eb3bbad34ec9e5c696f8" integrity sha512-qXDmcVlZV4XRtKFzddidpfVP4oMSGhga+xdMc25mv8kaLUHtgzCDhUxkrN8exkGdTlLNaXj7CV3GtON7zuGZ+w== +nwsapi@^2.2.12: + version "2.2.16" + resolved "https://registry.yarnpkg.com/nwsapi/-/nwsapi-2.2.16.tgz#177760bba02c351df1d2644e220c31dfec8cdb43" + integrity sha512-F1I/bimDpj3ncaNDhfyMWuFqmQDBwDB0Fogc2qpL3BWvkQteFD/8BzWuIRl83rq0DXfm8SGt/HFhLXZyljTXcQ== + nx-cloud@16.0.5: version "16.0.5" resolved "https://registry.yarnpkg.com/nx-cloud/-/nx-cloud-16.0.5.tgz#fa0b0185d254405ec47fcbcdbbd8b12ff1add096" @@ -16691,13 +17055,18 @@ on-exit-leak-free@^2.1.0: resolved "https://registry.yarnpkg.com/on-exit-leak-free/-/on-exit-leak-free-2.1.0.tgz#5c703c968f7e7f851885f6459bf8a8a57edc9cc4" integrity sha512-VuCaZZAjReZ3vUwgOB8LxAosIurDiAW0s13rI1YwmaP++jvcxP77AWoQvenZebpCA2m8WC1/EosPYPMjnRAp/w== -on-finished@^2.3.0: +on-finished@2.4.1, on-finished@^2.3.0: version "2.4.1" resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.4.1.tgz#58c8c44116e54845ad57f14ab10b03533184ac3f" integrity sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg== dependencies: ee-first "1.1.1" +on-headers@~1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/on-headers/-/on-headers-1.0.2.tgz#772b0ae6aaa525c399e489adfad90c403eb3c28f" + integrity sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA== + once@^1.3.0, once@^1.3.1, once@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" @@ -17148,7 +17517,7 @@ parse5@^7.1.2: dependencies: entities "^4.4.0" -parseurl@^1.3.2, parseurl@^1.3.3: +parseurl@^1.3.2, parseurl@^1.3.3, parseurl@~1.3.3: version "1.3.3" resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4" integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ== @@ -17212,7 +17581,15 @@ passport-strategy@1.x.x, passport-strategy@^1.0.0: resolved "https://registry.yarnpkg.com/passport-strategy/-/passport-strategy-1.0.0.tgz#b5539aa8fc225a3d1ad179476ddf236b440f52e4" integrity sha512-CB97UUvDKJde2V0KDWWB3lyf6PC3FaZP7YxZ2G8OAtn9p4HI9j9JLP9qjOGZFvyl8uwNT8qM+hGnz/n16NI7oA== -passport@0.6.0, passport@^0.4.0, passport@^0.6.0: +passport@^0.4.0: + version "0.4.1" + resolved "https://registry.yarnpkg.com/passport/-/passport-0.4.1.tgz#941446a21cb92fc688d97a0861c38ce9f738f270" + integrity sha512-IxXgZZs8d7uFSt3eqNjM9NQ3g3uQCW5avD8mRNoXV99Yig50vjuaez6dQK2qC0kVWPRTujxY0dWgGfT09adjYg== + dependencies: + passport-strategy "1.x.x" + pause "0.0.1" + +passport@^0.6.0: version "0.6.0" resolved "https://registry.yarnpkg.com/passport/-/passport-0.6.0.tgz#e869579fab465b5c0b291e841e6cc95c005fac9d" integrity sha512-0fe+p3ZnrWRW74fe8+SvCyf4a3Pb2/h7gFkQ8yTJpAO50gDzlfjZUZTO1k5Eg9kUct22OxHLqDZoKUWRHOh9ug== @@ -17262,7 +17639,7 @@ path-scurry@^1.11.1, path-scurry@^1.6.1: lru-cache "^10.2.0" minipass "^5.0.0 || ^6.0.2 || ^7.0.0" -path-to-regexp@^0.1.10: +path-to-regexp@0.1.12, path-to-regexp@^0.1.10: version "0.1.12" resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.12.tgz#d5e1a12e478a976d432ef3c58d534b9923164bb7" integrity sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ== @@ -18182,6 +18559,14 @@ protocols@^2.0.0, protocols@^2.0.1: resolved "https://registry.yarnpkg.com/protocols/-/protocols-2.0.1.tgz#8f155da3fc0f32644e83c5782c8e8212ccf70a86" integrity sha512-/XJ368cyBJ7fzLMwLKv1e4vLxOju2MNAIokcr7meSaNcVbWz/CPcW22cP04mwxOErdA5mwjA8Q6w/cdAQxVn7Q== +proxy-addr@~2.0.7: + version "2.0.7" + resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.7.tgz#f19fe69ceab311eeb94b42e70e8c2070f9ba1025" + integrity sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg== + dependencies: + forwarded "0.2.0" + ipaddr.js "1.9.1" + proxy-from-env@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz#e102f16ca355424865755d2c9e8ea4f24d58c3e2" @@ -18197,6 +18582,13 @@ pseudomap@^1.0.2: resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3" integrity sha512-b/YwNhb8lk1Zz2+bXXpS/LK9OisiZZ1SNsSLxN1x2OXVEhW2Ckr/7mWE5vrC1ZTiJlD9g19jWszTmJsB+oEpFQ== +psl@^1.1.28: + version "1.15.0" + resolved "https://registry.yarnpkg.com/psl/-/psl-1.15.0.tgz#bdace31896f1d97cec6a79e8224898ce93d974c6" + integrity sha512-JZd3gMVBAVQkSs6HdNZo9Sdo0LNcQeMNP3CozBJb3JYC/QUYZTnKxP+f8oWRX4rHP5EurWxqAHTSwUCjlNKa1w== + dependencies: + punycode "^2.3.1" + psl@^1.1.33: version "1.9.0" resolved "https://registry.yarnpkg.com/psl/-/psl-1.9.0.tgz#d0df2a137f00794565fcaf3b2c00cd09f8d5a5a7" @@ -18215,6 +18607,11 @@ pump@^3.0.0: end-of-stream "^1.1.0" once "^1.3.1" +punycode.js@2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/punycode.js/-/punycode.js-2.3.1.tgz#6b53e56ad75588234e79f4affa90972c7dd8cdb7" + integrity sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA== + punycode@1.3.2: version "1.3.2" resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.3.2.tgz#9653a036fb7c1ee42342f2325cceefea3926c48d" @@ -18230,6 +18627,11 @@ punycode@^2.1.0, punycode@^2.1.1, punycode@^2.3.0: resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.0.tgz#f67fa67c94da8f4d0cfff981aee4118064199b8f" integrity sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA== +punycode@^2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.1.tgz#027422e2faec0b25e1549c3e1bd8309b9133b6e5" + integrity sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg== + pupa@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/pupa/-/pupa-2.1.1.tgz#f5e8fd4afc2c5d97828faa523549ed8744a20d62" @@ -18254,7 +18656,7 @@ q@^1.1.2: resolved "https://registry.yarnpkg.com/q/-/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7" integrity sha512-kV/CThkXo6xyFEZUugw/+pIOywXcDbFYgSct5cT3gqlbkBE1SJdwy6UQoZvodiWF/ckQLZyDE/Bu1M6gVu5lVw== -qs@^6.10.3, qs@^6.11.0, qs@^6.4.0: +qs@6.13.0, qs@^6.10.3, qs@^6.11.0, qs@^6.4.0: version "6.13.0" resolved "https://registry.yarnpkg.com/qs/-/qs-6.13.0.tgz#6ca3bd58439f7e245655798997787b0d88a51906" integrity sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg== @@ -18334,12 +18736,12 @@ randomstring@1.1.5: dependencies: array-uniq "1.0.2" -range-parser@^1.2.0: +range-parser@^1.2.0, range-parser@~1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031" integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg== -raw-body@^2.2.0: +raw-body@2.5.2, raw-body@^2.2.0: version "2.5.2" resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.5.2.tgz#99febd83b90e08975087e8f1f9419a149366b68a" integrity sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA== @@ -18955,6 +19357,16 @@ rrweb-cssom@^0.6.0: resolved "https://registry.yarnpkg.com/rrweb-cssom/-/rrweb-cssom-0.6.0.tgz#ed298055b97cbddcdeb278f904857629dec5e0e1" integrity sha512-APM0Gt1KoXBz0iIkkdB/kfvGOwC4UuJFeG/c+yV7wSc7q96cG/kJ0HiYCnzivD9SB53cLV1MlHFNfOuPaadYSw== +rrweb-cssom@^0.7.1: + version "0.7.1" + resolved "https://registry.yarnpkg.com/rrweb-cssom/-/rrweb-cssom-0.7.1.tgz#c73451a484b86dd7cfb1e0b2898df4b703183e4b" + integrity sha512-TrEMa7JGdVm0UThDJSx7ddw5nVm3UJS9o9CCIZ72B1vSyEZoziDqBYP3XIoi/12lKrJR8rE3jeFHMok2F/Mnsg== + +rrweb-cssom@^0.8.0: + version "0.8.0" + resolved "https://registry.yarnpkg.com/rrweb-cssom/-/rrweb-cssom-0.8.0.tgz#3021d1b4352fbf3b614aaeed0bc0d5739abe0bc2" + integrity sha512-guoltQEx+9aMf2gDZ0s62EcV8lsXR+0w8915TC3ITdn2YueuNjdAYh/levpU9nFaoChh9RUS5ZdQMrKfVEN9tw== + run-async@^2.4.0: version "2.4.1" resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.4.1.tgz#8440eccf99ea3e70bd409d49aab88e10c189a455" @@ -19061,6 +19473,11 @@ sax@1.2.1: resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.1.tgz#7b8e656190b228e81a66aea748480d828cd2d37a" integrity sha512-8I2a3LovHTOpm7NV5yOyO8IHqgVsfK4+UuySrXU8YXkSRX7k6hCV9b3HrkKCr3nMpgj+0bmocaJJWpvp1oc7ZA== +sax@>=0.1.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/sax/-/sax-1.4.1.tgz#44cc8988377f126304d3b3fc1010c733b929ef0f" + integrity sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg== + sax@>=0.6.0: version "1.2.4" resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" @@ -19133,13 +19550,47 @@ semver-diff@^3.1.1: dependencies: semver "^6.3.0" -"semver@2 || 3 || 4 || 5", semver@7.5.3, semver@^5.6.0, semver@^5.7.1, semver@^6.0.0, semver@^6.1.1, semver@^6.1.2, semver@^6.2.0, semver@^6.3.0, semver@^6.3.1, semver@^7.0.0, semver@^7.1.1, semver@^7.3.2, semver@^7.3.4, semver@^7.3.5, semver@^7.3.7, semver@^7.3.8, semver@^7.5.3, semver@^7.5.4, semver@^7.6.0, semver@^7.6.2: +"semver@2 || 3 || 4 || 5", semver@^5.6.0, semver@^5.7.1: + version "5.7.2" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.2.tgz#48d55db737c3287cd4835e17fa13feace1c41ef8" + integrity sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g== + +semver@7.5.3, semver@^7.0.0, semver@^7.1.1, semver@^7.3.2, semver@^7.3.4, semver@^7.3.5, semver@^7.3.7, semver@^7.3.8, semver@^7.5.3: version "7.5.3" resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.3.tgz#161ce8c2c6b4b3bdca6caadc9fa3317a4c4fe88e" integrity sha512-QBlUtyVk/5EeHbi7X0fw6liDZc7BBmEaSYn01fMU1OUYbf6GPsbTtd8WmnqbI20SeycoHSeiybkE/q1Q+qlThQ== dependencies: lru-cache "^6.0.0" +semver@^6.0.0, semver@^6.1.1, semver@^6.1.2, semver@^6.2.0, semver@^6.3.0, semver@^6.3.1: + version "6.3.1" + resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4" + integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== + +semver@^7.5.4, semver@^7.6.0, semver@^7.6.2: + version "7.7.1" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.7.1.tgz#abd5098d82b18c6c81f6074ff2647fd3e7220c9f" + integrity sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA== + +send@0.19.0: + version "0.19.0" + resolved "https://registry.yarnpkg.com/send/-/send-0.19.0.tgz#bbc5a388c8ea6c048967049dbeac0e4a3f09d7f8" + integrity sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw== + dependencies: + debug "2.6.9" + depd "2.0.0" + destroy "1.2.0" + encodeurl "~1.0.2" + escape-html "~1.0.3" + etag "~1.8.1" + fresh "0.5.2" + http-errors "2.0.0" + mime "1.6.0" + ms "2.1.3" + on-finished "2.4.1" + range-parser "~1.2.1" + statuses "2.0.1" + seq-queue@^0.0.5: version "0.0.5" resolved "https://registry.yarnpkg.com/seq-queue/-/seq-queue-0.0.5.tgz#d56812e1c017a6e4e7c3e3a37a1da6d78dd3c93e" @@ -19166,6 +19617,16 @@ serialize-javascript@^6.0.1: dependencies: randombytes "^2.1.0" +serve-static@1.16.2: + version "1.16.2" + resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.16.2.tgz#b6a5343da47f6bdd2673848bf45754941e803296" + integrity sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw== + dependencies: + encodeurl "~2.0.0" + escape-html "~1.0.3" + parseurl "~1.3.3" + send "0.19.0" + server-destroy@1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/server-destroy/-/server-destroy-1.0.1.tgz#f13bf928e42b9c3e79383e61cc3998b5d14e6cdd" @@ -19350,6 +19811,16 @@ smob@^1.0.0: resolved "https://registry.yarnpkg.com/smob/-/smob-1.5.0.tgz#85d79a1403abf128d24d3ebc1cdc5e1a9548d3ab" integrity sha512-g6T+p7QO8npa+/hNx9ohv1E5pVCmWrVCUzUXJyLdMmftX6ER0oiWY/w9knEonLpnOp6b6FenKnMfR8gqwWdwig== +smtp-server@^3.13.4: + version "3.13.6" + resolved "https://registry.yarnpkg.com/smtp-server/-/smtp-server-3.13.6.tgz#779aa22fd3746bb8b94d25ab78447b6e4b7d5b78" + integrity sha512-dqbSPKn3PCq3Gp5hxBM99u7PET7cQSAWrauhtArJbc+zrf5xNEOjm9+Ob3lySySrRoIEvNE0dz+w2H/xWFJNRw== + dependencies: + base32.js "0.1.0" + ipv6-normalize "1.0.1" + nodemailer "6.9.15" + punycode.js "2.3.1" + snowflake-sdk@^1.15.0: version "1.15.0" resolved "https://registry.yarnpkg.com/snowflake-sdk/-/snowflake-sdk-1.15.0.tgz#cc32fa0f2869d9e5a026e293b50d387ddbd67aca" @@ -19412,7 +19883,7 @@ socket.io-parser@~4.2.4: "@socket.io/component-emitter" "~3.1.0" debug "~4.3.1" -socket.io@4.8.1: +socket.io@4.8.1, socket.io@^4.7.5: version "4.8.1" resolved "https://registry.yarnpkg.com/socket.io/-/socket.io-4.8.1.tgz#fa0eaff965cc97fdf4245e8d4794618459f7558a" integrity sha512-oZ7iUCxph8WYRHHcjBEc9unw3adt5CmSNlppj/5Q4k2RIrhl8Z5yY2Xr4j9zj0+wzVZ0bxmYoGSzKJnRl6A4yg== @@ -20621,7 +21092,7 @@ touch@^3.1.0: dependencies: nopt "~1.0.10" -tough-cookie@4.1.3, "tough-cookie@^2.3.3 || ^3.0.1 || ^4.0.0", tough-cookie@^4.0.0, tough-cookie@^4.1.2, tough-cookie@~2.5.0: +"tough-cookie@^2.3.3 || ^3.0.1 || ^4.0.0", tough-cookie@^4.0.0, tough-cookie@^4.1.2: version "4.1.3" resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-4.1.3.tgz#97b9adb0728b42280aa3d814b6b999b2ff0318bf" integrity sha512-aX/y5pVRkfRnfmuX+OdbSdXvPe6ieKX/G2s7e98f4poJHnqH3281gDPm/metm6E/WRamfx7WC4HUqkWHfQHprw== @@ -20631,6 +21102,24 @@ tough-cookie@4.1.3, "tough-cookie@^2.3.3 || ^3.0.1 || ^4.0.0", tough-cookie@^4.0 universalify "^0.2.0" url-parse "^1.5.3" +tough-cookie@^4.1.4: + version "4.1.4" + resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-4.1.4.tgz#945f1461b45b5a8c76821c33ea49c3ac192c1b36" + integrity sha512-Loo5UUvLD9ScZ6jh8beX1T6sO1w2/MpCRpEP7V280GKMVUQ0Jzar2U3UJPsrdbziLEMMhu3Ujnq//rhiFuIeag== + dependencies: + psl "^1.1.33" + punycode "^2.1.1" + universalify "^0.2.0" + url-parse "^1.5.3" + +tough-cookie@~2.5.0: + version "2.5.0" + resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.5.0.tgz#cd9fb2a0aa1d5a12b473bd9fb96fa3dcff65ade2" + integrity sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g== + dependencies: + psl "^1.1.28" + punycode "^2.1.1" + tr46@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/tr46/-/tr46-2.1.0.tgz#fa87aa81ca5d5941da8cbf1f9b749dc969a4e240" @@ -20645,6 +21134,13 @@ tr46@^4.1.1: dependencies: punycode "^2.3.0" +tr46@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/tr46/-/tr46-5.0.0.tgz#3b46d583613ec7283020d79019f1335723801cec" + integrity sha512-tk2G5R2KRwBd+ZN0zaEXpmzdKyOYksXwywulIX95MBODjSzMIuQnQ3m8JxgbhnL1LeVo7lqQKsYa1O3Htl7K5g== + dependencies: + punycode "^2.3.1" + tr46@~0.0.3: version "0.0.3" resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a" @@ -20845,7 +21341,7 @@ type-fest@^0.8.1: resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.8.1.tgz#09e249ebde851d3b1e48d27c105444667f17b83d" integrity sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA== -type-is@^1.6.14, type-is@^1.6.16, type-is@^1.6.18: +type-is@^1.6.14, type-is@^1.6.16, type-is@^1.6.18, type-is@~1.6.18: version "1.6.18" resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131" integrity sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g== @@ -21093,19 +21589,11 @@ universalify@^2.0.0: resolved "https://registry.yarnpkg.com/universalify/-/universalify-2.0.0.tgz#75a4984efedc4b08975c5aeb73f530d02df25717" integrity sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ== -unpipe@1.0.0: +unpipe@1.0.0, unpipe@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" integrity sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ== -unset-value@2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/unset-value/-/unset-value-2.0.1.tgz#57bed0c22d26f28d69acde5df9a11b77c74d2df3" - integrity sha512-2hvrBfjUE00PkqN+q0XP6yRAOGrR06uSiUoIQGZkc7GxvQ9H7v8quUPNtZjMg4uux69i8HWpIjLPUKwCuRGyNg== - dependencies: - has-value "^2.0.2" - isobject "^4.0.0" - untildify@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/untildify/-/untildify-4.0.0.tgz#2bc947b953652487e4600949fb091e3ae8cd919b" @@ -21214,11 +21702,19 @@ util@^0.12.4: is-typed-array "^1.1.3" which-typed-array "^1.1.2" -utils-merge@1.x.x, utils-merge@^1.0.1: +utils-merge@1.0.1, utils-merge@1.x.x, utils-merge@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" integrity sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA== +uue@3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/uue/-/uue-3.1.2.tgz#e99368414e87200012eb37de4dbaebaa1c742ad2" + integrity sha512-axKLXVqwtdI/czrjG0X8hyV1KLgeWx8F4KvSbvVCnS+RUvsQMGRjx0kfuZDXXqj0LYvVJmx3B9kWlKtEdRrJLg== + dependencies: + escape-string-regexp "~1.0.5" + extend "~3.0.0" + uuid-random@^1.3.2: version "1.3.2" resolved "https://registry.yarnpkg.com/uuid-random/-/uuid-random-1.3.2.tgz#96715edbaef4e84b1dcf5024b00d16f30220e2d0" @@ -21300,7 +21796,7 @@ validator@^13.6.0, validator@^13.7.0: resolved "https://registry.yarnpkg.com/validator/-/validator-13.9.0.tgz#33e7b85b604f3bbce9bb1a05d5c3e22e1c2ff855" integrity sha512-B+dGG8U3fdtM0/aNK4/X8CXq/EcxU2WPrPEkJGslb47qyHsxmbggTWK0yEA4qnYVNF+nxNlN88o14hIcPmSIEA== -vary@^1, vary@^1.1.2: +vary@^1, vary@^1.1.2, vary@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" integrity sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg== @@ -21418,6 +21914,13 @@ w3c-xmlserializer@^4.0.0: dependencies: xml-name-validator "^4.0.0" +w3c-xmlserializer@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/w3c-xmlserializer/-/w3c-xmlserializer-5.0.0.tgz#f925ba26855158594d907313cedd1476c5967f6c" + integrity sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA== + dependencies: + xml-name-validator "^5.0.0" + walkdir@^0.4.1: version "0.4.1" resolved "https://registry.yarnpkg.com/walkdir/-/walkdir-0.4.1.tgz#dc119f83f4421df52e3061e514228a2db20afa39" @@ -21489,6 +21992,13 @@ whatwg-encoding@^2.0.0: dependencies: iconv-lite "0.6.3" +whatwg-encoding@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/whatwg-encoding/-/whatwg-encoding-3.1.1.tgz#d0f4ef769905d426e1688f3e34381a99b60b76e5" + integrity sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ== + dependencies: + iconv-lite "0.6.3" + whatwg-mimetype@^2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz#3d4b1e0312d2079879f826aff18dbeeca5960fbf" @@ -21499,6 +22009,11 @@ whatwg-mimetype@^3.0.0: resolved "https://registry.yarnpkg.com/whatwg-mimetype/-/whatwg-mimetype-3.0.0.tgz#5fa1a7623867ff1af6ca3dc72ad6b8a4208beba7" integrity sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q== +whatwg-mimetype@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/whatwg-mimetype/-/whatwg-mimetype-4.0.0.tgz#bc1bf94a985dc50388d54a9258ac405c3ca2fc0a" + integrity sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg== + whatwg-url@^12.0.0, whatwg-url@^12.0.1: version "12.0.1" resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-12.0.1.tgz#fd7bcc71192e7c3a2a97b9a8d6b094853ed8773c" @@ -21515,6 +22030,14 @@ whatwg-url@^13.0.0: tr46 "^4.1.1" webidl-conversions "^7.0.0" +whatwg-url@^14.0.0: + version "14.1.1" + resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-14.1.1.tgz#ce71e240c61541315833b5cdafd139a479e47058" + integrity sha512-mDGf9diDad/giZ/Sm9Xi2YcyzaFpbdLpJPr+E9fSkyQ7KpQD4SdFcugkRQYzhmfI4KeV4Qpnn2sKPdo+kmsgRQ== + dependencies: + tr46 "^5.0.0" + webidl-conversions "^7.0.0" + whatwg-url@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-5.0.0.tgz#966454e8765462e37644d3626f6742ce8b70965d" @@ -21612,6 +22135,11 @@ widest-line@^3.1.0: dependencies: string-width "^4.0.0" +wildstring@1.0.9: + version "1.0.9" + resolved "https://registry.yarnpkg.com/wildstring/-/wildstring-1.0.9.tgz#82a696d5653c7d4ec9ba716859b6b53aba2761c5" + integrity sha512-XBNxKIMLO6uVHf1Xvo++HGWAZZoiVCHmEMCmZJzJ82vQsuUJCLw13Gzq0mRCATk7a3+ZcgeOKSDioavuYqtlfA== + winston-transport@^4.9.0: version "4.9.0" resolved "https://registry.yarnpkg.com/winston-transport/-/winston-transport-4.9.0.tgz#3bba345de10297654ea6f33519424560003b3bf9" @@ -21769,6 +22297,11 @@ ws@^8.13.0: resolved "https://registry.yarnpkg.com/ws/-/ws-8.18.0.tgz#0d7505a6eafe2b0e712d232b42279f53bc289bbc" integrity sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw== +ws@^8.18.0: + version "8.18.1" + resolved "https://registry.yarnpkg.com/ws/-/ws-8.18.1.tgz#ea131d3784e1dfdff91adb0a4a116b127515e3cb" + integrity sha512-RKW2aJZMXeMxVpnZ6bck+RswznaxmzdULiBr6KY7XkTnW8uvt0iT9H5DkHUChXrc+uurzwa0rVI16n/Xzjdz1w== + ws@~8.17.1: version "8.17.1" resolved "https://registry.yarnpkg.com/ws/-/ws-8.17.1.tgz#9293da530bb548febc95371d90f9c878727d919b" @@ -21804,12 +22337,24 @@ xml-name-validator@^4.0.0: resolved "https://registry.yarnpkg.com/xml-name-validator/-/xml-name-validator-4.0.0.tgz#79a006e2e63149a8600f15430f0a4725d1524835" integrity sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw== +xml-name-validator@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/xml-name-validator/-/xml-name-validator-5.0.0.tgz#82be9b957f7afdacf961e5980f1bf227c0bf7673" + integrity sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg== + xml-parse-from-string@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/xml-parse-from-string/-/xml-parse-from-string-1.0.1.tgz#a9029e929d3dbcded169f3c6e28238d95a5d5a28" integrity sha512-ErcKwJTF54uRzzNMXq2X5sMIy88zJvfN2DmdoQvy7PAFJ+tPRU6ydWuOKNMyfmOjdyBQTFREi60s0Y0SyI0G0g== -xml2js@0.1.x, xml2js@0.6.2, xml2js@^0.5.0: +xml2js@0.1.x: + version "0.1.14" + resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.1.14.tgz#5274e67f5a64c5f92974cd85139e0332adc6b90c" + integrity sha512-pbdws4PPPNc1HPluSUKamY4GWMk592K7qwcj6BExbVOhhubub8+pMda/ql68b6L3luZs/OGjGSB5goV7SnmgnA== + dependencies: + sax ">=0.1.1" + +xml2js@0.6.2: version "0.6.2" resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.6.2.tgz#dd0b630083aa09c161e25a4d0901e2b2a929b499" integrity sha512-T4rieHaC1EXcES0Kxxj4JWgaUQHDk+qwHcYOCFHfiwKz7tOVPLq7Hjq9dM1WCMhylqMEfP7hMcOIChvotiZegA== @@ -21817,6 +22362,14 @@ xml2js@0.1.x, xml2js@0.6.2, xml2js@^0.5.0: sax ">=0.6.0" xmlbuilder "~11.0.0" +xml2js@^0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.5.0.tgz#d9440631fbb2ed800203fad106f2724f62c493b7" + integrity sha512-drPFnkQJik/O+uPKpqSgr22mpuFHqKdbS835iAQrUC73L2F5WkboIRd63ai/2Yg6I1jzifPFKH2NTK+cfglkIA== + dependencies: + sax ">=0.6.0" + xmlbuilder "~11.0.0" + xmlbuilder@~11.0.0: version "11.0.1" resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-11.0.1.tgz#be9bae1c8a046e76b31127726347d0ad7002beb3" From 8df8494b162ec8158d91581327f01a3305c6dd2c Mon Sep 17 00:00:00 2001 From: Sam Rose Date: Thu, 27 Feb 2025 09:39:56 +0000 Subject: [PATCH 36/46] A little email test refactoring. --- .../src/api/routes/global/tests/email.spec.ts | 38 +++++++++---------- packages/worker/src/tests/api/email.ts | 20 +++++----- packages/worker/src/tests/mocks/email.ts | 8 ++++ 3 files changed, 37 insertions(+), 29 deletions(-) diff --git a/packages/worker/src/api/routes/global/tests/email.spec.ts b/packages/worker/src/api/routes/global/tests/email.spec.ts index 7bf56fabd3..9e48412caf 100644 --- a/packages/worker/src/api/routes/global/tests/email.spec.ts +++ b/packages/worker/src/api/routes/global/tests/email.spec.ts @@ -3,8 +3,7 @@ import { TestConfiguration } from "../../../../tests" import { captureEmail, deleteAllEmail, - getAttachment, - getUnusedPort, + getAttachments, Mailserver, startMailserver, stopMailserver, @@ -17,8 +16,7 @@ describe("/api/global/email", () => { beforeAll(async () => { await config.beforeAll() - const port = await getUnusedPort() - mailserver = await startMailserver(config, { smtp: port }) + mailserver = await startMailserver(config) }) afterAll(async () => { @@ -45,9 +43,13 @@ describe("/api/global/email", () => { }, ])("can send $purpose emails", async ({ purpose, expectedText }) => { const email = await captureEmail(mailserver, async () => { - const res = await config.api.emails.sendEmail(purpose) - expect(res.body.message).toBeDefined() - expect(res.status).toBe(200) + const res = await config.api.emails.sendEmail({ + email: "foo@example.com", + subject: "Test", + userId: config.user!._id, + purpose, + }) + expect(res.message).toBeDefined() }) expect(email.html).toContain(expectedText) @@ -74,12 +76,14 @@ describe("/api/global/email", () => { } const email = await captureEmail(mailserver, async () => { - const res = await config.api.emails.sendEmail( - EmailTemplatePurpose.WELCOME, - [attachmentObject] - ) - expect(res.body.message).toBeDefined() - expect(res.status).toBe(200) + const res = await config.api.emails.sendEmail({ + email: "foo@example.com", + subject: "Test", + userId: config.user!._id, + purpose: EmailTemplatePurpose.WELCOME, + attachments: [attachmentObject], + }) + expect(res.message).toBeDefined() }) expect(email.html).toContain( @@ -87,11 +91,7 @@ describe("/api/global/email", () => { ) expect(email.html).not.toContain("Invalid binding") - const attachment = await getAttachment( - mailserver, - email, - email.attachments[0] - ) - expect(attachment).toEqual("test data") + const attachments = await getAttachments(mailserver, email) + expect(attachments).toEqual(["test data"]) }) }) diff --git a/packages/worker/src/tests/api/email.ts b/packages/worker/src/tests/api/email.ts index a8f5967d58..810e5a9763 100644 --- a/packages/worker/src/tests/api/email.ts +++ b/packages/worker/src/tests/api/email.ts @@ -1,19 +1,19 @@ -import { EmailAttachment } from "@budibase/types" +import { + EmailAttachment, + SendEmailRequest, + SendEmailResponse, +} from "@budibase/types" import { TestAPI } from "./base" export class EmailAPI extends TestAPI { - sendEmail = (purpose: string, attachments?: EmailAttachment[]) => { - return this.request + sendEmail = async (req: SendEmailRequest): Promise => { + const res = await this.request .post(`/api/global/email/send`) - .send({ - email: "test@example.com", - attachments, - purpose, - tenantId: this.config.getTenantId(), - userId: this.config.user!._id!, - }) + .send(req) .set(this.config.defaultHeaders()) .expect("Content-Type", /json/) .expect(200) + + return res.body as SendEmailResponse } } diff --git a/packages/worker/src/tests/mocks/email.ts b/packages/worker/src/tests/mocks/email.ts index 67ea683ec2..811284ae11 100644 --- a/packages/worker/src/tests/mocks/email.ts +++ b/packages/worker/src/tests/mocks/email.ts @@ -146,3 +146,11 @@ export function getAttachment( ) }) } + +export function getAttachments(mailserver: Mailserver, email: Email) { + return Promise.all( + email.attachments.map(attachment => + getAttachment(mailserver, email, attachment) + ) + ) +} From 3e07627b7134a41c31f8706ef444d048458d77c0 Mon Sep 17 00:00:00 2001 From: Sam Rose Date: Thu, 27 Feb 2025 09:40:25 +0000 Subject: [PATCH 37/46] Update pro reference. --- packages/pro | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/pro b/packages/pro index 219be3ef38..e3843dd4ea 160000 --- a/packages/pro +++ b/packages/pro @@ -1 +1 @@ -Subproject commit 219be3ef380ac8cb16b34892f62117d31b50eec7 +Subproject commit e3843dd4eaced68ae063355b77df200dbc789c98 From 300734328f5483a1c7ff9dac39807ffa086687a5 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Thu, 27 Feb 2025 11:34:19 +0100 Subject: [PATCH 38/46] Remove unused index.js --- packages/client/src/index.js | 142 ----------------------------------- 1 file changed, 142 deletions(-) delete mode 100644 packages/client/src/index.js diff --git a/packages/client/src/index.js b/packages/client/src/index.js deleted file mode 100644 index f19c46a452..0000000000 --- a/packages/client/src/index.js +++ /dev/null @@ -1,142 +0,0 @@ -import ClientApp from "./components/ClientApp.svelte" -import UpdatingApp from "./components/UpdatingApp.svelte" -import { - builderStore, - appStore, - blockStore, - componentStore, - environmentStore, - dndStore, - eventStore, - hoverStore, - stateStore, - routeStore, -} from "./stores" -import loadSpectrumIcons from "@budibase/bbui/spectrum-icons-vite.js" -import { get } from "svelte/store" -import { initWebsocket } from "./websocket.js" - -// Provide svelte and svelte/internal as globals for custom components -import * as svelte from "svelte" -import * as internal from "svelte/internal" - -window.svelte_internal = internal -window.svelte = svelte - -// Initialise spectrum icons -loadSpectrumIcons() - -let app - -const loadBudibase = async () => { - // Update builder store with any builder flags - builderStore.set({ - ...get(builderStore), - inBuilder: !!window["##BUDIBASE_IN_BUILDER##"], - layout: window["##BUDIBASE_PREVIEW_LAYOUT##"], - screen: window["##BUDIBASE_PREVIEW_SCREEN##"], - selectedComponentId: window["##BUDIBASE_SELECTED_COMPONENT_ID##"], - previewId: window["##BUDIBASE_PREVIEW_ID##"], - theme: window["##BUDIBASE_PREVIEW_THEME##"], - customTheme: window["##BUDIBASE_PREVIEW_CUSTOM_THEME##"], - previewDevice: window["##BUDIBASE_PREVIEW_DEVICE##"], - navigation: window["##BUDIBASE_PREVIEW_NAVIGATION##"], - hiddenComponentIds: window["##BUDIBASE_HIDDEN_COMPONENT_IDS##"], - usedPlugins: window["##BUDIBASE_USED_PLUGINS##"], - location: window["##BUDIBASE_LOCATION##"], - snippets: window["##BUDIBASE_SNIPPETS##"], - componentErrors: window["##BUDIBASE_COMPONENT_ERRORS##"], - }) - - // Set app ID - this window flag is set by both the preview and the real - // server rendered app HTML - appStore.actions.setAppId(window["##BUDIBASE_APP_ID##"]) - - // Set the flag used to determine if the app is being loaded via an iframe - appStore.actions.setAppEmbedded( - window["##BUDIBASE_APP_EMBEDDED##"] === "true" - ) - - if (window.MIGRATING_APP) { - new UpdatingApp({ - target: window.document.body, - }) - return - } - - // Fetch environment info - if (!get(environmentStore)?.loaded) { - await environmentStore.actions.fetchEnvironment() - } - - // Register handler for runtime events from the builder - window.handleBuilderRuntimeEvent = (type, data) => { - if (!window["##BUDIBASE_IN_BUILDER##"]) { - return - } - if (type === "event-completed") { - eventStore.actions.resolveEvent(data) - } else if (type === "eject-block") { - const block = blockStore.actions.getBlock(data) - block?.eject() - } else if (type === "dragging-new-component") { - const { dragging, component } = data - if (dragging) { - const definition = - componentStore.actions.getComponentDefinition(component) - dndStore.actions.startDraggingNewComponent({ component, definition }) - } else { - dndStore.actions.reset() - } - } else if (type === "request-context") { - const { selectedComponentInstance, screenslotInstance } = - get(componentStore) - const instance = selectedComponentInstance || screenslotInstance - const context = instance?.getDataContext() - let stringifiedContext = null - try { - stringifiedContext = JSON.stringify(context) - } catch (error) { - // Ignore - invalid context - } - eventStore.actions.dispatchEvent("provide-context", { - context: stringifiedContext, - }) - } else if (type === "hover-component") { - hoverStore.actions.hoverComponent(data, false) - } else if (type === "builder-meta") { - builderStore.actions.setMetadata(data) - } else if (type === "builder-state") { - const [[key, value]] = Object.entries(data) - stateStore.actions.setValue(key, value) - } else if (type === "builder-url-test-data") { - const { route, testValue } = data - routeStore.actions.setTestUrlParams(route, testValue) - } - } - - // Register any custom components - if (window["##BUDIBASE_CUSTOM_COMPONENTS##"]) { - window["##BUDIBASE_CUSTOM_COMPONENTS##"].forEach(component => { - componentStore.actions.registerCustomComponent(component) - }) - } - - // Make a callback available for custom component bundles to register - // themselves at runtime - window.registerCustomComponent = - componentStore.actions.registerCustomComponent - - // Initialise websocket - initWebsocket() - - // Create app if one hasn't been created yet - if (!app) { - app = new ClientApp({ - target: window.document.body, - }) - } -} - -// Attach to window so the HTML template can call this when it loads -window.loadBudibase = loadBudibase From 2865af355681c2aa31440a6493e190ff1a8fef56 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Thu, 27 Feb 2025 11:43:15 +0100 Subject: [PATCH 39/46] Don't validate components within plugins --- packages/builder/src/stores/builder/screenComponent.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/builder/src/stores/builder/screenComponent.ts b/packages/builder/src/stores/builder/screenComponent.ts index 310bf2172c..003f8a47ff 100644 --- a/packages/builder/src/stores/builder/screenComponent.ts +++ b/packages/builder/src/stores/builder/screenComponent.ts @@ -239,7 +239,10 @@ function getMissingAncestors( ancestors: string[] ): UIComponentError[] { const definition = definitions[component._component] - + if (ancestors.some(a => !a.startsWith(BudibasePrefix))) { + // We don't have a way to know what components are used within a plugin component + return [] + } if (!definition?.requiredAncestors?.length) { return [] } From 6fc325a6fa24f2c80496368a27a91a88cad296e6 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Thu, 27 Feb 2025 11:49:04 +0100 Subject: [PATCH 40/46] Validate first missing ancestors --- packages/builder/src/stores/builder/screenComponent.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/builder/src/stores/builder/screenComponent.ts b/packages/builder/src/stores/builder/screenComponent.ts index 003f8a47ff..2b3dde91f8 100644 --- a/packages/builder/src/stores/builder/screenComponent.ts +++ b/packages/builder/src/stores/builder/screenComponent.ts @@ -81,11 +81,11 @@ export const screenComponentErrorList = derived( const errors: UIComponentError[] = [] function checkComponentErrors(component: Component, ancestors: string[]) { + errors.push(...getMissingAncestors(component, definitions, ancestors)) errors.push( ...getInvalidDatasources(screen, component, datasources, definitions) ) errors.push(...getMissingRequiredSettings(component, definitions)) - errors.push(...getMissingAncestors(component, definitions, ancestors)) for (const child of component._children || []) { checkComponentErrors(child, [...ancestors, component._component]) From 7443cd4598097a864e2224fba35409827fe810dd Mon Sep 17 00:00:00 2001 From: Sam Rose Date: Thu, 27 Feb 2025 11:32:13 +0000 Subject: [PATCH 41/46] More email tests. --- packages/types/src/api/web/global/email.ts | 1 - .../src/api/controllers/global/email.ts | 2 - .../src/api/routes/global/tests/email.spec.ts | 228 +++++++++++++++--- packages/worker/src/tests/api/email.ts | 7 +- packages/worker/src/tests/mocks/email.ts | 42 ++-- packages/worker/src/utilities/email.ts | 4 +- 6 files changed, 235 insertions(+), 49 deletions(-) diff --git a/packages/types/src/api/web/global/email.ts b/packages/types/src/api/web/global/email.ts index 3d2e007231..9b3713f91c 100644 --- a/packages/types/src/api/web/global/email.ts +++ b/packages/types/src/api/web/global/email.ts @@ -11,7 +11,6 @@ export enum EmailTemplatePurpose { } export interface SendEmailRequest { - workspaceId?: string email: string userId?: string purpose: EmailTemplatePurpose diff --git a/packages/worker/src/api/controllers/global/email.ts b/packages/worker/src/api/controllers/global/email.ts index 674fe5955f..801bb0d349 100644 --- a/packages/worker/src/api/controllers/global/email.ts +++ b/packages/worker/src/api/controllers/global/email.ts @@ -11,7 +11,6 @@ export async function sendEmail( ctx: UserCtx ) { let { - workspaceId, email, userId, purpose, @@ -33,7 +32,6 @@ export async function sendEmail( } } const response = await sendEmailFn(email, purpose, { - workspaceId, user, contents, from, diff --git a/packages/worker/src/api/routes/global/tests/email.spec.ts b/packages/worker/src/api/routes/global/tests/email.spec.ts index 9e48412caf..18ab0cd78a 100644 --- a/packages/worker/src/api/routes/global/tests/email.spec.ts +++ b/packages/worker/src/api/routes/global/tests/email.spec.ts @@ -1,4 +1,4 @@ -import { EmailTemplatePurpose } from "@budibase/types" +import { EmailTemplatePurpose, SendEmailRequest } from "@budibase/types" import { TestConfiguration } from "../../../../tests" import { captureEmail, @@ -28,33 +28,63 @@ describe("/api/global/email", () => { await deleteAllEmail(mailserver) }) - it.each([ - { - purpose: EmailTemplatePurpose.WELCOME, - expectedText: `Thanks for getting started with Budibase's Budibase platform.`, - }, - { - purpose: EmailTemplatePurpose.INVITATION, - expectedText: `Use the button below to set up your account and get started:`, - }, - { - purpose: EmailTemplatePurpose.PASSWORD_RECOVERY, - expectedText: `You recently requested to reset your password for your Budibase account in your Budibase platform`, - }, - ])("can send $purpose emails", async ({ purpose, expectedText }) => { - const email = await captureEmail(mailserver, async () => { - const res = await config.api.emails.sendEmail({ - email: "foo@example.com", - subject: "Test", - userId: config.user!._id, - purpose, - }) - expect(res.message).toBeDefined() - }) + interface TestCase { + req: Partial + expectedStatus?: number + expectedContents?: string + } - expect(email.html).toContain(expectedText) - expect(email.html).not.toContain("Invalid binding") - }) + const testCases: TestCase[] = [ + { + req: { + purpose: EmailTemplatePurpose.WELCOME, + }, + expectedContents: `Thanks for getting started with Budibase's Budibase platform.`, + }, + { + req: { + purpose: EmailTemplatePurpose.INVITATION, + }, + expectedContents: `Use the button below to set up your account and get started:`, + }, + { + req: { + purpose: EmailTemplatePurpose.PASSWORD_RECOVERY, + }, + expectedContents: `You recently requested to reset your password for your Budibase account in your Budibase platform`, + }, + { + req: { + purpose: EmailTemplatePurpose.CUSTOM, + contents: "Hello, world!", + }, + expectedContents: "Hello, world!", + }, + ] + + it.each(testCases)( + "can send $req.purpose emails", + async ({ req, expectedContents, expectedStatus }) => { + const email = await captureEmail(mailserver, async () => { + const res = await config.api.emails.sendEmail( + { + email: "to@example.com", + subject: "Test", + userId: config.user!._id, + purpose: EmailTemplatePurpose.WELCOME, + ...req, + }, + { + status: expectedStatus || 200, + } + ) + expect(res.message).toBeDefined() + }) + + expect(email.html).toContain(expectedContents) + expect(email.html).not.toContain("Invalid binding") + } + ) it("should be able to send an email with an attachment", async () => { let bucket = "testbucket" @@ -77,7 +107,7 @@ describe("/api/global/email", () => { const email = await captureEmail(mailserver, async () => { const res = await config.api.emails.sendEmail({ - email: "foo@example.com", + email: "to@example.com", subject: "Test", userId: config.user!._id, purpose: EmailTemplatePurpose.WELCOME, @@ -94,4 +124,146 @@ describe("/api/global/email", () => { const attachments = await getAttachments(mailserver, email) expect(attachments).toEqual(["test data"]) }) + + it("should be able to send email without a userId", async () => { + const res = await config.api.emails.sendEmail({ + email: "to@example.com", + subject: "Test", + purpose: EmailTemplatePurpose.WELCOME, + }) + expect(res.message).toBeDefined() + }) + + it("should fail to send a password reset email without a userId", async () => { + const res = await config.api.emails.sendEmail( + { + email: "to@example.com", + subject: "Test", + purpose: EmailTemplatePurpose.PASSWORD_RECOVERY, + }, + { + status: 400, + } + ) + expect(res.message).toBeDefined() + }) + + it("can cc people", async () => { + const email = await captureEmail(mailserver, async () => { + const res = await config.api.emails.sendEmail({ + email: "to@example.com", + cc: "cc@example.com", + subject: "Test", + purpose: EmailTemplatePurpose.CUSTOM, + contents: "Hello, world!", + }) + }) + + expect(email.cc).toEqual([{ address: "cc@example.com", name: "" }]) + }) + + it("can bcc people", async () => { + const email = await captureEmail(mailserver, async () => { + const res = await config.api.emails.sendEmail({ + email: "to@example.com", + bcc: "bcc@example.com", + subject: "Test", + purpose: EmailTemplatePurpose.CUSTOM, + contents: "Hello, world!", + }) + }) + + expect(email.calculatedBcc).toEqual([ + { address: "bcc@example.com", name: "" }, + ]) + }) + + it("can change the from address", async () => { + const email = await captureEmail(mailserver, async () => { + const res = await config.api.emails.sendEmail({ + email: "to@example.com", + from: "from@example.com", + subject: "Test", + purpose: EmailTemplatePurpose.CUSTOM, + contents: "Hello, world!", + }) + expect(res.message).toBeDefined() + }) + + expect(email.to).toEqual([{ address: "to@example.com", name: "" }]) + expect(email.from).toEqual([{ address: "from@example.com", name: "" }]) + }) + + it("can send a calendar invite", async () => { + const startTime = new Date() + const endTime = new Date() + + const email = await captureEmail(mailserver, async () => { + await config.api.emails.sendEmail({ + email: "to@example.com", + subject: "Test", + purpose: EmailTemplatePurpose.CUSTOM, + contents: "Hello, world!", + invite: { + startTime, + endTime, + summary: "Summary", + location: "Location", + url: "http://example.com", + }, + }) + }) + + expect(email.alternatives).toEqual([ + { + charset: "utf-8", + contentType: "text/calendar", + method: "REQUEST", + transferEncoding: "7bit", + content: expect.any(String), + }, + ]) + + // Reference iCal invite: + // BEGIN:VCALENDAR + // VERSION:2.0 + // PRODID:-//sebbo.net//ical-generator//EN + // NAME:Invite + // X-WR-CALNAME:Invite + // BEGIN:VEVENT + // UID:2b5947b7-ec5a-4341-8d70-8d8130183f2a + // SEQUENCE:0 + // DTSTAMP:20200101T000000Z + // DTSTART:20200101T000000Z + // DTEND:20200101T000000Z + // SUMMARY:Summary + // LOCATION:Location + // URL;VALUE=URI:http://example.com + // END:VEVENT + // END:VCALENDAR + expect(email.alternatives[0].content).toContain("BEGIN:VCALENDAR") + expect(email.alternatives[0].content).toContain("BEGIN:VEVENT") + expect(email.alternatives[0].content).toContain("UID:") + expect(email.alternatives[0].content).toContain("SEQUENCE:0") + expect(email.alternatives[0].content).toContain("SUMMARY:Summary") + expect(email.alternatives[0].content).toContain("LOCATION:Location") + expect(email.alternatives[0].content).toContain( + "URL;VALUE=URI:http://example.com" + ) + expect(email.alternatives[0].content).toContain("END:VEVENT") + expect(email.alternatives[0].content).toContain("END:VCALENDAR") + + const formatDate = (date: Date) => + date.toISOString().replace(/[-:]/g, "").split(".")[0] + "Z" + + expect(email.alternatives[0].content).toContain( + `DTSTAMP:${formatDate(startTime)}` + ) + expect(email.alternatives[0].content).toContain( + `DTSTART:${formatDate(startTime)}` + ) + expect(email.alternatives[0].content).toContain( + `DTEND:${formatDate(endTime)}` + ) + }) }) diff --git a/packages/worker/src/tests/api/email.ts b/packages/worker/src/tests/api/email.ts index 810e5a9763..2379f3b92b 100644 --- a/packages/worker/src/tests/api/email.ts +++ b/packages/worker/src/tests/api/email.ts @@ -6,13 +6,16 @@ import { import { TestAPI } from "./base" export class EmailAPI extends TestAPI { - sendEmail = async (req: SendEmailRequest): Promise => { + sendEmail = async ( + req: SendEmailRequest, + expectations?: { status?: number } + ): Promise => { const res = await this.request .post(`/api/global/email/send`) .send(req) .set(this.config.defaultHeaders()) .expect("Content-Type", /json/) - .expect(200) + .expect(expectations?.status || 200) return res.body as SendEmailResponse } diff --git a/packages/worker/src/tests/mocks/email.ts b/packages/worker/src/tests/mocks/email.ts index 811284ae11..d98552e1bc 100644 --- a/packages/worker/src/tests/mocks/email.ts +++ b/packages/worker/src/tests/mocks/email.ts @@ -22,6 +22,14 @@ export interface Address { name?: string } +export interface Alternative { + contentType: string + content: string + charset: string + method: string + transferEncoding: string +} + export interface Envelope { from: Address to: Address[] @@ -31,7 +39,9 @@ export interface Envelope { export interface Email { attachments: Attachment[] - calculatedBcc: string[] + alternatives: Alternative[] + calculatedBcc: Address[] + cc: Address[] date: string envelope: Envelope from: Address[] @@ -62,11 +72,18 @@ export function getUnusedPort(): Promise { }) } -export function waitForEmail( +export async function captureEmail( mailserver: Mailserver, - timeoutMs = 5000 + f: () => Promise ): Promise { - let timeout: ReturnType + const timeoutMs = 5000 + let timeout: ReturnType | undefined = undefined + const cancel = () => { + if (timeout) { + clearTimeout(timeout) + timeout = undefined + } + } const timeoutPromise = new Promise((_, reject) => { timeout = setTimeout(() => { reject(new Error("Timed out waiting for email")) @@ -76,18 +93,15 @@ export function waitForEmail( // @ts-expect-error - types are wrong mailserver.once("new", email => { resolve(email as Email) - clearTimeout(timeout) + cancel() }) }) - return Promise.race([mailPromise, timeoutPromise]) -} - -export async function captureEmail( - mailserver: Mailserver, - f: () => Promise -): Promise { - const emailPromise = waitForEmail(mailserver) - await f() + const emailPromise = Promise.race([mailPromise, timeoutPromise]) + try { + await f() + } finally { + cancel() + } return await emailPromise } diff --git a/packages/worker/src/utilities/email.ts b/packages/worker/src/utilities/email.ts index 5461a18b82..411f6b1e4a 100644 --- a/packages/worker/src/utilities/email.ts +++ b/packages/worker/src/utilities/email.ts @@ -9,7 +9,7 @@ import { EmailTemplatePurpose, User, } from "@budibase/types" -import { configs, cache, objectStore } from "@budibase/backend-core" +import { configs, cache, objectStore, HTTPError } from "@budibase/backend-core" import ical from "ical-generator" import _ from "lodash" @@ -147,7 +147,7 @@ export async function sendEmail( switch (purpose) { case EmailTemplatePurpose.PASSWORD_RECOVERY: if (!opts.user || !opts.user._id) { - throw "User must be provided for password recovery." + throw new HTTPError("User must be provided for password recovery.", 400) } code = await cache.passwordReset.createCode(opts.user._id, opts.info) break From c63d4f21ee5ef3cf619d728d3dc2b72aa566da34 Mon Sep 17 00:00:00 2001 From: Sam Rose Date: Thu, 27 Feb 2025 11:39:43 +0000 Subject: [PATCH 42/46] Fix lint. --- packages/worker/src/api/routes/global/tests/email.spec.ts | 4 ++-- packages/worker/src/tests/api/email.ts | 6 +----- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/packages/worker/src/api/routes/global/tests/email.spec.ts b/packages/worker/src/api/routes/global/tests/email.spec.ts index 18ab0cd78a..bbc6000b58 100644 --- a/packages/worker/src/api/routes/global/tests/email.spec.ts +++ b/packages/worker/src/api/routes/global/tests/email.spec.ts @@ -150,7 +150,7 @@ describe("/api/global/email", () => { it("can cc people", async () => { const email = await captureEmail(mailserver, async () => { - const res = await config.api.emails.sendEmail({ + await config.api.emails.sendEmail({ email: "to@example.com", cc: "cc@example.com", subject: "Test", @@ -164,7 +164,7 @@ describe("/api/global/email", () => { it("can bcc people", async () => { const email = await captureEmail(mailserver, async () => { - const res = await config.api.emails.sendEmail({ + await config.api.emails.sendEmail({ email: "to@example.com", bcc: "bcc@example.com", subject: "Test", diff --git a/packages/worker/src/tests/api/email.ts b/packages/worker/src/tests/api/email.ts index 2379f3b92b..8624f924a5 100644 --- a/packages/worker/src/tests/api/email.ts +++ b/packages/worker/src/tests/api/email.ts @@ -1,8 +1,4 @@ -import { - EmailAttachment, - SendEmailRequest, - SendEmailResponse, -} from "@budibase/types" +import { SendEmailRequest, SendEmailResponse } from "@budibase/types" import { TestAPI } from "./base" export class EmailAPI extends TestAPI { From e4ae1d90b1fffdda1af41044bb9443a1cc937c0d Mon Sep 17 00:00:00 2001 From: Sam Rose Date: Thu, 27 Feb 2025 14:27:34 +0000 Subject: [PATCH 43/46] Reinstate mocks.email.mock(), it wasn't as unused as I thought. --- packages/worker/src/tests/mocks/email.ts | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/packages/worker/src/tests/mocks/email.ts b/packages/worker/src/tests/mocks/email.ts index d98552e1bc..3fd2962fdd 100644 --- a/packages/worker/src/tests/mocks/email.ts +++ b/packages/worker/src/tests/mocks/email.ts @@ -2,6 +2,20 @@ import MailDev from "maildev" import { promisify } from "util" import TestConfiguration from "../TestConfiguration" +/** + * @deprecated please use the `MailDev` email server instead of this mock. + */ +export function mock() { + // mock the email system + const sendMailMock = jest.fn() + const nodemailer = require("nodemailer") + nodemailer.createTransport.mockReturnValue({ + sendMail: sendMailMock, + verify: jest.fn(), + }) + return sendMailMock +} + export type Mailserver = InstanceType export type MailserverConfig = ConstructorParameters[0] From 304047c922952e1801e5cafe7502ee77feacd665 Mon Sep 17 00:00:00 2001 From: Sam Rose Date: Thu, 27 Feb 2025 14:42:15 +0000 Subject: [PATCH 44/46] Update yarn.lock. --- yarn.lock | 192 ++++++++++++++---------------------------------------- 1 file changed, 50 insertions(+), 142 deletions(-) diff --git a/yarn.lock b/yarn.lock index 846a149495..279c4067a4 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1468,7 +1468,7 @@ "@azure/abort-controller" "^2.0.0" tslib "^2.6.2" -"@azure/identity@^4.2.1": +"@azure/identity@4.2.1", "@azure/identity@^4.2.1": version "4.2.1" resolved "https://registry.yarnpkg.com/@azure/identity/-/identity-4.2.1.tgz#22b366201e989b7b41c0e1690e103bd579c31e4c" integrity sha512-U8hsyC9YPcEIzoaObJlRDvp7KiF0MGS7xcWbyJSVvXRkC/HXo1f0oYeBYmEvVgRfacw7GHf6D6yAoh9JHz6A5Q== @@ -2795,6 +2795,28 @@ pouchdb-promise "^6.0.4" through2 "^2.0.0" +"@budibase/pro@npm:@budibase/pro@latest": + version "3.4.20" + resolved "https://registry.yarnpkg.com/@budibase/pro/-/pro-3.4.20.tgz#0d855d6ed8fe92fd178c74a8963d879cc124b034" + integrity sha512-hUteGvhMOKjBo0fluxcqNs7d4x8OU5W8Oqqrm7eIS9Ohe7ala2iWNCcrj+x+S9CavIm6s7JZZnAewa2Maiz2zQ== + dependencies: + "@anthropic-ai/sdk" "^0.27.3" + "@budibase/backend-core" "*" + "@budibase/shared-core" "*" + "@budibase/string-templates" "*" + "@budibase/types" "*" + "@koa/router" "13.1.0" + bull "4.10.1" + dd-trace "5.26.0" + joi "17.6.0" + jsonwebtoken "9.0.2" + lru-cache "^7.14.1" + memorystream "^0.3.1" + node-fetch "2.6.7" + openai "4.59.0" + scim-patch "^0.8.1" + scim2-parse-filter "^0.2.8" + "@budibase/vm-browserify@^1.1.4": version "1.1.4" resolved "https://registry.yarnpkg.com/@budibase/vm-browserify/-/vm-browserify-1.1.4.tgz#eecb001bd9521cb7647e26fb4d2d29d0a4dce262" @@ -8187,23 +8209,7 @@ aws4@^1.8.0: resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.13.2.tgz#0aa167216965ac9474ccfa83892cfb6b3e1e52ef" integrity sha512-lHe62zvbTB5eEABUVi/AwVh0ZKY9rMMDhmm+eeyuuUQbQ3+J+fONVQOZyj+DdrvD4BY33uYniyRJ4UJIaSKAfw== -axios@1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/axios/-/axios-1.1.3.tgz#8274250dada2edf53814ed7db644b9c2866c1e35" - integrity sha512-00tXVRwKx/FZr/IDVFt4C+f9FYairX517WoGCL6dpOntqLkZofjhu43F/Xl44UOpqa+9sLFDrG/XAnFsUYgkDA== - dependencies: - follow-redirects "^1.15.0" - form-data "^4.0.0" - proxy-from-env "^1.1.0" - -axios@^0.21.1: - version "0.21.4" - resolved "https://registry.yarnpkg.com/axios/-/axios-0.21.4.tgz#c67b90dc0568e5c1cf2b0b858c43ba28e2eda575" - integrity sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg== - dependencies: - follow-redirects "^1.14.0" - -axios@^1.0.0, axios@^1.1.3, axios@^1.4.0, axios@^1.6.2, axios@^1.6.8: +axios@1.1.3, axios@1.7.7, axios@^0.21.1, axios@^1.0.0, axios@^1.1.3, axios@^1.4.0, axios@^1.6.2, axios@^1.6.8: version "1.7.7" resolved "https://registry.yarnpkg.com/axios/-/axios-1.7.7.tgz#2f554296f9892a72ac8d8e4c5b79c14a91d0a47f" integrity sha512-S4kL7XrjgBmvdGut0sN3yJxqYzrDOnivkBiN0OFs6hLiUam3UPvswUo0kqGyhqUZGEOytHyumEdXsAkgCOUf3Q== @@ -11985,7 +11991,7 @@ fn.name@1.x.x: resolved "https://registry.yarnpkg.com/fn.name/-/fn.name-1.1.0.tgz#26cad8017967aea8731bc42961d04a3d5988accc" integrity sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw== -follow-redirects@^1.14.0, follow-redirects@^1.15.0, follow-redirects@^1.15.6: +follow-redirects@^1.15.6: version "1.15.9" resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.9.tgz#a604fa10e443bf98ca94228d9eebcc2e8a2c8ee1" integrity sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ== @@ -12605,22 +12611,10 @@ global@~4.4.0: min-document "^2.19.0" process "^0.11.10" -globals@^11.1.0: - version "11.12.0" - resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" - integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== - -globals@^13.19.0: - version "13.24.0" - resolved "https://registry.yarnpkg.com/globals/-/globals-13.24.0.tgz#8432a19d78ce0c1e833949c36adb345400bb1171" - integrity sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ== - dependencies: - type-fest "^0.20.2" - -globals@^14.0.0: - version "14.0.0" - resolved "https://registry.yarnpkg.com/globals/-/globals-14.0.0.tgz#898d7413c29babcf6bafe56fcadded858ada724e" - integrity sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ== +globals@15.13.0, globals@^11.1.0, globals@^13.19.0, globals@^14.0.0: + version "15.13.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-15.13.0.tgz#bbec719d69aafef188ecd67954aae76a696010fc" + integrity sha512-49TewVEz0UxZjr1WYYsWpPrhyC/B/pA8Bq0fUmet2n+eR7yn0IvNzNaoBwnK6mdkzcN+se7Ez9zUgULTz2QH4g== globalthis@^1.0.1, globalthis@^1.0.4: version "1.0.4" @@ -13037,12 +13031,7 @@ http-assert@^1.3.0: deep-equal "~1.0.1" http-errors "~1.8.0" -http-cache-semantics@3.8.1: - version "3.8.1" - resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-3.8.1.tgz#39b0e16add9b605bf0a9ef3d9daaf4843b4cacd2" - integrity sha512-5ai2iksyV8ZXmnZhHH4rWPoxxistEexSi5936zIQ1bnNTW5VnA85B6P/VpXiRM017IgRvb2kKo1a//y+0wSp3w== - -http-cache-semantics@^4.0.0, http-cache-semantics@^4.1.0, http-cache-semantics@^4.1.1: +http-cache-semantics@3.8.1, http-cache-semantics@4.1.1, http-cache-semantics@^4.0.0, http-cache-semantics@^4.1.0, http-cache-semantics@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz#abe02fcb2985460bf0323be664436ec3476a6d5a" integrity sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ== @@ -13523,11 +13512,6 @@ is-boolean-object@^1.1.0: call-bind "^1.0.2" has-tostringtag "^1.0.0" -is-buffer@^1.1.5: - version "1.1.6" - resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" - integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w== - is-buffer@^2.0.5: version "2.0.5" resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-2.0.5.tgz#ebc252e400d22ff8d77fa09888821a24a658c191" @@ -13967,6 +13951,11 @@ isobject@^3.0.1: resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" integrity sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg== +isobject@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/isobject/-/isobject-4.0.0.tgz#3f1c9155e73b192022a80819bacd0343711697b0" + integrity sha512-S/2fF5wH8SJA/kmwr6HYhK/RI/OkhD84k8ntalo0iJjZikgq1XFvR5M8NPT1x5F7fBwCG3qHfnzeP/Vh/ZxCUA== + isolated-vm@^4.7.2: version "4.7.2" resolved "https://registry.yarnpkg.com/isolated-vm/-/isolated-vm-4.7.2.tgz#5670d5cce1d92004f9b825bec5b0b11fc7501b65" @@ -14873,14 +14862,7 @@ kill-port@^1.6.1: get-them-args "1.3.2" shell-exec "1.0.2" -kind-of@^3.0.2, kind-of@^3.1.0: - version "3.2.2" - resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64" - integrity sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ== - dependencies: - is-buffer "^1.1.5" - -kind-of@^6.0.0, kind-of@^6.0.2, kind-of@^6.0.3: +kind-of@6.0.3, kind-of@^3.0.2, kind-of@^3.1.0, kind-of@^6.0.0, kind-of@^6.0.2, kind-of@^6.0.3: version "6.0.3" resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd" integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw== @@ -16314,7 +16296,7 @@ msgpackr-extract@^3.0.2: "@msgpackr-extract/msgpackr-extract-linux-x64" "3.0.2" "@msgpackr-extract/msgpackr-extract-win32-x64" "3.0.2" -msgpackr@^1.5.2: +msgpackr@1.10.1, msgpackr@^1.5.2: version "1.10.1" resolved "https://registry.yarnpkg.com/msgpackr/-/msgpackr-1.10.1.tgz#51953bb4ce4f3494f0c4af3f484f01cfbb306555" integrity sha512-r5VRLv9qouXuLiIBrLpl2d5ZvPt8svdQTl5/vMvE4nzDMyEX4sgW5yWhuBBj5UmgwOTWj8CIdSXn5sAfsHAWIQ== @@ -16512,27 +16494,13 @@ node-domexception@1.0.0: resolved "https://registry.yarnpkg.com/node-domexception/-/node-domexception-1.0.0.tgz#6888db46a1f71c0b76b3f7555016b63fe64766e5" integrity sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ== -node-fetch@2.6.7, node-fetch@^2.6.0, node-fetch@^2.6.1, node-fetch@^2.6.7: +node-fetch@2.6.7, node-fetch@2.6.9, node-fetch@^2.6.0, node-fetch@^2.6.1, node-fetch@^2.6.7, node-fetch@^2.6.9: version "2.6.7" resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.7.tgz#24de9fba827e3b4ae44dc8b20256a379160052ad" integrity sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ== dependencies: whatwg-url "^5.0.0" -node-fetch@2.6.9: - version "2.6.9" - resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.9.tgz#7c7f744b5cc6eb5fd404e0c7a9fec630a55657e6" - integrity sha512-DJm/CJkZkRjKKj4Zi4BsKVZh3ValV5IR5s7LVZnW+6YMh0W1BfNA8XSs6DLMGYlId5F3KnA70uu2qepcR08Qqg== - dependencies: - whatwg-url "^5.0.0" - -node-fetch@^2.6.9: - version "2.7.0" - resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.7.0.tgz#d0f0fa6e3e2dc1d27efcd8ad99d550bda94d187d" - integrity sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A== - dependencies: - whatwg-url "^5.0.0" - node-forge@^1.3.1: version "1.3.1" resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-1.3.1.tgz#be8da2af243b2417d5f646a770663a92b7e9ded3" @@ -17581,15 +17549,7 @@ passport-strategy@1.x.x, passport-strategy@^1.0.0: resolved "https://registry.yarnpkg.com/passport-strategy/-/passport-strategy-1.0.0.tgz#b5539aa8fc225a3d1ad179476ddf236b440f52e4" integrity sha512-CB97UUvDKJde2V0KDWWB3lyf6PC3FaZP7YxZ2G8OAtn9p4HI9j9JLP9qjOGZFvyl8uwNT8qM+hGnz/n16NI7oA== -passport@^0.4.0: - version "0.4.1" - resolved "https://registry.yarnpkg.com/passport/-/passport-0.4.1.tgz#941446a21cb92fc688d97a0861c38ce9f738f270" - integrity sha512-IxXgZZs8d7uFSt3eqNjM9NQ3g3uQCW5avD8mRNoXV99Yig50vjuaez6dQK2qC0kVWPRTujxY0dWgGfT09adjYg== - dependencies: - passport-strategy "1.x.x" - pause "0.0.1" - -passport@^0.6.0: +passport@0.6.0, passport@^0.4.0, passport@^0.6.0: version "0.6.0" resolved "https://registry.yarnpkg.com/passport/-/passport-0.6.0.tgz#e869579fab465b5c0b291e841e6cc95c005fac9d" integrity sha512-0fe+p3ZnrWRW74fe8+SvCyf4a3Pb2/h7gFkQ8yTJpAO50gDzlfjZUZTO1k5Eg9kUct22OxHLqDZoKUWRHOh9ug== @@ -18582,13 +18542,6 @@ pseudomap@^1.0.2: resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3" integrity sha512-b/YwNhb8lk1Zz2+bXXpS/LK9OisiZZ1SNsSLxN1x2OXVEhW2Ckr/7mWE5vrC1ZTiJlD9g19jWszTmJsB+oEpFQ== -psl@^1.1.28: - version "1.15.0" - resolved "https://registry.yarnpkg.com/psl/-/psl-1.15.0.tgz#bdace31896f1d97cec6a79e8224898ce93d974c6" - integrity sha512-JZd3gMVBAVQkSs6HdNZo9Sdo0LNcQeMNP3CozBJb3JYC/QUYZTnKxP+f8oWRX4rHP5EurWxqAHTSwUCjlNKa1w== - dependencies: - punycode "^2.3.1" - psl@^1.1.33: version "1.9.0" resolved "https://registry.yarnpkg.com/psl/-/psl-1.9.0.tgz#d0df2a137f00794565fcaf3b2c00cd09f8d5a5a7" @@ -19473,11 +19426,6 @@ sax@1.2.1: resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.1.tgz#7b8e656190b228e81a66aea748480d828cd2d37a" integrity sha512-8I2a3LovHTOpm7NV5yOyO8IHqgVsfK4+UuySrXU8YXkSRX7k6hCV9b3HrkKCr3nMpgj+0bmocaJJWpvp1oc7ZA== -sax@>=0.1.1: - version "1.4.1" - resolved "https://registry.yarnpkg.com/sax/-/sax-1.4.1.tgz#44cc8988377f126304d3b3fc1010c733b929ef0f" - integrity sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg== - sax@>=0.6.0: version "1.2.4" resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" @@ -19550,28 +19498,13 @@ semver-diff@^3.1.1: dependencies: semver "^6.3.0" -"semver@2 || 3 || 4 || 5", semver@^5.6.0, semver@^5.7.1: - version "5.7.2" - resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.2.tgz#48d55db737c3287cd4835e17fa13feace1c41ef8" - integrity sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g== - -semver@7.5.3, semver@^7.0.0, semver@^7.1.1, semver@^7.3.2, semver@^7.3.4, semver@^7.3.5, semver@^7.3.7, semver@^7.3.8, semver@^7.5.3: +"semver@2 || 3 || 4 || 5", semver@7.5.3, semver@^5.6.0, semver@^5.7.1, semver@^6.0.0, semver@^6.1.1, semver@^6.1.2, semver@^6.2.0, semver@^6.3.0, semver@^6.3.1, semver@^7.0.0, semver@^7.1.1, semver@^7.3.2, semver@^7.3.4, semver@^7.3.5, semver@^7.3.7, semver@^7.3.8, semver@^7.5.3, semver@^7.5.4, semver@^7.6.0, semver@^7.6.2: version "7.5.3" resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.3.tgz#161ce8c2c6b4b3bdca6caadc9fa3317a4c4fe88e" integrity sha512-QBlUtyVk/5EeHbi7X0fw6liDZc7BBmEaSYn01fMU1OUYbf6GPsbTtd8WmnqbI20SeycoHSeiybkE/q1Q+qlThQ== dependencies: lru-cache "^6.0.0" -semver@^6.0.0, semver@^6.1.1, semver@^6.1.2, semver@^6.2.0, semver@^6.3.0, semver@^6.3.1: - version "6.3.1" - resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4" - integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== - -semver@^7.5.4, semver@^7.6.0, semver@^7.6.2: - version "7.7.1" - resolved "https://registry.yarnpkg.com/semver/-/semver-7.7.1.tgz#abd5098d82b18c6c81f6074ff2647fd3e7220c9f" - integrity sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA== - send@0.19.0: version "0.19.0" resolved "https://registry.yarnpkg.com/send/-/send-0.19.0.tgz#bbc5a388c8ea6c048967049dbeac0e4a3f09d7f8" @@ -21092,7 +21025,7 @@ touch@^3.1.0: dependencies: nopt "~1.0.10" -"tough-cookie@^2.3.3 || ^3.0.1 || ^4.0.0", tough-cookie@^4.0.0, tough-cookie@^4.1.2: +tough-cookie@4.1.3, "tough-cookie@^2.3.3 || ^3.0.1 || ^4.0.0", tough-cookie@^4.0.0, tough-cookie@^4.1.2, tough-cookie@^4.1.4, tough-cookie@~2.5.0: version "4.1.3" resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-4.1.3.tgz#97b9adb0728b42280aa3d814b6b999b2ff0318bf" integrity sha512-aX/y5pVRkfRnfmuX+OdbSdXvPe6ieKX/G2s7e98f4poJHnqH3281gDPm/metm6E/WRamfx7WC4HUqkWHfQHprw== @@ -21102,24 +21035,6 @@ touch@^3.1.0: universalify "^0.2.0" url-parse "^1.5.3" -tough-cookie@^4.1.4: - version "4.1.4" - resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-4.1.4.tgz#945f1461b45b5a8c76821c33ea49c3ac192c1b36" - integrity sha512-Loo5UUvLD9ScZ6jh8beX1T6sO1w2/MpCRpEP7V280GKMVUQ0Jzar2U3UJPsrdbziLEMMhu3Ujnq//rhiFuIeag== - dependencies: - psl "^1.1.33" - punycode "^2.1.1" - universalify "^0.2.0" - url-parse "^1.5.3" - -tough-cookie@~2.5.0: - version "2.5.0" - resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.5.0.tgz#cd9fb2a0aa1d5a12b473bd9fb96fa3dcff65ade2" - integrity sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g== - dependencies: - psl "^1.1.28" - punycode "^2.1.1" - tr46@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/tr46/-/tr46-2.1.0.tgz#fa87aa81ca5d5941da8cbf1f9b749dc969a4e240" @@ -21594,6 +21509,14 @@ unpipe@1.0.0, unpipe@~1.0.0: resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" integrity sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ== +unset-value@2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/unset-value/-/unset-value-2.0.1.tgz#57bed0c22d26f28d69acde5df9a11b77c74d2df3" + integrity sha512-2hvrBfjUE00PkqN+q0XP6yRAOGrR06uSiUoIQGZkc7GxvQ9H7v8quUPNtZjMg4uux69i8HWpIjLPUKwCuRGyNg== + dependencies: + has-value "^2.0.2" + isobject "^4.0.0" + untildify@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/untildify/-/untildify-4.0.0.tgz#2bc947b953652487e4600949fb091e3ae8cd919b" @@ -22347,14 +22270,7 @@ xml-parse-from-string@^1.0.0: resolved "https://registry.yarnpkg.com/xml-parse-from-string/-/xml-parse-from-string-1.0.1.tgz#a9029e929d3dbcded169f3c6e28238d95a5d5a28" integrity sha512-ErcKwJTF54uRzzNMXq2X5sMIy88zJvfN2DmdoQvy7PAFJ+tPRU6ydWuOKNMyfmOjdyBQTFREi60s0Y0SyI0G0g== -xml2js@0.1.x: - version "0.1.14" - resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.1.14.tgz#5274e67f5a64c5f92974cd85139e0332adc6b90c" - integrity sha512-pbdws4PPPNc1HPluSUKamY4GWMk592K7qwcj6BExbVOhhubub8+pMda/ql68b6L3luZs/OGjGSB5goV7SnmgnA== - dependencies: - sax ">=0.1.1" - -xml2js@0.6.2: +xml2js@0.1.x, xml2js@0.6.2, xml2js@^0.5.0: version "0.6.2" resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.6.2.tgz#dd0b630083aa09c161e25a4d0901e2b2a929b499" integrity sha512-T4rieHaC1EXcES0Kxxj4JWgaUQHDk+qwHcYOCFHfiwKz7tOVPLq7Hjq9dM1WCMhylqMEfP7hMcOIChvotiZegA== @@ -22362,14 +22278,6 @@ xml2js@0.6.2: sax ">=0.6.0" xmlbuilder "~11.0.0" -xml2js@^0.5.0: - version "0.5.0" - resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.5.0.tgz#d9440631fbb2ed800203fad106f2724f62c493b7" - integrity sha512-drPFnkQJik/O+uPKpqSgr22mpuFHqKdbS835iAQrUC73L2F5WkboIRd63ai/2Yg6I1jzifPFKH2NTK+cfglkIA== - dependencies: - sax ">=0.6.0" - xmlbuilder "~11.0.0" - xmlbuilder@~11.0.0: version "11.0.1" resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-11.0.1.tgz#be9bae1c8a046e76b31127726347d0ad7002beb3" From 6b67eaf9a3c6d1e9f8aa1cf083ba7f32bb79350f Mon Sep 17 00:00:00 2001 From: Budibase Staging Release Bot <> Date: Thu, 27 Feb 2025 17:07:44 +0000 Subject: [PATCH 45/46] Bump version to 3.4.21 --- lerna.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lerna.json b/lerna.json index b391c8e05c..8972a00565 100644 --- a/lerna.json +++ b/lerna.json @@ -1,6 +1,6 @@ { "$schema": "node_modules/lerna/schemas/lerna-schema.json", - "version": "3.4.20", + "version": "3.4.21", "npmClient": "yarn", "concurrency": 20, "command": { From 48dafb42bc7cebcd791a803311c5980075de7dde Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Fri, 28 Feb 2025 10:47:31 +0100 Subject: [PATCH 46/46] Update md --- docs/CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/CONTRIBUTING.md b/docs/CONTRIBUTING.md index 311afbe706..ed2d94aacd 100644 --- a/docs/CONTRIBUTING.md +++ b/docs/CONTRIBUTING.md @@ -108,7 +108,7 @@ You can install them following any of the steps described below: - Installation steps: https://asdf-vm.com/guide/getting-started.html - asdf plugin add nodejs - asdf plugin add python - - npm install -g yarn + - asdf plugin add yarn ### Using NVM and pyenv