From 73c99910b11536395eea8ec8ffbdc665b163d53c Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Tue, 7 Feb 2023 15:32:59 +0000 Subject: [PATCH 001/106] initial commit of API design session outcomes. --- .../types/src/api/web/global/auditLogs.ts | 36 +++++++++++++++++++ packages/types/src/api/web/global/index.ts | 1 + packages/types/src/api/web/index.ts | 1 + packages/types/src/api/web/pagination.ts | 24 +++++++++++++ .../types/src/documents/global/auditLogs.ts | 11 ++++++ packages/types/src/sdk/events/event.ts | 4 +++ 6 files changed, 77 insertions(+) create mode 100644 packages/types/src/api/web/global/auditLogs.ts create mode 100644 packages/types/src/api/web/pagination.ts create mode 100644 packages/types/src/documents/global/auditLogs.ts diff --git a/packages/types/src/api/web/global/auditLogs.ts b/packages/types/src/api/web/global/auditLogs.ts new file mode 100644 index 0000000000..7281d0ca36 --- /dev/null +++ b/packages/types/src/api/web/global/auditLogs.ts @@ -0,0 +1,36 @@ +import { Event, AuditedEventFriendlyName } from "../../../sdk" +import { PaginationResponse, PaginationRequest } from "../" + +export interface DownloadAuditLogsRequest { + userId?: string[] + appId?: string[] + event?: Event[] + startDate?: string + endDate?: string + metadataSearch?: string +} + +export interface SearchAuditLogsRequest + extends PaginationRequest, + DownloadAuditLogsRequest {} + +export interface SearchAuditLogsResponse extends PaginationResponse { + data: { + app: { + _id: string + name: string + } + user: { + _id: string + name: string + } + event: Event + timestamp: string + name: string + metadata: any + }[] +} + +export interface DefinitionsAuditLogsResponse { + events: typeof AuditedEventFriendlyName +} diff --git a/packages/types/src/api/web/global/index.ts b/packages/types/src/api/web/global/index.ts index 415ed55ab1..f9eec2a779 100644 --- a/packages/types/src/api/web/global/index.ts +++ b/packages/types/src/api/web/global/index.ts @@ -1,2 +1,3 @@ export * from "./environmentVariables" +export * from "./auditLogs" export * from "./events" diff --git a/packages/types/src/api/web/index.ts b/packages/types/src/api/web/index.ts index 9688a89c7b..3d209f22bb 100644 --- a/packages/types/src/api/web/index.ts +++ b/packages/types/src/api/web/index.ts @@ -4,3 +4,4 @@ export * from "./errors" export * from "./schedule" export * from "./app" export * from "./global" +export * from "./pagination" diff --git a/packages/types/src/api/web/pagination.ts b/packages/types/src/api/web/pagination.ts new file mode 100644 index 0000000000..ca640d58db --- /dev/null +++ b/packages/types/src/api/web/pagination.ts @@ -0,0 +1,24 @@ +export enum SortOrder { + ASCENDING = "ascending", + DESCENDING = "descending", +} + +export enum SortType { + STRING = "string", + number = "number", +} + +export interface PaginationRequest { + limit?: number + bookmark?: string + sort?: { + order: SortOrder + column: string + type: SortType + } +} + +export interface PaginationResponse { + bookmark: string + hasNextPage: boolean +} diff --git a/packages/types/src/documents/global/auditLogs.ts b/packages/types/src/documents/global/auditLogs.ts new file mode 100644 index 0000000000..bc07bc88d4 --- /dev/null +++ b/packages/types/src/documents/global/auditLogs.ts @@ -0,0 +1,11 @@ +import { Document } from "../document" +import { Event } from "../../sdk" + +export interface AuditLogDocument extends Document { + appId: string + event: Event + userId: string + timestamp: string + metadata: any + name: string +} diff --git a/packages/types/src/sdk/events/event.ts b/packages/types/src/sdk/events/event.ts index f509682add..614dd18ded 100644 --- a/packages/types/src/sdk/events/event.ts +++ b/packages/types/src/sdk/events/event.ts @@ -182,6 +182,10 @@ export enum Event { ENVIRONMENT_VARIABLE_UPGRADE_PANEL_OPENED = "environment_variable:upgrade_panel_opened", } +export const AuditedEventFriendlyName = { + [Event.USER_CREATED]: "user created", +} + // properties added at the final stage of the event pipeline export interface BaseEvent { version?: string From 26becc9950ffdc4ed0965147654280bdd47c6fe0 Mon Sep 17 00:00:00 2001 From: Peter Clement Date: Wed, 8 Feb 2023 15:18:44 +0000 Subject: [PATCH 002/106] add generic page for paywall features --- .../portal/_components/LockedFeature.svelte | 76 +++++++++++++++++++ 1 file changed, 76 insertions(+) create mode 100644 packages/builder/src/pages/builder/portal/_components/LockedFeature.svelte diff --git a/packages/builder/src/pages/builder/portal/_components/LockedFeature.svelte b/packages/builder/src/pages/builder/portal/_components/LockedFeature.svelte new file mode 100644 index 0000000000..e6f4075e2e --- /dev/null +++ b/packages/builder/src/pages/builder/portal/_components/LockedFeature.svelte @@ -0,0 +1,76 @@ + + + + +
+ {title} + {#if !enabled} + + {planType} + + {/if} +
+ {description} +
+ + + {#if enabled} + + {:else} +
+ + + +
+ {/if} +
+ + From 2bd6ff627a83db7cd0984e20b3aec654c8022b94 Mon Sep 17 00:00:00 2001 From: Peter Clement Date: Fri, 10 Feb 2023 14:57:42 +0000 Subject: [PATCH 003/106] update env vars with geneic splash screen --- .../portal/settings/environment/index.svelte | 120 +++++------------- 1 file changed, 34 insertions(+), 86 deletions(-) diff --git a/packages/builder/src/pages/builder/portal/settings/environment/index.svelte b/packages/builder/src/pages/builder/portal/settings/environment/index.svelte index 3c170235e9..cff578febd 100644 --- a/packages/builder/src/pages/builder/portal/settings/environment/index.svelte +++ b/packages/builder/src/pages/builder/portal/settings/environment/index.svelte @@ -1,21 +1,17 @@ - - -
- Environment Variables - {#if !$licensing.environmentVariablesEnabled} - - Business plan - - {/if} -
- Add and manage environment variables for development and production -
- - - {#if $licensing.environmentVariablesEnabled} - {#if noEncryptionKey} - - {/if} -
- -
- - - - - {:else} -
- - - -
+ { + await environment.upgradePanelOpened() + $licensing.goToUpgradePage() + }} +> + {#if noEncryptionKey} + {/if} - +
+ +
+ +
+ + From 70ac7b81c3921b77cddce72d95816d2ada6fde94 Mon Sep 17 00:00:00 2001 From: Peter Clement Date: Mon, 13 Feb 2023 09:47:08 +0000 Subject: [PATCH 004/106] add base audit logs ui --- .../bbui/src/Form/Core/Multiselect.svelte | 2 + packages/bbui/src/Form/Core/Picker.svelte | 11 +- packages/bbui/src/Form/Multiselect.svelte | 5 + packages/bbui/src/Form/Select.svelte | 2 + .../builder/portal/account/_layout.svelte | 3 +- .../auditLogs/_components/UserRenderer.svelte | 6 + .../_components/ViewDetailsRenderer.svelte | 13 ++ .../portal/account/auditLogs/index.svelte | 200 ++++++++++++++++++ .../overview/[appId]/backups/index.svelte | 2 +- .../portal/settings/environment/index.svelte | 1 + .../builder/src/stores/portal/licensing.js | 5 + packages/builder/src/stores/portal/menu.js | 5 + packages/frontend-core/src/constants.js | 1 + 13 files changed, 249 insertions(+), 7 deletions(-) create mode 100644 packages/builder/src/pages/builder/portal/account/auditLogs/_components/UserRenderer.svelte create mode 100644 packages/builder/src/pages/builder/portal/account/auditLogs/_components/ViewDetailsRenderer.svelte create mode 100644 packages/builder/src/pages/builder/portal/account/auditLogs/index.svelte diff --git a/packages/bbui/src/Form/Core/Multiselect.svelte b/packages/bbui/src/Form/Core/Multiselect.svelte index d6c4dc23ac..a315f44a65 100644 --- a/packages/bbui/src/Form/Core/Multiselect.svelte +++ b/packages/bbui/src/Form/Core/Multiselect.svelte @@ -14,6 +14,7 @@ export let autocomplete = false export let sort = false export let autoWidth = false + export let fetchTerm = null const dispatch = createEventDispatcher() @@ -83,6 +84,7 @@ {options} isPlaceholder={!value?.length} {autocomplete} + bind:fetchTerm {isOptionSelected} {getOptionLabel} {getOptionValue} diff --git a/packages/bbui/src/Form/Core/Picker.svelte b/packages/bbui/src/Form/Core/Picker.svelte index 32cfcf3310..acd3c5da61 100644 --- a/packages/bbui/src/Form/Core/Picker.svelte +++ b/packages/bbui/src/Form/Core/Picker.svelte @@ -31,7 +31,8 @@ export let autoWidth = false export let autocomplete = false export let sort = false - + export let fetchTerm = null + $: console.log(fieldText) const dispatch = createEventDispatcher() let searchTerm = null @@ -71,7 +72,7 @@ } const getFilteredOptions = (options, term, getLabel) => { - if (autocomplete && term) { + if (autocomplete && term && !fetchTerm) { const lowerCaseTerm = term.toLowerCase() return options.filter(option => { return `${getLabel(option)}`.toLowerCase().includes(lowerCaseTerm) @@ -144,8 +145,8 @@ > {#if autocomplete} (searchTerm = event.detail)} + value={fetchTerm ? fetchTerm : searchTerm} + on:change={event => (fetchTerm = event.detail)} {disabled} placeholder="Search" /> @@ -247,7 +248,7 @@ } .popover-content.auto-width .spectrum-Menu-itemLabel { white-space: nowrap; - overflow: hidden; + overflow: none; text-overflow: ellipsis; } .popover-content:not(.auto-width) .spectrum-Menu-itemLabel { diff --git a/packages/bbui/src/Form/Multiselect.svelte b/packages/bbui/src/Form/Multiselect.svelte index 7bcf22aa06..d28401b608 100644 --- a/packages/bbui/src/Form/Multiselect.svelte +++ b/packages/bbui/src/Form/Multiselect.svelte @@ -15,6 +15,9 @@ export let getOptionValue = option => option export let sort = false export let autoWidth = false + export let autocomplete = false + export let fetchTerm = null + const dispatch = createEventDispatcher() const onChange = e => { value = e.detail @@ -34,6 +37,8 @@ {getOptionLabel} {getOptionValue} {autoWidth} + {autocomplete} + bind:fetchTerm on:change={onChange} on:click /> diff --git a/packages/bbui/src/Form/Select.svelte b/packages/bbui/src/Form/Select.svelte index 69126e648d..4f30318282 100644 --- a/packages/bbui/src/Form/Select.svelte +++ b/packages/bbui/src/Form/Select.svelte @@ -20,6 +20,7 @@ export let autoWidth = false export let sort = false export let tooltip = "" + export let autocomplete = false const dispatch = createEventDispatcher() const onChange = e => { @@ -51,6 +52,7 @@ {getOptionIcon} {getOptionColour} {isOptionEnabled} + {autocomplete} on:change={onChange} on:click /> diff --git a/packages/builder/src/pages/builder/portal/account/_layout.svelte b/packages/builder/src/pages/builder/portal/account/_layout.svelte index 3083b574a8..892e853aad 100644 --- a/packages/builder/src/pages/builder/portal/account/_layout.svelte +++ b/packages/builder/src/pages/builder/portal/account/_layout.svelte @@ -4,12 +4,13 @@ import { Content, SideNav, SideNavItem } from "components/portal/page" import { menu } from "stores/portal" + $: wide = $isActive("./auditLogs") $: pages = $menu.find(x => x.title === "Account")?.subPages || [] $: !pages.length && $goto("../") - +
{#each pages as { title, href }} diff --git a/packages/builder/src/pages/builder/portal/account/auditLogs/_components/UserRenderer.svelte b/packages/builder/src/pages/builder/portal/account/auditLogs/_components/UserRenderer.svelte new file mode 100644 index 0000000000..4baa24403e --- /dev/null +++ b/packages/builder/src/pages/builder/portal/account/auditLogs/_components/UserRenderer.svelte @@ -0,0 +1,6 @@ + + + diff --git a/packages/builder/src/pages/builder/portal/account/auditLogs/_components/ViewDetailsRenderer.svelte b/packages/builder/src/pages/builder/portal/account/auditLogs/_components/ViewDetailsRenderer.svelte new file mode 100644 index 0000000000..a222871966 --- /dev/null +++ b/packages/builder/src/pages/builder/portal/account/auditLogs/_components/ViewDetailsRenderer.svelte @@ -0,0 +1,13 @@ + + +Edit diff --git a/packages/builder/src/pages/builder/portal/account/auditLogs/index.svelte b/packages/builder/src/pages/builder/portal/account/auditLogs/index.svelte new file mode 100644 index 0000000000..a5d403491a --- /dev/null +++ b/packages/builder/src/pages/builder/portal/account/auditLogs/index.svelte @@ -0,0 +1,200 @@ + + + { + $licensing.goToUpgradePage() + }} +> +
+
+ + + +{#if selectedLog} + +
hello
+
+{/if} + + diff --git a/packages/builder/src/pages/builder/portal/overview/[appId]/backups/index.svelte b/packages/builder/src/pages/builder/portal/overview/[appId]/backups/index.svelte index c15f944601..49b4a5babc 100644 --- a/packages/builder/src/pages/builder/portal/overview/[appId]/backups/index.svelte +++ b/packages/builder/src/pages/builder/portal/overview/[appId]/backups/index.svelte @@ -184,7 +184,7 @@ {#if !$licensing.backupsEnabled} - {#if !$auth.accountPortalAccess && !$licensing.groupsEnabled && $admin.cloud} + {#if !$auth.accountPortalAccess && $admin.cloud} Contact your account holder to upgrade your plan. {/if}
diff --git a/packages/builder/src/pages/builder/portal/settings/environment/index.svelte b/packages/builder/src/pages/builder/portal/settings/environment/index.svelte index cff578febd..013d6b8ff4 100644 --- a/packages/builder/src/pages/builder/portal/settings/environment/index.svelte +++ b/packages/builder/src/pages/builder/portal/settings/environment/index.svelte @@ -55,6 +55,7 @@ notifications.error(`Error saving variable: ${err.message}`) } } + $: console.log($environment.variables) { Constants.Features.ENVIRONMENT_VARIABLES ) + let auditLogsEnabled = license.features.includes( + Constants.Features.AUDIT_LOGS + ) + auditLogsEnabled = true store.update(state => { return { ...state, @@ -72,6 +76,7 @@ export const createLicensingStore = () => { groupsEnabled, backupsEnabled, environmentVariablesEnabled, + auditLogsEnabled, } }) }, diff --git a/packages/builder/src/stores/portal/menu.js b/packages/builder/src/stores/portal/menu.js index 8eea36c08c..56956fc330 100644 --- a/packages/builder/src/stores/portal/menu.js +++ b/packages/builder/src/stores/portal/menu.js @@ -75,6 +75,10 @@ export const menu = derived([admin, auth], ([$admin, $auth]) => { title: "Usage", href: "/builder/portal/account/usage", }, + { + title: "Audit Logs", + href: "/builder/portal/account/auditLogs", + }, ] if ($admin.cloud && $auth?.user?.accountPortalAccess) { accountSubPages.push({ @@ -87,6 +91,7 @@ export const menu = derived([admin, auth], ([$admin, $auth]) => { href: "/builder/portal/account/upgrade", }) } + // add license check here if ( $auth?.user?.accountPortalAccess && $auth.user.account.stripeCustomerId diff --git a/packages/frontend-core/src/constants.js b/packages/frontend-core/src/constants.js index 3a16013df2..8c7103a88f 100644 --- a/packages/frontend-core/src/constants.js +++ b/packages/frontend-core/src/constants.js @@ -115,6 +115,7 @@ export const Features = { USER_GROUPS: "userGroups", BACKUPS: "appBackups", ENVIRONMENT_VARIABLES: "environmentVariables", + AUDIT_LOGS: "auditLogs", } // Role IDs From 2d2c960b75775feea171e09950327143a64838d5 Mon Sep 17 00:00:00 2001 From: Peter Clement Date: Mon, 13 Feb 2023 11:43:25 +0000 Subject: [PATCH 005/106] add audit logs feature --- packages/builder/src/stores/portal/licensing.js | 3 +-- packages/types/src/sdk/licensing/feature.ts | 1 + 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/builder/src/stores/portal/licensing.js b/packages/builder/src/stores/portal/licensing.js index 9adb76fa8c..4215e92741 100644 --- a/packages/builder/src/stores/portal/licensing.js +++ b/packages/builder/src/stores/portal/licensing.js @@ -64,10 +64,9 @@ export const createLicensingStore = () => { Constants.Features.ENVIRONMENT_VARIABLES ) - let auditLogsEnabled = license.features.includes( + const auditLogsEnabled = license.features.includes( Constants.Features.AUDIT_LOGS ) - auditLogsEnabled = true store.update(state => { return { ...state, diff --git a/packages/types/src/sdk/licensing/feature.ts b/packages/types/src/sdk/licensing/feature.ts index a39bcab18b..7ebd1574ca 100644 --- a/packages/types/src/sdk/licensing/feature.ts +++ b/packages/types/src/sdk/licensing/feature.ts @@ -2,4 +2,5 @@ export enum Feature { USER_GROUPS = "userGroups", APP_BACKUPS = "appBackups", ENVIRONMENT_VARIABLES = "environmentVariables", + AUDIT_LOGS = "auditLogs", } From 6d60c275211cc37000f5f01fd585af1fdcbeb900 Mon Sep 17 00:00:00 2001 From: Peter Clement Date: Mon, 13 Feb 2023 16:32:14 +0000 Subject: [PATCH 006/106] add store and api funcs --- .../builder/src/stores/portal/auditLogs.js | 37 ++++++++++++ packages/frontend-core/src/api/auditLogs.js | 58 +++++++++++++++++++ packages/frontend-core/src/api/index.js | 3 + 3 files changed, 98 insertions(+) create mode 100644 packages/builder/src/stores/portal/auditLogs.js create mode 100644 packages/frontend-core/src/api/auditLogs.js diff --git a/packages/builder/src/stores/portal/auditLogs.js b/packages/builder/src/stores/portal/auditLogs.js new file mode 100644 index 0000000000..9381bea86a --- /dev/null +++ b/packages/builder/src/stores/portal/auditLogs.js @@ -0,0 +1,37 @@ +import { writable, get } from "svelte/store" +import { API } from "api" +import { licensing } from "stores/portal" + +export function createAuditLogsStore() { + const { subscribe, set } = writable({ + logs: [], + }) + + async function search(opts = {}) { + if (get(licensing).auditLogsEnabled) { + const paged = await API.searchAuditLogs(opts) + set({ + ...paged, + ...opts, + }) + return paged + } + } + + async function getEventDefinitions() { + return await API.getEventDefinitions() + } + + async function downloadLogs(opts = {}) { + return await API.downloadLogs(opts) + } + + return { + subscribe, + search, + getEventDefinitions, + downloadLogs, + } +} + +export const environment = createAuditLogsStore() diff --git a/packages/frontend-core/src/api/auditLogs.js b/packages/frontend-core/src/api/auditLogs.js new file mode 100644 index 0000000000..9858a88c0b --- /dev/null +++ b/packages/frontend-core/src/api/auditLogs.js @@ -0,0 +1,58 @@ +const buildOpts = ({ + userIds, + appIds, + startDate, + endDate, + metadataSearch, + event, +}) => { + const opts = {} + + if (startDate && endDate) { + opts.startDate = startDate + opts.endDate = endDate + } + + if (metadataSearch) { + opts.metadataSearch = metadataSearch + } + + if (event) { + opts.event = event + } + + if (userIds) { + opts.userId = userIds + } + + if (appIds) { + opts.appId = appIds + } + + return opts +} + +export const buildAuditLogsEndpoints = API => ({ + /** + * Gets a list of users in the current tenant. + */ + searchAuditLogs: async opts => { + return await API.post({ + url: `/api/auditlogs/search`, + body: buildOpts(opts), + }) + }, + + getEventDefinitions: async () => { + return await API.get({ + url: `/api/auditlogs/definitions`, + }) + }, + + downloadLogs: async opts => { + return await API.post({ + url: `/api/auditlogs/definitions`, + body: buildOpts(opts), + }) + }, +}) diff --git a/packages/frontend-core/src/api/index.js b/packages/frontend-core/src/api/index.js index e2935b416b..f8eee45cb8 100644 --- a/packages/frontend-core/src/api/index.js +++ b/packages/frontend-core/src/api/index.js @@ -28,6 +28,8 @@ import { buildPluginEndpoints } from "./plugins" import { buildBackupsEndpoints } from "./backups" import { buildEnvironmentVariableEndpoints } from "./environmentVariables" import { buildEventEndpoints } from "./events" +import { buildAuditLogsEndpoints } from "./auditLogs" + const defaultAPIClientConfig = { /** * Certain definitions can't change at runtime for client apps, such as the @@ -250,5 +252,6 @@ export const createAPIClient = config => { ...buildBackupsEndpoints(API), ...buildEnvironmentVariableEndpoints(API), ...buildEventEndpoints(API), + ...buildAuditLogsEndpoints(API), } } From 05ceee1cfee2e91e2a6110c8e6d768fbdfbeeb45 Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Mon, 13 Feb 2023 17:13:59 +0000 Subject: [PATCH 007/106] Moving lucene handling to backend-core so that it can be used for other databases (outside row indexes). --- packages/backend-core/src/db/index.ts | 1 + packages/backend-core/src/db/lucene.ts | 563 ++++++++++++++++++ packages/backend-core/src/index.ts | 2 + .../src/api/controllers/row/internalSearch.ts | 527 +--------------- .../server/src/api/controllers/row/utils.ts | 3 +- packages/server/src/integrations/base/sql.ts | 4 +- .../server/src/integrations/base/utils.ts | 12 - packages/worker/src/api/routes/index.ts | 3 + 8 files changed, 578 insertions(+), 537 deletions(-) create mode 100644 packages/backend-core/src/db/lucene.ts delete mode 100644 packages/server/src/integrations/base/utils.ts diff --git a/packages/backend-core/src/db/index.ts b/packages/backend-core/src/db/index.ts index 0d9f75fa18..a569b17b36 100644 --- a/packages/backend-core/src/db/index.ts +++ b/packages/backend-core/src/db/index.ts @@ -7,3 +7,4 @@ export { default as Replication } from "./Replication" // exports to support old export structure export * from "../constants/db" export { getGlobalDBName, baseGlobalDBName } from "../context" +export * from "./lucene" diff --git a/packages/backend-core/src/db/lucene.ts b/packages/backend-core/src/db/lucene.ts new file mode 100644 index 0000000000..028750797f --- /dev/null +++ b/packages/backend-core/src/db/lucene.ts @@ -0,0 +1,563 @@ +import fetch from "node-fetch" +import { db as dbCore } from "../" +import { SearchFilters, Row } from "@budibase/types" + +const QUERY_START_REGEX = /\d[0-9]*:/g + +export type SearchParams = { + tableId: string + sort?: string + sortOrder?: string + sortType?: string + limit?: number + bookmark?: string + version?: string + rows?: Row[] +} + +export function removeKeyNumbering(key: any): string { + if (typeof key === "string" && key.match(QUERY_START_REGEX) != null) { + const parts = key.split(":") + // remove the number + parts.shift() + return parts.join(":") + } else { + return key + } +} + +/** + * Class to build lucene query URLs. + * Optionally takes a base lucene query object. + */ +export class QueryBuilder { + dbName: string + index: string + query: SearchFilters + limit: number + sort?: string + bookmark?: string + sortOrder: string + sortType: string + includeDocs: boolean + version?: string + + constructor(dbName: string, index: string, base?: SearchFilters) { + this.dbName = dbName + this.index = index + this.query = { + allOr: false, + string: {}, + fuzzy: {}, + range: {}, + equal: {}, + notEqual: {}, + empty: {}, + notEmpty: {}, + oneOf: {}, + contains: {}, + notContains: {}, + containsAny: {}, + ...base, + } + this.limit = 50 + this.sortOrder = "ascending" + this.sortType = "string" + this.includeDocs = true + } + + setVersion(version?: string) { + if (version != null) { + this.version = version + } + return this + } + + setTable(tableId: string) { + this.query.equal!.tableId = tableId + return this + } + + setLimit(limit?: number) { + if (limit != null) { + this.limit = limit + } + return this + } + + setSort(sort?: string) { + if (sort != null) { + this.sort = sort + } + return this + } + + setSortOrder(sortOrder?: string) { + if (sortOrder != null) { + this.sortOrder = sortOrder + } + return this + } + + setSortType(sortType?: string) { + if (sortType != null) { + this.sortType = sortType + } + return this + } + + setBookmark(bookmark?: string) { + if (bookmark != null) { + this.bookmark = bookmark + } + return this + } + + excludeDocs() { + this.includeDocs = false + return this + } + + addString(key: string, partial: string) { + this.query.string![key] = partial + return this + } + + addFuzzy(key: string, fuzzy: string) { + this.query.fuzzy![key] = fuzzy + return this + } + + addRange(key: string, low: string | number, high: string | number) { + this.query.range![key] = { + low, + high, + } + return this + } + + addEqual(key: string, value: any) { + this.query.equal![key] = value + return this + } + + addNotEqual(key: string, value: any) { + this.query.notEqual![key] = value + return this + } + + addEmpty(key: string, value: any) { + this.query.empty![key] = value + return this + } + + addNotEmpty(key: string, value: any) { + this.query.notEmpty![key] = value + return this + } + + addOneOf(key: string, value: any) { + this.query.oneOf![key] = value + return this + } + + addContains(key: string, value: any) { + this.query.contains![key] = value + return this + } + + addNotContains(key: string, value: any) { + this.query.notContains![key] = value + return this + } + + addContainsAny(key: string, value: any) { + this.query.containsAny![key] = value + return this + } + + /** + * Preprocesses a value before going into a lucene search. + * Transforms strings to lowercase and wraps strings and bools in quotes. + * @param value The value to process + * @param options The preprocess options + * @returns {string|*} + */ + preprocess(value: any, { escape, lowercase, wrap, type }: any = {}) { + const hasVersion = !!this.version + // Determine if type needs wrapped + const originalType = typeof value + // Convert to lowercase + if (value && lowercase) { + value = value.toLowerCase ? value.toLowerCase() : value + } + // Escape characters + if (escape && originalType === "string") { + value = `${value}`.replace(/[ #+\-&|!(){}\]^"~*?:\\]/g, "\\$&") + } + + // Wrap in quotes + if (originalType === "string" && !isNaN(value) && !type) { + value = `"${value}"` + } else if (hasVersion && wrap) { + value = originalType === "number" ? value : `"${value}"` + } + return value + } + + buildSearchQuery() { + const builder = this + let allOr = this.query && this.query.allOr + let query = allOr ? "" : "*:*" + const allPreProcessingOpts = { escape: true, lowercase: true, wrap: true } + let tableId + if (this.query.equal!.tableId) { + tableId = this.query.equal!.tableId + delete this.query.equal!.tableId + } + + const equal = (key: string, value: any) => { + // 0 evaluates to false, which means we would return all rows if we don't check it + if (!value && value !== 0) { + return null + } + return `${key}:${builder.preprocess(value, allPreProcessingOpts)}` + } + + const contains = (key: string, value: any, mode = "AND") => { + if (Array.isArray(value) && value.length === 0) { + return null + } + if (!Array.isArray(value)) { + return `${key}:${value}` + } + let statement = `${builder.preprocess(value[0], { escape: true })}` + for (let i = 1; i < value.length; i++) { + statement += ` ${mode} ${builder.preprocess(value[i], { + escape: true, + })}` + } + return `${key}:(${statement})` + } + + const notContains = (key: string, value: any) => { + // @ts-ignore + const allPrefix = allOr === "" ? "*:* AND" : "" + return allPrefix + "NOT " + contains(key, value) + } + + const containsAny = (key: string, value: any) => { + return contains(key, value, "OR") + } + + const oneOf = (key: string, value: any) => { + if (!Array.isArray(value)) { + if (typeof value === "string") { + value = value.split(",") + } else { + return "" + } + } + let orStatement = `${builder.preprocess(value[0], allPreProcessingOpts)}` + for (let i = 1; i < value.length; i++) { + orStatement += ` OR ${builder.preprocess( + value[i], + allPreProcessingOpts + )}` + } + return `${key}:(${orStatement})` + } + + function build(structure: any, queryFn: any) { + for (let [key, value] of Object.entries(structure)) { + // check for new format - remove numbering if needed + key = removeKeyNumbering(key) + key = builder.preprocess(key.replace(/ /g, "_"), { + escape: true, + }) + const expression = queryFn(key, value) + if (expression == null) { + continue + } + if (query.length > 0) { + query += ` ${allOr ? "OR" : "AND"} ` + } + query += expression + } + } + + // Construct the actual lucene search query string from JSON structure + if (this.query.string) { + build(this.query.string, (key: string, value: any) => { + if (!value) { + return null + } + value = builder.preprocess(value, { + escape: true, + lowercase: true, + type: "string", + }) + return `${key}:${value}*` + }) + } + if (this.query.range) { + build(this.query.range, (key: string, value: any) => { + if (!value) { + return null + } + if (value.low == null || value.low === "") { + return null + } + if (value.high == null || value.high === "") { + return null + } + const low = builder.preprocess(value.low, allPreProcessingOpts) + const high = builder.preprocess(value.high, allPreProcessingOpts) + return `${key}:[${low} TO ${high}]` + }) + } + if (this.query.fuzzy) { + build(this.query.fuzzy, (key: string, value: any) => { + if (!value) { + return null + } + value = builder.preprocess(value, { + escape: true, + lowercase: true, + type: "fuzzy", + }) + return `${key}:${value}~` + }) + } + if (this.query.equal) { + build(this.query.equal, equal) + } + if (this.query.notEqual) { + build(this.query.notEqual, (key: string, value: any) => { + if (!value) { + return null + } + return `!${key}:${builder.preprocess(value, allPreProcessingOpts)}` + }) + } + if (this.query.empty) { + build(this.query.empty, (key: string) => `!${key}:["" TO *]`) + } + if (this.query.notEmpty) { + build(this.query.notEmpty, (key: string) => `${key}:["" TO *]`) + } + if (this.query.oneOf) { + build(this.query.oneOf, oneOf) + } + if (this.query.contains) { + build(this.query.contains, contains) + } + if (this.query.notContains) { + build(this.query.notContains, notContains) + } + if (this.query.containsAny) { + build(this.query.containsAny, containsAny) + } + // make sure table ID is always added as an AND + if (tableId) { + query = `(${query})` + allOr = false + build({ tableId }, equal) + } + return query + } + + buildSearchBody() { + let body: any = { + q: this.buildSearchQuery(), + limit: Math.min(this.limit, 200), + include_docs: this.includeDocs, + } + if (this.bookmark) { + body.bookmark = this.bookmark + } + if (this.sort) { + const order = this.sortOrder === "descending" ? "-" : "" + const type = `<${this.sortType}>` + body.sort = `${order}${this.sort.replace(/ /g, "_")}${type}` + } + return body + } + + async run() { + const { url, cookie } = dbCore.getCouchInfo() + const fullPath = `${url}/${this.dbName}/_design/database/_search/${this.index}` + const body = this.buildSearchBody() + return await runQuery(fullPath, body, cookie) + } +} + +/** + * Executes a lucene search query. + * @param url The query URL + * @param body The request body defining search criteria + * @param cookie The auth cookie for CouchDB + * @returns {Promise<{rows: []}>} + */ +const runQuery = async (url: string, body: any, cookie: string) => { + const response = await fetch(url, { + body: JSON.stringify(body), + method: "POST", + headers: { + Authorization: cookie, + }, + }) + const json = await response.json() + + let output: any = { + rows: [], + } + if (json.rows != null && json.rows.length > 0) { + output.rows = json.rows.map((row: any) => row.doc) + } + if (json.bookmark) { + output.bookmark = json.bookmark + } + return output +} + +/** + * Gets round the fixed limit of 200 results from a query by fetching as many + * pages as required and concatenating the results. This recursively operates + * until enough results have been found. + * @param dbName {string} Which database to run a lucene query on + * @param index {string} Which search index to utilise + * @param query {object} The JSON query structure + * @param params {object} The search params including: + * tableId {string} The table ID to search + * sort {string} The sort column + * sortOrder {string} The sort order ("ascending" or "descending") + * sortType {string} Whether to treat sortable values as strings or + * numbers. ("string" or "number") + * limit {number} The number of results to fetch + * bookmark {string|null} Current bookmark in the recursive search + * rows {array|null} Current results in the recursive search + * @returns {Promise<*[]|*>} + */ +async function recursiveSearch( + dbName: string, + index: string, + query: any, + params: any +): Promise { + const bookmark = params.bookmark + const rows = params.rows || [] + if (rows.length >= params.limit) { + return rows + } + let pageSize = 200 + if (rows.length > params.limit - 200) { + pageSize = params.limit - rows.length + } + const page = await new QueryBuilder(dbName, index, query) + .setVersion(params.version) + .setTable(params.tableId) + .setBookmark(bookmark) + .setLimit(pageSize) + .setSort(params.sort) + .setSortOrder(params.sortOrder) + .setSortType(params.sortType) + .run() + if (!page.rows.length) { + return rows + } + if (page.rows.length < 200) { + return [...rows, ...page.rows] + } + const newParams = { + ...params, + bookmark: page.bookmark, + rows: [...rows, ...page.rows], + } + return await recursiveSearch(dbName, index, query, newParams) +} + +/** + * Performs a paginated search. A bookmark will be returned to allow the next + * page to be fetched. There is a max limit off 200 results per page in a + * paginated search. + * @param dbName {string} Which database to run a lucene query on + * @param index {string} Which search index to utilise + * @param query {object} The JSON query structure + * @param params {object} The search params including: + * tableId {string} The table ID to search + * sort {string} The sort column + * sortOrder {string} The sort order ("ascending" or "descending") + * sortType {string} Whether to treat sortable values as strings or + * numbers. ("string" or "number") + * limit {number} The desired page size + * bookmark {string} The bookmark to resume from + * @returns {Promise<{hasNextPage: boolean, rows: *[]}>} + */ +export async function paginatedSearch( + dbName: string, + index: string, + query: SearchFilters, + params: SearchParams +) { + let limit = params.limit + if (limit == null || isNaN(limit) || limit < 0) { + limit = 50 + } + limit = Math.min(limit, 200) + const search = new QueryBuilder(dbName, index, query) + .setVersion(params.version) + .setTable(params.tableId) + .setSort(params.sort) + .setSortOrder(params.sortOrder) + .setSortType(params.sortType) + const searchResults = await search + .setBookmark(params.bookmark) + .setLimit(limit) + .run() + + // Try fetching 1 row in the next page to see if another page of results + // exists or not + const nextResults = await search + .setTable(params.tableId) + .setBookmark(searchResults.bookmark) + .setLimit(1) + .run() + + return { + ...searchResults, + hasNextPage: nextResults.rows && nextResults.rows.length > 0, + } +} + +/** + * Performs a full search, fetching multiple pages if required to return the + * desired amount of results. There is a limit of 1000 results to avoid + * heavy performance hits, and to avoid client components breaking from + * handling too much data. + * @param dbName {string} Which database to run a lucene query on + * @param index {string} Which search index to utilise + * @param query {object} The JSON query structure + * @param params {object} The search params including: + * tableId {string} The table ID to search + * sort {string} The sort column + * sortOrder {string} The sort order ("ascending" or "descending") + * sortType {string} Whether to treat sortable values as strings or + * numbers. ("string" or "number") + * limit {number} The desired number of results + * @returns {Promise<{rows: *}>} + */ +export async function fullSearch( + dbName: string, + index: string, + query: SearchFilters, + params: SearchParams +) { + let limit = params.limit + if (limit == null || isNaN(limit) || limit < 0) { + limit = 1000 + } + params.limit = Math.min(limit, 1000) + const rows = await recursiveSearch(dbName, index, query, params) + return { rows } +} diff --git a/packages/backend-core/src/index.ts b/packages/backend-core/src/index.ts index b38a53e9e4..aa205e0317 100644 --- a/packages/backend-core/src/index.ts +++ b/packages/backend-core/src/index.ts @@ -25,6 +25,8 @@ export * as utils from "./utils" export * as errors from "./errors" export { default as env } from "./environment" +export { SearchParams } from "./db" + // expose error classes directly export * from "./errors" diff --git a/packages/server/src/api/controllers/row/internalSearch.ts b/packages/server/src/api/controllers/row/internalSearch.ts index 7068aabc5a..a250fe0429 100644 --- a/packages/server/src/api/controllers/row/internalSearch.ts +++ b/packages/server/src/api/controllers/row/internalSearch.ts @@ -1,531 +1,16 @@ import { SearchIndexes } from "../../../db/utils" -import { removeKeyNumbering } from "./utils" -import fetch from "node-fetch" -import { db as dbCore, context } from "@budibase/backend-core" -import { SearchFilters, Row } from "@budibase/types" +import { db as dbCore, context, SearchParams } from "@budibase/backend-core" +import { SearchFilters } from "@budibase/types" -type SearchParams = { - tableId: string - sort?: string - sortOrder?: string - sortType?: string - limit?: number - bookmark?: string - version?: string - rows?: Row[] -} - -/** - * Class to build lucene query URLs. - * Optionally takes a base lucene query object. - */ -export class QueryBuilder { - query: SearchFilters - limit: number - sort?: string - bookmark?: string - sortOrder: string - sortType: string - includeDocs: boolean - version?: string - - constructor(base?: SearchFilters) { - this.query = { - allOr: false, - string: {}, - fuzzy: {}, - range: {}, - equal: {}, - notEqual: {}, - empty: {}, - notEmpty: {}, - oneOf: {}, - contains: {}, - notContains: {}, - containsAny: {}, - ...base, - } - this.limit = 50 - this.sortOrder = "ascending" - this.sortType = "string" - this.includeDocs = true - } - - setVersion(version?: string) { - if (version != null) { - this.version = version - } - return this - } - - setTable(tableId: string) { - this.query.equal!.tableId = tableId - return this - } - - setLimit(limit?: number) { - if (limit != null) { - this.limit = limit - } - return this - } - - setSort(sort?: string) { - if (sort != null) { - this.sort = sort - } - return this - } - - setSortOrder(sortOrder?: string) { - if (sortOrder != null) { - this.sortOrder = sortOrder - } - return this - } - - setSortType(sortType?: string) { - if (sortType != null) { - this.sortType = sortType - } - return this - } - - setBookmark(bookmark?: string) { - if (bookmark != null) { - this.bookmark = bookmark - } - return this - } - - excludeDocs() { - this.includeDocs = false - return this - } - - addString(key: string, partial: string) { - this.query.string![key] = partial - return this - } - - addFuzzy(key: string, fuzzy: string) { - this.query.fuzzy![key] = fuzzy - return this - } - - addRange(key: string, low: string | number, high: string | number) { - this.query.range![key] = { - low, - high, - } - return this - } - - addEqual(key: string, value: any) { - this.query.equal![key] = value - return this - } - - addNotEqual(key: string, value: any) { - this.query.notEqual![key] = value - return this - } - - addEmpty(key: string, value: any) { - this.query.empty![key] = value - return this - } - - addNotEmpty(key: string, value: any) { - this.query.notEmpty![key] = value - return this - } - - addOneOf(key: string, value: any) { - this.query.oneOf![key] = value - return this - } - - addContains(key: string, value: any) { - this.query.contains![key] = value - return this - } - - addNotContains(key: string, value: any) { - this.query.notContains![key] = value - return this - } - - addContainsAny(key: string, value: any) { - this.query.containsAny![key] = value - return this - } - - /** - * Preprocesses a value before going into a lucene search. - * Transforms strings to lowercase and wraps strings and bools in quotes. - * @param value The value to process - * @param options The preprocess options - * @returns {string|*} - */ - preprocess(value: any, { escape, lowercase, wrap, type }: any = {}) { - const hasVersion = !!this.version - // Determine if type needs wrapped - const originalType = typeof value - // Convert to lowercase - if (value && lowercase) { - value = value.toLowerCase ? value.toLowerCase() : value - } - // Escape characters - if (escape && originalType === "string") { - value = `${value}`.replace(/[ #+\-&|!(){}\]^"~*?:\\]/g, "\\$&") - } - - // Wrap in quotes - if (originalType === "string" && !isNaN(value) && !type) { - value = `"${value}"` - } else if (hasVersion && wrap) { - value = originalType === "number" ? value : `"${value}"` - } - return value - } - - buildSearchQuery() { - const builder = this - let allOr = this.query && this.query.allOr - let query = allOr ? "" : "*:*" - const allPreProcessingOpts = { escape: true, lowercase: true, wrap: true } - let tableId - if (this.query.equal!.tableId) { - tableId = this.query.equal!.tableId - delete this.query.equal!.tableId - } - - const equal = (key: string, value: any) => { - // 0 evaluates to false, which means we would return all rows if we don't check it - if (!value && value !== 0) { - return null - } - return `${key}:${builder.preprocess(value, allPreProcessingOpts)}` - } - - const contains = (key: string, value: any, mode = "AND") => { - if (Array.isArray(value) && value.length === 0) { - return null - } - if (!Array.isArray(value)) { - return `${key}:${value}` - } - let statement = `${builder.preprocess(value[0], { escape: true })}` - for (let i = 1; i < value.length; i++) { - statement += ` ${mode} ${builder.preprocess(value[i], { - escape: true, - })}` - } - return `${key}:(${statement})` - } - - const notContains = (key: string, value: any) => { - // @ts-ignore - const allPrefix = allOr === "" ? "*:* AND" : "" - return allPrefix + "NOT " + contains(key, value) - } - - const containsAny = (key: string, value: any) => { - return contains(key, value, "OR") - } - - const oneOf = (key: string, value: any) => { - if (!Array.isArray(value)) { - if (typeof value === "string") { - value = value.split(",") - } else { - return "" - } - } - let orStatement = `${builder.preprocess(value[0], allPreProcessingOpts)}` - for (let i = 1; i < value.length; i++) { - orStatement += ` OR ${builder.preprocess( - value[i], - allPreProcessingOpts - )}` - } - return `${key}:(${orStatement})` - } - - function build(structure: any, queryFn: any) { - for (let [key, value] of Object.entries(structure)) { - // check for new format - remove numbering if needed - key = removeKeyNumbering(key) - key = builder.preprocess(key.replace(/ /g, "_"), { - escape: true, - }) - const expression = queryFn(key, value) - if (expression == null) { - continue - } - if (query.length > 0) { - query += ` ${allOr ? "OR" : "AND"} ` - } - query += expression - } - } - - // Construct the actual lucene search query string from JSON structure - if (this.query.string) { - build(this.query.string, (key: string, value: any) => { - if (!value) { - return null - } - value = builder.preprocess(value, { - escape: true, - lowercase: true, - type: "string", - }) - return `${key}:${value}*` - }) - } - if (this.query.range) { - build(this.query.range, (key: string, value: any) => { - if (!value) { - return null - } - if (value.low == null || value.low === "") { - return null - } - if (value.high == null || value.high === "") { - return null - } - const low = builder.preprocess(value.low, allPreProcessingOpts) - const high = builder.preprocess(value.high, allPreProcessingOpts) - return `${key}:[${low} TO ${high}]` - }) - } - if (this.query.fuzzy) { - build(this.query.fuzzy, (key: string, value: any) => { - if (!value) { - return null - } - value = builder.preprocess(value, { - escape: true, - lowercase: true, - type: "fuzzy", - }) - return `${key}:${value}~` - }) - } - if (this.query.equal) { - build(this.query.equal, equal) - } - if (this.query.notEqual) { - build(this.query.notEqual, (key: string, value: any) => { - if (!value) { - return null - } - return `!${key}:${builder.preprocess(value, allPreProcessingOpts)}` - }) - } - if (this.query.empty) { - build(this.query.empty, (key: string) => `!${key}:["" TO *]`) - } - if (this.query.notEmpty) { - build(this.query.notEmpty, (key: string) => `${key}:["" TO *]`) - } - if (this.query.oneOf) { - build(this.query.oneOf, oneOf) - } - if (this.query.contains) { - build(this.query.contains, contains) - } - if (this.query.notContains) { - build(this.query.notContains, notContains) - } - if (this.query.containsAny) { - build(this.query.containsAny, containsAny) - } - // make sure table ID is always added as an AND - if (tableId) { - query = `(${query})` - allOr = false - build({ tableId }, equal) - } - return query - } - - buildSearchBody() { - let body: any = { - q: this.buildSearchQuery(), - limit: Math.min(this.limit, 200), - include_docs: this.includeDocs, - } - if (this.bookmark) { - body.bookmark = this.bookmark - } - if (this.sort) { - const order = this.sortOrder === "descending" ? "-" : "" - const type = `<${this.sortType}>` - body.sort = `${order}${this.sort.replace(/ /g, "_")}${type}` - } - return body - } - - async run() { - const appId = context.getAppId() - const { url, cookie } = dbCore.getCouchInfo() - const fullPath = `${url}/${appId}/_design/database/_search/${SearchIndexes.ROWS}` - const body = this.buildSearchBody() - return await runQuery(fullPath, body, cookie) - } -} - -/** - * Executes a lucene search query. - * @param url The query URL - * @param body The request body defining search criteria - * @param cookie The auth cookie for CouchDB - * @returns {Promise<{rows: []}>} - */ -const runQuery = async (url: string, body: any, cookie: string) => { - const response = await fetch(url, { - body: JSON.stringify(body), - method: "POST", - headers: { - Authorization: cookie, - }, - }) - const json = await response.json() - - let output: any = { - rows: [], - } - if (json.rows != null && json.rows.length > 0) { - output.rows = json.rows.map((row: any) => row.doc) - } - if (json.bookmark) { - output.bookmark = json.bookmark - } - return output -} - -/** - * Gets round the fixed limit of 200 results from a query by fetching as many - * pages as required and concatenating the results. This recursively operates - * until enough results have been found. - * @param query {object} The JSON query structure - * @param params {object} The search params including: - * tableId {string} The table ID to search - * sort {string} The sort column - * sortOrder {string} The sort order ("ascending" or "descending") - * sortType {string} Whether to treat sortable values as strings or - * numbers. ("string" or "number") - * limit {number} The number of results to fetch - * bookmark {string|null} Current bookmark in the recursive search - * rows {array|null} Current results in the recursive search - * @returns {Promise<*[]|*>} - */ -async function recursiveSearch(query: any, params: any): Promise { - const bookmark = params.bookmark - const rows = params.rows || [] - if (rows.length >= params.limit) { - return rows - } - let pageSize = 200 - if (rows.length > params.limit - 200) { - pageSize = params.limit - rows.length - } - const page = await new QueryBuilder(query) - .setVersion(params.version) - .setTable(params.tableId) - .setBookmark(bookmark) - .setLimit(pageSize) - .setSort(params.sort) - .setSortOrder(params.sortOrder) - .setSortType(params.sortType) - .run() - if (!page.rows.length) { - return rows - } - if (page.rows.length < 200) { - return [...rows, ...page.rows] - } - const newParams = { - ...params, - bookmark: page.bookmark, - rows: [...rows, ...page.rows], - } - return await recursiveSearch(query, newParams) -} - -/** - * Performs a paginated search. A bookmark will be returned to allow the next - * page to be fetched. There is a max limit off 200 results per page in a - * paginated search. - * @param query {object} The JSON query structure - * @param params {object} The search params including: - * tableId {string} The table ID to search - * sort {string} The sort column - * sortOrder {string} The sort order ("ascending" or "descending") - * sortType {string} Whether to treat sortable values as strings or - * numbers. ("string" or "number") - * limit {number} The desired page size - * bookmark {string} The bookmark to resume from - * @returns {Promise<{hasNextPage: boolean, rows: *[]}>} - */ export async function paginatedSearch( query: SearchFilters, params: SearchParams ) { - let limit = params.limit - if (limit == null || isNaN(limit) || limit < 0) { - limit = 50 - } - limit = Math.min(limit, 200) - const search = new QueryBuilder(query) - .setVersion(params.version) - .setTable(params.tableId) - .setSort(params.sort) - .setSortOrder(params.sortOrder) - .setSortType(params.sortType) - const searchResults = await search - .setBookmark(params.bookmark) - .setLimit(limit) - .run() - - // Try fetching 1 row in the next page to see if another page of results - // exists or not - const nextResults = await search - .setTable(params.tableId) - .setBookmark(searchResults.bookmark) - .setLimit(1) - .run() - - return { - ...searchResults, - hasNextPage: nextResults.rows && nextResults.rows.length > 0, - } + const appId = context.getAppId() + return dbCore.paginatedSearch(appId!, SearchIndexes.ROWS, query, params) } -/** - * Performs a full search, fetching multiple pages if required to return the - * desired amount of results. There is a limit of 1000 results to avoid - * heavy performance hits, and to avoid client components breaking from - * handling too much data. - * @param query {object} The JSON query structure - * @param params {object} The search params including: - * tableId {string} The table ID to search - * sort {string} The sort column - * sortOrder {string} The sort order ("ascending" or "descending") - * sortType {string} Whether to treat sortable values as strings or - * numbers. ("string" or "number") - * limit {number} The desired number of results - * @returns {Promise<{rows: *}>} - */ export async function fullSearch(query: SearchFilters, params: SearchParams) { - let limit = params.limit - if (limit == null || isNaN(limit) || limit < 0) { - limit = 1000 - } - params.limit = Math.min(limit, 1000) - const rows = await recursiveSearch(query, params) - return { rows } + const appId = context.getAppId() + return dbCore.fullSearch(appId!, SearchIndexes.ROWS, query, params) } diff --git a/packages/server/src/api/controllers/row/utils.ts b/packages/server/src/api/controllers/row/utils.ts index f0f1075205..82232b7f98 100644 --- a/packages/server/src/api/controllers/row/utils.ts +++ b/packages/server/src/api/controllers/row/utils.ts @@ -3,8 +3,7 @@ import * as userController from "../user" import { FieldTypes } from "../../../constants" import { context } from "@budibase/backend-core" import { makeExternalQuery } from "../../../integrations/base/query" -import { BBContext, Row, Table } from "@budibase/types" -export { removeKeyNumbering } from "../../../integrations/base/utils" +import { Row, Table } from "@budibase/types" const validateJs = require("validate.js") const { cloneDeep } = require("lodash/fp") import { Format } from "../view/exporters" diff --git a/packages/server/src/integrations/base/sql.ts b/packages/server/src/integrations/base/sql.ts index e42350091b..557fbbedfd 100644 --- a/packages/server/src/integrations/base/sql.ts +++ b/packages/server/src/integrations/base/sql.ts @@ -6,11 +6,11 @@ import { SearchFilters, SortDirection, } from "@budibase/types" +import { db as dbCore } from "@budibase/backend-core" import { QueryOptions } from "../../definitions/datasource" import { isIsoDateString, SqlClient } from "../utils" import SqlTableQueryBuilder from "./sqlTable" import environment from "../../environment" -import { removeKeyNumbering } from "./utils" const envLimit = environment.SQL_MAX_ROWS ? parseInt(environment.SQL_MAX_ROWS) @@ -136,7 +136,7 @@ class InternalBuilder { fn: (key: string, value: any) => void ) { for (let [key, value] of Object.entries(structure)) { - const updatedKey = removeKeyNumbering(key) + const updatedKey = dbCore.removeKeyNumbering(key) const isRelationshipField = updatedKey.includes(".") if (!opts.relationship && !isRelationshipField) { fn(`${opts.tableName}.${updatedKey}`, value) diff --git a/packages/server/src/integrations/base/utils.ts b/packages/server/src/integrations/base/utils.ts deleted file mode 100644 index 54efdb91a0..0000000000 --- a/packages/server/src/integrations/base/utils.ts +++ /dev/null @@ -1,12 +0,0 @@ -const QUERY_START_REGEX = /\d[0-9]*:/g - -export function removeKeyNumbering(key: any): string { - if (typeof key === "string" && key.match(QUERY_START_REGEX) != null) { - const parts = key.split(":") - // remove the number - parts.shift() - return parts.join(":") - } else { - return key - } -} diff --git a/packages/worker/src/api/routes/index.ts b/packages/worker/src/api/routes/index.ts index 3aa9422238..c64ad44423 100644 --- a/packages/worker/src/api/routes/index.ts +++ b/packages/worker/src/api/routes/index.ts @@ -18,6 +18,8 @@ import accountRoutes from "./system/accounts" import restoreRoutes from "./system/restore" let userGroupRoutes = api.groups +let auditLogRoutes = api.auditLogs + export const routes: Router[] = [ configRoutes, userRoutes, @@ -32,6 +34,7 @@ export const routes: Router[] = [ selfRoutes, licenseRoutes, userGroupRoutes, + auditLogRoutes, migrationRoutes, accountRoutes, restoreRoutes, From 46e9bf144393b62163984113cb23b9ed87a5aab0 Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Mon, 13 Feb 2023 18:16:13 +0000 Subject: [PATCH 008/106] Some updates to add in the audit log DB. --- packages/backend-core/src/constants/db.ts | 4 ++++ packages/backend-core/src/context/mainContext.ts | 14 ++++++++++++++ packages/types/src/api/web/global/auditLogs.ts | 6 ++++-- packages/types/src/documents/global/auditLogs.ts | 4 ++-- packages/types/src/documents/global/index.ts | 1 + 5 files changed, 25 insertions(+), 4 deletions(-) diff --git a/packages/backend-core/src/constants/db.ts b/packages/backend-core/src/constants/db.ts index f7d15b3880..d41098c405 100644 --- a/packages/backend-core/src/constants/db.ts +++ b/packages/backend-core/src/constants/db.ts @@ -68,6 +68,7 @@ export enum DocumentType { MEM_VIEW = "view", USER_FLAG = "flag", AUTOMATION_METADATA = "meta_au", + AUDIT_LOG = "al", } export const StaticDatabases = { @@ -88,6 +89,9 @@ export const StaticDatabases = { install: "install", }, }, + AUDIT_LOGS: { + name: "audit-logs", + }, } export const APP_PREFIX = DocumentType.APP + SEPARATOR diff --git a/packages/backend-core/src/context/mainContext.ts b/packages/backend-core/src/context/mainContext.ts index 9884d25d5a..1f14a20778 100644 --- a/packages/backend-core/src/context/mainContext.ts +++ b/packages/backend-core/src/context/mainContext.ts @@ -30,6 +30,13 @@ export function getGlobalDBName(tenantId?: string) { return baseGlobalDBName(tenantId) } +export function getAuditLogDBName(tenantId?: string) { + if (!tenantId) { + tenantId = getTenantId() + } + return `${tenantId}${SEPARATOR}${StaticDatabases.AUDIT_LOGS.name}` +} + export function baseGlobalDBName(tenantId: string | undefined | null) { let dbName if (!tenantId || tenantId === DEFAULT_TENANT_ID) { @@ -228,6 +235,13 @@ export function getGlobalDB(): Database { return getDB(baseGlobalDBName(context?.tenantId)) } +export function getAuditLogsDB(): Database { + if (!getTenantId()) { + throw new Error("Audit log DB not found") + } + return getDB(getAuditLogDBName()) +} + /** * Gets the app database based on whatever the request * contained, dev or prod. diff --git a/packages/types/src/api/web/global/auditLogs.ts b/packages/types/src/api/web/global/auditLogs.ts index 7281d0ca36..443cd79aa1 100644 --- a/packages/types/src/api/web/global/auditLogs.ts +++ b/packages/types/src/api/web/global/auditLogs.ts @@ -1,7 +1,7 @@ import { Event, AuditedEventFriendlyName } from "../../../sdk" import { PaginationResponse, PaginationRequest } from "../" -export interface DownloadAuditLogsRequest { +export interface AuditLogSearchParams { userId?: string[] appId?: string[] event?: Event[] @@ -10,9 +10,11 @@ export interface DownloadAuditLogsRequest { metadataSearch?: string } +export interface DownloadAuditLogsRequest extends AuditLogSearchParams {} + export interface SearchAuditLogsRequest extends PaginationRequest, - DownloadAuditLogsRequest {} + AuditLogSearchParams {} export interface SearchAuditLogsResponse extends PaginationResponse { data: { diff --git a/packages/types/src/documents/global/auditLogs.ts b/packages/types/src/documents/global/auditLogs.ts index bc07bc88d4..5b23650eec 100644 --- a/packages/types/src/documents/global/auditLogs.ts +++ b/packages/types/src/documents/global/auditLogs.ts @@ -1,8 +1,8 @@ import { Document } from "../document" import { Event } from "../../sdk" -export interface AuditLogDocument extends Document { - appId: string +export interface AuditLogDoc extends Document { + appId?: string event: Event userId: string timestamp: string diff --git a/packages/types/src/documents/global/index.ts b/packages/types/src/documents/global/index.ts index 11ce7513f2..b728439dd6 100644 --- a/packages/types/src/documents/global/index.ts +++ b/packages/types/src/documents/global/index.ts @@ -6,3 +6,4 @@ export * from "./quotas" export * from "./schedule" export * from "./templates" export * from "./environmentVariables" +export * from "./auditLogs" From 1ed4f4b8feea5d2d06b719a97b81d2db9895fa17 Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Wed, 15 Feb 2023 12:37:32 +0000 Subject: [PATCH 009/106] Update on audit logs, getting the full write flow from events configured. --- packages/backend-core/package.json | 1 + packages/backend-core/src/events/events.ts | 11 +- packages/backend-core/tsconfig.json | 6 +- packages/backend-core/yarn.lock | 118 ++- packages/server/package.json | 1 + .../api/controllers/row/ExternalRequest.ts | 5 +- packages/server/yarn.lock | 812 +++++++++++++++++- .../types/src/documents/global/auditLogs.ts | 2 + scripts/link-dependencies.sh | 4 + 9 files changed, 932 insertions(+), 28 deletions(-) diff --git a/packages/backend-core/package.json b/packages/backend-core/package.json index 705e4b1114..b51afcb8b1 100644 --- a/packages/backend-core/package.json +++ b/packages/backend-core/package.json @@ -25,6 +25,7 @@ "@budibase/nano": "10.1.1", "@budibase/pouchdb-replication-stream": "1.2.10", "@budibase/types": "2.3.14-alpha.0", + "@budibase/pro": "2.3.14-alpha.0", "@shopify/jest-koa-mocks": "5.0.1", "@techpass/passport-openidconnect": "0.3.2", "aws-cloudfront-sign": "2.2.0", diff --git a/packages/backend-core/src/events/events.ts b/packages/backend-core/src/events/events.ts index 01928221a0..e54497c0cf 100644 --- a/packages/backend-core/src/events/events.ts +++ b/packages/backend-core/src/events/events.ts @@ -1,6 +1,8 @@ -import { Event } from "@budibase/types" +import { Event, IdentityType } from "@budibase/types" +import { sdk } from "@budibase/pro" import { processors } from "./processors" import identification from "./identification" +import { getAppId } from "../context" import * as backfill from "./backfill" export const publishEvent = async ( @@ -14,6 +16,13 @@ export const publishEvent = async ( const backfilling = await backfill.isBackfillingEvent(event) // no backfill - send the event and exit if (!backfilling) { + // only audit log actual events, don't include backfills + const userId = identity.type === IdentityType.USER ? identity.id : undefined + await sdk.auditLogs.write(event, properties, { + userId, + timestamp, + appId: getAppId(), + }) await processors.processEvent(event, identity, properties, timestamp) return } diff --git a/packages/backend-core/tsconfig.json b/packages/backend-core/tsconfig.json index e95fb9ab4d..62944d7f2c 100644 --- a/packages/backend-core/tsconfig.json +++ b/packages/backend-core/tsconfig.json @@ -4,11 +4,13 @@ "composite": true, "baseUrl": ".", "paths": { - "@budibase/types": ["../types/src"] + "@budibase/types": ["../types/src"], + "@budibase/pro": ["../../../budibase-pro/packages/pro/src"] } }, "references": [ - { "path": "../types" } + { "path": "../types" }, + { "path": "../../../budibase-pro/packages/pro" } ], "exclude": [ "node_modules", diff --git a/packages/backend-core/yarn.lock b/packages/backend-core/yarn.lock index d88b1058f9..93ca39ab35 100644 --- a/packages/backend-core/yarn.lock +++ b/packages/backend-core/yarn.lock @@ -475,6 +475,45 @@ resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== +"@budibase/backend-core@2.3.14-alpha.0": + version "2.3.14-alpha.0" + resolved "https://registry.yarnpkg.com/@budibase/backend-core/-/backend-core-2.3.14-alpha.0.tgz#8d60c93e9861301296907f61e770bdf1881b560c" + integrity sha512-lvRl6o9CCUx1VQ6ftu4FYuTp5mGgvbshNYoeaH0DbWFfhLNbibEHxx+pR+6M1ufhbu/EO6jKEr7DDeNiRBBMTw== + dependencies: + "@budibase/nano" "10.1.1" + "@budibase/pouchdb-replication-stream" "1.2.10" + "@budibase/types" "2.3.14-alpha.0" + "@shopify/jest-koa-mocks" "5.0.1" + "@techpass/passport-openidconnect" "0.3.2" + aws-cloudfront-sign "2.2.0" + aws-sdk "2.1030.0" + bcrypt "5.0.1" + bcryptjs "2.4.3" + bull "4.10.1" + correlation-id "4.0.0" + dotenv "16.0.1" + emitter-listener "1.1.2" + ioredis "4.28.0" + joi "17.6.0" + jsonwebtoken "9.0.0" + koa-passport "4.1.4" + lodash "4.17.21" + lodash.isarguments "3.1.0" + node-fetch "2.6.7" + passport-google-oauth "2.0.0" + passport-jwt "4.0.0" + passport-local "1.0.0" + passport-oauth2-refresh "^2.1.0" + posthog-node "1.3.0" + pouchdb "7.3.0" + pouchdb-find "7.2.2" + redlock "4.2.0" + sanitize-s3-objectkey "0.0.1" + semver "7.3.7" + tar-fs "2.1.1" + uuid "8.3.2" + zlib "1.0.5" + "@budibase/nano@10.1.1": version "10.1.1" resolved "https://registry.yarnpkg.com/@budibase/nano/-/nano-10.1.1.tgz#36ccda4d9bb64b5ee14dd2b27a295b40739b1038" @@ -500,6 +539,25 @@ pouchdb-promise "^6.0.4" through2 "^2.0.0" +"@budibase/pro@2.3.14-alpha.0": + version "2.3.14-alpha.0" + resolved "https://registry.yarnpkg.com/@budibase/pro/-/pro-2.3.14-alpha.0.tgz#db8ac1d0cacea21240c59458c4143e3e55663a4d" + integrity sha512-RJqXlvZmYrKCLxe7uVnc2KmDwE5OmoUZCA9M6b5Ne7ZHqrhtaNB/4Xlr1ESG79///epEWLv+Fde7mpHPzCvsZw== + dependencies: + "@budibase/backend-core" "2.3.14-alpha.0" + "@budibase/types" "2.3.14-alpha.0" + "@koa/router" "8.0.8" + bull "4.10.1" + joi "17.6.0" + jsonwebtoken "8.5.1" + lru-cache "^7.14.1" + node-fetch "^2.6.1" + +"@budibase/types@2.3.14-alpha.0": + version "2.3.14-alpha.0" + resolved "https://registry.yarnpkg.com/@budibase/types/-/types-2.3.14-alpha.0.tgz#03072a669c016c616278dc01c577119dd710e4fe" + integrity sha512-D5qOD7YJhHUrPy81C9OpTlVzsXBmZwbF9WdoxYo/M8JYmhTJfj7Fu5dGTyDpipPQVqknFpTsig5kQqG3r08ZZw== + "@cspotcode/source-map-support@^0.8.0": version "0.8.1" resolved "https://registry.yarnpkg.com/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz#00629c35a688e05a88b1cda684fb9d5e73f000a1" @@ -826,6 +884,18 @@ "@jridgewell/resolve-uri" "^3.0.3" "@jridgewell/sourcemap-codec" "^1.4.10" +"@koa/router@8.0.8": + version "8.0.8" + resolved "https://registry.yarnpkg.com/@koa/router/-/router-8.0.8.tgz#95f32d11373d03d89dcb63fabe9ac6f471095236" + integrity sha512-FnT93N4NUehnXr+juupDmG2yfi0JnWdCmNEuIXpCG4TtG+9xvtrLambBH3RclycopVUOEYAim2lydiNBI7IRVg== + dependencies: + debug "^4.1.1" + http-errors "^1.7.3" + koa-compose "^4.1.0" + methods "^1.1.2" + path-to-regexp "1.x" + urijs "^1.19.2" + "@mapbox/node-pre-gyp@^1.0.0": version "1.0.9" resolved "https://registry.yarnpkg.com/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.9.tgz#09a8781a3a036151cdebbe8719d6f8b25d4058bc" @@ -3145,7 +3215,7 @@ http-cookie-agent@^4.0.2: dependencies: agent-base "^6.0.2" -http-errors@^1.6.3, http-errors@~1.8.0: +http-errors@^1.6.3, http-errors@^1.7.3, http-errors@~1.8.0: version "1.8.1" resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.8.1.tgz#7c3f28577cbc8a207388455dbd62295ed07bd68c" integrity sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g== @@ -3935,17 +4005,7 @@ jsonc-parser@^3.2.0: resolved "https://registry.yarnpkg.com/jsonc-parser/-/jsonc-parser-3.2.0.tgz#31ff3f4c2b9793f89c67212627c51c6394f88e76" integrity sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w== -jsonwebtoken@9.0.0: - version "9.0.0" - resolved "https://registry.yarnpkg.com/jsonwebtoken/-/jsonwebtoken-9.0.0.tgz#d0faf9ba1cc3a56255fe49c0961a67e520c1926d" - integrity sha512-tuGfYXxkQGDPnLJ7SibiQgVgeDgfbPq2k2ICcbgqW8WxWLBAxKQM/ZCu/IT8SOSwmaYl4dpTFCW5xZv7YbbWUw== - dependencies: - jws "^3.2.2" - lodash "^4.17.21" - ms "^2.1.1" - semver "^7.3.8" - -jsonwebtoken@^8.2.0: +jsonwebtoken@8.5.1, jsonwebtoken@^8.2.0: version "8.5.1" resolved "https://registry.yarnpkg.com/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz#00e71e0b8df54c2121a1f26137df2280673bcc0d" integrity sha512-XjwVfRS6jTMsqYs0EsuJ4LGxXV14zQybNd4L2r0UvbVnSF9Af8x7p5MzbJ90Ioz/9TI41/hTCvznF/loiSzn8w== @@ -3961,6 +4021,16 @@ jsonwebtoken@^8.2.0: ms "^2.1.1" semver "^5.6.0" +jsonwebtoken@9.0.0: + version "9.0.0" + resolved "https://registry.yarnpkg.com/jsonwebtoken/-/jsonwebtoken-9.0.0.tgz#d0faf9ba1cc3a56255fe49c0961a67e520c1926d" + integrity sha512-tuGfYXxkQGDPnLJ7SibiQgVgeDgfbPq2k2ICcbgqW8WxWLBAxKQM/ZCu/IT8SOSwmaYl4dpTFCW5xZv7YbbWUw== + dependencies: + jws "^3.2.2" + lodash "^4.17.21" + ms "^2.1.1" + semver "^7.3.8" + jsprim@^1.2.2: version "1.4.2" resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.2.tgz#712c65533a15c878ba59e9ed5f0e26d5b77c5feb" @@ -4263,6 +4333,11 @@ lru-cache@^6.0.0: dependencies: yallist "^4.0.0" +lru-cache@^7.14.1: + version "7.14.1" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-7.14.1.tgz#8da8d2f5f59827edb388e63e459ac23d6d408fea" + integrity sha512-ysxwsnTKdAx96aTRdhDOCQfDgbHnt8SK0KY8SEjO0wHinhWOFTESbjVCMPbU1uGXg/ch4lifqx0wfjOawU2+WA== + ltgt@2.2.1, ltgt@^2.1.2, ltgt@~2.2.0: version "2.2.1" resolved "https://registry.yarnpkg.com/ltgt/-/ltgt-2.2.1.tgz#f35ca91c493f7b73da0e07495304f17b31f87ee5" @@ -4505,6 +4580,13 @@ node-fetch@2.6.7, node-fetch@^2.6.7: dependencies: whatwg-url "^5.0.0" +node-fetch@^2.6.1: + 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-gyp-build-optional-packages@5.0.3: version "5.0.3" resolved "https://registry.yarnpkg.com/node-gyp-build-optional-packages/-/node-gyp-build-optional-packages-5.0.3.tgz#92a89d400352c44ad3975010368072b41ad66c17" @@ -4837,6 +4919,13 @@ path-parse@^1.0.7: resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== +path-to-regexp@1.x: + version "1.8.0" + resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-1.8.0.tgz#887b3ba9d84393e87a0a0b9f4cb756198b53548a" + integrity sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA== + dependencies: + isarray "0.0.1" + pause@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/pause/-/pause-0.0.1.tgz#1d408b3fdb76923b9543d96fb4c9dfd535d9cb5d" @@ -6154,6 +6243,11 @@ uri-js@^4.2.2: dependencies: punycode "^2.1.0" +urijs@^1.19.2: + version "1.19.11" + resolved "https://registry.yarnpkg.com/urijs/-/urijs-1.19.11.tgz#204b0d6b605ae80bea54bea39280cdb7c9f923cc" + integrity sha512-HXgFDgDommxn5/bIv0cnQZsPhHDA90NPHD6+c/v21U5+Sx5hoP8+dP9IZXBU1gIfvdRfhG8cel9QNPeionfcCQ== + url-parse-lax@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/url-parse-lax/-/url-parse-lax-3.0.0.tgz#16b5cafc07dbe3676c1b1999177823d6503acb0c" diff --git a/packages/server/package.json b/packages/server/package.json index a367f65aed..68ed73beed 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -141,6 +141,7 @@ "@types/pouchdb": "6.4.0", "@types/redis": "4.0.11", "@types/server-destroy": "1.0.1", + "@types/supertest": "^2.0.12", "@types/tar": "6.1.3", "@typescript-eslint/parser": "5.45.0", "apidoc": "0.50.4", diff --git a/packages/server/src/api/controllers/row/ExternalRequest.ts b/packages/server/src/api/controllers/row/ExternalRequest.ts index 2faff95595..a1522f6c6d 100644 --- a/packages/server/src/api/controllers/row/ExternalRequest.ts +++ b/packages/server/src/api/controllers/row/ExternalRequest.ts @@ -24,8 +24,7 @@ import { breakExternalTableId, isSQL } from "../../../integrations/utils" import { processObjectSync } from "@budibase/string-templates" import { cloneDeep } from "lodash/fp" import { processFormulas, processDates } from "../../../utilities/rowProcessor" -import { context } from "@budibase/backend-core" -import { removeKeyNumbering } from "./utils" +import { db as dbCore } from "@budibase/backend-core" import sdk from "../../../sdk" export interface ManyRelationship { @@ -61,7 +60,7 @@ function buildFilters( let prefix = 1 for (let operator of Object.values(filters)) { for (let field of Object.keys(operator || {})) { - if (removeKeyNumbering(field) === "_id") { + if (dbCore.removeKeyNumbering(field) === "_id") { if (primary) { const parts = breakRowIdField(operator[field]) for (let field of primary) { diff --git a/packages/server/yarn.lock b/packages/server/yarn.lock index 16c86dd298..7efb1e4672 100644 --- a/packages/server/yarn.lock +++ b/packages/server/yarn.lock @@ -2,6 +2,11 @@ # yarn lockfile v1 +"@adobe/spectrum-css-workflow-icons@1.2.1": + version "1.2.1" + resolved "https://registry.yarnpkg.com/@adobe/spectrum-css-workflow-icons/-/spectrum-css-workflow-icons-1.2.1.tgz#7e2cb3fcfb5c8b12d7275afafbb6ec44913551b4" + integrity sha512-uVgekyBXnOVkxp+CUssjN/gefARtudZC8duEn1vm0lBQFwGRZFlDEzU1QC+aIRWCrD1Z8OgRpmBYlSZ7QS003w== + "@adobe/spectrum-css-workflow-icons@^1.2.1": version "1.5.3" resolved "https://registry.yarnpkg.com/@adobe/spectrum-css-workflow-icons/-/spectrum-css-workflow-icons-1.5.3.tgz#5e31ce842b7626f4b99f9d5cd0b17599d287b0bf" @@ -1317,6 +1322,60 @@ uuid "8.3.2" zlib "1.0.5" +"@budibase/bbui@2.3.14-alpha.0": + version "2.3.14-alpha.0" + resolved "https://registry.yarnpkg.com/@budibase/bbui/-/bbui-2.3.14-alpha.0.tgz#b27a689e221ff94ebf502b9b3c93a20cd327dab4" + integrity sha512-IGO+AsC5tizGUAl+PQrXac9LdSlLDoenADIbxwTZ4Rcr7insPPvH2Xfq0KRHiJCEp9xcHlpkp5ta8ND1uVp1nw== + dependencies: + "@adobe/spectrum-css-workflow-icons" "1.2.1" + "@budibase/string-templates" "2.3.14-alpha.0" + "@spectrum-css/accordion" "3.0.24" + "@spectrum-css/actionbutton" "1.0.1" + "@spectrum-css/actiongroup" "1.0.1" + "@spectrum-css/avatar" "3.0.2" + "@spectrum-css/button" "3.0.1" + "@spectrum-css/buttongroup" "3.0.2" + "@spectrum-css/checkbox" "3.0.2" + "@spectrum-css/dialog" "3.0.1" + "@spectrum-css/divider" "1.0.3" + "@spectrum-css/dropzone" "3.0.2" + "@spectrum-css/fieldgroup" "3.0.2" + "@spectrum-css/fieldlabel" "3.0.1" + "@spectrum-css/icon" "3.0.1" + "@spectrum-css/illustratedmessage" "3.0.2" + "@spectrum-css/inlinealert" "2.0.1" + "@spectrum-css/inputgroup" "3.0.2" + "@spectrum-css/label" "2.0.10" + "@spectrum-css/link" "3.1.1" + "@spectrum-css/menu" "3.0.1" + "@spectrum-css/modal" "3.0.1" + "@spectrum-css/pagination" "3.0.3" + "@spectrum-css/picker" "1.0.1" + "@spectrum-css/popover" "3.0.1" + "@spectrum-css/progressbar" "1.0.2" + "@spectrum-css/progresscircle" "1.0.2" + "@spectrum-css/radio" "3.0.2" + "@spectrum-css/search" "3.0.2" + "@spectrum-css/sidenav" "3.0.2" + "@spectrum-css/slider" "3.0.1" + "@spectrum-css/statuslight" "3.0.2" + "@spectrum-css/stepper" "3.0.3" + "@spectrum-css/switch" "1.0.2" + "@spectrum-css/table" "3.0.1" + "@spectrum-css/tabs" "3.2.12" + "@spectrum-css/tags" "3.0.2" + "@spectrum-css/textfield" "3.0.1" + "@spectrum-css/toast" "3.0.1" + "@spectrum-css/tooltip" "3.0.3" + "@spectrum-css/treeview" "3.0.2" + "@spectrum-css/typography" "3.0.1" + "@spectrum-css/underlay" "2.0.9" + "@spectrum-css/vars" "3.0.1" + dayjs "^1.10.4" + easymde "^2.16.1" + svelte-flatpickr "^3.2.3" + svelte-portal "^1.0.0" + "@budibase/bbui@^0.9.139": version "0.9.190" resolved "https://registry.yarnpkg.com/@budibase/bbui/-/bbui-0.9.190.tgz#e1ec400ac90f556bfbc80fc23a04506f1585ea81" @@ -1367,6 +1426,71 @@ svelte-flatpickr "^3.2.3" svelte-portal "^1.0.0" +"@budibase/client@2.3.14-alpha.0": + version "2.3.14-alpha.0" + resolved "https://registry.yarnpkg.com/@budibase/client/-/client-2.3.14-alpha.0.tgz#86fc86e557ab708e160b5c85c8853d11c6ad571f" + integrity sha512-pqPau8P7MG99rilSNh5MjNdNJKSytyr8b83i8vHydAvB++6+ekMwZfRcYrnR2wLXkg6ZztI/CmSkAYU4i1AYtw== + dependencies: + "@budibase/bbui" "2.3.14-alpha.0" + "@budibase/frontend-core" "2.3.14-alpha.0" + "@budibase/string-templates" "2.3.14-alpha.0" + "@spectrum-css/button" "^3.0.3" + "@spectrum-css/card" "^3.0.3" + "@spectrum-css/divider" "^1.0.3" + "@spectrum-css/link" "^3.1.3" + "@spectrum-css/page" "^3.0.1" + "@spectrum-css/tag" "^3.1.4" + "@spectrum-css/typography" "^3.0.2" + "@spectrum-css/vars" "^3.0.1" + apexcharts "^3.22.1" + dayjs "^1.10.5" + downloadjs "1.4.7" + html5-qrcode "^2.2.1" + leaflet "^1.7.1" + regexparam "^1.3.0" + sanitize-html "^2.7.0" + screenfull "^6.0.1" + shortid "^2.2.15" + socket.io-client "^4.5.1" + svelte "^3.49.0" + svelte-apexcharts "^1.0.2" + svelte-flatpickr "^3.1.0" + svelte-spa-router "^3.0.5" + +"@budibase/frontend-core@2.3.14-alpha.0": + version "2.3.14-alpha.0" + resolved "https://registry.yarnpkg.com/@budibase/frontend-core/-/frontend-core-2.3.14-alpha.0.tgz#8c976af3f30feed688f4f36329bd715d5b5825af" + integrity sha512-Jjhy1+oGnyMVoZDnO612Hvvpxe0yBXzvEmhV+o4SN0eMvpZU48NKBU3buG1SvB1D5Y4rCn1FGsCboSTIk9n7rw== + dependencies: + "@budibase/bbui" "2.3.14-alpha.0" + lodash "^4.17.21" + svelte "^3.46.2" + +"@budibase/handlebars-helpers@^0.11.8": + version "0.11.8" + resolved "https://registry.yarnpkg.com/@budibase/handlebars-helpers/-/handlebars-helpers-0.11.8.tgz#6953d29673a8c5c407e096c0a84890465c7ce841" + integrity sha512-ggWJUt0GqsHFAEup5tlWlcrmYML57nKhpNGGLzVsqXVYN8eVmf3xluYmmMe7fDYhQH0leSprrdEXmsdFQF3HAQ== + dependencies: + array-sort "^1.0.0" + define-property "^2.0.2" + extend-shallow "^3.0.2" + for-in "^1.0.2" + get-object "^0.2.0" + get-value "^3.0.1" + handlebars "^4.7.7" + handlebars-utils "^1.0.6" + has-value "^2.0.2" + helper-md "^0.2.2" + html-tag "^2.0.0" + is-even "^1.0.0" + is-glob "^4.0.1" + kind-of "^6.0.3" + micromatch "^3.1.5" + relative "^3.0.2" + striptags "^3.1.1" + to-gfm-code-block "^0.1.1" + year "^0.2.1" + "@budibase/nano@10.1.1": version "10.1.1" resolved "https://registry.yarnpkg.com/@budibase/nano/-/nano-10.1.1.tgz#36ccda4d9bb64b5ee14dd2b27a295b40739b1038" @@ -1424,6 +1548,18 @@ svelte-apexcharts "^1.0.2" svelte-flatpickr "^3.1.0" +"@budibase/string-templates@2.3.14-alpha.0": + version "2.3.14-alpha.0" + resolved "https://registry.yarnpkg.com/@budibase/string-templates/-/string-templates-2.3.14-alpha.0.tgz#a4c2bf4d328e383929699a5f9c70ed718ef4727b" + integrity sha512-Ekza3NntysyEXyAI6ha/SawkueCnHmMvudW5XtfIS2byLMdph0KqBp03MCW/sdkZ2mdkGi2Nwu/3nowOGSJxNw== + dependencies: + "@budibase/handlebars-helpers" "^0.11.8" + dayjs "^1.10.4" + handlebars "^4.7.6" + handlebars-utils "^1.0.6" + lodash "^4.17.20" + vm2 "^3.9.4" + "@budibase/types@2.3.14-alpha.0": version "2.3.14-alpha.0" resolved "https://registry.yarnpkg.com/@budibase/types/-/types-2.3.14-alpha.0.tgz#03072a669c016c616278dc01c577119dd710e4fe" @@ -2636,26 +2772,51 @@ resolved "https://registry.yarnpkg.com/@socket.io/component-emitter/-/component-emitter-3.1.0.tgz#96116f2a912e0c02817345b3c10751069920d553" integrity sha512-+9jVqKhRSpsc591z5vX+X5Yyw+he/HCB4iQ/RYxw35CEPaY1gnsNE43nf9n9AaYjAQrTiI/mOwKUKdUs9vf7Xg== +"@spectrum-css/accordion@3.0.24": + version "3.0.24" + resolved "https://registry.yarnpkg.com/@spectrum-css/accordion/-/accordion-3.0.24.tgz#f89066c120c57b0cfc9aba66d60c39fc1cf69f74" + integrity sha512-jNOmUsxmiT3lRLButnN5KKHM94fd+87fjiF8L0c4uRNgJl6ZsBuxPXrM15lV4y1f8D2IACAw01/ZkGRAeaCOFA== + +"@spectrum-css/actionbutton@1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@spectrum-css/actionbutton/-/actionbutton-1.0.1.tgz#9c75da37ea6915919fb574c74bd60dacc03b6577" + integrity sha512-AUqtyNabHF451Aj9i3xz82TxS5Z6k1dttA68/1hMeU9kbPCSS4P6Viw3vaRGs9CSspuR8xnnhDgrq+F+zMy2Hw== + "@spectrum-css/actionbutton@^1.0.1": version "1.1.14" resolved "https://registry.yarnpkg.com/@spectrum-css/actionbutton/-/actionbutton-1.1.14.tgz#4e12eb7f482fb5944c3d97547591964baebeb1d4" integrity sha512-ViBjdWi23J6vIR4t8JTRQ6jY/+KgpZgCALj3otgy495zMNG7jPeN7sKoy6i6JZJcdIRJA4MjOTVvcDOGkYWUZg== +"@spectrum-css/actiongroup@1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@spectrum-css/actiongroup/-/actiongroup-1.0.1.tgz#b95b86e7af229e90fe1e70399d8d4b547b4bd31c" + integrity sha512-5Q6uMjzv5BFA2TwGASr/jAtJpTWl26fhWvgGY8kOA0RCSij35l+YJg/FPXf6Nnj2qCOl8DkNycjT9YXJ+bhyVA== + "@spectrum-css/actiongroup@^1.0.1": version "1.0.26" resolved "https://registry.yarnpkg.com/@spectrum-css/actiongroup/-/actiongroup-1.0.26.tgz#181ee059f28b1342389a128c39d20d2e10566aae" integrity sha512-T1IK9a2Gxix9givm+chGvFtZh5oGBZQc/S2UA9F76JZKu45eCkLkvUH6F670XOrBhDGkVfzvN21QnFymSY43ow== -"@spectrum-css/avatar@^3.0.2": +"@spectrum-css/avatar@3.0.2", "@spectrum-css/avatar@^3.0.2": version "3.0.2" resolved "https://registry.yarnpkg.com/@spectrum-css/avatar/-/avatar-3.0.2.tgz#4f1826223eae330e64b6d3cc899e9bc2e98dac95" integrity sha512-wEczvSqxttTWSiL3cOvXV/RmGRwSkw2w6+slcHhnf0kb7ovymMM+9oz8vvEpEsSeo5u598bc+7ktrKFpAd6soQ== +"@spectrum-css/button@3.0.1": + version "3.0.1" + resolved "https://registry.yarnpkg.com/@spectrum-css/button/-/button-3.0.1.tgz#6db8c3e851baecd0f1c2d88fef37d49d01c6e643" + integrity sha512-YXrBtjIYisk4Vaxnp0RiE4gdElQX04P2mc4Pi2GlQ27dJKlHmufYcF+kAqGdtiyK5yjdN/vKRcC8y13aA4rusA== + "@spectrum-css/button@^3.0.1", "@spectrum-css/button@^3.0.3": version "3.0.3" resolved "https://registry.yarnpkg.com/@spectrum-css/button/-/button-3.0.3.tgz#2df1efaab6c7e0b3b06cb4b59e1eae59c7f1fc84" integrity sha512-6CnLPqqtaU/PcSSIGeGRi0iFIIxIUByYLKFO6zn5NEUc12KQ28dJ4PLwB6WBa0L8vRoAGlnWWH2ZZweTijbXgg== +"@spectrum-css/buttongroup@3.0.2": + version "3.0.2" + resolved "https://registry.yarnpkg.com/@spectrum-css/buttongroup/-/buttongroup-3.0.2.tgz#fd3387973ca3131609e32112de42a1c0400a48d8" + integrity sha512-Wu7B4GJ/SAeVHz9SUGAkeIH8pLaZh4t+w2ykSKOPQIRuK2jCBoudkEClVxviNVwqekccf5XLFXg9GpYF1a3Uaw== + "@spectrum-css/buttongroup@^3.0.2": version "3.0.10" resolved "https://registry.yarnpkg.com/@spectrum-css/buttongroup/-/buttongroup-3.0.10.tgz#897ea04b3ffea389fc7fe5bf67a6d1f3454b774d" @@ -2666,16 +2827,33 @@ resolved "https://registry.yarnpkg.com/@spectrum-css/card/-/card-3.0.3.tgz#56b2e2da6b80c1583228baa279de7407383bfb6b" integrity sha512-+oKLUI2a0QmQP9EzySeq/G4FpUkkdaDNbuEbqCj2IkPMc/2v/nwzsPhh1fj2UIghGAiiUwXfPpzax1e8fyhQUg== +"@spectrum-css/checkbox@3.0.2": + version "3.0.2" + resolved "https://registry.yarnpkg.com/@spectrum-css/checkbox/-/checkbox-3.0.2.tgz#53ca2fba0d9faa1fead10e7206eb1f6cdcfd6ddd" + integrity sha512-hPbGcnm7kJvJS4jp/P/bdaZvbyR1eIE9mteuZqcBgdmyp9m/k6+mW5jmsbtqb3Y4mMPWvOJFfz/sIvWJP0F0Zg== + "@spectrum-css/checkbox@^3.0.2": version "3.1.2" resolved "https://registry.yarnpkg.com/@spectrum-css/checkbox/-/checkbox-3.1.2.tgz#88698969091da9b50de781d25839446084b4a5f4" integrity sha512-vIuknIhRF/Xtq6OHjOtlhYt722FPcTLBb7Y7tY0Ho8VEpynj3JrVLP/1YYp/YIrYMpsTugxPmbCrEkikkdL6Mg== +"@spectrum-css/dialog@3.0.1": + version "3.0.1" + resolved "https://registry.yarnpkg.com/@spectrum-css/dialog/-/dialog-3.0.1.tgz#33aae036282159f6aa998848b8c0828640a9620a" + integrity sha512-hUFbRR6RGT63MNuP7wP+k9KU+uRuICsduMihskh700e+jiQ+Gsv53fBFDlB843FoZYlIXzFQXgtjMUC5a4Qibw== + "@spectrum-css/dialog@^3.0.1": version "3.0.12" resolved "https://registry.yarnpkg.com/@spectrum-css/dialog/-/dialog-3.0.12.tgz#fc97e002ca768a3d99dd10cb6a135c2b06052004" integrity sha512-50rbFa+9eUKT+3uYBX7CkmI7SbQ0Z3CAFwjyjai+itYZ8kf/FcHVFwcLjgrry9scUnKhexMs94kkr0gfQpPe8Q== +"@spectrum-css/divider@1.0.3": + version "1.0.3" + resolved "https://registry.yarnpkg.com/@spectrum-css/divider/-/divider-1.0.3.tgz#639e2ebaa0834efa40f42397668bbd5c153ea385" + integrity sha512-Zy4Rn40w8UtzMh3wx/U9+CepSCpm1aOCGftHgWDub0XZuVTzh0c1WwyzTuLCx2Hf21z5VRGNiDh8bGEEzSbtNA== + dependencies: + "@spectrum-css/vars" "^3.0.2" + "@spectrum-css/divider@^1.0.3": version "1.0.26" resolved "https://registry.yarnpkg.com/@spectrum-css/divider/-/divider-1.0.26.tgz#44b610b1b6c747536fca08b3f09286341e18ab29" @@ -2683,56 +2861,106 @@ dependencies: "@spectrum-css/vars" "^8.0.0" +"@spectrum-css/dropzone@3.0.2": + version "3.0.2" + resolved "https://registry.yarnpkg.com/@spectrum-css/dropzone/-/dropzone-3.0.2.tgz#34f137851054442b219fed7f32006b93fc5e0bcf" + integrity sha512-BuBBzm5re6lM0AWgd6V+mI5eEGnnmFEtcFiJBEn9jYNEQYgflFhvnERUt89jMX5WmspiecwI2JBWJFrtFsOzug== + "@spectrum-css/dropzone@^3.0.2": version "3.0.24" resolved "https://registry.yarnpkg.com/@spectrum-css/dropzone/-/dropzone-3.0.24.tgz#edefb3ca5a01705a64d0161a599c59199bab6299" integrity sha512-JY60hUZAAuzS+o2xFOKv0o31cc+5/cjLpTyKEy73oGKsdUXEEMiQtW2PQBCuxh7PNyw29wCULeZ1EW1QdNPyxg== +"@spectrum-css/fieldgroup@3.0.2": + version "3.0.2" + resolved "https://registry.yarnpkg.com/@spectrum-css/fieldgroup/-/fieldgroup-3.0.2.tgz#1c1afd3c444d8650fefac275dc66a7a913933846" + integrity sha512-Vyw0kQJdLW18J6w4H+YAsoLntvkw5rXmW3CH5H3SDTXkBztxtHSSe3e106Nw5MoZxTfHlom6CxbYXYCTjQfqGw== + "@spectrum-css/fieldgroup@^3.0.2": version "3.1.3" resolved "https://registry.yarnpkg.com/@spectrum-css/fieldgroup/-/fieldgroup-3.1.3.tgz#945123da56534f1ff6118a9defd18b8a883e34a8" integrity sha512-HIbB3jweNviWXcADoYQW3hanww9RTUIsBUhe0YxSMXUXnQJc/7nlyeLoTRMr2eEVSCREfRnMot/8bZloW7ctnA== +"@spectrum-css/fieldlabel@3.0.1": + version "3.0.1" + resolved "https://registry.yarnpkg.com/@spectrum-css/fieldlabel/-/fieldlabel-3.0.1.tgz#39f7c0f25cc2ff402afeff005341b0832f7c588c" + integrity sha512-LMfwrwIq8wEEvxFLobdLvXRwKrp8o9Fty4iJ9aYl2Rj1uXkfRd8qLz9HGZjLEE1OuJgoTBgamYABl7EvoA5PLw== + "@spectrum-css/fieldlabel@^3.0.1": version "3.0.3" resolved "https://registry.yarnpkg.com/@spectrum-css/fieldlabel/-/fieldlabel-3.0.3.tgz#f73c04d20734d4718ffb620dc46458904685b449" integrity sha512-nEvIkEXCD5n4fW67Unq6Iu7VXoauEd/JGpfTY02VsC5p4FJLnwKfPDbJUuUsqClAxqw7nAsmXVKtn4zQFf5yPQ== +"@spectrum-css/icon@3.0.1": + version "3.0.1" + resolved "https://registry.yarnpkg.com/@spectrum-css/icon/-/icon-3.0.1.tgz#e300a6fc353c85c6b5d6e7a364408a940c31b177" + integrity sha512-cGFtIrcQ/7tthdkHK1npuEFiCdYVHLqwmLxghUYQw8Tb8KgJaw3OBO1tpjgsUizexNgu26BjVRIbGxNWuBXIHQ== + "@spectrum-css/icon@^3.0.1": version "3.0.22" resolved "https://registry.yarnpkg.com/@spectrum-css/icon/-/icon-3.0.22.tgz#1dd77e2460121951c60c583edb470d0ba52e6822" integrity sha512-ilrPlHDRGzn7kXVVAwUhoSaMfS6sGlb21ix2gn8IRLBAjDOV8BBV1wJJtjGNw+kzCXMhnVnVOekTdht17Oe9bw== +"@spectrum-css/illustratedmessage@3.0.2": + version "3.0.2" + resolved "https://registry.yarnpkg.com/@spectrum-css/illustratedmessage/-/illustratedmessage-3.0.2.tgz#6a480be98b027e050b086e7899e40d87adb0a8c0" + integrity sha512-dqnE8X27bGcO0HN8+dYx8O4o0dNNIAqeivOzDHhe2El+V4dTzMrNIerF6G0NLm3GjVf6XliwmitsZK+K6FmbtA== + "@spectrum-css/illustratedmessage@^3.0.2": version "3.0.17" resolved "https://registry.yarnpkg.com/@spectrum-css/illustratedmessage/-/illustratedmessage-3.0.17.tgz#49cb2549fda97a6812156bfba6ccdd3a18bebd11" integrity sha512-kpDqeq1U+rEjG1XuiXkbGvS71vn6mpFF/hiwCgFJWudVOfypDPQ4KLfYw1ditFSUzMCm5H6U/RqAShAJn8oMWA== +"@spectrum-css/inlinealert@2.0.1": + version "2.0.1" + resolved "https://registry.yarnpkg.com/@spectrum-css/inlinealert/-/inlinealert-2.0.1.tgz#7521f88f6c845806403cc7d925773c7414e204a2" + integrity sha512-Xy5RCOwgurqUXuGQCsEDUduDd5408bmEpmFg+feynG7VFUgLFZWBeylSENB/OqjlFtO76PHXNVdHkhDscPIHTA== + "@spectrum-css/inlinealert@^2.0.1": version "2.0.6" resolved "https://registry.yarnpkg.com/@spectrum-css/inlinealert/-/inlinealert-2.0.6.tgz#4c5e923a1f56a96cc1adb30ef1f06ae04f2c6376" integrity sha512-OpvvoWP02wWyCnF4IgG8SOPkXymovkC9cGtgMS1FdDubnG3tJZB/JeKTsRR9C9Vt3WBaOmISRdSKlZ4lC9CFzA== +"@spectrum-css/inputgroup@3.0.2": + version "3.0.2" + resolved "https://registry.yarnpkg.com/@spectrum-css/inputgroup/-/inputgroup-3.0.2.tgz#f1b13603832cbd22394f3d898af13203961f8691" + integrity sha512-O0G3Lw9gxsh8gTLQWIAKkN1O8cWhjpEUl+oR1PguIKFni72uNr2ikU9piOwy/r0gJG2Q/TVs6hAshoAAkmsSzw== + "@spectrum-css/inputgroup@^3.0.2": version "3.0.8" resolved "https://registry.yarnpkg.com/@spectrum-css/inputgroup/-/inputgroup-3.0.8.tgz#fc23afc8a73c24d17249c9d2337e8b42085b298b" integrity sha512-cmQWzFp0GU+4IMc8SSeVFdmQDlRUdPelXaQdKUR9mZuO2iYettg37s0lfBCeJyYkUNTagz0zP8O7A0iXfmeE6g== -"@spectrum-css/label@^2.0.10": +"@spectrum-css/label@2.0.10", "@spectrum-css/label@^2.0.10": version "2.0.10" resolved "https://registry.yarnpkg.com/@spectrum-css/label/-/label-2.0.10.tgz#2368651d7636a19385b5d300cdf6272db1916001" integrity sha512-xCbtEiQkZIlLdWFikuw7ifDCC21DOC/KMgVrrVJHXFc4KRQe9LTZSqmGF3tovm+CSq1adE59mYoTbojVQ9YuEQ== +"@spectrum-css/link@3.1.1": + version "3.1.1" + resolved "https://registry.yarnpkg.com/@spectrum-css/link/-/link-3.1.1.tgz#cb526a2e10b50ef5a7ae29cca7272e2610d597eb" + integrity sha512-Bi88lRhTY7g6nM/ryW1yY4Cji211ZYNtRxkxbV7n2lPvwMAAQtyx0qVD3ru4kTGj/FFVvmPR3XiOE10K13HSNA== + "@spectrum-css/link@^3.1.1", "@spectrum-css/link@^3.1.3": version "3.1.22" resolved "https://registry.yarnpkg.com/@spectrum-css/link/-/link-3.1.22.tgz#1e061d674789c5b3be5b0680f9f6eae3e695e1c1" integrity sha512-Zf8bfy+rtq07l4qoR6chNxefmatLZQZjudIm96v+lsCXBkjVbiMpjkW9oOcNwTqKB08koMONHHhOf1wk2Faqiw== +"@spectrum-css/menu@3.0.1": + version "3.0.1" + resolved "https://registry.yarnpkg.com/@spectrum-css/menu/-/menu-3.0.1.tgz#2a376f991acc24e12ec892bb6b9db2650fc41fbe" + integrity sha512-Qjg0+1O0eC89sb/bRFq2AGnQ8XqhVy23TUXHyffNM8qdcMssnlny3QmhzjURCZKvx/Y5UytCpzhedPQqSpQwZg== + "@spectrum-css/menu@^3.0.1": version "3.0.21" resolved "https://registry.yarnpkg.com/@spectrum-css/menu/-/menu-3.0.21.tgz#d1f7e6e69d30b5e1edd7ed2c86ea4e08dfd670ab" integrity sha512-G5AIUO26O6IAc6HUGZu4AZgyw0QRyLfSbcKlFGu4oJHzP36cQc1S1uCh8Xp4g5d+n6mU62LxNDLSMpVbwnA00A== +"@spectrum-css/modal@3.0.1": + version "3.0.1" + resolved "https://registry.yarnpkg.com/@spectrum-css/modal/-/modal-3.0.1.tgz#613a6b83d0330a4d38db41a98090800751c56d8d" + integrity sha512-F7D99F3cjDGT9DM9sogx/p49jrNYT7a1J6TUoqV73wUf+0gP+dTsskBOo9jB8VbUE+POQPjiDLB+SWLp6iBB+w== + "@spectrum-css/modal@^3.0.1": version "3.0.22" resolved "https://registry.yarnpkg.com/@spectrum-css/modal/-/modal-3.0.22.tgz#05593a613e246a7cbef85d08a6945219e1207209" @@ -2745,107 +2973,222 @@ dependencies: "@spectrum-css/vars" "^4.3.1" +"@spectrum-css/pagination@3.0.3": + version "3.0.3" + resolved "https://registry.yarnpkg.com/@spectrum-css/pagination/-/pagination-3.0.3.tgz#b204c3ada384c4af751a354bc428346d82eeea65" + integrity sha512-OJ/v9GeNXJOZ9Yr9LDBYPrR2NCiLOWP9wANT/a5sqFuugRnQbn/HYMnRp9TBxwpDY6ihaPo0T/wi7kLiAJFdDw== + "@spectrum-css/pagination@^3.0.3": version "3.0.11" resolved "https://registry.yarnpkg.com/@spectrum-css/pagination/-/pagination-3.0.11.tgz#68d9f34fe8eb36bf922e41b11f49eac62ac2fc41" integrity sha512-wjZr7NAcqHK6fxNIGKTYEVtAOJugJTbcz4d8K7DZuUDgBVwLJJHJBi4uJ4KrIRYliMWOvqWTZzCJLmmTfx4cyw== +"@spectrum-css/picker@1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@spectrum-css/picker/-/picker-1.0.1.tgz#98991198576d26bd14160824e7b6f3c278ff930b" + integrity sha512-Rv4/UBOdNW1gs7WVBCJnPD5VFly8MqP++psDX6kcugUIcfJy0GC3acvElotmKRlCDk8Qxks2W2A0jKeSgphTmA== + "@spectrum-css/picker@^1.0.1": version "1.2.9" resolved "https://registry.yarnpkg.com/@spectrum-css/picker/-/picker-1.2.9.tgz#854cdca407daaf8e1f821777978690f0804b3c08" integrity sha512-HDUDiqHwM84xfbHJWm4wR67Km3NXcDluhDrkVn8uqOEZrm8y4YiW+esL6FzPgzqLdPIHboQjrdpRq4LiDzGjjA== +"@spectrum-css/popover@3.0.1": + version "3.0.1" + resolved "https://registry.yarnpkg.com/@spectrum-css/popover/-/popover-3.0.1.tgz#5863c1efc53f98f9aba2de9186666780041303fc" + integrity sha512-LmOSj/yCwQQ9iGmCYnHiJsJR/HfPiGqI1Jl7pkKxBOCxYBMS/5+ans9vfCN2Qnd0eK7WSbfPg72S6mjye7db2Q== + "@spectrum-css/popover@^3.0.1": version "3.0.11" resolved "https://registry.yarnpkg.com/@spectrum-css/popover/-/popover-3.0.11.tgz#a7450c01bcf1609264b4a9df58821368b9e224d1" integrity sha512-bzyNQJVw6Mn1EBelTaRlXCdd0ZfykNX9O6SHx3a+jXPYu8VBrRpHm0gsfWzPAz1etd1vj1CxwG/teQt4qvyZ/Q== +"@spectrum-css/progressbar@1.0.2": + version "1.0.2" + resolved "https://registry.yarnpkg.com/@spectrum-css/progressbar/-/progressbar-1.0.2.tgz#b5a59432517f9ae6dad49d9504691bc5ac42b424" + integrity sha512-+jExeBLtVCqo3BqtFq5WCtZ028Dzk+oUnX6y4z6ZamKPqOyOELOtFnhYnyhyRndQOqYwKUTXx9zsaWA/lpJOHw== + "@spectrum-css/progressbar@^1.0.2": version "1.0.30" resolved "https://registry.yarnpkg.com/@spectrum-css/progressbar/-/progressbar-1.0.30.tgz#1f1e81ab6080fb843831421f736ed2bccc9b18ed" integrity sha512-tUquDN33RQG8gyrWmwPaCu6I2rxRyv5BBGBPii+1sK7L/DTCJrKXe7TAqoxjNEYzdCvTF/HI1NvnSColWNq0Rw== +"@spectrum-css/progresscircle@1.0.2": + version "1.0.2" + resolved "https://registry.yarnpkg.com/@spectrum-css/progresscircle/-/progresscircle-1.0.2.tgz#258ea9170fb70f795edda03e38a61d93bef4487c" + integrity sha512-JLULpyzjIY95lzlWR1yE1gv4l1K6p+scQ+edmuZZUHBzwM3pUtkvHJmUlA9TYdResUYW6Uka60VRdY6lZ8gnFQ== + "@spectrum-css/progresscircle@^1.0.2": version "1.0.22" resolved "https://registry.yarnpkg.com/@spectrum-css/progresscircle/-/progresscircle-1.0.22.tgz#80c8fd2ac4ee6855297d98c60c3b36082020a32a" integrity sha512-EGb+q+7RxbbsrEPFpJ1P4XBQ4s6Ra0okjQCDDTTKTp/sUY2WIT2BjPzwxlZTxVmSXWiiuRyzyuSYUrgBw9UgWg== +"@spectrum-css/radio@3.0.2": + version "3.0.2" + resolved "https://registry.yarnpkg.com/@spectrum-css/radio/-/radio-3.0.2.tgz#9c1386894920bbed604e4e174fbbd45d9d762152" + integrity sha512-0TDdzC9omNXnpKHEXNuuGeXdNh4x8jvTKVUqMRLb7vY4hY94hAdt6X01NBqka+jzK35HxGzpDdPADAz62yZLPQ== + "@spectrum-css/radio@^3.0.2": version "3.0.23" resolved "https://registry.yarnpkg.com/@spectrum-css/radio/-/radio-3.0.23.tgz#118a28c407e7b58bec139483d7e23074d840ae77" integrity sha512-x+08GSufmsyrUU4iBOOMRXZrcHxabXMMm/q2vazDJE8CShztvmdjghCxcwtyM74sjiYmXnCW1V3ztr6zaG5xig== +"@spectrum-css/search@3.0.2": + version "3.0.2" + resolved "https://registry.yarnpkg.com/@spectrum-css/search/-/search-3.0.2.tgz#70e93e321032d40b399498b2324e3b70e050551e" + integrity sha512-3UbT8yZmNOwrZxq+CUmumE+26ZySZ8OoKNM6U20SLMPLgdx6MrRugVE88r3Bl0sJ0RZX/5bU8nausdiHeX+Jlw== + "@spectrum-css/search@^3.0.2": version "3.1.2" resolved "https://registry.yarnpkg.com/@spectrum-css/search/-/search-3.1.2.tgz#8d43f35f884f7c190e7694c8d26a3f2cfed01ef0" integrity sha512-8cMK1QB07dbReZ/ECyTyoT2dELZ7hK1b3jEDiWSeLBbXcKirR1OI24sZEnewQY/XWFd/62Z1YdNaaA8S6UuXWQ== +"@spectrum-css/sidenav@3.0.2": + version "3.0.2" + resolved "https://registry.yarnpkg.com/@spectrum-css/sidenav/-/sidenav-3.0.2.tgz#9d70f408d588ee79c69857751010333671f32713" + integrity sha512-YpIdH/F0jEICYmoduGrnkTmxwJq1kfKxEp0wOs+ZkQOsvKMv1an7nyhsfOKCQqcGNfYzJ9mJAk7/u5+vsxHa8g== + "@spectrum-css/sidenav@^3.0.2": version "3.0.23" resolved "https://registry.yarnpkg.com/@spectrum-css/sidenav/-/sidenav-3.0.23.tgz#c218560d472e13a3e0d1499b762df1206dcffbfd" integrity sha512-4IFw2/HMQJRzM0M2c5na/HeY7y5vJoGpMFBkXNpQyhW4TRo7N1rGwYQ5dRD3s4OVEWV4/rjfGV0d/qhfwKUTog== +"@spectrum-css/slider@3.0.1": + version "3.0.1" + resolved "https://registry.yarnpkg.com/@spectrum-css/slider/-/slider-3.0.1.tgz#5281e6f47eb5a4fd3d1816c138bf66d01d7f2e49" + integrity sha512-DI2dtMRnQuDM1miVzl3SGyR1khUEKnwdXfO5EHDFwkC3yav43F5QogkfjmjFmWWobMVovdJlAuiaaJ/IHejD0Q== + +"@spectrum-css/statuslight@3.0.2": + version "3.0.2" + resolved "https://registry.yarnpkg.com/@spectrum-css/statuslight/-/statuslight-3.0.2.tgz#dc54b6cd113413dcdb909c486b5d7bae60db65c5" + integrity sha512-xodB8g8vGJH20XmUj9ZsPlM1jHrGeRbvmVXkz0q7YvQrYAhim8pP3W+XKKZAletPFAuu8cmUOc6SWn6i4X4z6w== + "@spectrum-css/statuslight@^3.0.2": version "3.0.8" resolved "https://registry.yarnpkg.com/@spectrum-css/statuslight/-/statuslight-3.0.8.tgz#3b0ea80712573679870a85d469850230e794a0f7" integrity sha512-zMTHs8lk+I7fLdi9waEEbsCmJ1FxeHcjQ0yltWxuRmGk2vl4MQdQIuHIMI63iblqEaiwnJRjXJoKnWlNvndTJQ== +"@spectrum-css/stepper@3.0.3": + version "3.0.3" + resolved "https://registry.yarnpkg.com/@spectrum-css/stepper/-/stepper-3.0.3.tgz#ae89846886431e3edeee060207b8f81540f73a34" + integrity sha512-prAD61ImlOTs9b6PfB3cB08x4lAfxtvnW+RZiTYky0E8GgZdrc/MfCkL5/oqQaIQUtyQv/3Lb7ELAf/0K8QTXw== + "@spectrum-css/stepper@^3.0.3": version "3.0.25" resolved "https://registry.yarnpkg.com/@spectrum-css/stepper/-/stepper-3.0.25.tgz#a6e77d501a9671c083b6dd9a37c6a3f224ffc961" integrity sha512-nlAZKY4KCYQ4IFuFj/P0LXPsB4Ze36ziuaa3k3iy3+1pBDD4gDcGmNpNcTG1LENu0Bt87KhSj8Ba2NV3wBSY8w== +"@spectrum-css/switch@1.0.2": + version "1.0.2" + resolved "https://registry.yarnpkg.com/@spectrum-css/switch/-/switch-1.0.2.tgz#f0b4c69271964573e02b08e90998096e49e1de44" + integrity sha512-zqmHpgWPNg1gEwdUNFYV3CBX5JaeALfIqcJIxE0FLZqr9d1C4+oLE0ItIFzt1bwr4bFAOmkEpvtiY+amluzGxQ== + "@spectrum-css/switch@^1.0.2": version "1.0.22" resolved "https://registry.yarnpkg.com/@spectrum-css/switch/-/switch-1.0.22.tgz#8f2fe25a52b4511b9cfde7af45f9bd824b9774d7" integrity sha512-/Q8IxnkSQYo+i3G3BObslSvoKgM0Mm1mS7kmssULOtaQPbaRlRsUNQVaHzcNEX33+fiF/9zKSvs7ypgIvbWp+Q== +"@spectrum-css/table@3.0.1": + version "3.0.1" + resolved "https://registry.yarnpkg.com/@spectrum-css/table/-/table-3.0.1.tgz#753e0e2498082c0c36b9600828516aff3ac338cd" + integrity sha512-XQ+srMTv9hK1H0nctWUtqyzitmvyb5TNR+7mjAmKRdkBRSTQQSipDhenxZp72ekzMtMoSYZVZ77kgo0Iw3Fpug== + "@spectrum-css/table@^3.0.1": version "3.0.3" resolved "https://registry.yarnpkg.com/@spectrum-css/table/-/table-3.0.3.tgz#7f7f19905ef3275cbf907ce3a5818e63c30b2caf" integrity sha512-nxwzVjLPsXoY/v4sdxOVYLcC+cEbGgJyLcLclT5LT9MGSbngFeUMJzzVR4EvehzuN4dH7hrATG7Mbuq29Mf0Hg== +"@spectrum-css/tabs@3.2.12": + version "3.2.12" + resolved "https://registry.yarnpkg.com/@spectrum-css/tabs/-/tabs-3.2.12.tgz#9b08f23d5aa881b3441af7757800c7173e5685ff" + integrity sha512-rPFUW9SSW4+3/UJ3UrtY2/l3sQvlqB1fqxHLPDjgykvbfrnMejcCTNV4ZrFNHXpE/6+kGnk+yVViSPtWGwJzkA== + "@spectrum-css/tabs@^3.0.1": version "3.2.16" resolved "https://registry.yarnpkg.com/@spectrum-css/tabs/-/tabs-3.2.16.tgz#c3f7800d8d6f7c9930c28cd01354816328bf72b1" integrity sha512-JUcMB/fiDG/KoyrVstlUMacFJUY4OHKqhMRuPtu9ggUXWCRbSkY8he92v6u0HwY3DuhDoOxNTK8d/PLjk/fsbg== +"@spectrum-css/tag@^3.1.4": + version "3.3.15" + resolved "https://registry.yarnpkg.com/@spectrum-css/tag/-/tag-3.3.15.tgz#971184fd8cb977b85a529f808313851863123278" + integrity sha512-pF6Wh61Z7hmAy20twIlpjdDuivYj6UPtWIzK7giyJKr/qcn20BjVN2ChIeFB1N+vBamJdLsuQOewv4AJ3+LZ2Q== + +"@spectrum-css/tags@3.0.2": + version "3.0.2" + resolved "https://registry.yarnpkg.com/@spectrum-css/tags/-/tags-3.0.2.tgz#5bf35fb79c97cd9344de485bd4626ad5b9f07757" + integrity sha512-HbvMk+QHvCDD1/ScvSErpKROcpAbXuMD4Hl/Gz/1A1lQ0fJ/CJeCq/MMsL7zjK1nlItU/ySu8r8KIuRF+6F8SQ== + "@spectrum-css/tags@^3.0.2": version "3.0.3" resolved "https://registry.yarnpkg.com/@spectrum-css/tags/-/tags-3.0.3.tgz#fc76d2735cdc442de91b7eb3bee49a928c0767ac" integrity sha512-SL8vPxVDfWcY5VdIuyl0TImEXcOU1I7yCyXkk7MudMwfnYs81FaIyY32hFV9OHj0Tz/36UzRzc7AVMSuRQ53pw== +"@spectrum-css/textfield@3.0.1": + version "3.0.1" + resolved "https://registry.yarnpkg.com/@spectrum-css/textfield/-/textfield-3.0.1.tgz#e875b8e37817378ad08fc4af7d53026df38911e5" + integrity sha512-MUV5q87CVxbkNdSNoxGrFbgyKc51ft/WWf3aVEoPdPw5yBnXqFe1w1YmAit5zYDOOhhs58sCLAlUcCMlOpkgrA== + "@spectrum-css/textfield@^3.0.1": version "3.2.3" resolved "https://registry.yarnpkg.com/@spectrum-css/textfield/-/textfield-3.2.3.tgz#52830498fb3b8957f84bb9bf2cafec7edc55e490" integrity sha512-mtxSQe8VZjQ8PHKlUE03dATAjjxp2Y8XfYmWWFBWWZLeqaojSLv9Q8C/ouK5AenhzCaYpJxTotMjAoivwtmUSw== +"@spectrum-css/toast@3.0.1": + version "3.0.1" + resolved "https://registry.yarnpkg.com/@spectrum-css/toast/-/toast-3.0.1.tgz#36f62ea05302761e59b9d53e05f6c04423861796" + integrity sha512-jov++S358BrN2tmMfaoYk1N6u9HojgeuQk61keXrK2m3VE5/n94x7Lg3kIPeSWO0odyDfBlMqT9jacbRey3QTg== + "@spectrum-css/toast@^3.0.1": version "3.0.3" resolved "https://registry.yarnpkg.com/@spectrum-css/toast/-/toast-3.0.3.tgz#97c1527384707600832ecda35643ed304615250f" integrity sha512-CjLeaMs+cjUXojCCRtbj0YkD2BoZW16kjj2o5omkEpUTjA34IJ8xJ1a+CCtDILWekhXvN0MBN4sbumcnwcnx8w== +"@spectrum-css/tooltip@3.0.3": + version "3.0.3" + resolved "https://registry.yarnpkg.com/@spectrum-css/tooltip/-/tooltip-3.0.3.tgz#26b8ca3b3d30e29630244d85eb4fc11d0c841281" + integrity sha512-ztRF7WW1FzyNavXBRc+80z67UoOrY9wl3cMYsVD3MpDnyxdzP8cjza1pCcolKBaFqRTcQKkxKw3GWtGICRKR5A== + "@spectrum-css/tooltip@^3.0.3": version "3.1.17" resolved "https://registry.yarnpkg.com/@spectrum-css/tooltip/-/tooltip-3.1.17.tgz#1f0822c8b69d16d5f940a2b7eb6514d719e6a0fd" integrity sha512-YDuC+Cc6B8DExjL/7fkPnWb8QwlCkjuMHyuttwP/tq/lryWnrdntojgwK5KvgFRjnZ2WfepZVryIt5LOD3tMdg== +"@spectrum-css/treeview@3.0.2": + version "3.0.2" + resolved "https://registry.yarnpkg.com/@spectrum-css/treeview/-/treeview-3.0.2.tgz#d54d8f17290babb1c885f5d9355e225421beb0d2" + integrity sha512-foO7UBJv1JMFaKgDPVt8jBghZSVbqhXR8TaGaxHSnMubv7ygmKkc1AITrWC2STILCn84ju2vchOohMZfW6sYwg== + "@spectrum-css/treeview@^3.0.2": version "3.0.3" resolved "https://registry.yarnpkg.com/@spectrum-css/treeview/-/treeview-3.0.3.tgz#aeda5175158b9f8d7529cb2b394428eb2a428046" integrity sha512-D5gGzZC/KtRArdx86Mesc9+99W9nTbUOeyYGqoJoAfJSOttoT6Tk5CrDvlCmAqjKf5rajemAkGri1ChqvUIwkw== +"@spectrum-css/typography@3.0.1": + version "3.0.1" + resolved "https://registry.yarnpkg.com/@spectrum-css/typography/-/typography-3.0.1.tgz#957dafd9b18c314fa37a88b549042ba2175f5b3f" + integrity sha512-XyR68K2rIZX3u4j7HhMLOqLVHDJZcapp3XUqgYMzMWccBFleA0qPxKpfRWqVIA5DzTMSIw0wEcZPYKWFZ2e6dA== + "@spectrum-css/typography@^3.0.1", "@spectrum-css/typography@^3.0.2": version "3.0.2" resolved "https://registry.yarnpkg.com/@spectrum-css/typography/-/typography-3.0.2.tgz#ea3ca0a60e18064527819d48c8c4364cab4fcd38" integrity sha512-5ZOLmQe0edzsDMyhghUd4hBb5uxGsFrxzf+WasfcUw9klSfTsRZ09n1BsaaWbgrLjlMQ+EEHS46v5VNo0Ms2CA== +"@spectrum-css/underlay@2.0.9": + version "2.0.9" + resolved "https://registry.yarnpkg.com/@spectrum-css/underlay/-/underlay-2.0.9.tgz#fc10f971d1325cc844b727e6260f7217844060e8" + integrity sha512-X86xd0PG4QobmUyXA90BFGnyygaI8kW64dA4ysf4z0cOvUWjNbAAl3a/DB/WRyrnp63Zqv83T/cgNbetagTbWg== + "@spectrum-css/underlay@^2.0.9": version "2.0.30" resolved "https://registry.yarnpkg.com/@spectrum-css/underlay/-/underlay-2.0.30.tgz#401cfd68df945692bd6bbe281fee98889c930dd1" integrity sha512-Ssq/KERbDuJu3PUWPkBv9+ZIbKooke3oncRoYMXeyP/Gcw5bmQSXOvnlddU5DIK4PJR+pPGVZ9CUUFaYZot4YQ== -"@spectrum-css/vars@^3.0.1": +"@spectrum-css/vars@3.0.1": + version "3.0.1" + resolved "https://registry.yarnpkg.com/@spectrum-css/vars/-/vars-3.0.1.tgz#561fd69098f896a647242dd8d6108af603bfa31e" + integrity sha512-l4oRcCOqInChYXZN6OQhpe3isk6l4OE6Ys8cgdlsiKp53suNoQxyyd9p/eGRbCjZgH3xQ8nK0t4DHa7QYC0S6w== + +"@spectrum-css/vars@^3.0.1", "@spectrum-css/vars@^3.0.2": version "3.0.2" resolved "https://registry.yarnpkg.com/@spectrum-css/vars/-/vars-3.0.2.tgz#ea9062c3c98dfc6ba59e5df14a03025ad8969999" integrity sha512-vzS9KqYXot4J3AEER/u618MXWAS+IoMvYMNrOoscKiLLKYQWenaueakUWulFonToPd/9vIpqtdbwxznqrK5qDw== @@ -3057,6 +3400,13 @@ resolved "https://registry.yarnpkg.com/@types/caseless/-/caseless-0.12.2.tgz#f65d3d6389e01eeb458bd54dc8f52b95a9463bc8" integrity sha512-6ckxMjBBD8URvjB6J3NcnuAn5Pkl7t3TizAg+xdlzzQGSPSmBcXf8KoIH0ua/i+tio+ZRUHEXp0HEmvaR4kt0w== +"@types/codemirror@^5.60.4": + version "5.60.7" + resolved "https://registry.yarnpkg.com/@types/codemirror/-/codemirror-5.60.7.tgz#efbb78e5e79f90c6762c2127c02096648e600808" + integrity sha512-QXIC+RPzt/1BGSuD6iFn6UMC9TDp+9hkOANYNPVsjjrDdzKphfRkwQDKGp2YaC54Yhz0g6P5uYTCCibZZEiMAA== + dependencies: + "@types/tern" "*" + "@types/connect@*": version "3.4.35" resolved "https://registry.yarnpkg.com/@types/connect/-/connect-3.4.35.tgz#5fcf6ae445e4021d1fc2219a4873cc73a3bb2ad1" @@ -3272,6 +3622,11 @@ resolved "https://registry.yarnpkg.com/@types/long/-/long-4.0.2.tgz#b74129719fc8d11c01868010082d483b7545591a" integrity sha512-MqTGEo5bj5t157U6fA/BiDynNkn0YknVdh48CMPkTSpFTVmvao5UQmm7uEF6xBEo7qIMAlY/JSleYaE6VOdpaA== +"@types/marked@^4.0.7": + version "4.0.8" + resolved "https://registry.yarnpkg.com/@types/marked/-/marked-4.0.8.tgz#b316887ab3499d0a8f4c70b7bd8508f92d477955" + integrity sha512-HVNzMT5QlWCOdeuBsgXP8EZzKUf0+AXzN+sLmjvaB3ZlLqO+e4u0uXrdw9ub69wBKFs+c6/pA4r9sy6cCDvImw== + "@types/mime@^1": version "1.3.2" resolved "https://registry.yarnpkg.com/@types/mime/-/mime-1.3.2.tgz#93e25bf9ee75fe0fd80b594bc4feb0e862111b5a" @@ -3547,6 +3902,14 @@ resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-2.0.1.tgz#20f18294f797f2209b5f65c8e3b5c8e8261d127c" integrity sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw== +"@types/superagent@*": + version "4.1.16" + resolved "https://registry.yarnpkg.com/@types/superagent/-/superagent-4.1.16.tgz#12c9c16f232f9d89beab91d69368f96ce8e2d881" + integrity sha512-tLfnlJf6A5mB6ddqF159GqcDizfzbMUB1/DeT59/wBNqzRTNNKsaw79A/1TZ84X+f/EwWH8FeuSkjlCLyqS/zQ== + dependencies: + "@types/cookiejar" "*" + "@types/node" "*" + "@types/superagent@^4.1.12": version "4.1.15" resolved "https://registry.yarnpkg.com/@types/superagent/-/superagent-4.1.15.tgz#63297de457eba5e2bc502a7609426c4cceab434a" @@ -3555,6 +3918,13 @@ "@types/cookiejar" "*" "@types/node" "*" +"@types/supertest@^2.0.12": + version "2.0.12" + resolved "https://registry.yarnpkg.com/@types/supertest/-/supertest-2.0.12.tgz#ddb4a0568597c9aadff8dbec5b2e8fddbe8692fc" + integrity sha512-X3HPWTwXRerBZS7Mo1k6vMVR1Z6zmJcDVn5O/31whe0tnjE4te6ZJSJGq1RiqHPjzPdMTfjCFogDJmwng9xHaQ== + dependencies: + "@types/superagent" "*" + "@types/tar@6.1.3": version "6.1.3" resolved "https://registry.yarnpkg.com/@types/tar/-/tar-6.1.3.tgz#46a2ce7617950c4852dfd7e9cd41aa8161b9d750" @@ -3563,6 +3933,13 @@ "@types/node" "*" minipass "^3.3.5" +"@types/tern@*": + version "0.23.4" + resolved "https://registry.yarnpkg.com/@types/tern/-/tern-0.23.4.tgz#03926eb13dbeaf3ae0d390caf706b2643a0127fb" + integrity sha512-JAUw1iXGO1qaWwEOzxTKJZ/5JxVeON9kvGZ/osgZaJImBnyjyn0cjovPsf6FNLmyGY8Vw9DoXZCMlfMkMwHRWg== + dependencies: + "@types/estree" "*" + "@types/tough-cookie@*", "@types/tough-cookie@^4.0.2": version "4.0.2" resolved "https://registry.yarnpkg.com/@types/tough-cookie/-/tough-cookie-4.0.2.tgz#6286b4c7228d58ab7866d19716f3696e03a09397" @@ -4168,7 +4545,7 @@ arg@^4.1.0: resolved "https://registry.yarnpkg.com/arg/-/arg-4.1.3.tgz#269fc7ad5b8e42cb63c896d5666017261c144089" integrity sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA== -argparse@^1.0.7: +argparse@^1.0.10, argparse@^1.0.7: version "1.0.10" resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== @@ -4215,6 +4592,15 @@ array-equal@^1.0.0: resolved "https://registry.yarnpkg.com/array-equal/-/array-equal-1.0.0.tgz#8c2a5ef2472fd9ea742b04c77a75093ba2757c93" integrity sha512-H3LU5RLiSsGXPhN+Nipar0iR0IofH+8r89G2y1tBKxQ/agagKyAjhkAFDRBfodP2caPrNKHpAWNIM/c9yeL7uA== +array-sort@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/array-sort/-/array-sort-1.0.0.tgz#e4c05356453f56f53512a7d1d6123f2c54c0a88a" + integrity sha512-ihLeJkonmdiAsD7vpgN3CRcx2J2S0TiYW+IS/5zHBI7mKUq3ySvBdzzBfD236ubDBQFiiyG3SWCPc+msQ9KoYg== + dependencies: + default-compare "^1.0.0" + get-value "^2.0.6" + kind-of "^5.0.2" + array-union@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d" @@ -4358,6 +4744,13 @@ atomic-sleep@^1.0.0: resolved "https://registry.yarnpkg.com/atomic-sleep/-/atomic-sleep-1.0.0.tgz#eb85b77a601fc932cfe432c5acd364a9e2c9075b" integrity sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ== +autolinker@~0.28.0: + version "0.28.1" + resolved "https://registry.yarnpkg.com/autolinker/-/autolinker-0.28.1.tgz#0652b491881879f0775dace0cdca3233942a4e47" + integrity sha512-zQAFO1Dlsn69eXaO6+7YZc+v84aquQKbwpzCE3L0stj56ERn9hutFxPopViLjo9G+rWwjozRhgS5KJ25Xy19cQ== + dependencies: + gulp-header "^1.7.1" + available-typed-arrays@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz#92f95616501069d07d10edb2fc37d3e1c65123b7" @@ -5288,6 +5681,18 @@ co@^4.6.0: resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" integrity sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ== +codemirror-spell-checker@1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/codemirror-spell-checker/-/codemirror-spell-checker-1.1.2.tgz#1c660f9089483ccb5113b9ba9ca19c3f4993371e" + integrity sha512-2Tl6n0v+GJRsC9K3MLCdLaMOmvWL0uukajNJseorZJsslaxZyZMgENocPU8R0DyoTAiKsyqiemSOZo7kjGV0LQ== + dependencies: + typo-js "*" + +codemirror@^5.63.1: + version "5.65.11" + resolved "https://registry.yarnpkg.com/codemirror/-/codemirror-5.65.11.tgz#c818edc3274788c008f636520c5490a1f7009b4f" + integrity sha512-Gp62g2eKSCHYt10axmGhKq3WoJSvVpvhXmowNq7pZdRVowwtvBR/hi2LSP5srtctKkRT33T6/n8Kv1UGp7JW4A== + collect-v8-coverage@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz#cc2c8e94fc18bbdffe64d6534570c8a673b27f59" @@ -5438,6 +5843,13 @@ concat-map@0.0.1: resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== +concat-with-sourcemaps@*: + version "1.1.0" + resolved "https://registry.yarnpkg.com/concat-with-sourcemaps/-/concat-with-sourcemaps-1.1.0.tgz#d4ea93f05ae25790951b99e7b3b09e3908a4082e" + integrity sha512-4gEjHJFT9e+2W/77h/DS5SGUgwDaOwprX8L/gl5+3ixnzkVJJsZWDSelmN3Oilw3LNDZjZV0yqH1hLG3k6nghg== + dependencies: + source-map "^0.6.1" + condense-newlines@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/condense-newlines/-/condense-newlines-0.2.1.tgz#3de985553139475d32502c83b02f60684d24c55f" @@ -5841,6 +6253,13 @@ deepmerge@^4.2.2: resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.2.2.tgz#44d2ea3679b8f4d4ffba33f03d865fc1e7bf4955" integrity sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg== +default-compare@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/default-compare/-/default-compare-1.0.0.tgz#cb61131844ad84d84788fb68fd01681ca7781a2f" + integrity sha512-QWfXlM0EkAbqOCbD/6HjdwT19j7WCkMyiRhWilc4H9/5h/RzTF9gv5LYh1+CmDV5d1rki6KAWLtQale0xt20eQ== + dependencies: + kind-of "^5.0.2" + default-shell@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/default-shell/-/default-shell-1.0.1.tgz#752304bddc6174f49eb29cb988feea0b8813c8bc" @@ -6037,11 +6456,25 @@ doctrine@3.0.0, doctrine@^3.0.0: dependencies: esutils "^2.0.2" +dom-serializer@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-2.0.0.tgz#e41b802e1eedf9f6cae183ce5e622d789d7d8e53" + integrity sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg== + dependencies: + domelementtype "^2.3.0" + domhandler "^5.0.2" + entities "^4.2.0" + dom-walk@^0.1.0: version "0.1.2" resolved "https://registry.yarnpkg.com/dom-walk/-/dom-walk-0.1.2.tgz#0c548bef048f4d1f2a97249002236060daa3fd84" integrity sha512-6QvTW9mrGeIegrFXdtQi9pk7O/nSK6lSdXW2eqUspN5LWD7UTji2Fqw5V2YLjBpHEoU9Xl/eUWNpDeZvoyOv2w== +domelementtype@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-2.3.0.tgz#5c45e8e869952626331d7aab326d01daf65d589d" + integrity sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw== + domexception@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/domexception/-/domexception-1.0.1.tgz#937442644ca6a31261ef36e3ec677fe805582c90" @@ -6049,6 +6482,22 @@ domexception@^1.0.1: dependencies: webidl-conversions "^4.0.2" +domhandler@^5.0.1, domhandler@^5.0.2: + version "5.0.3" + resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-5.0.3.tgz#cc385f7f751f1d1fc650c21374804254538c7d31" + integrity sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w== + dependencies: + domelementtype "^2.3.0" + +domutils@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/domutils/-/domutils-3.0.1.tgz#696b3875238338cb186b6c0612bd4901c89a4f1c" + integrity sha512-z08c1l761iKhDFtfXO04C7kTdPBLi41zwOZl00WS8b5eiaebNpY00HKbztwBq+e3vyqWNwWF3mP9YLUeqIrF+Q== + dependencies: + dom-serializer "^2.0.0" + domelementtype "^2.3.0" + domhandler "^5.0.1" + dot-prop@^5.2.0: version "5.3.0" resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-5.3.0.tgz#90ccce708cd9cd82cc4dc8c3ddd9abdd55b20e88" @@ -6093,6 +6542,11 @@ download@8.0.0: p-event "^2.1.0" pify "^4.0.1" +downloadjs@1.4.7: + version "1.4.7" + resolved "https://registry.yarnpkg.com/downloadjs/-/downloadjs-1.4.7.tgz#f69f96f940e0d0553dac291139865a3cd0101e3c" + integrity sha512-LN1gO7+u9xjU5oEScGFKvXhYf7Y/empUIIEAGBs1LzUq/rg5duiDrkuH5A2lQGd5jfMOb9X9usDa2oVXwJ0U/Q== + duplexer3@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/duplexer3/-/duplexer3-0.1.4.tgz#ee01dd1cac0ed3cbc7fdbea37dc0a8f1ce002ce2" @@ -6108,6 +6562,17 @@ duplexify@^4.0.0: readable-stream "^3.1.1" stream-shift "^1.0.0" +easymde@^2.16.1: + version "2.18.0" + resolved "https://registry.yarnpkg.com/easymde/-/easymde-2.18.0.tgz#ff1397d07329b1a7b9187d2d0c20766fa16b3b1b" + integrity sha512-IxVVUxNWIoXLeqtBU4BLc+eS/ScYhT1Dcb6yF5Wchoj1iXAV+TIIDWx+NCaZhY7RcSHqDPKllbYq7nwGKILnoA== + dependencies: + "@types/codemirror" "^5.60.4" + "@types/marked" "^4.0.7" + codemirror "^5.63.1" + codemirror-spell-checker "1.1.2" + marked "^4.1.0" + ecc-jsbn@~0.1.1: version "0.1.2" resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz#3a83a904e54353287874c564b7549386849a98c9" @@ -6270,6 +6735,17 @@ end-stream@~0.1.0: dependencies: write-stream "~0.4.3" +engine.io-client@~6.4.0: + version "6.4.0" + resolved "https://registry.yarnpkg.com/engine.io-client/-/engine.io-client-6.4.0.tgz#88cd3082609ca86d7d3c12f0e746d12db4f47c91" + integrity sha512-GyKPDyoEha+XZ7iEqam49vz6auPnNJ9ZBfy89f+rMMas8AuiMWOZ9PVzu8xb9ZC6rafUqiGHSCfu22ih66E+1g== + dependencies: + "@socket.io/component-emitter" "~3.1.0" + debug "~4.3.1" + engine.io-parser "~5.0.3" + ws "~8.11.0" + xmlhttprequest-ssl "~2.0.0" + engine.io-parser@~5.0.3: version "5.0.4" resolved "https://registry.yarnpkg.com/engine.io-parser/-/engine.io-parser-5.0.4.tgz#0b13f704fa9271b3ec4f33112410d8f3f41d0fc0" @@ -6299,6 +6775,16 @@ enhanced-resolve@^5.9.3: graceful-fs "^4.2.4" tapable "^2.2.0" +ent@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/ent/-/ent-2.2.0.tgz#e964219325a21d05f44466a2f686ed6ce5f5dd1d" + integrity sha512-GHrMyVZQWvTIdDtpiEXdHZnFQKzeO09apj8Cbl4pKWy4i0Oprcq17usfDt5aO63swf0JOeMWjWQE/LzgSRuWpA== + +entities@^4.2.0, entities@^4.3.0: + version "4.4.0" + resolved "https://registry.yarnpkg.com/entities/-/entities-4.4.0.tgz#97bdaba170339446495e653cfd2db78962900174" + integrity sha512-oYp7156SP8LkeGD0GF85ad1X9Ai79WtRsZ2gxJqtBuzH+98YUV6jkHEKlZkMbcrjJjIVJNIDP/3WL9wQkoPbWA== + entities@~2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/entities/-/entities-2.1.0.tgz#992d3129cf7df6870b96c57858c249a120f8b8b5" @@ -7479,6 +7965,14 @@ get-intrinsic@^1.0.2, get-intrinsic@^1.1.0, get-intrinsic@^1.1.1: has "^1.0.3" has-symbols "^1.0.3" +get-object@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/get-object/-/get-object-0.2.0.tgz#d92ff7d5190c64530cda0543dac63a3d47fe8c0c" + integrity sha512-7P6y6k6EzEFmO/XyUyFlXm1YLJy9xeA1x/grNV8276abX5GuwUtYgKFkRFkLixw4hf4Pz9q2vgv/8Ar42R0HuQ== + dependencies: + is-number "^2.0.2" + isobject "^0.2.0" + get-package-type@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/get-package-type/-/get-package-type-0.1.0.tgz#8de2d803cff44df3bc6c456e6668b36c3926e11a" @@ -7541,6 +8035,13 @@ get-value@^2.0.3, get-value@^2.0.6: resolved "https://registry.yarnpkg.com/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28" integrity sha512-Ln0UQDlxH1BapMu3GPtf7CuYNwRZf2gwCuPqbyG6pB8WfmFpzqcy4xtAaAMUhnNqjMKTiCPZG2oMT3YSx8U2NA== +get-value@^3.0.0, get-value@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/get-value/-/get-value-3.0.1.tgz#5efd2a157f1d6a516d7524e124ac52d0a39ef5a8" + integrity sha512-mKZj9JLQrwMBtj5wxi6MH8Z5eSKaERpAwjg43dPtlGI1ZVEgH/qC7T8/6R2OBSUA+zzHBZgICsVJaEIV2tKTDA== + dependencies: + isobject "^3.0.1" + getopts@2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/getopts/-/getopts-2.3.0.tgz#71e5593284807e03e2427449d4f6712a268666f4" @@ -7828,7 +8329,24 @@ gtoken@^5.0.4: google-p12-pem "^3.1.3" jws "^4.0.0" -handlebars@^4.7.7: +gulp-header@^1.7.1: + version "1.8.12" + resolved "https://registry.yarnpkg.com/gulp-header/-/gulp-header-1.8.12.tgz#ad306be0066599127281c4f8786660e705080a84" + integrity sha512-lh9HLdb53sC7XIZOYzTXM4lFuXElv3EVkSDhsd7DoJBj7hm+Ni7D3qYbb+Rr8DuM8nRanBvkVO9d7askreXGnQ== + dependencies: + concat-with-sourcemaps "*" + lodash.template "^4.4.0" + through2 "^2.0.0" + +handlebars-utils@^1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/handlebars-utils/-/handlebars-utils-1.0.6.tgz#cb9db43362479054782d86ffe10f47abc76357f9" + integrity sha512-d5mmoQXdeEqSKMtQQZ9WkiUcO1E3tPbWxluCK9hVgIDPzQa9WsKo3Lbe/sGflTe7TomHEeZaOgwIkyIr1kfzkw== + dependencies: + kind-of "^6.0.0" + typeof-article "^0.1.1" + +handlebars@^4.7.6, handlebars@^4.7.7: version "4.7.7" resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.7.7.tgz#9ce33416aad02dbd6c8fafa8240d5d98004945a1" integrity sha512-aAcXm5OAfE/8IXkcZvCepKU3VzW1/39Fb5ZuqMtgI/hT8X2YgoMvBY5dLhq/cpOvw7Lk1nK/UF71aLG/ZnVYRA== @@ -7922,6 +8440,14 @@ has-value@^1.0.0: has-values "^1.0.0" isobject "^3.0.0" +has-value@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/has-value/-/has-value-2.0.2.tgz#d0f12e8780ba8e90e66ad1a21c707fdb67c25658" + integrity sha512-ybKOlcRsK2MqrM3Hmz/lQxXHZ6ejzSPzpNabKB45jb5qDgJvKPa3SdapTsTLwEb9WltgWpOmNax7i+DzNOk4TA== + dependencies: + get-value "^3.0.0" + has-values "^2.0.1" + has-values@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/has-values/-/has-values-0.1.4.tgz#6d61de95d91dfca9b9a02089ad384bff8f62b771" @@ -7935,6 +8461,13 @@ has-values@^1.0.0: is-number "^3.0.0" kind-of "^4.0.0" +has-values@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/has-values/-/has-values-2.0.1.tgz#3876200ff86d8a8546a9264a952c17d5fc17579d" + integrity sha512-+QdH3jOmq9P8GfdjFg0eJudqx1FqU62NQJ4P16rOEHeRdl7ckgwn6uqQjzYE0ZoHVV/e5E2esuJ5Gl5+HUW19w== + dependencies: + kind-of "^6.0.2" + has-yarn@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/has-yarn/-/has-yarn-2.1.0.tgz#137e11354a7b5bf11aa5cb649cf0c6f3ff2b2e77" @@ -7947,6 +8480,16 @@ has@^1.0.3: dependencies: function-bind "^1.1.1" +helper-md@^0.2.2: + version "0.2.2" + resolved "https://registry.yarnpkg.com/helper-md/-/helper-md-0.2.2.tgz#c1f59d7e55bbae23362fd8a0e971607aec69d41f" + integrity sha512-49TaQzK+Ic7ZVTq4i1UZxRUJEmAilTk8hz7q4I0WNUaTclLR8ArJV5B3A1fe1xF2HtsDTr2gYKLaVTof/Lt84Q== + dependencies: + ent "^2.2.0" + extend-shallow "^2.0.1" + fs-exists-sync "^0.1.0" + remarkable "^1.6.2" + homedir-polyfill@^1.0.0, homedir-polyfill@^1.0.1: version "1.0.3" resolved "https://registry.yarnpkg.com/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz#743298cef4e5af3e194161fbadcc2151d3a058e8" @@ -7976,6 +8519,29 @@ html-escaper@^2.0.0: resolved "https://registry.yarnpkg.com/html-escaper/-/html-escaper-2.0.2.tgz#dfd60027da36a36dfcbe236262c00a5822681453" integrity sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg== +html-tag@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/html-tag/-/html-tag-2.0.0.tgz#36c3bc8d816fd30b570d5764a497a641640c2fed" + integrity sha512-XxzooSo6oBoxBEUazgjdXj7VwTn/iSTSZzTYKzYY6I916tkaYzypHxy+pbVU1h+0UQ9JlVf5XkNQyxOAiiQO1g== + dependencies: + is-self-closing "^1.0.1" + kind-of "^6.0.0" + +html5-qrcode@^2.2.1: + version "2.3.6" + resolved "https://registry.yarnpkg.com/html5-qrcode/-/html5-qrcode-2.3.6.tgz#95f572fd79b84cbce0e509da80eda43a394cec3c" + integrity sha512-yuCJUFzm04xGPM2a40XYPptpioV6K5uJA3Ogy0Xi/a7tAYrcD7T4ZCsbg0T1H2qX/143SZfDG1EINnNFh5rH0A== + +htmlparser2@^8.0.0: + version "8.0.1" + resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-8.0.1.tgz#abaa985474fcefe269bc761a779b544d7196d010" + integrity sha512-4lVbmc1diZC7GUJQtRQ5yBAeUCL1exyMwmForWkRLnwyzWBFxN633SALPMGYaWZvKe9j1pRZJpauvmxENSp/EA== + dependencies: + domelementtype "^2.3.0" + domhandler "^5.0.2" + domutils "^3.0.1" + entities "^4.3.0" + http-assert@^1.3.0: version "1.5.0" resolved "https://registry.yarnpkg.com/http-assert/-/http-assert-1.5.0.tgz#c389ccd87ac16ed2dfa6246fd73b926aa00e6b8f" @@ -8440,6 +9006,13 @@ is-docker@^2.0.0, is-docker@^2.1.1: resolved "https://registry.yarnpkg.com/is-docker/-/is-docker-2.2.1.tgz#33eeabe23cfe86f14bde4408a02c0cfb853acdaa" integrity sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ== +is-even@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-even/-/is-even-1.0.0.tgz#76b5055fbad8d294a86b6a949015e1c97b717c06" + integrity sha512-LEhnkAdJqic4Dbqn58A0y52IXoHWlsueqQkKfMfdEnIYG8A1sm/GHidKkS6yvXlMoRrkM34csHnXQtOqcb+Jzg== + dependencies: + is-odd "^0.1.2" + is-extendable@^0.1.0, is-extendable@^0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89" @@ -8546,6 +9119,13 @@ is-number-object@^1.0.4: dependencies: has-tostringtag "^1.0.0" +is-number@^2.0.2: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-2.1.0.tgz#01fcbbb393463a548f2f466cce16dece49db908f" + integrity sha512-QUzH43Gfb9+5yckcrSA0VBDwEtDUchrk4F6tfJZQuNzDJbEDB9cZNzSfXGQ1jqmdDY/kl41lUOWM9syA8z8jlg== + dependencies: + kind-of "^3.0.2" + is-number@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/is-number/-/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195" @@ -8568,6 +9148,13 @@ is-object@^1.0.1: resolved "https://registry.yarnpkg.com/is-object/-/is-object-1.0.2.tgz#a56552e1c665c9e950b4a025461da87e72f86fcf" integrity sha512-2rRIahhZr2UWb45fIOuvZGpFtz0TyOZLf32KxBbSoUCeZR495zCKlWUKKUByk3geS2eAs7ZAABt0Y/Rx0GiQGA== +is-odd@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/is-odd/-/is-odd-0.1.2.tgz#bc573b5ce371ef2aad6e6f49799b72bef13978a7" + integrity sha512-Ri7C2K7o5IrUU9UEI8losXJCCD/UtsaIrkR5sxIcFg4xQ9cRJXlWA5DQvTE0yDc0krvSNLsRGXN11UPS6KyfBw== + dependencies: + is-number "^3.0.0" + is-path-inside@^3.0.2: version "3.0.3" resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-3.0.3.tgz#d231362e53a07ff2b0e0ea7fed049161ffd16283" @@ -8585,6 +9172,11 @@ is-plain-object@^2.0.3, is-plain-object@^2.0.4: dependencies: isobject "^3.0.1" +is-plain-object@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-5.0.0.tgz#4427f50ab3429e9025ea7d52e9043a9ef4159344" + integrity sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q== + is-property@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/is-property/-/is-property-1.0.2.tgz#57fe1c4e48474edd65b09911f26b1cd4095dda84" @@ -8608,6 +9200,13 @@ is-retry-allowed@^2.2.0: resolved "https://registry.yarnpkg.com/is-retry-allowed/-/is-retry-allowed-2.2.0.tgz#88f34cbd236e043e71b6932d09b0c65fb7b4d71d" integrity sha512-XVm7LOeLpTW4jV19QSH38vkswxoLud8sQ57YwJVTPWdiaI9I8keEhGFpBlslyVsgdQy4Opg8QOLb8YRgsyZiQg== +is-self-closing@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-self-closing/-/is-self-closing-1.0.1.tgz#5f406b527c7b12610176320338af0fa3896416e4" + integrity sha512-E+60FomW7Blv5GXTlYee2KDrnG6srxF7Xt1SjrhWUGUEsTFIqY/nq2y3DaftCsgUMdh89V07IVfhY9KIJhLezg== + dependencies: + self-closing-tags "^1.0.1" + is-shared-array-buffer@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz#8f259c573b60b6a32d4058a1a07430c0a7344c79" @@ -8723,6 +9322,11 @@ isexe@^2.0.0: resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== +isobject@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/isobject/-/isobject-0.2.0.tgz#a3432192f39b910b5f02cc989487836ec70aa85e" + integrity sha512-VaWq6XYAsbvM0wf4dyBO7WH9D7GosB7ZZlqrawI9BBiTMINBeCyqSKBa35m870MY3O4aM31pYyZi9DfGrYMJrQ== + isobject@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89" @@ -9917,7 +10521,7 @@ keyv@^3.0.0: dependencies: json-buffer "3.0.0" -kind-of@^3.0.2, kind-of@^3.0.3, kind-of@^3.2.0: +kind-of@^3.0.2, kind-of@^3.0.3, kind-of@^3.1.0, kind-of@^3.2.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== @@ -9931,12 +10535,12 @@ kind-of@^4.0.0: dependencies: is-buffer "^1.1.5" -kind-of@^5.0.0: +kind-of@^5.0.0, kind-of@^5.0.2: version "5.1.0" resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-5.1.0.tgz#729c91e2d857b7a419a1f9aa65685c4c33f5845d" integrity sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw== -kind-of@^6.0.0, kind-of@^6.0.2: +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== @@ -10152,6 +10756,11 @@ lcid@^2.0.0: dependencies: invert-kv "^2.0.0" +leaflet@^1.7.1: + version "1.9.3" + resolved "https://registry.yarnpkg.com/leaflet/-/leaflet-1.9.3.tgz#52ec436954964e2d3d39e0d433da4b2500d74414" + integrity sha512-iB2cR9vAkDOu5l3HAay2obcUHZ7xwUBBjph8+PGtmW/2lYhbLizWtG7nTeYht36WfOslixQF9D/uSIzhZgGMfQ== + left-pad@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/left-pad/-/left-pad-1.3.0.tgz#5b8a3a7765dfe001261dde915589e782f8c94d1e" @@ -10346,6 +10955,11 @@ locate-path@^5.0.0: dependencies: p-locate "^4.1.0" +lodash._reinterpolate@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz#0ccf2d89166af03b3663c796538b75ac6e114d9d" + integrity sha512-xYHt68QRoYGjeeM/XOE1uJtvXQAgvszfBhjV4yvsQH0u2i9I6cI6c6/eG4Hh3UAOVn0y/xAXwmTzEay49Q//HA== + lodash.camelcase@^4.3.0: version "4.3.0" resolved "https://registry.yarnpkg.com/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz#b28aa6288a2b9fc651035c7711f65ab6190331a6" @@ -10451,6 +11065,21 @@ lodash.sortby@^4.7.0: resolved "https://registry.yarnpkg.com/lodash.sortby/-/lodash.sortby-4.7.0.tgz#edd14c824e2cc9c1e0b0a1b42bb5210516a42438" integrity sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA== +lodash.template@^4.4.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/lodash.template/-/lodash.template-4.5.0.tgz#f976195cf3f347d0d5f52483569fe8031ccce8ab" + integrity sha512-84vYFxIkmidUiFxidA/KjjH9pAycqW+h980j7Fuz5qxRtO9pgB7MDFTdys1N7A5mcucRiDyEq4fusljItR1T/A== + dependencies: + lodash._reinterpolate "^3.0.0" + lodash.templatesettings "^4.0.0" + +lodash.templatesettings@^4.0.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/lodash.templatesettings/-/lodash.templatesettings-4.2.0.tgz#e481310f049d3cf6d47e912ad09313b154f0fb33" + integrity sha512-stgLz+i3Aa9mZgnjr/O+v9ruKZsPsndy7qPZOchbqk2cnTU1ZaldKK+v7m54WoKIyxiuMZTKT2H81F8BeAc3ZQ== + dependencies: + lodash._reinterpolate "^3.0.0" + lodash.without@^4.4.0: version "4.4.0" resolved "https://registry.yarnpkg.com/lodash.without/-/lodash.without-4.4.0.tgz#3cd4574a00b67bae373a94b748772640507b7aac" @@ -10461,7 +11090,7 @@ lodash.xor@^4.5.0: resolved "https://registry.yarnpkg.com/lodash.xor/-/lodash.xor-4.5.0.tgz#4d48ed7e98095b0632582ba714d3ff8ae8fb1db6" integrity sha512-sVN2zimthq7aZ5sPGXnSz32rZPuqcparVW50chJQe+mzTYV+IsxSsl/2gnkWWE2Of7K3myBQBqtLKOUEHJKRsQ== -lodash@4.17.21, lodash@^4.17.11, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.21, lodash@^4.17.3: +lodash@4.17.21, lodash@^4.17.11, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.20, lodash@^4.17.21, lodash@^4.17.3: version "4.17.21" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== @@ -10613,6 +11242,11 @@ markdown-it@^12.2.0: mdurl "^1.0.1" uc.micro "^1.0.5" +marked@^4.1.0: + version "4.2.12" + resolved "https://registry.yarnpkg.com/marked/-/marked-4.2.12.tgz#d69a64e21d71b06250da995dcd065c11083bebb5" + integrity sha512-yr8hSKa3Fv4D3jdZmtMMPghgVt6TWbk86WQaWhDloQjRSQhMMYCAro7jP7VDJrjjdV8pxVxMssXS8B8Y5DZ5aw== + matcher@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/matcher/-/matcher-3.0.0.tgz#bd9060f4c5b70aa8041ccc6f80368760994f30ca" @@ -10708,7 +11342,7 @@ methods@^1.1.1, methods@^1.1.2: resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" integrity sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w== -micromatch@^3.1.10, micromatch@^3.1.4: +micromatch@^3.1.10, micromatch@^3.1.4, micromatch@^3.1.5: version "3.1.10" resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23" integrity sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg== @@ -11011,6 +11645,16 @@ nan@^2.15.0, nan@^2.16.0: resolved "https://registry.yarnpkg.com/nan/-/nan-2.17.0.tgz#c0150a2368a182f033e9aa5195ec76ea41a199cb" integrity sha512-2ZTgtl0nJsO0KQCjEpxcIr5D+Yv90plTitZt9JBfQvVJDS5seMl3FOvsh3+9CoYWXf/1l5OaZzzF6nDm4cagaQ== +nanoid@^2.1.0: + version "2.1.11" + resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-2.1.11.tgz#ec24b8a758d591561531b4176a01e3ab4f0f0280" + integrity sha512-s/snB+WGm6uwi0WjsZdaVcuf3KJXlfGl2LcxgwkEwJF0D/BWzVWAZW/XY4bFaiR7s0Jk3FPvlnepg1H1b1UwlA== + +nanoid@^3.3.4: + version "3.3.4" + resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.4.tgz#730b67e3cd09e2deacf03c027c81c9d9dbc5e8ab" + integrity sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw== + nanomatch@^1.2.9: version "1.2.13" resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119" @@ -11689,6 +12333,11 @@ parse-passwd@^1.0.0: resolved "https://registry.yarnpkg.com/parse-passwd/-/parse-passwd-1.0.0.tgz#6d5b934a456993b23d37f40a382d6f1666a8e5c6" integrity sha512-1Y1A//QUXEZK7YKz+rD9WydcE1+EuPr6ZBgKecAB8tmoW6UFv0NREVJe1p+jRxtThkcbbKkfwIbWJe/IeE6m2Q== +parse-srcset@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/parse-srcset/-/parse-srcset-1.0.2.tgz#f2bd221f6cc970a938d88556abc589caaaa2bde1" + integrity sha512-/2qh0lav6CmI15FzA3i/2Bzk2zCgQhGMkvhOhKNcBVQ1ldgpbfiNTVslmooUmWJcADi1f1kIeynbDRVzNlfR6Q== + parse5@4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/parse5/-/parse5-4.0.0.tgz#6d78656e3da8d78b4ec0b906f7c08ef1dfe3f608" @@ -12037,6 +12686,15 @@ posix-character-classes@^0.1.0: resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab" integrity sha512-xTgYBc3fuo7Yt7JbiuFxSYGToMoz8fLoE6TC9Wx1P/u+LfeThMOAqmuyECnlBaaJb+u1m9hHiXUEtwW4OzfUJg== +postcss@^8.3.11: + version "8.4.21" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.21.tgz#c639b719a57efc3187b13a1d765675485f4134f4" + integrity sha512-tP7u/Sn/dVxK2NnruI4H9BG+x+Wxz6oeZ1cJ8P6G/PZY0IKk4k/63TDsQf2kQq3+qoJeLm2kIBUNlZe3zgb4Zg== + dependencies: + nanoid "^3.3.4" + picocolors "^1.0.0" + source-map-js "^1.0.2" + postgres-array@~2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/postgres-array/-/postgres-array-2.0.0.tgz#48f8fce054fbc69671999329b8834b772652d82e" @@ -12808,6 +13466,16 @@ regexp.prototype.flags@^1.4.3: define-properties "^1.1.3" functions-have-names "^1.2.2" +regexparam@2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/regexparam/-/regexparam-2.0.1.tgz#c912f5dae371e3798100b3c9ce22b7414d0889fa" + integrity sha512-zRgSaYemnNYxUv+/5SeoHI0eJIgTL/A2pUtXUPLHQxUldagouJ9p+K6IbIZ/JiQuCEv2E2B1O11SjVQy3aMCkw== + +regexparam@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/regexparam/-/regexparam-1.3.0.tgz#2fe42c93e32a40eff6235d635e0ffa344b92965f" + integrity sha512-6IQpFBv6e5vz1QAqI+V4k8P2e/3gRrqfCJ9FI+O1FLQTO+Uz6RXZEZOPmTJ6hlGj7gkERzY5BRCv09whKP96/g== + regexpp@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-2.0.1.tgz#8d19d31cf632482b589049f8281f93dbcba4d07f" @@ -12856,6 +13524,21 @@ relative-microtime@^2.0.0: resolved "https://registry.yarnpkg.com/relative-microtime/-/relative-microtime-2.0.0.tgz#cceed2af095ecd72ea32011279c79e5fcc7de29b" integrity sha512-l18ha6HEZc+No/uK4GyAnNxgKW7nvEe35IaeN54sShMojtqik2a6GbTyuiezkjpPaqP874Z3lW5ysBo5irz4NA== +relative@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/relative/-/relative-3.0.2.tgz#0dcd8ec54a5d35a3c15e104503d65375b5a5367f" + integrity sha512-Q5W2qeYtY9GbiR8z1yHNZ1DGhyjb4AnLEjt8iE6XfcC1QIu+FAtj3HQaO0wH28H1mX6cqNLvAqWhP402dxJGyA== + dependencies: + isobject "^2.0.0" + +remarkable@^1.6.2: + version "1.7.4" + resolved "https://registry.yarnpkg.com/remarkable/-/remarkable-1.7.4.tgz#19073cb960398c87a7d6546eaa5e50d2022fcd00" + integrity sha512-e6NKUXgX95whv7IgddywbeN/ItCkWbISmc2DiqHJb0wTrqZIexqdco5b8Z3XZoo/48IdNVKM9ZCvTPJ4F5uvhg== + dependencies: + argparse "^1.0.10" + autolinker "~0.28.0" + remove-trailing-separator@^1.0.1: version "1.1.0" resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef" @@ -13151,6 +13834,18 @@ sane@^4.0.3: minimist "^1.1.1" walker "~1.0.5" +sanitize-html@^2.7.0: + version "2.9.0" + resolved "https://registry.yarnpkg.com/sanitize-html/-/sanitize-html-2.9.0.tgz#f4829557b0175df9059d90fe972d5e6facb8565c" + integrity sha512-KY1hpSbqFNcpoLf+nP7iStbP5JfQZ2Nd19ZEE7qFsQqRdp+sO5yX/e5+HoG9puFAcSTEpzQuihfKUltDcLlQjg== + dependencies: + deepmerge "^4.2.2" + escape-string-regexp "^4.0.0" + htmlparser2 "^8.0.0" + is-plain-object "^5.0.0" + parse-srcset "^1.0.2" + postcss "^8.3.11" + sanitize-s3-objectkey@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/sanitize-s3-objectkey/-/sanitize-s3-objectkey-0.0.1.tgz#efa9887cd45275b40234fb4bb12fc5754fe64e7e" @@ -13182,6 +13877,11 @@ schema-utils@^3.1.0, schema-utils@^3.1.1: ajv "^6.12.5" ajv-keywords "^3.5.2" +screenfull@^6.0.1: + version "6.0.2" + resolved "https://registry.yarnpkg.com/screenfull/-/screenfull-6.0.2.tgz#3dbe4b8c4f8f49fb8e33caa8f69d0bca730ab238" + integrity sha512-AQdy8s4WhNvUZ6P8F6PB21tSPIYKniic+Ogx0AacBMjKP1GUHN2E9URxQHtCusiwxudnCKkdy4GrHXPPJSkCCw== + search-params@3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/search-params/-/search-params-3.0.0.tgz#dbc7c243058e5a33ae1e9870be91f5aced4100d8" @@ -13199,6 +13899,11 @@ seek-bzip@^1.0.5: dependencies: commander "^2.8.1" +self-closing-tags@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/self-closing-tags/-/self-closing-tags-1.0.1.tgz#6c5fa497994bb826b484216916371accee490a5d" + integrity sha512-7t6hNbYMxM+VHXTgJmxwgZgLGktuXtVVD5AivWzNTdJBM4DBjnDKDzkf2SrNjihaArpeJYNjxkELBu1evI4lQA== + semver-compare@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/semver-compare/-/semver-compare-1.0.0.tgz#0dee216a1c941ab37e9efb1788f6afc5ff5537fc" @@ -13351,6 +14056,13 @@ shimmer@^1.2.0: resolved "https://registry.yarnpkg.com/shimmer/-/shimmer-1.2.1.tgz#610859f7de327b587efebf501fb43117f9aff337" integrity sha512-sQTKC1Re/rM6XyFM6fIAGHRPVGvyXfgzIDvzoq608vM+jeyVD0Tu1E6Np0Kc2zAIFWIj963V2800iF/9LPieQw== +shortid@^2.2.15: + version "2.2.16" + resolved "https://registry.yarnpkg.com/shortid/-/shortid-2.2.16.tgz#b742b8f0cb96406fd391c76bfc18a67a57fe5608" + integrity sha512-Ugt+GIZqvGXCIItnsL+lvFJOiN7RYqlGy7QE41O3YC1xbNSeDGIRO7xg2JJXIAj1cAGnOeC1r7/T9pgrtQbv4g== + dependencies: + nanoid "^2.1.0" + side-channel@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.4.tgz#efce5c8fdc104ee751b25c58d4290011fa5ea2cf" @@ -13491,6 +14203,16 @@ socket.io-adapter@~2.4.0: resolved "https://registry.yarnpkg.com/socket.io-adapter/-/socket.io-adapter-2.4.0.tgz#b50a4a9ecdd00c34d4c8c808224daa1a786152a6" integrity sha512-W4N+o69rkMEGVuk2D/cvca3uYsvGlMwsySWV447y99gUPghxq42BxqLNMndb+a1mm/5/7NeXVQS7RLa2XyXvYg== +socket.io-client@^4.5.1: + version "4.6.0" + resolved "https://registry.yarnpkg.com/socket.io-client/-/socket.io-client-4.6.0.tgz#449255d2e0fe429f5ab47ecd3e3b1716b0039c13" + integrity sha512-2XOp18xnGghUICSd5ziUIS4rB0dhr6S8OvAps8y+HhOjFQlqGcf+FIh6fCIsKKZyWFxJeFPrZRNPGsHDTsz1Ug== + dependencies: + "@socket.io/component-emitter" "~3.1.0" + debug "~4.3.2" + engine.io-client "~6.4.0" + socket.io-parser "~4.2.1" + socket.io-parser@~4.2.0: version "4.2.1" resolved "https://registry.yarnpkg.com/socket.io-parser/-/socket.io-parser-4.2.1.tgz#01c96efa11ded938dcb21cbe590c26af5eff65e5" @@ -13499,6 +14221,14 @@ socket.io-parser@~4.2.0: "@socket.io/component-emitter" "~3.1.0" debug "~4.3.1" +socket.io-parser@~4.2.1: + version "4.2.2" + resolved "https://registry.yarnpkg.com/socket.io-parser/-/socket.io-parser-4.2.2.tgz#1dd384019e25b7a3d374877f492ab34f2ad0d206" + integrity sha512-DJtziuKypFkMMHCm2uIshOYC7QaylbtzQwiMYDuCKy3OPkjLzu4B2vAhTlqipRHHzrI0NJeBAizTK7X+6m1jVw== + dependencies: + "@socket.io/component-emitter" "~3.1.0" + debug "~4.3.1" + socket.io@^4.5.1: version "4.5.2" resolved "https://registry.yarnpkg.com/socket.io/-/socket.io-4.5.2.tgz#1eb25fd380ab3d63470aa8279f8e48d922d443ac" @@ -13553,6 +14283,11 @@ source-list-map@^2.0.1: resolved "https://registry.yarnpkg.com/source-list-map/-/source-list-map-2.0.1.tgz#3993bd873bfc48479cca9ea3a547835c7c154b34" integrity sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw== +source-map-js@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.0.2.tgz#adbc361d9c62df380125e7f161f71c826f1e490c" + integrity sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw== + source-map-resolve@^0.5.0: version "0.5.3" resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.5.3.tgz#190866bece7553e1f8f267a2ee82c606b5509a1a" @@ -13975,6 +14710,11 @@ strip-outer@^1.0.0: dependencies: escape-string-regexp "^1.0.2" +striptags@^3.1.1: + version "3.2.0" + resolved "https://registry.yarnpkg.com/striptags/-/striptags-3.2.0.tgz#cc74a137db2de8b0b9a370006334161f7dd67052" + integrity sha512-g45ZOGzHDMe2bdYMdIvdAfCQkCTDMGBazSw1ypMowwGIee7ZQ5dU0rBJ8Jqgl+jAKIv4dbeE1jscZq9wid1Tkw== + style-loader@^3.3.1: version "3.3.1" resolved "https://registry.yarnpkg.com/style-loader/-/style-loader-3.3.1.tgz#057dfa6b3d4d7c7064462830f9113ed417d38575" @@ -14074,11 +14814,23 @@ svelte-portal@^1.0.0: resolved "https://registry.yarnpkg.com/svelte-portal/-/svelte-portal-1.0.0.tgz#36a47c5578b1a4d9b4dc60fa32a904640ec4cdd3" integrity sha512-nHf+DS/jZ6jjnZSleBMSaZua9JlG5rZv9lOGKgJuaZStfevtjIlUJrkLc3vbV8QdBvPPVmvcjTlazAzfKu0v3Q== +svelte-spa-router@^3.0.5: + version "3.3.0" + resolved "https://registry.yarnpkg.com/svelte-spa-router/-/svelte-spa-router-3.3.0.tgz#2fc0967a49dc361dfe4d38dddad6e662eed5b42c" + integrity sha512-cwRNe7cxD43sCvSfEeaKiNZg3FCizGxeMcf7CPiWRP3jKXjEma3vxyyuDtPOam6nWbVxl9TNM3hlE/i87ZlqcQ== + dependencies: + regexparam "2.0.1" + svelte@3.49.0: version "3.49.0" resolved "https://registry.yarnpkg.com/svelte/-/svelte-3.49.0.tgz#5baee3c672306de1070c3b7888fc2204e36a4029" integrity sha512-+lmjic1pApJWDfPCpUUTc1m8azDqYCG1JN9YEngrx/hUyIcFJo6VZhj0A1Ai0wqoHcEIuQy+e9tk+4uDgdtsFA== +svelte@^3.46.2, svelte@^3.49.0: + version "3.55.1" + resolved "https://registry.yarnpkg.com/svelte/-/svelte-3.55.1.tgz#6f93b153e5248039906ce5fe196efdb9e05dfce8" + integrity sha512-S+87/P0Ve67HxKkEV23iCdAh/SX1xiSfjF1HOglno/YTbSTW7RniICMCofWGdJJbdjw3S+0PfFb1JtGfTXE0oQ== + svg.draggable.js@^2.2.2: version "2.2.2" resolved "https://registry.yarnpkg.com/svg.draggable.js/-/svg.draggable.js-2.2.2.tgz#c514a2f1405efb6f0263e7958f5b68fce50603ba" @@ -14458,6 +15210,11 @@ to-fast-properties@^2.0.0: resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" integrity sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4= +to-gfm-code-block@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/to-gfm-code-block/-/to-gfm-code-block-0.1.1.tgz#25d045a5fae553189e9637b590900da732d8aa82" + integrity sha512-LQRZWyn8d5amUKnfR9A9Uu7x9ss7Re8peuWR2gkh1E+ildOfv2aF26JpuDg8JtvCduu5+hOrMIH+XstZtnagqg== + to-json-schema@0.2.5: version "0.2.5" resolved "https://registry.yarnpkg.com/to-json-schema/-/to-json-schema-0.2.5.tgz#ef3c3f11ad64460dcfbdbafd0fd525d69d62a98f" @@ -14726,6 +15483,13 @@ typedarray-to-buffer@^3.1.5: dependencies: is-typedarray "^1.0.0" +typeof-article@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/typeof-article/-/typeof-article-0.1.1.tgz#9f07e733c3fbb646ffa9e61c08debacd460e06af" + integrity sha512-Vn42zdX3FhmUrzEmitX3iYyLb+Umwpmv8fkZRIknYh84lmdrwqZA5xYaoKiIj2Rc5i/5wcDrpUmZcbk1U51vTw== + dependencies: + kind-of "^3.1.0" + typeof@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/typeof/-/typeof-1.0.0.tgz#9c84403f2323ae5399167275497638ea1d2f2440" @@ -14736,6 +15500,11 @@ typescript@4.7.3: resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.7.3.tgz#8364b502d5257b540f9de4c40be84c98e23a129d" integrity sha512-WOkT3XYvrpXx4vMMqlD+8R8R37fZkjyLGlxavMc4iB8lrl8L0DeTcHbYgw/v0N/z9wAFsgBhcsF0ruoySS22mA== +typo-js@*: + version "1.2.2" + resolved "https://registry.yarnpkg.com/typo-js/-/typo-js-1.2.2.tgz#340484d81fe518e77c81a5a770162b14492f183b" + integrity sha512-C7pYBQK17EjSg8tVNY91KHdUt5Nf6FMJ+c3js076quPmBML57PmNMzAcIq/2kf/hSYtFABNDIYNYlJRl5BJhGw== + uc.micro@^1.0.1, uc.micro@^1.0.5: version "1.0.6" resolved "https://registry.yarnpkg.com/uc.micro/-/uc.micro-1.0.6.tgz#9c411a802a409a91fc6cf74081baba34b24499ac" @@ -15086,6 +15855,14 @@ vm2@3.9.11: acorn "^8.7.0" acorn-walk "^8.2.0" +vm2@^3.9.4: + version "3.9.14" + resolved "https://registry.yarnpkg.com/vm2/-/vm2-3.9.14.tgz#964042b474cf1e6e4f475a39144773cdb9deb734" + integrity sha512-HgvPHYHeQy8+QhzlFryvSteA4uQLBCOub02mgqdR+0bN/akRZ48TGB1v0aCv7ksyc0HXx16AZtMHKS38alc6TA== + dependencies: + acorn "^8.7.0" + acorn-walk "^8.2.0" + vuvuzela@1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/vuvuzela/-/vuvuzela-1.0.3.tgz#3be145e58271c73ca55279dd851f12a682114b0b" @@ -15441,6 +16218,11 @@ ws@^5.2.0: dependencies: async-limiter "~1.0.0" +ws@~8.11.0: + version "8.11.0" + resolved "https://registry.yarnpkg.com/ws/-/ws-8.11.0.tgz#6a0d36b8edfd9f96d8b25683db2f8d7de6e8e143" + integrity sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg== + ws@~8.2.3: version "8.2.3" resolved "https://registry.yarnpkg.com/ws/-/ws-8.2.3.tgz#63a56456db1b04367d0b721a0b80cae6d8becbba" @@ -15509,6 +16291,11 @@ xmlbuilder@~9.0.1: resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-9.0.7.tgz#132ee63d2ec5565c557e20f4c22df9aca686b10d" integrity sha1-Ey7mPS7FVlxVfiD0wi35rKaGsQ0= +xmlhttprequest-ssl@~2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/xmlhttprequest-ssl/-/xmlhttprequest-ssl-2.0.0.tgz#91360c86b914e67f44dce769180027c0da618c67" + integrity sha512-QKxVRxiRACQcVuQEYFsI1hhkrMlrXHPegbbd1yn9UHOmRxY+si12nQYzri3vbzt8VdTTRviqcKxcyllFas5z2A== + xpath.js@~1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/xpath.js/-/xpath.js-1.1.0.tgz#3816a44ed4bb352091083d002a383dd5104a5ff1" @@ -15647,6 +16434,11 @@ yauzl@^2.4.2: buffer-crc32 "~0.2.3" fd-slicer "~1.1.0" +year@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/year/-/year-0.2.1.tgz#4083ae520a318b23ec86037f3000cb892bdf9bb0" + integrity sha512-9GnJUZ0QM4OgXuOzsKNzTJ5EOkums1Xc+3YQXp+Q+UxFjf7zLucp9dQ8QMIft0Szs1E1hUiXFim1OYfEKFq97w== + ylru@^1.2.0: version "1.3.2" resolved "https://registry.yarnpkg.com/ylru/-/ylru-1.3.2.tgz#0de48017473275a4cbdfc83a1eaf67c01af8a785" diff --git a/packages/types/src/documents/global/auditLogs.ts b/packages/types/src/documents/global/auditLogs.ts index 5b23650eec..7902997b39 100644 --- a/packages/types/src/documents/global/auditLogs.ts +++ b/packages/types/src/documents/global/auditLogs.ts @@ -1,6 +1,8 @@ import { Document } from "../document" import { Event } from "../../sdk" +export const AuditLogSystemUser = "SYSTEM" + export interface AuditLogDoc extends Document { appId?: string event: Event diff --git a/scripts/link-dependencies.sh b/scripts/link-dependencies.sh index d2a501162b..3a401e1f02 100755 --- a/scripts/link-dependencies.sh +++ b/scripts/link-dependencies.sh @@ -53,6 +53,10 @@ if [ -d "../budibase-pro" ]; then echo "Linking pro to server" cd packages/server && yarn link '@budibase/pro' cd - + + echo "Linking pro to backend-core" + cd packages/backend-core && yarn link '@budibase/pro' + cd - fi if [ -d "../account-portal" ]; then From c60b6da0abca77ab0b96a7edcbe52a2cf806135f Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Wed, 15 Feb 2023 13:49:30 +0000 Subject: [PATCH 010/106] Removing pro from backend-core. --- packages/backend-core/package.json | 1 - packages/backend-core/src/events/events.ts | 21 ++++++++++++++------- packages/backend-core/tsconfig.json | 6 ++---- packages/types/src/sdk/auditLogs.ts | 13 +++++++++++++ packages/types/src/sdk/index.ts | 1 + scripts/link-dependencies.sh | 4 ---- 6 files changed, 30 insertions(+), 16 deletions(-) create mode 100644 packages/types/src/sdk/auditLogs.ts diff --git a/packages/backend-core/package.json b/packages/backend-core/package.json index b51afcb8b1..705e4b1114 100644 --- a/packages/backend-core/package.json +++ b/packages/backend-core/package.json @@ -25,7 +25,6 @@ "@budibase/nano": "10.1.1", "@budibase/pouchdb-replication-stream": "1.2.10", "@budibase/types": "2.3.14-alpha.0", - "@budibase/pro": "2.3.14-alpha.0", "@shopify/jest-koa-mocks": "5.0.1", "@techpass/passport-openidconnect": "0.3.2", "aws-cloudfront-sign": "2.2.0", diff --git a/packages/backend-core/src/events/events.ts b/packages/backend-core/src/events/events.ts index e54497c0cf..14ef50b69c 100644 --- a/packages/backend-core/src/events/events.ts +++ b/packages/backend-core/src/events/events.ts @@ -1,10 +1,15 @@ -import { Event, IdentityType } from "@budibase/types" -import { sdk } from "@budibase/pro" +import { Event, IdentityType, AuditLogFn } from "@budibase/types" import { processors } from "./processors" import identification from "./identification" import { getAppId } from "../context" import * as backfill from "./backfill" +let writeAuditLogs: AuditLogFn | undefined + +export const initAuditLogs = (fn: AuditLogFn) => { + writeAuditLogs = fn +} + export const publishEvent = async ( event: Event, properties: any, @@ -18,11 +23,13 @@ export const publishEvent = async ( if (!backfilling) { // only audit log actual events, don't include backfills const userId = identity.type === IdentityType.USER ? identity.id : undefined - await sdk.auditLogs.write(event, properties, { - userId, - timestamp, - appId: getAppId(), - }) + if (writeAuditLogs) { + await writeAuditLogs(event, properties, { + userId, + timestamp, + appId: getAppId(), + }) + } await processors.processEvent(event, identity, properties, timestamp) return } diff --git a/packages/backend-core/tsconfig.json b/packages/backend-core/tsconfig.json index 62944d7f2c..e95fb9ab4d 100644 --- a/packages/backend-core/tsconfig.json +++ b/packages/backend-core/tsconfig.json @@ -4,13 +4,11 @@ "composite": true, "baseUrl": ".", "paths": { - "@budibase/types": ["../types/src"], - "@budibase/pro": ["../../../budibase-pro/packages/pro/src"] + "@budibase/types": ["../types/src"] } }, "references": [ - { "path": "../types" }, - { "path": "../../../budibase-pro/packages/pro" } + { "path": "../types" } ], "exclude": [ "node_modules", diff --git a/packages/types/src/sdk/auditLogs.ts b/packages/types/src/sdk/auditLogs.ts new file mode 100644 index 0000000000..9f8eb3825c --- /dev/null +++ b/packages/types/src/sdk/auditLogs.ts @@ -0,0 +1,13 @@ +import { Event } from "./events" + +export type AuditWriteOpts = { + appId?: string + timestamp?: string | number + userId?: string +} + +export type AuditLogFn = ( + event: Event, + metadata: any, + opts: AuditWriteOpts +) => Promise diff --git a/packages/types/src/sdk/index.ts b/packages/types/src/sdk/index.ts index f8f9d9cb97..1b0fdb193b 100644 --- a/packages/types/src/sdk/index.ts +++ b/packages/types/src/sdk/index.ts @@ -12,3 +12,4 @@ export * from "./db" export * from "./middleware" export * from "./featureFlag" export * from "./environmentVariables" +export * from "./auditLogs" diff --git a/scripts/link-dependencies.sh b/scripts/link-dependencies.sh index 3a401e1f02..d2a501162b 100755 --- a/scripts/link-dependencies.sh +++ b/scripts/link-dependencies.sh @@ -53,10 +53,6 @@ if [ -d "../budibase-pro" ]; then echo "Linking pro to server" cd packages/server && yarn link '@budibase/pro' cd - - - echo "Linking pro to backend-core" - cd packages/backend-core && yarn link '@budibase/pro' - cd - fi if [ -d "../account-portal" ]; then From 6d83ea9becd14a1a9e8372933843dd8dc2683ff8 Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Wed, 15 Feb 2023 18:03:55 +0000 Subject: [PATCH 011/106] Adding in event auditing to server/worker. --- packages/backend-core/src/events/events.ts | 2 +- packages/backend-core/src/events/index.ts | 1 + packages/backend-core/yarn.lock | 118 +-- packages/server/src/app.ts | 5 + packages/server/yarn.lock | 797 +-------------------- packages/worker/src/index.ts | 5 + 6 files changed, 34 insertions(+), 894 deletions(-) diff --git a/packages/backend-core/src/events/events.ts b/packages/backend-core/src/events/events.ts index 14ef50b69c..ba4b0a7448 100644 --- a/packages/backend-core/src/events/events.ts +++ b/packages/backend-core/src/events/events.ts @@ -6,7 +6,7 @@ import * as backfill from "./backfill" let writeAuditLogs: AuditLogFn | undefined -export const initAuditLogs = (fn: AuditLogFn) => { +export const configure = (fn: AuditLogFn) => { writeAuditLogs = fn } diff --git a/packages/backend-core/src/events/index.ts b/packages/backend-core/src/events/index.ts index d0d59a5b22..7aa4d06e58 100644 --- a/packages/backend-core/src/events/index.ts +++ b/packages/backend-core/src/events/index.ts @@ -3,6 +3,7 @@ export * as processors from "./processors" export * as analytics from "./analytics" export { default as identification } from "./identification" export * as backfillCache from "./backfill" +export { configure } from "./events" import { processors } from "./processors" diff --git a/packages/backend-core/yarn.lock b/packages/backend-core/yarn.lock index 93ca39ab35..d88b1058f9 100644 --- a/packages/backend-core/yarn.lock +++ b/packages/backend-core/yarn.lock @@ -475,45 +475,6 @@ resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== -"@budibase/backend-core@2.3.14-alpha.0": - version "2.3.14-alpha.0" - resolved "https://registry.yarnpkg.com/@budibase/backend-core/-/backend-core-2.3.14-alpha.0.tgz#8d60c93e9861301296907f61e770bdf1881b560c" - integrity sha512-lvRl6o9CCUx1VQ6ftu4FYuTp5mGgvbshNYoeaH0DbWFfhLNbibEHxx+pR+6M1ufhbu/EO6jKEr7DDeNiRBBMTw== - dependencies: - "@budibase/nano" "10.1.1" - "@budibase/pouchdb-replication-stream" "1.2.10" - "@budibase/types" "2.3.14-alpha.0" - "@shopify/jest-koa-mocks" "5.0.1" - "@techpass/passport-openidconnect" "0.3.2" - aws-cloudfront-sign "2.2.0" - aws-sdk "2.1030.0" - bcrypt "5.0.1" - bcryptjs "2.4.3" - bull "4.10.1" - correlation-id "4.0.0" - dotenv "16.0.1" - emitter-listener "1.1.2" - ioredis "4.28.0" - joi "17.6.0" - jsonwebtoken "9.0.0" - koa-passport "4.1.4" - lodash "4.17.21" - lodash.isarguments "3.1.0" - node-fetch "2.6.7" - passport-google-oauth "2.0.0" - passport-jwt "4.0.0" - passport-local "1.0.0" - passport-oauth2-refresh "^2.1.0" - posthog-node "1.3.0" - pouchdb "7.3.0" - pouchdb-find "7.2.2" - redlock "4.2.0" - sanitize-s3-objectkey "0.0.1" - semver "7.3.7" - tar-fs "2.1.1" - uuid "8.3.2" - zlib "1.0.5" - "@budibase/nano@10.1.1": version "10.1.1" resolved "https://registry.yarnpkg.com/@budibase/nano/-/nano-10.1.1.tgz#36ccda4d9bb64b5ee14dd2b27a295b40739b1038" @@ -539,25 +500,6 @@ pouchdb-promise "^6.0.4" through2 "^2.0.0" -"@budibase/pro@2.3.14-alpha.0": - version "2.3.14-alpha.0" - resolved "https://registry.yarnpkg.com/@budibase/pro/-/pro-2.3.14-alpha.0.tgz#db8ac1d0cacea21240c59458c4143e3e55663a4d" - integrity sha512-RJqXlvZmYrKCLxe7uVnc2KmDwE5OmoUZCA9M6b5Ne7ZHqrhtaNB/4Xlr1ESG79///epEWLv+Fde7mpHPzCvsZw== - dependencies: - "@budibase/backend-core" "2.3.14-alpha.0" - "@budibase/types" "2.3.14-alpha.0" - "@koa/router" "8.0.8" - bull "4.10.1" - joi "17.6.0" - jsonwebtoken "8.5.1" - lru-cache "^7.14.1" - node-fetch "^2.6.1" - -"@budibase/types@2.3.14-alpha.0": - version "2.3.14-alpha.0" - resolved "https://registry.yarnpkg.com/@budibase/types/-/types-2.3.14-alpha.0.tgz#03072a669c016c616278dc01c577119dd710e4fe" - integrity sha512-D5qOD7YJhHUrPy81C9OpTlVzsXBmZwbF9WdoxYo/M8JYmhTJfj7Fu5dGTyDpipPQVqknFpTsig5kQqG3r08ZZw== - "@cspotcode/source-map-support@^0.8.0": version "0.8.1" resolved "https://registry.yarnpkg.com/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz#00629c35a688e05a88b1cda684fb9d5e73f000a1" @@ -884,18 +826,6 @@ "@jridgewell/resolve-uri" "^3.0.3" "@jridgewell/sourcemap-codec" "^1.4.10" -"@koa/router@8.0.8": - version "8.0.8" - resolved "https://registry.yarnpkg.com/@koa/router/-/router-8.0.8.tgz#95f32d11373d03d89dcb63fabe9ac6f471095236" - integrity sha512-FnT93N4NUehnXr+juupDmG2yfi0JnWdCmNEuIXpCG4TtG+9xvtrLambBH3RclycopVUOEYAim2lydiNBI7IRVg== - dependencies: - debug "^4.1.1" - http-errors "^1.7.3" - koa-compose "^4.1.0" - methods "^1.1.2" - path-to-regexp "1.x" - urijs "^1.19.2" - "@mapbox/node-pre-gyp@^1.0.0": version "1.0.9" resolved "https://registry.yarnpkg.com/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.9.tgz#09a8781a3a036151cdebbe8719d6f8b25d4058bc" @@ -3215,7 +3145,7 @@ http-cookie-agent@^4.0.2: dependencies: agent-base "^6.0.2" -http-errors@^1.6.3, http-errors@^1.7.3, http-errors@~1.8.0: +http-errors@^1.6.3, http-errors@~1.8.0: version "1.8.1" resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.8.1.tgz#7c3f28577cbc8a207388455dbd62295ed07bd68c" integrity sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g== @@ -4005,7 +3935,17 @@ jsonc-parser@^3.2.0: resolved "https://registry.yarnpkg.com/jsonc-parser/-/jsonc-parser-3.2.0.tgz#31ff3f4c2b9793f89c67212627c51c6394f88e76" integrity sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w== -jsonwebtoken@8.5.1, jsonwebtoken@^8.2.0: +jsonwebtoken@9.0.0: + version "9.0.0" + resolved "https://registry.yarnpkg.com/jsonwebtoken/-/jsonwebtoken-9.0.0.tgz#d0faf9ba1cc3a56255fe49c0961a67e520c1926d" + integrity sha512-tuGfYXxkQGDPnLJ7SibiQgVgeDgfbPq2k2ICcbgqW8WxWLBAxKQM/ZCu/IT8SOSwmaYl4dpTFCW5xZv7YbbWUw== + dependencies: + jws "^3.2.2" + lodash "^4.17.21" + ms "^2.1.1" + semver "^7.3.8" + +jsonwebtoken@^8.2.0: version "8.5.1" resolved "https://registry.yarnpkg.com/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz#00e71e0b8df54c2121a1f26137df2280673bcc0d" integrity sha512-XjwVfRS6jTMsqYs0EsuJ4LGxXV14zQybNd4L2r0UvbVnSF9Af8x7p5MzbJ90Ioz/9TI41/hTCvznF/loiSzn8w== @@ -4021,16 +3961,6 @@ jsonwebtoken@8.5.1, jsonwebtoken@^8.2.0: ms "^2.1.1" semver "^5.6.0" -jsonwebtoken@9.0.0: - version "9.0.0" - resolved "https://registry.yarnpkg.com/jsonwebtoken/-/jsonwebtoken-9.0.0.tgz#d0faf9ba1cc3a56255fe49c0961a67e520c1926d" - integrity sha512-tuGfYXxkQGDPnLJ7SibiQgVgeDgfbPq2k2ICcbgqW8WxWLBAxKQM/ZCu/IT8SOSwmaYl4dpTFCW5xZv7YbbWUw== - dependencies: - jws "^3.2.2" - lodash "^4.17.21" - ms "^2.1.1" - semver "^7.3.8" - jsprim@^1.2.2: version "1.4.2" resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.2.tgz#712c65533a15c878ba59e9ed5f0e26d5b77c5feb" @@ -4333,11 +4263,6 @@ lru-cache@^6.0.0: dependencies: yallist "^4.0.0" -lru-cache@^7.14.1: - version "7.14.1" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-7.14.1.tgz#8da8d2f5f59827edb388e63e459ac23d6d408fea" - integrity sha512-ysxwsnTKdAx96aTRdhDOCQfDgbHnt8SK0KY8SEjO0wHinhWOFTESbjVCMPbU1uGXg/ch4lifqx0wfjOawU2+WA== - ltgt@2.2.1, ltgt@^2.1.2, ltgt@~2.2.0: version "2.2.1" resolved "https://registry.yarnpkg.com/ltgt/-/ltgt-2.2.1.tgz#f35ca91c493f7b73da0e07495304f17b31f87ee5" @@ -4580,13 +4505,6 @@ node-fetch@2.6.7, node-fetch@^2.6.7: dependencies: whatwg-url "^5.0.0" -node-fetch@^2.6.1: - 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-gyp-build-optional-packages@5.0.3: version "5.0.3" resolved "https://registry.yarnpkg.com/node-gyp-build-optional-packages/-/node-gyp-build-optional-packages-5.0.3.tgz#92a89d400352c44ad3975010368072b41ad66c17" @@ -4919,13 +4837,6 @@ path-parse@^1.0.7: resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== -path-to-regexp@1.x: - version "1.8.0" - resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-1.8.0.tgz#887b3ba9d84393e87a0a0b9f4cb756198b53548a" - integrity sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA== - dependencies: - isarray "0.0.1" - pause@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/pause/-/pause-0.0.1.tgz#1d408b3fdb76923b9543d96fb4c9dfd535d9cb5d" @@ -6243,11 +6154,6 @@ uri-js@^4.2.2: dependencies: punycode "^2.1.0" -urijs@^1.19.2: - version "1.19.11" - resolved "https://registry.yarnpkg.com/urijs/-/urijs-1.19.11.tgz#204b0d6b605ae80bea54bea39280cdb7c9f923cc" - integrity sha512-HXgFDgDommxn5/bIv0cnQZsPhHDA90NPHD6+c/v21U5+Sx5hoP8+dP9IZXBU1gIfvdRfhG8cel9QNPeionfcCQ== - url-parse-lax@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/url-parse-lax/-/url-parse-lax-3.0.0.tgz#16b5cafc07dbe3676c1b1999177823d6503acb0c" diff --git a/packages/server/src/app.ts b/packages/server/src/app.ts index be0c63f06a..af67f9c3b3 100644 --- a/packages/server/src/app.ts +++ b/packages/server/src/app.ts @@ -20,11 +20,16 @@ import * as automations from "./automations" import { Thread } from "./threads" import * as redis from "./utilities/redis" import { events, logging, middleware } from "@budibase/backend-core" +import { sdk } from "@budibase/pro" import { initialise as initialiseWebsockets } from "./websocket" import { startup } from "./startup" const Sentry = require("@sentry/node") const destroyable = require("server-destroy") +// configure events to use the pro audit log write +// can't integrate directly into backend-core due to cyclic issues +events.configure(sdk.auditLogs.write) + const app = new Koa() let mbNumber = parseInt(env.HTTP_MB_LIMIT || "10") diff --git a/packages/server/yarn.lock b/packages/server/yarn.lock index 7efb1e4672..f79b1d80fe 100644 --- a/packages/server/yarn.lock +++ b/packages/server/yarn.lock @@ -2,11 +2,6 @@ # yarn lockfile v1 -"@adobe/spectrum-css-workflow-icons@1.2.1": - version "1.2.1" - resolved "https://registry.yarnpkg.com/@adobe/spectrum-css-workflow-icons/-/spectrum-css-workflow-icons-1.2.1.tgz#7e2cb3fcfb5c8b12d7275afafbb6ec44913551b4" - integrity sha512-uVgekyBXnOVkxp+CUssjN/gefARtudZC8duEn1vm0lBQFwGRZFlDEzU1QC+aIRWCrD1Z8OgRpmBYlSZ7QS003w== - "@adobe/spectrum-css-workflow-icons@^1.2.1": version "1.5.3" resolved "https://registry.yarnpkg.com/@adobe/spectrum-css-workflow-icons/-/spectrum-css-workflow-icons-1.5.3.tgz#5e31ce842b7626f4b99f9d5cd0b17599d287b0bf" @@ -1322,60 +1317,6 @@ uuid "8.3.2" zlib "1.0.5" -"@budibase/bbui@2.3.14-alpha.0": - version "2.3.14-alpha.0" - resolved "https://registry.yarnpkg.com/@budibase/bbui/-/bbui-2.3.14-alpha.0.tgz#b27a689e221ff94ebf502b9b3c93a20cd327dab4" - integrity sha512-IGO+AsC5tizGUAl+PQrXac9LdSlLDoenADIbxwTZ4Rcr7insPPvH2Xfq0KRHiJCEp9xcHlpkp5ta8ND1uVp1nw== - dependencies: - "@adobe/spectrum-css-workflow-icons" "1.2.1" - "@budibase/string-templates" "2.3.14-alpha.0" - "@spectrum-css/accordion" "3.0.24" - "@spectrum-css/actionbutton" "1.0.1" - "@spectrum-css/actiongroup" "1.0.1" - "@spectrum-css/avatar" "3.0.2" - "@spectrum-css/button" "3.0.1" - "@spectrum-css/buttongroup" "3.0.2" - "@spectrum-css/checkbox" "3.0.2" - "@spectrum-css/dialog" "3.0.1" - "@spectrum-css/divider" "1.0.3" - "@spectrum-css/dropzone" "3.0.2" - "@spectrum-css/fieldgroup" "3.0.2" - "@spectrum-css/fieldlabel" "3.0.1" - "@spectrum-css/icon" "3.0.1" - "@spectrum-css/illustratedmessage" "3.0.2" - "@spectrum-css/inlinealert" "2.0.1" - "@spectrum-css/inputgroup" "3.0.2" - "@spectrum-css/label" "2.0.10" - "@spectrum-css/link" "3.1.1" - "@spectrum-css/menu" "3.0.1" - "@spectrum-css/modal" "3.0.1" - "@spectrum-css/pagination" "3.0.3" - "@spectrum-css/picker" "1.0.1" - "@spectrum-css/popover" "3.0.1" - "@spectrum-css/progressbar" "1.0.2" - "@spectrum-css/progresscircle" "1.0.2" - "@spectrum-css/radio" "3.0.2" - "@spectrum-css/search" "3.0.2" - "@spectrum-css/sidenav" "3.0.2" - "@spectrum-css/slider" "3.0.1" - "@spectrum-css/statuslight" "3.0.2" - "@spectrum-css/stepper" "3.0.3" - "@spectrum-css/switch" "1.0.2" - "@spectrum-css/table" "3.0.1" - "@spectrum-css/tabs" "3.2.12" - "@spectrum-css/tags" "3.0.2" - "@spectrum-css/textfield" "3.0.1" - "@spectrum-css/toast" "3.0.1" - "@spectrum-css/tooltip" "3.0.3" - "@spectrum-css/treeview" "3.0.2" - "@spectrum-css/typography" "3.0.1" - "@spectrum-css/underlay" "2.0.9" - "@spectrum-css/vars" "3.0.1" - dayjs "^1.10.4" - easymde "^2.16.1" - svelte-flatpickr "^3.2.3" - svelte-portal "^1.0.0" - "@budibase/bbui@^0.9.139": version "0.9.190" resolved "https://registry.yarnpkg.com/@budibase/bbui/-/bbui-0.9.190.tgz#e1ec400ac90f556bfbc80fc23a04506f1585ea81" @@ -1426,71 +1367,6 @@ svelte-flatpickr "^3.2.3" svelte-portal "^1.0.0" -"@budibase/client@2.3.14-alpha.0": - version "2.3.14-alpha.0" - resolved "https://registry.yarnpkg.com/@budibase/client/-/client-2.3.14-alpha.0.tgz#86fc86e557ab708e160b5c85c8853d11c6ad571f" - integrity sha512-pqPau8P7MG99rilSNh5MjNdNJKSytyr8b83i8vHydAvB++6+ekMwZfRcYrnR2wLXkg6ZztI/CmSkAYU4i1AYtw== - dependencies: - "@budibase/bbui" "2.3.14-alpha.0" - "@budibase/frontend-core" "2.3.14-alpha.0" - "@budibase/string-templates" "2.3.14-alpha.0" - "@spectrum-css/button" "^3.0.3" - "@spectrum-css/card" "^3.0.3" - "@spectrum-css/divider" "^1.0.3" - "@spectrum-css/link" "^3.1.3" - "@spectrum-css/page" "^3.0.1" - "@spectrum-css/tag" "^3.1.4" - "@spectrum-css/typography" "^3.0.2" - "@spectrum-css/vars" "^3.0.1" - apexcharts "^3.22.1" - dayjs "^1.10.5" - downloadjs "1.4.7" - html5-qrcode "^2.2.1" - leaflet "^1.7.1" - regexparam "^1.3.0" - sanitize-html "^2.7.0" - screenfull "^6.0.1" - shortid "^2.2.15" - socket.io-client "^4.5.1" - svelte "^3.49.0" - svelte-apexcharts "^1.0.2" - svelte-flatpickr "^3.1.0" - svelte-spa-router "^3.0.5" - -"@budibase/frontend-core@2.3.14-alpha.0": - version "2.3.14-alpha.0" - resolved "https://registry.yarnpkg.com/@budibase/frontend-core/-/frontend-core-2.3.14-alpha.0.tgz#8c976af3f30feed688f4f36329bd715d5b5825af" - integrity sha512-Jjhy1+oGnyMVoZDnO612Hvvpxe0yBXzvEmhV+o4SN0eMvpZU48NKBU3buG1SvB1D5Y4rCn1FGsCboSTIk9n7rw== - dependencies: - "@budibase/bbui" "2.3.14-alpha.0" - lodash "^4.17.21" - svelte "^3.46.2" - -"@budibase/handlebars-helpers@^0.11.8": - version "0.11.8" - resolved "https://registry.yarnpkg.com/@budibase/handlebars-helpers/-/handlebars-helpers-0.11.8.tgz#6953d29673a8c5c407e096c0a84890465c7ce841" - integrity sha512-ggWJUt0GqsHFAEup5tlWlcrmYML57nKhpNGGLzVsqXVYN8eVmf3xluYmmMe7fDYhQH0leSprrdEXmsdFQF3HAQ== - dependencies: - array-sort "^1.0.0" - define-property "^2.0.2" - extend-shallow "^3.0.2" - for-in "^1.0.2" - get-object "^0.2.0" - get-value "^3.0.1" - handlebars "^4.7.7" - handlebars-utils "^1.0.6" - has-value "^2.0.2" - helper-md "^0.2.2" - html-tag "^2.0.0" - is-even "^1.0.0" - is-glob "^4.0.1" - kind-of "^6.0.3" - micromatch "^3.1.5" - relative "^3.0.2" - striptags "^3.1.1" - to-gfm-code-block "^0.1.1" - year "^0.2.1" - "@budibase/nano@10.1.1": version "10.1.1" resolved "https://registry.yarnpkg.com/@budibase/nano/-/nano-10.1.1.tgz#36ccda4d9bb64b5ee14dd2b27a295b40739b1038" @@ -1548,18 +1424,6 @@ svelte-apexcharts "^1.0.2" svelte-flatpickr "^3.1.0" -"@budibase/string-templates@2.3.14-alpha.0": - version "2.3.14-alpha.0" - resolved "https://registry.yarnpkg.com/@budibase/string-templates/-/string-templates-2.3.14-alpha.0.tgz#a4c2bf4d328e383929699a5f9c70ed718ef4727b" - integrity sha512-Ekza3NntysyEXyAI6ha/SawkueCnHmMvudW5XtfIS2byLMdph0KqBp03MCW/sdkZ2mdkGi2Nwu/3nowOGSJxNw== - dependencies: - "@budibase/handlebars-helpers" "^0.11.8" - dayjs "^1.10.4" - handlebars "^4.7.6" - handlebars-utils "^1.0.6" - lodash "^4.17.20" - vm2 "^3.9.4" - "@budibase/types@2.3.14-alpha.0": version "2.3.14-alpha.0" resolved "https://registry.yarnpkg.com/@budibase/types/-/types-2.3.14-alpha.0.tgz#03072a669c016c616278dc01c577119dd710e4fe" @@ -2772,51 +2636,26 @@ resolved "https://registry.yarnpkg.com/@socket.io/component-emitter/-/component-emitter-3.1.0.tgz#96116f2a912e0c02817345b3c10751069920d553" integrity sha512-+9jVqKhRSpsc591z5vX+X5Yyw+he/HCB4iQ/RYxw35CEPaY1gnsNE43nf9n9AaYjAQrTiI/mOwKUKdUs9vf7Xg== -"@spectrum-css/accordion@3.0.24": - version "3.0.24" - resolved "https://registry.yarnpkg.com/@spectrum-css/accordion/-/accordion-3.0.24.tgz#f89066c120c57b0cfc9aba66d60c39fc1cf69f74" - integrity sha512-jNOmUsxmiT3lRLButnN5KKHM94fd+87fjiF8L0c4uRNgJl6ZsBuxPXrM15lV4y1f8D2IACAw01/ZkGRAeaCOFA== - -"@spectrum-css/actionbutton@1.0.1": - version "1.0.1" - resolved "https://registry.yarnpkg.com/@spectrum-css/actionbutton/-/actionbutton-1.0.1.tgz#9c75da37ea6915919fb574c74bd60dacc03b6577" - integrity sha512-AUqtyNabHF451Aj9i3xz82TxS5Z6k1dttA68/1hMeU9kbPCSS4P6Viw3vaRGs9CSspuR8xnnhDgrq+F+zMy2Hw== - "@spectrum-css/actionbutton@^1.0.1": version "1.1.14" resolved "https://registry.yarnpkg.com/@spectrum-css/actionbutton/-/actionbutton-1.1.14.tgz#4e12eb7f482fb5944c3d97547591964baebeb1d4" integrity sha512-ViBjdWi23J6vIR4t8JTRQ6jY/+KgpZgCALj3otgy495zMNG7jPeN7sKoy6i6JZJcdIRJA4MjOTVvcDOGkYWUZg== -"@spectrum-css/actiongroup@1.0.1": - version "1.0.1" - resolved "https://registry.yarnpkg.com/@spectrum-css/actiongroup/-/actiongroup-1.0.1.tgz#b95b86e7af229e90fe1e70399d8d4b547b4bd31c" - integrity sha512-5Q6uMjzv5BFA2TwGASr/jAtJpTWl26fhWvgGY8kOA0RCSij35l+YJg/FPXf6Nnj2qCOl8DkNycjT9YXJ+bhyVA== - "@spectrum-css/actiongroup@^1.0.1": version "1.0.26" resolved "https://registry.yarnpkg.com/@spectrum-css/actiongroup/-/actiongroup-1.0.26.tgz#181ee059f28b1342389a128c39d20d2e10566aae" integrity sha512-T1IK9a2Gxix9givm+chGvFtZh5oGBZQc/S2UA9F76JZKu45eCkLkvUH6F670XOrBhDGkVfzvN21QnFymSY43ow== -"@spectrum-css/avatar@3.0.2", "@spectrum-css/avatar@^3.0.2": +"@spectrum-css/avatar@^3.0.2": version "3.0.2" resolved "https://registry.yarnpkg.com/@spectrum-css/avatar/-/avatar-3.0.2.tgz#4f1826223eae330e64b6d3cc899e9bc2e98dac95" integrity sha512-wEczvSqxttTWSiL3cOvXV/RmGRwSkw2w6+slcHhnf0kb7ovymMM+9oz8vvEpEsSeo5u598bc+7ktrKFpAd6soQ== -"@spectrum-css/button@3.0.1": - version "3.0.1" - resolved "https://registry.yarnpkg.com/@spectrum-css/button/-/button-3.0.1.tgz#6db8c3e851baecd0f1c2d88fef37d49d01c6e643" - integrity sha512-YXrBtjIYisk4Vaxnp0RiE4gdElQX04P2mc4Pi2GlQ27dJKlHmufYcF+kAqGdtiyK5yjdN/vKRcC8y13aA4rusA== - "@spectrum-css/button@^3.0.1", "@spectrum-css/button@^3.0.3": version "3.0.3" resolved "https://registry.yarnpkg.com/@spectrum-css/button/-/button-3.0.3.tgz#2df1efaab6c7e0b3b06cb4b59e1eae59c7f1fc84" integrity sha512-6CnLPqqtaU/PcSSIGeGRi0iFIIxIUByYLKFO6zn5NEUc12KQ28dJ4PLwB6WBa0L8vRoAGlnWWH2ZZweTijbXgg== -"@spectrum-css/buttongroup@3.0.2": - version "3.0.2" - resolved "https://registry.yarnpkg.com/@spectrum-css/buttongroup/-/buttongroup-3.0.2.tgz#fd3387973ca3131609e32112de42a1c0400a48d8" - integrity sha512-Wu7B4GJ/SAeVHz9SUGAkeIH8pLaZh4t+w2ykSKOPQIRuK2jCBoudkEClVxviNVwqekccf5XLFXg9GpYF1a3Uaw== - "@spectrum-css/buttongroup@^3.0.2": version "3.0.10" resolved "https://registry.yarnpkg.com/@spectrum-css/buttongroup/-/buttongroup-3.0.10.tgz#897ea04b3ffea389fc7fe5bf67a6d1f3454b774d" @@ -2827,33 +2666,16 @@ resolved "https://registry.yarnpkg.com/@spectrum-css/card/-/card-3.0.3.tgz#56b2e2da6b80c1583228baa279de7407383bfb6b" integrity sha512-+oKLUI2a0QmQP9EzySeq/G4FpUkkdaDNbuEbqCj2IkPMc/2v/nwzsPhh1fj2UIghGAiiUwXfPpzax1e8fyhQUg== -"@spectrum-css/checkbox@3.0.2": - version "3.0.2" - resolved "https://registry.yarnpkg.com/@spectrum-css/checkbox/-/checkbox-3.0.2.tgz#53ca2fba0d9faa1fead10e7206eb1f6cdcfd6ddd" - integrity sha512-hPbGcnm7kJvJS4jp/P/bdaZvbyR1eIE9mteuZqcBgdmyp9m/k6+mW5jmsbtqb3Y4mMPWvOJFfz/sIvWJP0F0Zg== - "@spectrum-css/checkbox@^3.0.2": version "3.1.2" resolved "https://registry.yarnpkg.com/@spectrum-css/checkbox/-/checkbox-3.1.2.tgz#88698969091da9b50de781d25839446084b4a5f4" integrity sha512-vIuknIhRF/Xtq6OHjOtlhYt722FPcTLBb7Y7tY0Ho8VEpynj3JrVLP/1YYp/YIrYMpsTugxPmbCrEkikkdL6Mg== -"@spectrum-css/dialog@3.0.1": - version "3.0.1" - resolved "https://registry.yarnpkg.com/@spectrum-css/dialog/-/dialog-3.0.1.tgz#33aae036282159f6aa998848b8c0828640a9620a" - integrity sha512-hUFbRR6RGT63MNuP7wP+k9KU+uRuICsduMihskh700e+jiQ+Gsv53fBFDlB843FoZYlIXzFQXgtjMUC5a4Qibw== - "@spectrum-css/dialog@^3.0.1": version "3.0.12" resolved "https://registry.yarnpkg.com/@spectrum-css/dialog/-/dialog-3.0.12.tgz#fc97e002ca768a3d99dd10cb6a135c2b06052004" integrity sha512-50rbFa+9eUKT+3uYBX7CkmI7SbQ0Z3CAFwjyjai+itYZ8kf/FcHVFwcLjgrry9scUnKhexMs94kkr0gfQpPe8Q== -"@spectrum-css/divider@1.0.3": - version "1.0.3" - resolved "https://registry.yarnpkg.com/@spectrum-css/divider/-/divider-1.0.3.tgz#639e2ebaa0834efa40f42397668bbd5c153ea385" - integrity sha512-Zy4Rn40w8UtzMh3wx/U9+CepSCpm1aOCGftHgWDub0XZuVTzh0c1WwyzTuLCx2Hf21z5VRGNiDh8bGEEzSbtNA== - dependencies: - "@spectrum-css/vars" "^3.0.2" - "@spectrum-css/divider@^1.0.3": version "1.0.26" resolved "https://registry.yarnpkg.com/@spectrum-css/divider/-/divider-1.0.26.tgz#44b610b1b6c747536fca08b3f09286341e18ab29" @@ -2861,106 +2683,56 @@ dependencies: "@spectrum-css/vars" "^8.0.0" -"@spectrum-css/dropzone@3.0.2": - version "3.0.2" - resolved "https://registry.yarnpkg.com/@spectrum-css/dropzone/-/dropzone-3.0.2.tgz#34f137851054442b219fed7f32006b93fc5e0bcf" - integrity sha512-BuBBzm5re6lM0AWgd6V+mI5eEGnnmFEtcFiJBEn9jYNEQYgflFhvnERUt89jMX5WmspiecwI2JBWJFrtFsOzug== - "@spectrum-css/dropzone@^3.0.2": version "3.0.24" resolved "https://registry.yarnpkg.com/@spectrum-css/dropzone/-/dropzone-3.0.24.tgz#edefb3ca5a01705a64d0161a599c59199bab6299" integrity sha512-JY60hUZAAuzS+o2xFOKv0o31cc+5/cjLpTyKEy73oGKsdUXEEMiQtW2PQBCuxh7PNyw29wCULeZ1EW1QdNPyxg== -"@spectrum-css/fieldgroup@3.0.2": - version "3.0.2" - resolved "https://registry.yarnpkg.com/@spectrum-css/fieldgroup/-/fieldgroup-3.0.2.tgz#1c1afd3c444d8650fefac275dc66a7a913933846" - integrity sha512-Vyw0kQJdLW18J6w4H+YAsoLntvkw5rXmW3CH5H3SDTXkBztxtHSSe3e106Nw5MoZxTfHlom6CxbYXYCTjQfqGw== - "@spectrum-css/fieldgroup@^3.0.2": version "3.1.3" resolved "https://registry.yarnpkg.com/@spectrum-css/fieldgroup/-/fieldgroup-3.1.3.tgz#945123da56534f1ff6118a9defd18b8a883e34a8" integrity sha512-HIbB3jweNviWXcADoYQW3hanww9RTUIsBUhe0YxSMXUXnQJc/7nlyeLoTRMr2eEVSCREfRnMot/8bZloW7ctnA== -"@spectrum-css/fieldlabel@3.0.1": - version "3.0.1" - resolved "https://registry.yarnpkg.com/@spectrum-css/fieldlabel/-/fieldlabel-3.0.1.tgz#39f7c0f25cc2ff402afeff005341b0832f7c588c" - integrity sha512-LMfwrwIq8wEEvxFLobdLvXRwKrp8o9Fty4iJ9aYl2Rj1uXkfRd8qLz9HGZjLEE1OuJgoTBgamYABl7EvoA5PLw== - "@spectrum-css/fieldlabel@^3.0.1": version "3.0.3" resolved "https://registry.yarnpkg.com/@spectrum-css/fieldlabel/-/fieldlabel-3.0.3.tgz#f73c04d20734d4718ffb620dc46458904685b449" integrity sha512-nEvIkEXCD5n4fW67Unq6Iu7VXoauEd/JGpfTY02VsC5p4FJLnwKfPDbJUuUsqClAxqw7nAsmXVKtn4zQFf5yPQ== -"@spectrum-css/icon@3.0.1": - version "3.0.1" - resolved "https://registry.yarnpkg.com/@spectrum-css/icon/-/icon-3.0.1.tgz#e300a6fc353c85c6b5d6e7a364408a940c31b177" - integrity sha512-cGFtIrcQ/7tthdkHK1npuEFiCdYVHLqwmLxghUYQw8Tb8KgJaw3OBO1tpjgsUizexNgu26BjVRIbGxNWuBXIHQ== - "@spectrum-css/icon@^3.0.1": version "3.0.22" resolved "https://registry.yarnpkg.com/@spectrum-css/icon/-/icon-3.0.22.tgz#1dd77e2460121951c60c583edb470d0ba52e6822" integrity sha512-ilrPlHDRGzn7kXVVAwUhoSaMfS6sGlb21ix2gn8IRLBAjDOV8BBV1wJJtjGNw+kzCXMhnVnVOekTdht17Oe9bw== -"@spectrum-css/illustratedmessage@3.0.2": - version "3.0.2" - resolved "https://registry.yarnpkg.com/@spectrum-css/illustratedmessage/-/illustratedmessage-3.0.2.tgz#6a480be98b027e050b086e7899e40d87adb0a8c0" - integrity sha512-dqnE8X27bGcO0HN8+dYx8O4o0dNNIAqeivOzDHhe2El+V4dTzMrNIerF6G0NLm3GjVf6XliwmitsZK+K6FmbtA== - "@spectrum-css/illustratedmessage@^3.0.2": version "3.0.17" resolved "https://registry.yarnpkg.com/@spectrum-css/illustratedmessage/-/illustratedmessage-3.0.17.tgz#49cb2549fda97a6812156bfba6ccdd3a18bebd11" integrity sha512-kpDqeq1U+rEjG1XuiXkbGvS71vn6mpFF/hiwCgFJWudVOfypDPQ4KLfYw1ditFSUzMCm5H6U/RqAShAJn8oMWA== -"@spectrum-css/inlinealert@2.0.1": - version "2.0.1" - resolved "https://registry.yarnpkg.com/@spectrum-css/inlinealert/-/inlinealert-2.0.1.tgz#7521f88f6c845806403cc7d925773c7414e204a2" - integrity sha512-Xy5RCOwgurqUXuGQCsEDUduDd5408bmEpmFg+feynG7VFUgLFZWBeylSENB/OqjlFtO76PHXNVdHkhDscPIHTA== - "@spectrum-css/inlinealert@^2.0.1": version "2.0.6" resolved "https://registry.yarnpkg.com/@spectrum-css/inlinealert/-/inlinealert-2.0.6.tgz#4c5e923a1f56a96cc1adb30ef1f06ae04f2c6376" integrity sha512-OpvvoWP02wWyCnF4IgG8SOPkXymovkC9cGtgMS1FdDubnG3tJZB/JeKTsRR9C9Vt3WBaOmISRdSKlZ4lC9CFzA== -"@spectrum-css/inputgroup@3.0.2": - version "3.0.2" - resolved "https://registry.yarnpkg.com/@spectrum-css/inputgroup/-/inputgroup-3.0.2.tgz#f1b13603832cbd22394f3d898af13203961f8691" - integrity sha512-O0G3Lw9gxsh8gTLQWIAKkN1O8cWhjpEUl+oR1PguIKFni72uNr2ikU9piOwy/r0gJG2Q/TVs6hAshoAAkmsSzw== - "@spectrum-css/inputgroup@^3.0.2": version "3.0.8" resolved "https://registry.yarnpkg.com/@spectrum-css/inputgroup/-/inputgroup-3.0.8.tgz#fc23afc8a73c24d17249c9d2337e8b42085b298b" integrity sha512-cmQWzFp0GU+4IMc8SSeVFdmQDlRUdPelXaQdKUR9mZuO2iYettg37s0lfBCeJyYkUNTagz0zP8O7A0iXfmeE6g== -"@spectrum-css/label@2.0.10", "@spectrum-css/label@^2.0.10": +"@spectrum-css/label@^2.0.10": version "2.0.10" resolved "https://registry.yarnpkg.com/@spectrum-css/label/-/label-2.0.10.tgz#2368651d7636a19385b5d300cdf6272db1916001" integrity sha512-xCbtEiQkZIlLdWFikuw7ifDCC21DOC/KMgVrrVJHXFc4KRQe9LTZSqmGF3tovm+CSq1adE59mYoTbojVQ9YuEQ== -"@spectrum-css/link@3.1.1": - version "3.1.1" - resolved "https://registry.yarnpkg.com/@spectrum-css/link/-/link-3.1.1.tgz#cb526a2e10b50ef5a7ae29cca7272e2610d597eb" - integrity sha512-Bi88lRhTY7g6nM/ryW1yY4Cji211ZYNtRxkxbV7n2lPvwMAAQtyx0qVD3ru4kTGj/FFVvmPR3XiOE10K13HSNA== - "@spectrum-css/link@^3.1.1", "@spectrum-css/link@^3.1.3": version "3.1.22" resolved "https://registry.yarnpkg.com/@spectrum-css/link/-/link-3.1.22.tgz#1e061d674789c5b3be5b0680f9f6eae3e695e1c1" integrity sha512-Zf8bfy+rtq07l4qoR6chNxefmatLZQZjudIm96v+lsCXBkjVbiMpjkW9oOcNwTqKB08koMONHHhOf1wk2Faqiw== -"@spectrum-css/menu@3.0.1": - version "3.0.1" - resolved "https://registry.yarnpkg.com/@spectrum-css/menu/-/menu-3.0.1.tgz#2a376f991acc24e12ec892bb6b9db2650fc41fbe" - integrity sha512-Qjg0+1O0eC89sb/bRFq2AGnQ8XqhVy23TUXHyffNM8qdcMssnlny3QmhzjURCZKvx/Y5UytCpzhedPQqSpQwZg== - "@spectrum-css/menu@^3.0.1": version "3.0.21" resolved "https://registry.yarnpkg.com/@spectrum-css/menu/-/menu-3.0.21.tgz#d1f7e6e69d30b5e1edd7ed2c86ea4e08dfd670ab" integrity sha512-G5AIUO26O6IAc6HUGZu4AZgyw0QRyLfSbcKlFGu4oJHzP36cQc1S1uCh8Xp4g5d+n6mU62LxNDLSMpVbwnA00A== -"@spectrum-css/modal@3.0.1": - version "3.0.1" - resolved "https://registry.yarnpkg.com/@spectrum-css/modal/-/modal-3.0.1.tgz#613a6b83d0330a4d38db41a98090800751c56d8d" - integrity sha512-F7D99F3cjDGT9DM9sogx/p49jrNYT7a1J6TUoqV73wUf+0gP+dTsskBOo9jB8VbUE+POQPjiDLB+SWLp6iBB+w== - "@spectrum-css/modal@^3.0.1": version "3.0.22" resolved "https://registry.yarnpkg.com/@spectrum-css/modal/-/modal-3.0.22.tgz#05593a613e246a7cbef85d08a6945219e1207209" @@ -2973,222 +2745,107 @@ dependencies: "@spectrum-css/vars" "^4.3.1" -"@spectrum-css/pagination@3.0.3": - version "3.0.3" - resolved "https://registry.yarnpkg.com/@spectrum-css/pagination/-/pagination-3.0.3.tgz#b204c3ada384c4af751a354bc428346d82eeea65" - integrity sha512-OJ/v9GeNXJOZ9Yr9LDBYPrR2NCiLOWP9wANT/a5sqFuugRnQbn/HYMnRp9TBxwpDY6ihaPo0T/wi7kLiAJFdDw== - "@spectrum-css/pagination@^3.0.3": version "3.0.11" resolved "https://registry.yarnpkg.com/@spectrum-css/pagination/-/pagination-3.0.11.tgz#68d9f34fe8eb36bf922e41b11f49eac62ac2fc41" integrity sha512-wjZr7NAcqHK6fxNIGKTYEVtAOJugJTbcz4d8K7DZuUDgBVwLJJHJBi4uJ4KrIRYliMWOvqWTZzCJLmmTfx4cyw== -"@spectrum-css/picker@1.0.1": - version "1.0.1" - resolved "https://registry.yarnpkg.com/@spectrum-css/picker/-/picker-1.0.1.tgz#98991198576d26bd14160824e7b6f3c278ff930b" - integrity sha512-Rv4/UBOdNW1gs7WVBCJnPD5VFly8MqP++psDX6kcugUIcfJy0GC3acvElotmKRlCDk8Qxks2W2A0jKeSgphTmA== - "@spectrum-css/picker@^1.0.1": version "1.2.9" resolved "https://registry.yarnpkg.com/@spectrum-css/picker/-/picker-1.2.9.tgz#854cdca407daaf8e1f821777978690f0804b3c08" integrity sha512-HDUDiqHwM84xfbHJWm4wR67Km3NXcDluhDrkVn8uqOEZrm8y4YiW+esL6FzPgzqLdPIHboQjrdpRq4LiDzGjjA== -"@spectrum-css/popover@3.0.1": - version "3.0.1" - resolved "https://registry.yarnpkg.com/@spectrum-css/popover/-/popover-3.0.1.tgz#5863c1efc53f98f9aba2de9186666780041303fc" - integrity sha512-LmOSj/yCwQQ9iGmCYnHiJsJR/HfPiGqI1Jl7pkKxBOCxYBMS/5+ans9vfCN2Qnd0eK7WSbfPg72S6mjye7db2Q== - "@spectrum-css/popover@^3.0.1": version "3.0.11" resolved "https://registry.yarnpkg.com/@spectrum-css/popover/-/popover-3.0.11.tgz#a7450c01bcf1609264b4a9df58821368b9e224d1" integrity sha512-bzyNQJVw6Mn1EBelTaRlXCdd0ZfykNX9O6SHx3a+jXPYu8VBrRpHm0gsfWzPAz1etd1vj1CxwG/teQt4qvyZ/Q== -"@spectrum-css/progressbar@1.0.2": - version "1.0.2" - resolved "https://registry.yarnpkg.com/@spectrum-css/progressbar/-/progressbar-1.0.2.tgz#b5a59432517f9ae6dad49d9504691bc5ac42b424" - integrity sha512-+jExeBLtVCqo3BqtFq5WCtZ028Dzk+oUnX6y4z6ZamKPqOyOELOtFnhYnyhyRndQOqYwKUTXx9zsaWA/lpJOHw== - "@spectrum-css/progressbar@^1.0.2": version "1.0.30" resolved "https://registry.yarnpkg.com/@spectrum-css/progressbar/-/progressbar-1.0.30.tgz#1f1e81ab6080fb843831421f736ed2bccc9b18ed" integrity sha512-tUquDN33RQG8gyrWmwPaCu6I2rxRyv5BBGBPii+1sK7L/DTCJrKXe7TAqoxjNEYzdCvTF/HI1NvnSColWNq0Rw== -"@spectrum-css/progresscircle@1.0.2": - version "1.0.2" - resolved "https://registry.yarnpkg.com/@spectrum-css/progresscircle/-/progresscircle-1.0.2.tgz#258ea9170fb70f795edda03e38a61d93bef4487c" - integrity sha512-JLULpyzjIY95lzlWR1yE1gv4l1K6p+scQ+edmuZZUHBzwM3pUtkvHJmUlA9TYdResUYW6Uka60VRdY6lZ8gnFQ== - "@spectrum-css/progresscircle@^1.0.2": version "1.0.22" resolved "https://registry.yarnpkg.com/@spectrum-css/progresscircle/-/progresscircle-1.0.22.tgz#80c8fd2ac4ee6855297d98c60c3b36082020a32a" integrity sha512-EGb+q+7RxbbsrEPFpJ1P4XBQ4s6Ra0okjQCDDTTKTp/sUY2WIT2BjPzwxlZTxVmSXWiiuRyzyuSYUrgBw9UgWg== -"@spectrum-css/radio@3.0.2": - version "3.0.2" - resolved "https://registry.yarnpkg.com/@spectrum-css/radio/-/radio-3.0.2.tgz#9c1386894920bbed604e4e174fbbd45d9d762152" - integrity sha512-0TDdzC9omNXnpKHEXNuuGeXdNh4x8jvTKVUqMRLb7vY4hY94hAdt6X01NBqka+jzK35HxGzpDdPADAz62yZLPQ== - "@spectrum-css/radio@^3.0.2": version "3.0.23" resolved "https://registry.yarnpkg.com/@spectrum-css/radio/-/radio-3.0.23.tgz#118a28c407e7b58bec139483d7e23074d840ae77" integrity sha512-x+08GSufmsyrUU4iBOOMRXZrcHxabXMMm/q2vazDJE8CShztvmdjghCxcwtyM74sjiYmXnCW1V3ztr6zaG5xig== -"@spectrum-css/search@3.0.2": - version "3.0.2" - resolved "https://registry.yarnpkg.com/@spectrum-css/search/-/search-3.0.2.tgz#70e93e321032d40b399498b2324e3b70e050551e" - integrity sha512-3UbT8yZmNOwrZxq+CUmumE+26ZySZ8OoKNM6U20SLMPLgdx6MrRugVE88r3Bl0sJ0RZX/5bU8nausdiHeX+Jlw== - "@spectrum-css/search@^3.0.2": version "3.1.2" resolved "https://registry.yarnpkg.com/@spectrum-css/search/-/search-3.1.2.tgz#8d43f35f884f7c190e7694c8d26a3f2cfed01ef0" integrity sha512-8cMK1QB07dbReZ/ECyTyoT2dELZ7hK1b3jEDiWSeLBbXcKirR1OI24sZEnewQY/XWFd/62Z1YdNaaA8S6UuXWQ== -"@spectrum-css/sidenav@3.0.2": - version "3.0.2" - resolved "https://registry.yarnpkg.com/@spectrum-css/sidenav/-/sidenav-3.0.2.tgz#9d70f408d588ee79c69857751010333671f32713" - integrity sha512-YpIdH/F0jEICYmoduGrnkTmxwJq1kfKxEp0wOs+ZkQOsvKMv1an7nyhsfOKCQqcGNfYzJ9mJAk7/u5+vsxHa8g== - "@spectrum-css/sidenav@^3.0.2": version "3.0.23" resolved "https://registry.yarnpkg.com/@spectrum-css/sidenav/-/sidenav-3.0.23.tgz#c218560d472e13a3e0d1499b762df1206dcffbfd" integrity sha512-4IFw2/HMQJRzM0M2c5na/HeY7y5vJoGpMFBkXNpQyhW4TRo7N1rGwYQ5dRD3s4OVEWV4/rjfGV0d/qhfwKUTog== -"@spectrum-css/slider@3.0.1": - version "3.0.1" - resolved "https://registry.yarnpkg.com/@spectrum-css/slider/-/slider-3.0.1.tgz#5281e6f47eb5a4fd3d1816c138bf66d01d7f2e49" - integrity sha512-DI2dtMRnQuDM1miVzl3SGyR1khUEKnwdXfO5EHDFwkC3yav43F5QogkfjmjFmWWobMVovdJlAuiaaJ/IHejD0Q== - -"@spectrum-css/statuslight@3.0.2": - version "3.0.2" - resolved "https://registry.yarnpkg.com/@spectrum-css/statuslight/-/statuslight-3.0.2.tgz#dc54b6cd113413dcdb909c486b5d7bae60db65c5" - integrity sha512-xodB8g8vGJH20XmUj9ZsPlM1jHrGeRbvmVXkz0q7YvQrYAhim8pP3W+XKKZAletPFAuu8cmUOc6SWn6i4X4z6w== - "@spectrum-css/statuslight@^3.0.2": version "3.0.8" resolved "https://registry.yarnpkg.com/@spectrum-css/statuslight/-/statuslight-3.0.8.tgz#3b0ea80712573679870a85d469850230e794a0f7" integrity sha512-zMTHs8lk+I7fLdi9waEEbsCmJ1FxeHcjQ0yltWxuRmGk2vl4MQdQIuHIMI63iblqEaiwnJRjXJoKnWlNvndTJQ== -"@spectrum-css/stepper@3.0.3": - version "3.0.3" - resolved "https://registry.yarnpkg.com/@spectrum-css/stepper/-/stepper-3.0.3.tgz#ae89846886431e3edeee060207b8f81540f73a34" - integrity sha512-prAD61ImlOTs9b6PfB3cB08x4lAfxtvnW+RZiTYky0E8GgZdrc/MfCkL5/oqQaIQUtyQv/3Lb7ELAf/0K8QTXw== - "@spectrum-css/stepper@^3.0.3": version "3.0.25" resolved "https://registry.yarnpkg.com/@spectrum-css/stepper/-/stepper-3.0.25.tgz#a6e77d501a9671c083b6dd9a37c6a3f224ffc961" integrity sha512-nlAZKY4KCYQ4IFuFj/P0LXPsB4Ze36ziuaa3k3iy3+1pBDD4gDcGmNpNcTG1LENu0Bt87KhSj8Ba2NV3wBSY8w== -"@spectrum-css/switch@1.0.2": - version "1.0.2" - resolved "https://registry.yarnpkg.com/@spectrum-css/switch/-/switch-1.0.2.tgz#f0b4c69271964573e02b08e90998096e49e1de44" - integrity sha512-zqmHpgWPNg1gEwdUNFYV3CBX5JaeALfIqcJIxE0FLZqr9d1C4+oLE0ItIFzt1bwr4bFAOmkEpvtiY+amluzGxQ== - "@spectrum-css/switch@^1.0.2": version "1.0.22" resolved "https://registry.yarnpkg.com/@spectrum-css/switch/-/switch-1.0.22.tgz#8f2fe25a52b4511b9cfde7af45f9bd824b9774d7" integrity sha512-/Q8IxnkSQYo+i3G3BObslSvoKgM0Mm1mS7kmssULOtaQPbaRlRsUNQVaHzcNEX33+fiF/9zKSvs7ypgIvbWp+Q== -"@spectrum-css/table@3.0.1": - version "3.0.1" - resolved "https://registry.yarnpkg.com/@spectrum-css/table/-/table-3.0.1.tgz#753e0e2498082c0c36b9600828516aff3ac338cd" - integrity sha512-XQ+srMTv9hK1H0nctWUtqyzitmvyb5TNR+7mjAmKRdkBRSTQQSipDhenxZp72ekzMtMoSYZVZ77kgo0Iw3Fpug== - "@spectrum-css/table@^3.0.1": version "3.0.3" resolved "https://registry.yarnpkg.com/@spectrum-css/table/-/table-3.0.3.tgz#7f7f19905ef3275cbf907ce3a5818e63c30b2caf" integrity sha512-nxwzVjLPsXoY/v4sdxOVYLcC+cEbGgJyLcLclT5LT9MGSbngFeUMJzzVR4EvehzuN4dH7hrATG7Mbuq29Mf0Hg== -"@spectrum-css/tabs@3.2.12": - version "3.2.12" - resolved "https://registry.yarnpkg.com/@spectrum-css/tabs/-/tabs-3.2.12.tgz#9b08f23d5aa881b3441af7757800c7173e5685ff" - integrity sha512-rPFUW9SSW4+3/UJ3UrtY2/l3sQvlqB1fqxHLPDjgykvbfrnMejcCTNV4ZrFNHXpE/6+kGnk+yVViSPtWGwJzkA== - "@spectrum-css/tabs@^3.0.1": version "3.2.16" resolved "https://registry.yarnpkg.com/@spectrum-css/tabs/-/tabs-3.2.16.tgz#c3f7800d8d6f7c9930c28cd01354816328bf72b1" integrity sha512-JUcMB/fiDG/KoyrVstlUMacFJUY4OHKqhMRuPtu9ggUXWCRbSkY8he92v6u0HwY3DuhDoOxNTK8d/PLjk/fsbg== -"@spectrum-css/tag@^3.1.4": - version "3.3.15" - resolved "https://registry.yarnpkg.com/@spectrum-css/tag/-/tag-3.3.15.tgz#971184fd8cb977b85a529f808313851863123278" - integrity sha512-pF6Wh61Z7hmAy20twIlpjdDuivYj6UPtWIzK7giyJKr/qcn20BjVN2ChIeFB1N+vBamJdLsuQOewv4AJ3+LZ2Q== - -"@spectrum-css/tags@3.0.2": - version "3.0.2" - resolved "https://registry.yarnpkg.com/@spectrum-css/tags/-/tags-3.0.2.tgz#5bf35fb79c97cd9344de485bd4626ad5b9f07757" - integrity sha512-HbvMk+QHvCDD1/ScvSErpKROcpAbXuMD4Hl/Gz/1A1lQ0fJ/CJeCq/MMsL7zjK1nlItU/ySu8r8KIuRF+6F8SQ== - "@spectrum-css/tags@^3.0.2": version "3.0.3" resolved "https://registry.yarnpkg.com/@spectrum-css/tags/-/tags-3.0.3.tgz#fc76d2735cdc442de91b7eb3bee49a928c0767ac" integrity sha512-SL8vPxVDfWcY5VdIuyl0TImEXcOU1I7yCyXkk7MudMwfnYs81FaIyY32hFV9OHj0Tz/36UzRzc7AVMSuRQ53pw== -"@spectrum-css/textfield@3.0.1": - version "3.0.1" - resolved "https://registry.yarnpkg.com/@spectrum-css/textfield/-/textfield-3.0.1.tgz#e875b8e37817378ad08fc4af7d53026df38911e5" - integrity sha512-MUV5q87CVxbkNdSNoxGrFbgyKc51ft/WWf3aVEoPdPw5yBnXqFe1w1YmAit5zYDOOhhs58sCLAlUcCMlOpkgrA== - "@spectrum-css/textfield@^3.0.1": version "3.2.3" resolved "https://registry.yarnpkg.com/@spectrum-css/textfield/-/textfield-3.2.3.tgz#52830498fb3b8957f84bb9bf2cafec7edc55e490" integrity sha512-mtxSQe8VZjQ8PHKlUE03dATAjjxp2Y8XfYmWWFBWWZLeqaojSLv9Q8C/ouK5AenhzCaYpJxTotMjAoivwtmUSw== -"@spectrum-css/toast@3.0.1": - version "3.0.1" - resolved "https://registry.yarnpkg.com/@spectrum-css/toast/-/toast-3.0.1.tgz#36f62ea05302761e59b9d53e05f6c04423861796" - integrity sha512-jov++S358BrN2tmMfaoYk1N6u9HojgeuQk61keXrK2m3VE5/n94x7Lg3kIPeSWO0odyDfBlMqT9jacbRey3QTg== - "@spectrum-css/toast@^3.0.1": version "3.0.3" resolved "https://registry.yarnpkg.com/@spectrum-css/toast/-/toast-3.0.3.tgz#97c1527384707600832ecda35643ed304615250f" integrity sha512-CjLeaMs+cjUXojCCRtbj0YkD2BoZW16kjj2o5omkEpUTjA34IJ8xJ1a+CCtDILWekhXvN0MBN4sbumcnwcnx8w== -"@spectrum-css/tooltip@3.0.3": - version "3.0.3" - resolved "https://registry.yarnpkg.com/@spectrum-css/tooltip/-/tooltip-3.0.3.tgz#26b8ca3b3d30e29630244d85eb4fc11d0c841281" - integrity sha512-ztRF7WW1FzyNavXBRc+80z67UoOrY9wl3cMYsVD3MpDnyxdzP8cjza1pCcolKBaFqRTcQKkxKw3GWtGICRKR5A== - "@spectrum-css/tooltip@^3.0.3": version "3.1.17" resolved "https://registry.yarnpkg.com/@spectrum-css/tooltip/-/tooltip-3.1.17.tgz#1f0822c8b69d16d5f940a2b7eb6514d719e6a0fd" integrity sha512-YDuC+Cc6B8DExjL/7fkPnWb8QwlCkjuMHyuttwP/tq/lryWnrdntojgwK5KvgFRjnZ2WfepZVryIt5LOD3tMdg== -"@spectrum-css/treeview@3.0.2": - version "3.0.2" - resolved "https://registry.yarnpkg.com/@spectrum-css/treeview/-/treeview-3.0.2.tgz#d54d8f17290babb1c885f5d9355e225421beb0d2" - integrity sha512-foO7UBJv1JMFaKgDPVt8jBghZSVbqhXR8TaGaxHSnMubv7ygmKkc1AITrWC2STILCn84ju2vchOohMZfW6sYwg== - "@spectrum-css/treeview@^3.0.2": version "3.0.3" resolved "https://registry.yarnpkg.com/@spectrum-css/treeview/-/treeview-3.0.3.tgz#aeda5175158b9f8d7529cb2b394428eb2a428046" integrity sha512-D5gGzZC/KtRArdx86Mesc9+99W9nTbUOeyYGqoJoAfJSOttoT6Tk5CrDvlCmAqjKf5rajemAkGri1ChqvUIwkw== -"@spectrum-css/typography@3.0.1": - version "3.0.1" - resolved "https://registry.yarnpkg.com/@spectrum-css/typography/-/typography-3.0.1.tgz#957dafd9b18c314fa37a88b549042ba2175f5b3f" - integrity sha512-XyR68K2rIZX3u4j7HhMLOqLVHDJZcapp3XUqgYMzMWccBFleA0qPxKpfRWqVIA5DzTMSIw0wEcZPYKWFZ2e6dA== - "@spectrum-css/typography@^3.0.1", "@spectrum-css/typography@^3.0.2": version "3.0.2" resolved "https://registry.yarnpkg.com/@spectrum-css/typography/-/typography-3.0.2.tgz#ea3ca0a60e18064527819d48c8c4364cab4fcd38" integrity sha512-5ZOLmQe0edzsDMyhghUd4hBb5uxGsFrxzf+WasfcUw9klSfTsRZ09n1BsaaWbgrLjlMQ+EEHS46v5VNo0Ms2CA== -"@spectrum-css/underlay@2.0.9": - version "2.0.9" - resolved "https://registry.yarnpkg.com/@spectrum-css/underlay/-/underlay-2.0.9.tgz#fc10f971d1325cc844b727e6260f7217844060e8" - integrity sha512-X86xd0PG4QobmUyXA90BFGnyygaI8kW64dA4ysf4z0cOvUWjNbAAl3a/DB/WRyrnp63Zqv83T/cgNbetagTbWg== - "@spectrum-css/underlay@^2.0.9": version "2.0.30" resolved "https://registry.yarnpkg.com/@spectrum-css/underlay/-/underlay-2.0.30.tgz#401cfd68df945692bd6bbe281fee98889c930dd1" integrity sha512-Ssq/KERbDuJu3PUWPkBv9+ZIbKooke3oncRoYMXeyP/Gcw5bmQSXOvnlddU5DIK4PJR+pPGVZ9CUUFaYZot4YQ== -"@spectrum-css/vars@3.0.1": - version "3.0.1" - resolved "https://registry.yarnpkg.com/@spectrum-css/vars/-/vars-3.0.1.tgz#561fd69098f896a647242dd8d6108af603bfa31e" - integrity sha512-l4oRcCOqInChYXZN6OQhpe3isk6l4OE6Ys8cgdlsiKp53suNoQxyyd9p/eGRbCjZgH3xQ8nK0t4DHa7QYC0S6w== - -"@spectrum-css/vars@^3.0.1", "@spectrum-css/vars@^3.0.2": +"@spectrum-css/vars@^3.0.1": version "3.0.2" resolved "https://registry.yarnpkg.com/@spectrum-css/vars/-/vars-3.0.2.tgz#ea9062c3c98dfc6ba59e5df14a03025ad8969999" integrity sha512-vzS9KqYXot4J3AEER/u618MXWAS+IoMvYMNrOoscKiLLKYQWenaueakUWulFonToPd/9vIpqtdbwxznqrK5qDw== @@ -3400,13 +3057,6 @@ resolved "https://registry.yarnpkg.com/@types/caseless/-/caseless-0.12.2.tgz#f65d3d6389e01eeb458bd54dc8f52b95a9463bc8" integrity sha512-6ckxMjBBD8URvjB6J3NcnuAn5Pkl7t3TizAg+xdlzzQGSPSmBcXf8KoIH0ua/i+tio+ZRUHEXp0HEmvaR4kt0w== -"@types/codemirror@^5.60.4": - version "5.60.7" - resolved "https://registry.yarnpkg.com/@types/codemirror/-/codemirror-5.60.7.tgz#efbb78e5e79f90c6762c2127c02096648e600808" - integrity sha512-QXIC+RPzt/1BGSuD6iFn6UMC9TDp+9hkOANYNPVsjjrDdzKphfRkwQDKGp2YaC54Yhz0g6P5uYTCCibZZEiMAA== - dependencies: - "@types/tern" "*" - "@types/connect@*": version "3.4.35" resolved "https://registry.yarnpkg.com/@types/connect/-/connect-3.4.35.tgz#5fcf6ae445e4021d1fc2219a4873cc73a3bb2ad1" @@ -3622,11 +3272,6 @@ resolved "https://registry.yarnpkg.com/@types/long/-/long-4.0.2.tgz#b74129719fc8d11c01868010082d483b7545591a" integrity sha512-MqTGEo5bj5t157U6fA/BiDynNkn0YknVdh48CMPkTSpFTVmvao5UQmm7uEF6xBEo7qIMAlY/JSleYaE6VOdpaA== -"@types/marked@^4.0.7": - version "4.0.8" - resolved "https://registry.yarnpkg.com/@types/marked/-/marked-4.0.8.tgz#b316887ab3499d0a8f4c70b7bd8508f92d477955" - integrity sha512-HVNzMT5QlWCOdeuBsgXP8EZzKUf0+AXzN+sLmjvaB3ZlLqO+e4u0uXrdw9ub69wBKFs+c6/pA4r9sy6cCDvImw== - "@types/mime@^1": version "1.3.2" resolved "https://registry.yarnpkg.com/@types/mime/-/mime-1.3.2.tgz#93e25bf9ee75fe0fd80b594bc4feb0e862111b5a" @@ -3933,13 +3578,6 @@ "@types/node" "*" minipass "^3.3.5" -"@types/tern@*": - version "0.23.4" - resolved "https://registry.yarnpkg.com/@types/tern/-/tern-0.23.4.tgz#03926eb13dbeaf3ae0d390caf706b2643a0127fb" - integrity sha512-JAUw1iXGO1qaWwEOzxTKJZ/5JxVeON9kvGZ/osgZaJImBnyjyn0cjovPsf6FNLmyGY8Vw9DoXZCMlfMkMwHRWg== - dependencies: - "@types/estree" "*" - "@types/tough-cookie@*", "@types/tough-cookie@^4.0.2": version "4.0.2" resolved "https://registry.yarnpkg.com/@types/tough-cookie/-/tough-cookie-4.0.2.tgz#6286b4c7228d58ab7866d19716f3696e03a09397" @@ -4545,7 +4183,7 @@ arg@^4.1.0: resolved "https://registry.yarnpkg.com/arg/-/arg-4.1.3.tgz#269fc7ad5b8e42cb63c896d5666017261c144089" integrity sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA== -argparse@^1.0.10, argparse@^1.0.7: +argparse@^1.0.7: version "1.0.10" resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== @@ -4592,15 +4230,6 @@ array-equal@^1.0.0: resolved "https://registry.yarnpkg.com/array-equal/-/array-equal-1.0.0.tgz#8c2a5ef2472fd9ea742b04c77a75093ba2757c93" integrity sha512-H3LU5RLiSsGXPhN+Nipar0iR0IofH+8r89G2y1tBKxQ/agagKyAjhkAFDRBfodP2caPrNKHpAWNIM/c9yeL7uA== -array-sort@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/array-sort/-/array-sort-1.0.0.tgz#e4c05356453f56f53512a7d1d6123f2c54c0a88a" - integrity sha512-ihLeJkonmdiAsD7vpgN3CRcx2J2S0TiYW+IS/5zHBI7mKUq3ySvBdzzBfD236ubDBQFiiyG3SWCPc+msQ9KoYg== - dependencies: - default-compare "^1.0.0" - get-value "^2.0.6" - kind-of "^5.0.2" - array-union@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d" @@ -4744,13 +4373,6 @@ atomic-sleep@^1.0.0: resolved "https://registry.yarnpkg.com/atomic-sleep/-/atomic-sleep-1.0.0.tgz#eb85b77a601fc932cfe432c5acd364a9e2c9075b" integrity sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ== -autolinker@~0.28.0: - version "0.28.1" - resolved "https://registry.yarnpkg.com/autolinker/-/autolinker-0.28.1.tgz#0652b491881879f0775dace0cdca3233942a4e47" - integrity sha512-zQAFO1Dlsn69eXaO6+7YZc+v84aquQKbwpzCE3L0stj56ERn9hutFxPopViLjo9G+rWwjozRhgS5KJ25Xy19cQ== - dependencies: - gulp-header "^1.7.1" - available-typed-arrays@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz#92f95616501069d07d10edb2fc37d3e1c65123b7" @@ -5681,18 +5303,6 @@ co@^4.6.0: resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" integrity sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ== -codemirror-spell-checker@1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/codemirror-spell-checker/-/codemirror-spell-checker-1.1.2.tgz#1c660f9089483ccb5113b9ba9ca19c3f4993371e" - integrity sha512-2Tl6n0v+GJRsC9K3MLCdLaMOmvWL0uukajNJseorZJsslaxZyZMgENocPU8R0DyoTAiKsyqiemSOZo7kjGV0LQ== - dependencies: - typo-js "*" - -codemirror@^5.63.1: - version "5.65.11" - resolved "https://registry.yarnpkg.com/codemirror/-/codemirror-5.65.11.tgz#c818edc3274788c008f636520c5490a1f7009b4f" - integrity sha512-Gp62g2eKSCHYt10axmGhKq3WoJSvVpvhXmowNq7pZdRVowwtvBR/hi2LSP5srtctKkRT33T6/n8Kv1UGp7JW4A== - collect-v8-coverage@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz#cc2c8e94fc18bbdffe64d6534570c8a673b27f59" @@ -5843,13 +5453,6 @@ concat-map@0.0.1: resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== -concat-with-sourcemaps@*: - version "1.1.0" - resolved "https://registry.yarnpkg.com/concat-with-sourcemaps/-/concat-with-sourcemaps-1.1.0.tgz#d4ea93f05ae25790951b99e7b3b09e3908a4082e" - integrity sha512-4gEjHJFT9e+2W/77h/DS5SGUgwDaOwprX8L/gl5+3ixnzkVJJsZWDSelmN3Oilw3LNDZjZV0yqH1hLG3k6nghg== - dependencies: - source-map "^0.6.1" - condense-newlines@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/condense-newlines/-/condense-newlines-0.2.1.tgz#3de985553139475d32502c83b02f60684d24c55f" @@ -6253,13 +5856,6 @@ deepmerge@^4.2.2: resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.2.2.tgz#44d2ea3679b8f4d4ffba33f03d865fc1e7bf4955" integrity sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg== -default-compare@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/default-compare/-/default-compare-1.0.0.tgz#cb61131844ad84d84788fb68fd01681ca7781a2f" - integrity sha512-QWfXlM0EkAbqOCbD/6HjdwT19j7WCkMyiRhWilc4H9/5h/RzTF9gv5LYh1+CmDV5d1rki6KAWLtQale0xt20eQ== - dependencies: - kind-of "^5.0.2" - default-shell@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/default-shell/-/default-shell-1.0.1.tgz#752304bddc6174f49eb29cb988feea0b8813c8bc" @@ -6456,25 +6052,11 @@ doctrine@3.0.0, doctrine@^3.0.0: dependencies: esutils "^2.0.2" -dom-serializer@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-2.0.0.tgz#e41b802e1eedf9f6cae183ce5e622d789d7d8e53" - integrity sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg== - dependencies: - domelementtype "^2.3.0" - domhandler "^5.0.2" - entities "^4.2.0" - dom-walk@^0.1.0: version "0.1.2" resolved "https://registry.yarnpkg.com/dom-walk/-/dom-walk-0.1.2.tgz#0c548bef048f4d1f2a97249002236060daa3fd84" integrity sha512-6QvTW9mrGeIegrFXdtQi9pk7O/nSK6lSdXW2eqUspN5LWD7UTji2Fqw5V2YLjBpHEoU9Xl/eUWNpDeZvoyOv2w== -domelementtype@^2.3.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-2.3.0.tgz#5c45e8e869952626331d7aab326d01daf65d589d" - integrity sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw== - domexception@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/domexception/-/domexception-1.0.1.tgz#937442644ca6a31261ef36e3ec677fe805582c90" @@ -6482,22 +6064,6 @@ domexception@^1.0.1: dependencies: webidl-conversions "^4.0.2" -domhandler@^5.0.1, domhandler@^5.0.2: - version "5.0.3" - resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-5.0.3.tgz#cc385f7f751f1d1fc650c21374804254538c7d31" - integrity sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w== - dependencies: - domelementtype "^2.3.0" - -domutils@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/domutils/-/domutils-3.0.1.tgz#696b3875238338cb186b6c0612bd4901c89a4f1c" - integrity sha512-z08c1l761iKhDFtfXO04C7kTdPBLi41zwOZl00WS8b5eiaebNpY00HKbztwBq+e3vyqWNwWF3mP9YLUeqIrF+Q== - dependencies: - dom-serializer "^2.0.0" - domelementtype "^2.3.0" - domhandler "^5.0.1" - dot-prop@^5.2.0: version "5.3.0" resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-5.3.0.tgz#90ccce708cd9cd82cc4dc8c3ddd9abdd55b20e88" @@ -6542,11 +6108,6 @@ download@8.0.0: p-event "^2.1.0" pify "^4.0.1" -downloadjs@1.4.7: - version "1.4.7" - resolved "https://registry.yarnpkg.com/downloadjs/-/downloadjs-1.4.7.tgz#f69f96f940e0d0553dac291139865a3cd0101e3c" - integrity sha512-LN1gO7+u9xjU5oEScGFKvXhYf7Y/empUIIEAGBs1LzUq/rg5duiDrkuH5A2lQGd5jfMOb9X9usDa2oVXwJ0U/Q== - duplexer3@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/duplexer3/-/duplexer3-0.1.4.tgz#ee01dd1cac0ed3cbc7fdbea37dc0a8f1ce002ce2" @@ -6562,17 +6123,6 @@ duplexify@^4.0.0: readable-stream "^3.1.1" stream-shift "^1.0.0" -easymde@^2.16.1: - version "2.18.0" - resolved "https://registry.yarnpkg.com/easymde/-/easymde-2.18.0.tgz#ff1397d07329b1a7b9187d2d0c20766fa16b3b1b" - integrity sha512-IxVVUxNWIoXLeqtBU4BLc+eS/ScYhT1Dcb6yF5Wchoj1iXAV+TIIDWx+NCaZhY7RcSHqDPKllbYq7nwGKILnoA== - dependencies: - "@types/codemirror" "^5.60.4" - "@types/marked" "^4.0.7" - codemirror "^5.63.1" - codemirror-spell-checker "1.1.2" - marked "^4.1.0" - ecc-jsbn@~0.1.1: version "0.1.2" resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz#3a83a904e54353287874c564b7549386849a98c9" @@ -6735,17 +6285,6 @@ end-stream@~0.1.0: dependencies: write-stream "~0.4.3" -engine.io-client@~6.4.0: - version "6.4.0" - resolved "https://registry.yarnpkg.com/engine.io-client/-/engine.io-client-6.4.0.tgz#88cd3082609ca86d7d3c12f0e746d12db4f47c91" - integrity sha512-GyKPDyoEha+XZ7iEqam49vz6auPnNJ9ZBfy89f+rMMas8AuiMWOZ9PVzu8xb9ZC6rafUqiGHSCfu22ih66E+1g== - dependencies: - "@socket.io/component-emitter" "~3.1.0" - debug "~4.3.1" - engine.io-parser "~5.0.3" - ws "~8.11.0" - xmlhttprequest-ssl "~2.0.0" - engine.io-parser@~5.0.3: version "5.0.4" resolved "https://registry.yarnpkg.com/engine.io-parser/-/engine.io-parser-5.0.4.tgz#0b13f704fa9271b3ec4f33112410d8f3f41d0fc0" @@ -6775,16 +6314,6 @@ enhanced-resolve@^5.9.3: graceful-fs "^4.2.4" tapable "^2.2.0" -ent@^2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/ent/-/ent-2.2.0.tgz#e964219325a21d05f44466a2f686ed6ce5f5dd1d" - integrity sha512-GHrMyVZQWvTIdDtpiEXdHZnFQKzeO09apj8Cbl4pKWy4i0Oprcq17usfDt5aO63swf0JOeMWjWQE/LzgSRuWpA== - -entities@^4.2.0, entities@^4.3.0: - version "4.4.0" - resolved "https://registry.yarnpkg.com/entities/-/entities-4.4.0.tgz#97bdaba170339446495e653cfd2db78962900174" - integrity sha512-oYp7156SP8LkeGD0GF85ad1X9Ai79WtRsZ2gxJqtBuzH+98YUV6jkHEKlZkMbcrjJjIVJNIDP/3WL9wQkoPbWA== - entities@~2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/entities/-/entities-2.1.0.tgz#992d3129cf7df6870b96c57858c249a120f8b8b5" @@ -7965,14 +7494,6 @@ get-intrinsic@^1.0.2, get-intrinsic@^1.1.0, get-intrinsic@^1.1.1: has "^1.0.3" has-symbols "^1.0.3" -get-object@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/get-object/-/get-object-0.2.0.tgz#d92ff7d5190c64530cda0543dac63a3d47fe8c0c" - integrity sha512-7P6y6k6EzEFmO/XyUyFlXm1YLJy9xeA1x/grNV8276abX5GuwUtYgKFkRFkLixw4hf4Pz9q2vgv/8Ar42R0HuQ== - dependencies: - is-number "^2.0.2" - isobject "^0.2.0" - get-package-type@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/get-package-type/-/get-package-type-0.1.0.tgz#8de2d803cff44df3bc6c456e6668b36c3926e11a" @@ -8035,13 +7556,6 @@ get-value@^2.0.3, get-value@^2.0.6: resolved "https://registry.yarnpkg.com/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28" integrity sha512-Ln0UQDlxH1BapMu3GPtf7CuYNwRZf2gwCuPqbyG6pB8WfmFpzqcy4xtAaAMUhnNqjMKTiCPZG2oMT3YSx8U2NA== -get-value@^3.0.0, get-value@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/get-value/-/get-value-3.0.1.tgz#5efd2a157f1d6a516d7524e124ac52d0a39ef5a8" - integrity sha512-mKZj9JLQrwMBtj5wxi6MH8Z5eSKaERpAwjg43dPtlGI1ZVEgH/qC7T8/6R2OBSUA+zzHBZgICsVJaEIV2tKTDA== - dependencies: - isobject "^3.0.1" - getopts@2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/getopts/-/getopts-2.3.0.tgz#71e5593284807e03e2427449d4f6712a268666f4" @@ -8329,24 +7843,7 @@ gtoken@^5.0.4: google-p12-pem "^3.1.3" jws "^4.0.0" -gulp-header@^1.7.1: - version "1.8.12" - resolved "https://registry.yarnpkg.com/gulp-header/-/gulp-header-1.8.12.tgz#ad306be0066599127281c4f8786660e705080a84" - integrity sha512-lh9HLdb53sC7XIZOYzTXM4lFuXElv3EVkSDhsd7DoJBj7hm+Ni7D3qYbb+Rr8DuM8nRanBvkVO9d7askreXGnQ== - dependencies: - concat-with-sourcemaps "*" - lodash.template "^4.4.0" - through2 "^2.0.0" - -handlebars-utils@^1.0.6: - version "1.0.6" - resolved "https://registry.yarnpkg.com/handlebars-utils/-/handlebars-utils-1.0.6.tgz#cb9db43362479054782d86ffe10f47abc76357f9" - integrity sha512-d5mmoQXdeEqSKMtQQZ9WkiUcO1E3tPbWxluCK9hVgIDPzQa9WsKo3Lbe/sGflTe7TomHEeZaOgwIkyIr1kfzkw== - dependencies: - kind-of "^6.0.0" - typeof-article "^0.1.1" - -handlebars@^4.7.6, handlebars@^4.7.7: +handlebars@^4.7.7: version "4.7.7" resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.7.7.tgz#9ce33416aad02dbd6c8fafa8240d5d98004945a1" integrity sha512-aAcXm5OAfE/8IXkcZvCepKU3VzW1/39Fb5ZuqMtgI/hT8X2YgoMvBY5dLhq/cpOvw7Lk1nK/UF71aLG/ZnVYRA== @@ -8440,14 +7937,6 @@ has-value@^1.0.0: has-values "^1.0.0" isobject "^3.0.0" -has-value@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/has-value/-/has-value-2.0.2.tgz#d0f12e8780ba8e90e66ad1a21c707fdb67c25658" - integrity sha512-ybKOlcRsK2MqrM3Hmz/lQxXHZ6ejzSPzpNabKB45jb5qDgJvKPa3SdapTsTLwEb9WltgWpOmNax7i+DzNOk4TA== - dependencies: - get-value "^3.0.0" - has-values "^2.0.1" - has-values@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/has-values/-/has-values-0.1.4.tgz#6d61de95d91dfca9b9a02089ad384bff8f62b771" @@ -8461,13 +7950,6 @@ has-values@^1.0.0: is-number "^3.0.0" kind-of "^4.0.0" -has-values@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/has-values/-/has-values-2.0.1.tgz#3876200ff86d8a8546a9264a952c17d5fc17579d" - integrity sha512-+QdH3jOmq9P8GfdjFg0eJudqx1FqU62NQJ4P16rOEHeRdl7ckgwn6uqQjzYE0ZoHVV/e5E2esuJ5Gl5+HUW19w== - dependencies: - kind-of "^6.0.2" - has-yarn@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/has-yarn/-/has-yarn-2.1.0.tgz#137e11354a7b5bf11aa5cb649cf0c6f3ff2b2e77" @@ -8480,16 +7962,6 @@ has@^1.0.3: dependencies: function-bind "^1.1.1" -helper-md@^0.2.2: - version "0.2.2" - resolved "https://registry.yarnpkg.com/helper-md/-/helper-md-0.2.2.tgz#c1f59d7e55bbae23362fd8a0e971607aec69d41f" - integrity sha512-49TaQzK+Ic7ZVTq4i1UZxRUJEmAilTk8hz7q4I0WNUaTclLR8ArJV5B3A1fe1xF2HtsDTr2gYKLaVTof/Lt84Q== - dependencies: - ent "^2.2.0" - extend-shallow "^2.0.1" - fs-exists-sync "^0.1.0" - remarkable "^1.6.2" - homedir-polyfill@^1.0.0, homedir-polyfill@^1.0.1: version "1.0.3" resolved "https://registry.yarnpkg.com/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz#743298cef4e5af3e194161fbadcc2151d3a058e8" @@ -8519,29 +7991,6 @@ html-escaper@^2.0.0: resolved "https://registry.yarnpkg.com/html-escaper/-/html-escaper-2.0.2.tgz#dfd60027da36a36dfcbe236262c00a5822681453" integrity sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg== -html-tag@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/html-tag/-/html-tag-2.0.0.tgz#36c3bc8d816fd30b570d5764a497a641640c2fed" - integrity sha512-XxzooSo6oBoxBEUazgjdXj7VwTn/iSTSZzTYKzYY6I916tkaYzypHxy+pbVU1h+0UQ9JlVf5XkNQyxOAiiQO1g== - dependencies: - is-self-closing "^1.0.1" - kind-of "^6.0.0" - -html5-qrcode@^2.2.1: - version "2.3.6" - resolved "https://registry.yarnpkg.com/html5-qrcode/-/html5-qrcode-2.3.6.tgz#95f572fd79b84cbce0e509da80eda43a394cec3c" - integrity sha512-yuCJUFzm04xGPM2a40XYPptpioV6K5uJA3Ogy0Xi/a7tAYrcD7T4ZCsbg0T1H2qX/143SZfDG1EINnNFh5rH0A== - -htmlparser2@^8.0.0: - version "8.0.1" - resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-8.0.1.tgz#abaa985474fcefe269bc761a779b544d7196d010" - integrity sha512-4lVbmc1diZC7GUJQtRQ5yBAeUCL1exyMwmForWkRLnwyzWBFxN633SALPMGYaWZvKe9j1pRZJpauvmxENSp/EA== - dependencies: - domelementtype "^2.3.0" - domhandler "^5.0.2" - domutils "^3.0.1" - entities "^4.3.0" - http-assert@^1.3.0: version "1.5.0" resolved "https://registry.yarnpkg.com/http-assert/-/http-assert-1.5.0.tgz#c389ccd87ac16ed2dfa6246fd73b926aa00e6b8f" @@ -9006,13 +8455,6 @@ is-docker@^2.0.0, is-docker@^2.1.1: resolved "https://registry.yarnpkg.com/is-docker/-/is-docker-2.2.1.tgz#33eeabe23cfe86f14bde4408a02c0cfb853acdaa" integrity sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ== -is-even@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-even/-/is-even-1.0.0.tgz#76b5055fbad8d294a86b6a949015e1c97b717c06" - integrity sha512-LEhnkAdJqic4Dbqn58A0y52IXoHWlsueqQkKfMfdEnIYG8A1sm/GHidKkS6yvXlMoRrkM34csHnXQtOqcb+Jzg== - dependencies: - is-odd "^0.1.2" - is-extendable@^0.1.0, is-extendable@^0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89" @@ -9119,13 +8561,6 @@ is-number-object@^1.0.4: dependencies: has-tostringtag "^1.0.0" -is-number@^2.0.2: - version "2.1.0" - resolved "https://registry.yarnpkg.com/is-number/-/is-number-2.1.0.tgz#01fcbbb393463a548f2f466cce16dece49db908f" - integrity sha512-QUzH43Gfb9+5yckcrSA0VBDwEtDUchrk4F6tfJZQuNzDJbEDB9cZNzSfXGQ1jqmdDY/kl41lUOWM9syA8z8jlg== - dependencies: - kind-of "^3.0.2" - is-number@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/is-number/-/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195" @@ -9148,13 +8583,6 @@ is-object@^1.0.1: resolved "https://registry.yarnpkg.com/is-object/-/is-object-1.0.2.tgz#a56552e1c665c9e950b4a025461da87e72f86fcf" integrity sha512-2rRIahhZr2UWb45fIOuvZGpFtz0TyOZLf32KxBbSoUCeZR495zCKlWUKKUByk3geS2eAs7ZAABt0Y/Rx0GiQGA== -is-odd@^0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/is-odd/-/is-odd-0.1.2.tgz#bc573b5ce371ef2aad6e6f49799b72bef13978a7" - integrity sha512-Ri7C2K7o5IrUU9UEI8losXJCCD/UtsaIrkR5sxIcFg4xQ9cRJXlWA5DQvTE0yDc0krvSNLsRGXN11UPS6KyfBw== - dependencies: - is-number "^3.0.0" - is-path-inside@^3.0.2: version "3.0.3" resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-3.0.3.tgz#d231362e53a07ff2b0e0ea7fed049161ffd16283" @@ -9172,11 +8600,6 @@ is-plain-object@^2.0.3, is-plain-object@^2.0.4: dependencies: isobject "^3.0.1" -is-plain-object@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-5.0.0.tgz#4427f50ab3429e9025ea7d52e9043a9ef4159344" - integrity sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q== - is-property@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/is-property/-/is-property-1.0.2.tgz#57fe1c4e48474edd65b09911f26b1cd4095dda84" @@ -9200,13 +8623,6 @@ is-retry-allowed@^2.2.0: resolved "https://registry.yarnpkg.com/is-retry-allowed/-/is-retry-allowed-2.2.0.tgz#88f34cbd236e043e71b6932d09b0c65fb7b4d71d" integrity sha512-XVm7LOeLpTW4jV19QSH38vkswxoLud8sQ57YwJVTPWdiaI9I8keEhGFpBlslyVsgdQy4Opg8QOLb8YRgsyZiQg== -is-self-closing@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/is-self-closing/-/is-self-closing-1.0.1.tgz#5f406b527c7b12610176320338af0fa3896416e4" - integrity sha512-E+60FomW7Blv5GXTlYee2KDrnG6srxF7Xt1SjrhWUGUEsTFIqY/nq2y3DaftCsgUMdh89V07IVfhY9KIJhLezg== - dependencies: - self-closing-tags "^1.0.1" - is-shared-array-buffer@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz#8f259c573b60b6a32d4058a1a07430c0a7344c79" @@ -9322,11 +8738,6 @@ isexe@^2.0.0: resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== -isobject@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/isobject/-/isobject-0.2.0.tgz#a3432192f39b910b5f02cc989487836ec70aa85e" - integrity sha512-VaWq6XYAsbvM0wf4dyBO7WH9D7GosB7ZZlqrawI9BBiTMINBeCyqSKBa35m870MY3O4aM31pYyZi9DfGrYMJrQ== - isobject@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89" @@ -10521,7 +9932,7 @@ keyv@^3.0.0: dependencies: json-buffer "3.0.0" -kind-of@^3.0.2, kind-of@^3.0.3, kind-of@^3.1.0, kind-of@^3.2.0: +kind-of@^3.0.2, kind-of@^3.0.3, kind-of@^3.2.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== @@ -10535,12 +9946,12 @@ kind-of@^4.0.0: dependencies: is-buffer "^1.1.5" -kind-of@^5.0.0, kind-of@^5.0.2: +kind-of@^5.0.0: version "5.1.0" resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-5.1.0.tgz#729c91e2d857b7a419a1f9aa65685c4c33f5845d" integrity sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw== -kind-of@^6.0.0, kind-of@^6.0.2, kind-of@^6.0.3: +kind-of@^6.0.0, kind-of@^6.0.2: 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== @@ -10756,11 +10167,6 @@ lcid@^2.0.0: dependencies: invert-kv "^2.0.0" -leaflet@^1.7.1: - version "1.9.3" - resolved "https://registry.yarnpkg.com/leaflet/-/leaflet-1.9.3.tgz#52ec436954964e2d3d39e0d433da4b2500d74414" - integrity sha512-iB2cR9vAkDOu5l3HAay2obcUHZ7xwUBBjph8+PGtmW/2lYhbLizWtG7nTeYht36WfOslixQF9D/uSIzhZgGMfQ== - left-pad@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/left-pad/-/left-pad-1.3.0.tgz#5b8a3a7765dfe001261dde915589e782f8c94d1e" @@ -10955,11 +10361,6 @@ locate-path@^5.0.0: dependencies: p-locate "^4.1.0" -lodash._reinterpolate@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz#0ccf2d89166af03b3663c796538b75ac6e114d9d" - integrity sha512-xYHt68QRoYGjeeM/XOE1uJtvXQAgvszfBhjV4yvsQH0u2i9I6cI6c6/eG4Hh3UAOVn0y/xAXwmTzEay49Q//HA== - lodash.camelcase@^4.3.0: version "4.3.0" resolved "https://registry.yarnpkg.com/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz#b28aa6288a2b9fc651035c7711f65ab6190331a6" @@ -11065,21 +10466,6 @@ lodash.sortby@^4.7.0: resolved "https://registry.yarnpkg.com/lodash.sortby/-/lodash.sortby-4.7.0.tgz#edd14c824e2cc9c1e0b0a1b42bb5210516a42438" integrity sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA== -lodash.template@^4.4.0: - version "4.5.0" - resolved "https://registry.yarnpkg.com/lodash.template/-/lodash.template-4.5.0.tgz#f976195cf3f347d0d5f52483569fe8031ccce8ab" - integrity sha512-84vYFxIkmidUiFxidA/KjjH9pAycqW+h980j7Fuz5qxRtO9pgB7MDFTdys1N7A5mcucRiDyEq4fusljItR1T/A== - dependencies: - lodash._reinterpolate "^3.0.0" - lodash.templatesettings "^4.0.0" - -lodash.templatesettings@^4.0.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/lodash.templatesettings/-/lodash.templatesettings-4.2.0.tgz#e481310f049d3cf6d47e912ad09313b154f0fb33" - integrity sha512-stgLz+i3Aa9mZgnjr/O+v9ruKZsPsndy7qPZOchbqk2cnTU1ZaldKK+v7m54WoKIyxiuMZTKT2H81F8BeAc3ZQ== - dependencies: - lodash._reinterpolate "^3.0.0" - lodash.without@^4.4.0: version "4.4.0" resolved "https://registry.yarnpkg.com/lodash.without/-/lodash.without-4.4.0.tgz#3cd4574a00b67bae373a94b748772640507b7aac" @@ -11090,7 +10476,7 @@ lodash.xor@^4.5.0: resolved "https://registry.yarnpkg.com/lodash.xor/-/lodash.xor-4.5.0.tgz#4d48ed7e98095b0632582ba714d3ff8ae8fb1db6" integrity sha512-sVN2zimthq7aZ5sPGXnSz32rZPuqcparVW50chJQe+mzTYV+IsxSsl/2gnkWWE2Of7K3myBQBqtLKOUEHJKRsQ== -lodash@4.17.21, lodash@^4.17.11, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.20, lodash@^4.17.21, lodash@^4.17.3: +lodash@4.17.21, lodash@^4.17.11, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.21, lodash@^4.17.3: version "4.17.21" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== @@ -11242,11 +10628,6 @@ markdown-it@^12.2.0: mdurl "^1.0.1" uc.micro "^1.0.5" -marked@^4.1.0: - version "4.2.12" - resolved "https://registry.yarnpkg.com/marked/-/marked-4.2.12.tgz#d69a64e21d71b06250da995dcd065c11083bebb5" - integrity sha512-yr8hSKa3Fv4D3jdZmtMMPghgVt6TWbk86WQaWhDloQjRSQhMMYCAro7jP7VDJrjjdV8pxVxMssXS8B8Y5DZ5aw== - matcher@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/matcher/-/matcher-3.0.0.tgz#bd9060f4c5b70aa8041ccc6f80368760994f30ca" @@ -11342,7 +10723,7 @@ methods@^1.1.1, methods@^1.1.2: resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" integrity sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w== -micromatch@^3.1.10, micromatch@^3.1.4, micromatch@^3.1.5: +micromatch@^3.1.10, micromatch@^3.1.4: version "3.1.10" resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23" integrity sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg== @@ -11645,16 +11026,6 @@ nan@^2.15.0, nan@^2.16.0: resolved "https://registry.yarnpkg.com/nan/-/nan-2.17.0.tgz#c0150a2368a182f033e9aa5195ec76ea41a199cb" integrity sha512-2ZTgtl0nJsO0KQCjEpxcIr5D+Yv90plTitZt9JBfQvVJDS5seMl3FOvsh3+9CoYWXf/1l5OaZzzF6nDm4cagaQ== -nanoid@^2.1.0: - version "2.1.11" - resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-2.1.11.tgz#ec24b8a758d591561531b4176a01e3ab4f0f0280" - integrity sha512-s/snB+WGm6uwi0WjsZdaVcuf3KJXlfGl2LcxgwkEwJF0D/BWzVWAZW/XY4bFaiR7s0Jk3FPvlnepg1H1b1UwlA== - -nanoid@^3.3.4: - version "3.3.4" - resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.4.tgz#730b67e3cd09e2deacf03c027c81c9d9dbc5e8ab" - integrity sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw== - nanomatch@^1.2.9: version "1.2.13" resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119" @@ -12333,11 +11704,6 @@ parse-passwd@^1.0.0: resolved "https://registry.yarnpkg.com/parse-passwd/-/parse-passwd-1.0.0.tgz#6d5b934a456993b23d37f40a382d6f1666a8e5c6" integrity sha512-1Y1A//QUXEZK7YKz+rD9WydcE1+EuPr6ZBgKecAB8tmoW6UFv0NREVJe1p+jRxtThkcbbKkfwIbWJe/IeE6m2Q== -parse-srcset@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/parse-srcset/-/parse-srcset-1.0.2.tgz#f2bd221f6cc970a938d88556abc589caaaa2bde1" - integrity sha512-/2qh0lav6CmI15FzA3i/2Bzk2zCgQhGMkvhOhKNcBVQ1ldgpbfiNTVslmooUmWJcADi1f1kIeynbDRVzNlfR6Q== - parse5@4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/parse5/-/parse5-4.0.0.tgz#6d78656e3da8d78b4ec0b906f7c08ef1dfe3f608" @@ -12686,15 +12052,6 @@ posix-character-classes@^0.1.0: resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab" integrity sha512-xTgYBc3fuo7Yt7JbiuFxSYGToMoz8fLoE6TC9Wx1P/u+LfeThMOAqmuyECnlBaaJb+u1m9hHiXUEtwW4OzfUJg== -postcss@^8.3.11: - version "8.4.21" - resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.21.tgz#c639b719a57efc3187b13a1d765675485f4134f4" - integrity sha512-tP7u/Sn/dVxK2NnruI4H9BG+x+Wxz6oeZ1cJ8P6G/PZY0IKk4k/63TDsQf2kQq3+qoJeLm2kIBUNlZe3zgb4Zg== - dependencies: - nanoid "^3.3.4" - picocolors "^1.0.0" - source-map-js "^1.0.2" - postgres-array@~2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/postgres-array/-/postgres-array-2.0.0.tgz#48f8fce054fbc69671999329b8834b772652d82e" @@ -13466,16 +12823,6 @@ regexp.prototype.flags@^1.4.3: define-properties "^1.1.3" functions-have-names "^1.2.2" -regexparam@2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/regexparam/-/regexparam-2.0.1.tgz#c912f5dae371e3798100b3c9ce22b7414d0889fa" - integrity sha512-zRgSaYemnNYxUv+/5SeoHI0eJIgTL/A2pUtXUPLHQxUldagouJ9p+K6IbIZ/JiQuCEv2E2B1O11SjVQy3aMCkw== - -regexparam@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/regexparam/-/regexparam-1.3.0.tgz#2fe42c93e32a40eff6235d635e0ffa344b92965f" - integrity sha512-6IQpFBv6e5vz1QAqI+V4k8P2e/3gRrqfCJ9FI+O1FLQTO+Uz6RXZEZOPmTJ6hlGj7gkERzY5BRCv09whKP96/g== - regexpp@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-2.0.1.tgz#8d19d31cf632482b589049f8281f93dbcba4d07f" @@ -13524,21 +12871,6 @@ relative-microtime@^2.0.0: resolved "https://registry.yarnpkg.com/relative-microtime/-/relative-microtime-2.0.0.tgz#cceed2af095ecd72ea32011279c79e5fcc7de29b" integrity sha512-l18ha6HEZc+No/uK4GyAnNxgKW7nvEe35IaeN54sShMojtqik2a6GbTyuiezkjpPaqP874Z3lW5ysBo5irz4NA== -relative@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/relative/-/relative-3.0.2.tgz#0dcd8ec54a5d35a3c15e104503d65375b5a5367f" - integrity sha512-Q5W2qeYtY9GbiR8z1yHNZ1DGhyjb4AnLEjt8iE6XfcC1QIu+FAtj3HQaO0wH28H1mX6cqNLvAqWhP402dxJGyA== - dependencies: - isobject "^2.0.0" - -remarkable@^1.6.2: - version "1.7.4" - resolved "https://registry.yarnpkg.com/remarkable/-/remarkable-1.7.4.tgz#19073cb960398c87a7d6546eaa5e50d2022fcd00" - integrity sha512-e6NKUXgX95whv7IgddywbeN/ItCkWbISmc2DiqHJb0wTrqZIexqdco5b8Z3XZoo/48IdNVKM9ZCvTPJ4F5uvhg== - dependencies: - argparse "^1.0.10" - autolinker "~0.28.0" - remove-trailing-separator@^1.0.1: version "1.1.0" resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef" @@ -13834,18 +13166,6 @@ sane@^4.0.3: minimist "^1.1.1" walker "~1.0.5" -sanitize-html@^2.7.0: - version "2.9.0" - resolved "https://registry.yarnpkg.com/sanitize-html/-/sanitize-html-2.9.0.tgz#f4829557b0175df9059d90fe972d5e6facb8565c" - integrity sha512-KY1hpSbqFNcpoLf+nP7iStbP5JfQZ2Nd19ZEE7qFsQqRdp+sO5yX/e5+HoG9puFAcSTEpzQuihfKUltDcLlQjg== - dependencies: - deepmerge "^4.2.2" - escape-string-regexp "^4.0.0" - htmlparser2 "^8.0.0" - is-plain-object "^5.0.0" - parse-srcset "^1.0.2" - postcss "^8.3.11" - sanitize-s3-objectkey@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/sanitize-s3-objectkey/-/sanitize-s3-objectkey-0.0.1.tgz#efa9887cd45275b40234fb4bb12fc5754fe64e7e" @@ -13877,11 +13197,6 @@ schema-utils@^3.1.0, schema-utils@^3.1.1: ajv "^6.12.5" ajv-keywords "^3.5.2" -screenfull@^6.0.1: - version "6.0.2" - resolved "https://registry.yarnpkg.com/screenfull/-/screenfull-6.0.2.tgz#3dbe4b8c4f8f49fb8e33caa8f69d0bca730ab238" - integrity sha512-AQdy8s4WhNvUZ6P8F6PB21tSPIYKniic+Ogx0AacBMjKP1GUHN2E9URxQHtCusiwxudnCKkdy4GrHXPPJSkCCw== - search-params@3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/search-params/-/search-params-3.0.0.tgz#dbc7c243058e5a33ae1e9870be91f5aced4100d8" @@ -13899,11 +13214,6 @@ seek-bzip@^1.0.5: dependencies: commander "^2.8.1" -self-closing-tags@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/self-closing-tags/-/self-closing-tags-1.0.1.tgz#6c5fa497994bb826b484216916371accee490a5d" - integrity sha512-7t6hNbYMxM+VHXTgJmxwgZgLGktuXtVVD5AivWzNTdJBM4DBjnDKDzkf2SrNjihaArpeJYNjxkELBu1evI4lQA== - semver-compare@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/semver-compare/-/semver-compare-1.0.0.tgz#0dee216a1c941ab37e9efb1788f6afc5ff5537fc" @@ -14056,13 +13366,6 @@ shimmer@^1.2.0: resolved "https://registry.yarnpkg.com/shimmer/-/shimmer-1.2.1.tgz#610859f7de327b587efebf501fb43117f9aff337" integrity sha512-sQTKC1Re/rM6XyFM6fIAGHRPVGvyXfgzIDvzoq608vM+jeyVD0Tu1E6Np0Kc2zAIFWIj963V2800iF/9LPieQw== -shortid@^2.2.15: - version "2.2.16" - resolved "https://registry.yarnpkg.com/shortid/-/shortid-2.2.16.tgz#b742b8f0cb96406fd391c76bfc18a67a57fe5608" - integrity sha512-Ugt+GIZqvGXCIItnsL+lvFJOiN7RYqlGy7QE41O3YC1xbNSeDGIRO7xg2JJXIAj1cAGnOeC1r7/T9pgrtQbv4g== - dependencies: - nanoid "^2.1.0" - side-channel@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.4.tgz#efce5c8fdc104ee751b25c58d4290011fa5ea2cf" @@ -14203,16 +13506,6 @@ socket.io-adapter@~2.4.0: resolved "https://registry.yarnpkg.com/socket.io-adapter/-/socket.io-adapter-2.4.0.tgz#b50a4a9ecdd00c34d4c8c808224daa1a786152a6" integrity sha512-W4N+o69rkMEGVuk2D/cvca3uYsvGlMwsySWV447y99gUPghxq42BxqLNMndb+a1mm/5/7NeXVQS7RLa2XyXvYg== -socket.io-client@^4.5.1: - version "4.6.0" - resolved "https://registry.yarnpkg.com/socket.io-client/-/socket.io-client-4.6.0.tgz#449255d2e0fe429f5ab47ecd3e3b1716b0039c13" - integrity sha512-2XOp18xnGghUICSd5ziUIS4rB0dhr6S8OvAps8y+HhOjFQlqGcf+FIh6fCIsKKZyWFxJeFPrZRNPGsHDTsz1Ug== - dependencies: - "@socket.io/component-emitter" "~3.1.0" - debug "~4.3.2" - engine.io-client "~6.4.0" - socket.io-parser "~4.2.1" - socket.io-parser@~4.2.0: version "4.2.1" resolved "https://registry.yarnpkg.com/socket.io-parser/-/socket.io-parser-4.2.1.tgz#01c96efa11ded938dcb21cbe590c26af5eff65e5" @@ -14221,14 +13514,6 @@ socket.io-parser@~4.2.0: "@socket.io/component-emitter" "~3.1.0" debug "~4.3.1" -socket.io-parser@~4.2.1: - version "4.2.2" - resolved "https://registry.yarnpkg.com/socket.io-parser/-/socket.io-parser-4.2.2.tgz#1dd384019e25b7a3d374877f492ab34f2ad0d206" - integrity sha512-DJtziuKypFkMMHCm2uIshOYC7QaylbtzQwiMYDuCKy3OPkjLzu4B2vAhTlqipRHHzrI0NJeBAizTK7X+6m1jVw== - dependencies: - "@socket.io/component-emitter" "~3.1.0" - debug "~4.3.1" - socket.io@^4.5.1: version "4.5.2" resolved "https://registry.yarnpkg.com/socket.io/-/socket.io-4.5.2.tgz#1eb25fd380ab3d63470aa8279f8e48d922d443ac" @@ -14283,11 +13568,6 @@ source-list-map@^2.0.1: resolved "https://registry.yarnpkg.com/source-list-map/-/source-list-map-2.0.1.tgz#3993bd873bfc48479cca9ea3a547835c7c154b34" integrity sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw== -source-map-js@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.0.2.tgz#adbc361d9c62df380125e7f161f71c826f1e490c" - integrity sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw== - source-map-resolve@^0.5.0: version "0.5.3" resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.5.3.tgz#190866bece7553e1f8f267a2ee82c606b5509a1a" @@ -14710,11 +13990,6 @@ strip-outer@^1.0.0: dependencies: escape-string-regexp "^1.0.2" -striptags@^3.1.1: - version "3.2.0" - resolved "https://registry.yarnpkg.com/striptags/-/striptags-3.2.0.tgz#cc74a137db2de8b0b9a370006334161f7dd67052" - integrity sha512-g45ZOGzHDMe2bdYMdIvdAfCQkCTDMGBazSw1ypMowwGIee7ZQ5dU0rBJ8Jqgl+jAKIv4dbeE1jscZq9wid1Tkw== - style-loader@^3.3.1: version "3.3.1" resolved "https://registry.yarnpkg.com/style-loader/-/style-loader-3.3.1.tgz#057dfa6b3d4d7c7064462830f9113ed417d38575" @@ -14814,23 +14089,11 @@ svelte-portal@^1.0.0: resolved "https://registry.yarnpkg.com/svelte-portal/-/svelte-portal-1.0.0.tgz#36a47c5578b1a4d9b4dc60fa32a904640ec4cdd3" integrity sha512-nHf+DS/jZ6jjnZSleBMSaZua9JlG5rZv9lOGKgJuaZStfevtjIlUJrkLc3vbV8QdBvPPVmvcjTlazAzfKu0v3Q== -svelte-spa-router@^3.0.5: - version "3.3.0" - resolved "https://registry.yarnpkg.com/svelte-spa-router/-/svelte-spa-router-3.3.0.tgz#2fc0967a49dc361dfe4d38dddad6e662eed5b42c" - integrity sha512-cwRNe7cxD43sCvSfEeaKiNZg3FCizGxeMcf7CPiWRP3jKXjEma3vxyyuDtPOam6nWbVxl9TNM3hlE/i87ZlqcQ== - dependencies: - regexparam "2.0.1" - svelte@3.49.0: version "3.49.0" resolved "https://registry.yarnpkg.com/svelte/-/svelte-3.49.0.tgz#5baee3c672306de1070c3b7888fc2204e36a4029" integrity sha512-+lmjic1pApJWDfPCpUUTc1m8azDqYCG1JN9YEngrx/hUyIcFJo6VZhj0A1Ai0wqoHcEIuQy+e9tk+4uDgdtsFA== -svelte@^3.46.2, svelte@^3.49.0: - version "3.55.1" - resolved "https://registry.yarnpkg.com/svelte/-/svelte-3.55.1.tgz#6f93b153e5248039906ce5fe196efdb9e05dfce8" - integrity sha512-S+87/P0Ve67HxKkEV23iCdAh/SX1xiSfjF1HOglno/YTbSTW7RniICMCofWGdJJbdjw3S+0PfFb1JtGfTXE0oQ== - svg.draggable.js@^2.2.2: version "2.2.2" resolved "https://registry.yarnpkg.com/svg.draggable.js/-/svg.draggable.js-2.2.2.tgz#c514a2f1405efb6f0263e7958f5b68fce50603ba" @@ -15210,11 +14473,6 @@ to-fast-properties@^2.0.0: resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" integrity sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4= -to-gfm-code-block@^0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/to-gfm-code-block/-/to-gfm-code-block-0.1.1.tgz#25d045a5fae553189e9637b590900da732d8aa82" - integrity sha512-LQRZWyn8d5amUKnfR9A9Uu7x9ss7Re8peuWR2gkh1E+ildOfv2aF26JpuDg8JtvCduu5+hOrMIH+XstZtnagqg== - to-json-schema@0.2.5: version "0.2.5" resolved "https://registry.yarnpkg.com/to-json-schema/-/to-json-schema-0.2.5.tgz#ef3c3f11ad64460dcfbdbafd0fd525d69d62a98f" @@ -15483,13 +14741,6 @@ typedarray-to-buffer@^3.1.5: dependencies: is-typedarray "^1.0.0" -typeof-article@^0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/typeof-article/-/typeof-article-0.1.1.tgz#9f07e733c3fbb646ffa9e61c08debacd460e06af" - integrity sha512-Vn42zdX3FhmUrzEmitX3iYyLb+Umwpmv8fkZRIknYh84lmdrwqZA5xYaoKiIj2Rc5i/5wcDrpUmZcbk1U51vTw== - dependencies: - kind-of "^3.1.0" - typeof@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/typeof/-/typeof-1.0.0.tgz#9c84403f2323ae5399167275497638ea1d2f2440" @@ -15500,11 +14751,6 @@ typescript@4.7.3: resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.7.3.tgz#8364b502d5257b540f9de4c40be84c98e23a129d" integrity sha512-WOkT3XYvrpXx4vMMqlD+8R8R37fZkjyLGlxavMc4iB8lrl8L0DeTcHbYgw/v0N/z9wAFsgBhcsF0ruoySS22mA== -typo-js@*: - version "1.2.2" - resolved "https://registry.yarnpkg.com/typo-js/-/typo-js-1.2.2.tgz#340484d81fe518e77c81a5a770162b14492f183b" - integrity sha512-C7pYBQK17EjSg8tVNY91KHdUt5Nf6FMJ+c3js076quPmBML57PmNMzAcIq/2kf/hSYtFABNDIYNYlJRl5BJhGw== - uc.micro@^1.0.1, uc.micro@^1.0.5: version "1.0.6" resolved "https://registry.yarnpkg.com/uc.micro/-/uc.micro-1.0.6.tgz#9c411a802a409a91fc6cf74081baba34b24499ac" @@ -15855,14 +15101,6 @@ vm2@3.9.11: acorn "^8.7.0" acorn-walk "^8.2.0" -vm2@^3.9.4: - version "3.9.14" - resolved "https://registry.yarnpkg.com/vm2/-/vm2-3.9.14.tgz#964042b474cf1e6e4f475a39144773cdb9deb734" - integrity sha512-HgvPHYHeQy8+QhzlFryvSteA4uQLBCOub02mgqdR+0bN/akRZ48TGB1v0aCv7ksyc0HXx16AZtMHKS38alc6TA== - dependencies: - acorn "^8.7.0" - acorn-walk "^8.2.0" - vuvuzela@1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/vuvuzela/-/vuvuzela-1.0.3.tgz#3be145e58271c73ca55279dd851f12a682114b0b" @@ -16218,11 +15456,6 @@ ws@^5.2.0: dependencies: async-limiter "~1.0.0" -ws@~8.11.0: - version "8.11.0" - resolved "https://registry.yarnpkg.com/ws/-/ws-8.11.0.tgz#6a0d36b8edfd9f96d8b25683db2f8d7de6e8e143" - integrity sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg== - ws@~8.2.3: version "8.2.3" resolved "https://registry.yarnpkg.com/ws/-/ws-8.2.3.tgz#63a56456db1b04367d0b721a0b80cae6d8becbba" @@ -16291,11 +15524,6 @@ xmlbuilder@~9.0.1: resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-9.0.7.tgz#132ee63d2ec5565c557e20f4c22df9aca686b10d" integrity sha1-Ey7mPS7FVlxVfiD0wi35rKaGsQ0= -xmlhttprequest-ssl@~2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/xmlhttprequest-ssl/-/xmlhttprequest-ssl-2.0.0.tgz#91360c86b914e67f44dce769180027c0da618c67" - integrity sha512-QKxVRxiRACQcVuQEYFsI1hhkrMlrXHPegbbd1yn9UHOmRxY+si12nQYzri3vbzt8VdTTRviqcKxcyllFas5z2A== - xpath.js@~1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/xpath.js/-/xpath.js-1.1.0.tgz#3816a44ed4bb352091083d002a383dd5104a5ff1" @@ -16434,11 +15662,6 @@ yauzl@^2.4.2: buffer-crc32 "~0.2.3" fd-slicer "~1.1.0" -year@^0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/year/-/year-0.2.1.tgz#4083ae520a318b23ec86037f3000cb892bdf9bb0" - integrity sha512-9GnJUZ0QM4OgXuOzsKNzTJ5EOkums1Xc+3YQXp+Q+UxFjf7zLucp9dQ8QMIft0Szs1E1hUiXFim1OYfEKFq97w== - ylru@^1.2.0: version "1.3.2" resolved "https://registry.yarnpkg.com/ylru/-/ylru-1.3.2.tgz#0de48017473275a4cbdfc83a1eaf67c01af8a785" diff --git a/packages/worker/src/index.ts b/packages/worker/src/index.ts index dfb96a061c..48cbd74c4c 100644 --- a/packages/worker/src/index.ts +++ b/packages/worker/src/index.ts @@ -15,6 +15,7 @@ import Application from "koa" import { bootstrap } from "global-agent" import * as db from "./db" import { auth, logging, events, middleware } from "@budibase/backend-core" +import { sdk } from "@budibase/pro" db.init() import Koa from "koa" import koaBody from "koa-body" @@ -26,6 +27,10 @@ const koaSession = require("koa-session") const logger = require("koa-pino-logger") import destroyable from "server-destroy" +// configure events to use the pro audit log write +// can't integrate directly into backend-core due to cyclic issues +events.configure(sdk.auditLogs.write) + // this will setup http and https proxies form env variables bootstrap() From 2afd3e1580930045944194f4a5a204a8f6136a41 Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Wed, 15 Feb 2023 19:44:32 +0000 Subject: [PATCH 012/106] Updating events to include a proper friendly map of audited events. --- .../backend-core/src/events/publishers/app.ts | 11 +++ .../src/events/publishers/auth.ts | 6 +- .../src/events/publishers/backup.ts | 5 +- .../src/events/publishers/group.ts | 14 ++- .../src/events/publishers/user.ts | 17 +++- packages/backend-core/src/utils/utils.ts | 3 +- packages/types/src/sdk/events/app.ts | 11 +++ packages/types/src/sdk/events/auth.ts | 2 + packages/types/src/sdk/events/backup.ts | 2 + packages/types/src/sdk/events/event.ts | 98 ++++++++++++++++++- packages/types/src/sdk/events/user.ts | 15 ++- packages/types/src/sdk/events/userGroup.ts | 11 +++ .../worker/src/api/controllers/global/auth.ts | 6 +- packages/worker/src/sdk/users/users.ts | 2 +- 14 files changed, 187 insertions(+), 16 deletions(-) diff --git a/packages/backend-core/src/events/publishers/app.ts b/packages/backend-core/src/events/publishers/app.ts index 90da21f3f5..a4d578bb4f 100644 --- a/packages/backend-core/src/events/publishers/app.ts +++ b/packages/backend-core/src/events/publishers/app.ts @@ -19,6 +19,7 @@ const created = async (app: App, timestamp?: string | number) => { const properties: AppCreatedEvent = { appId: app.appId, version: app.version, + name: app.name, } await publishEvent(Event.APP_CREATED, properties, timestamp) } @@ -27,6 +28,7 @@ async function updated(app: App) { const properties: AppUpdatedEvent = { appId: app.appId, version: app.version, + name: app.name, } await publishEvent(Event.APP_UPDATED, properties) } @@ -34,6 +36,7 @@ async function updated(app: App) { async function deleted(app: App) { const properties: AppDeletedEvent = { appId: app.appId, + name: app.name, } await publishEvent(Event.APP_DELETED, properties) } @@ -41,6 +44,7 @@ async function deleted(app: App) { async function published(app: App, timestamp?: string | number) { const properties: AppPublishedEvent = { appId: app.appId, + name: app.name, } await publishEvent(Event.APP_PUBLISHED, properties, timestamp) } @@ -48,6 +52,7 @@ async function published(app: App, timestamp?: string | number) { async function unpublished(app: App) { const properties: AppUnpublishedEvent = { appId: app.appId, + name: app.name, } await publishEvent(Event.APP_UNPUBLISHED, properties) } @@ -55,6 +60,7 @@ async function unpublished(app: App) { async function fileImported(app: App) { const properties: AppFileImportedEvent = { appId: app.appId, + name: app.name, } await publishEvent(Event.APP_FILE_IMPORTED, properties) } @@ -63,6 +69,7 @@ async function templateImported(app: App, templateKey: string) { const properties: AppTemplateImportedEvent = { appId: app.appId, templateKey, + name: app.name, } await publishEvent(Event.APP_TEMPLATE_IMPORTED, properties) } @@ -76,6 +83,7 @@ async function versionUpdated( appId: app.appId, currentVersion, updatedToVersion, + name: app.name, } await publishEvent(Event.APP_VERSION_UPDATED, properties) } @@ -89,6 +97,7 @@ async function versionReverted( appId: app.appId, currentVersion, revertedToVersion, + name: app.name, } await publishEvent(Event.APP_VERSION_REVERTED, properties) } @@ -96,6 +105,7 @@ async function versionReverted( async function reverted(app: App) { const properties: AppRevertedEvent = { appId: app.appId, + name: app.name, } await publishEvent(Event.APP_REVERTED, properties) } @@ -103,6 +113,7 @@ async function reverted(app: App) { async function exported(app: App) { const properties: AppExportedEvent = { appId: app.appId, + name: app.name, } await publishEvent(Event.APP_EXPORTED, properties) } diff --git a/packages/backend-core/src/events/publishers/auth.ts b/packages/backend-core/src/events/publishers/auth.ts index 4436045599..5527e02a34 100644 --- a/packages/backend-core/src/events/publishers/auth.ts +++ b/packages/backend-core/src/events/publishers/auth.ts @@ -12,19 +12,21 @@ import { } from "@budibase/types" import { identification } from ".." -async function login(source: LoginSource) { +async function login(source: LoginSource, email: string) { const identity = await identification.getCurrentIdentity() const properties: LoginEvent = { userId: identity.id, source, + email, } await publishEvent(Event.AUTH_LOGIN, properties) } -async function logout() { +async function logout(email: string) { const identity = await identification.getCurrentIdentity() const properties: LogoutEvent = { userId: identity.id, + email, } await publishEvent(Event.AUTH_LOGOUT, properties) } diff --git a/packages/backend-core/src/events/publishers/backup.ts b/packages/backend-core/src/events/publishers/backup.ts index 12263fe1ff..d7d87f09f1 100644 --- a/packages/backend-core/src/events/publishers/backup.ts +++ b/packages/backend-core/src/events/publishers/backup.ts @@ -13,6 +13,7 @@ async function appBackupRestored(backup: AppBackup) { appId: backup.appId, restoreId: backup._id!, backupCreatedAt: backup.timestamp, + name: backup.name as string, } await publishEvent(Event.APP_BACKUP_RESTORED, properties) @@ -22,13 +23,15 @@ async function appBackupTriggered( appId: string, backupId: string, type: AppBackupType, - trigger: AppBackupTrigger + trigger: AppBackupTrigger, + name: string ) { const properties: AppBackupTriggeredEvent = { appId: appId, backupId, type, trigger, + name, } await publishEvent(Event.APP_BACKUP_TRIGGERED, properties) } diff --git a/packages/backend-core/src/events/publishers/group.ts b/packages/backend-core/src/events/publishers/group.ts index d79920562b..d8de4ccba4 100644 --- a/packages/backend-core/src/events/publishers/group.ts +++ b/packages/backend-core/src/events/publishers/group.ts @@ -8,12 +8,14 @@ import { GroupUsersAddedEvent, GroupUsersDeletedEvent, GroupAddedOnboardingEvent, + GroupPermissionsEditedEvent, UserGroupRoles, } from "@budibase/types" async function created(group: UserGroup, timestamp?: number) { const properties: GroupCreatedEvent = { groupId: group._id as string, + name: group.name, } await publishEvent(Event.USER_GROUP_CREATED, properties, timestamp) } @@ -21,6 +23,7 @@ async function created(group: UserGroup, timestamp?: number) { async function updated(group: UserGroup) { const properties: GroupUpdatedEvent = { groupId: group._id as string, + name: group.name, } await publishEvent(Event.USER_GROUP_UPDATED, properties) } @@ -28,6 +31,7 @@ async function updated(group: UserGroup) { async function deleted(group: UserGroup) { const properties: GroupDeletedEvent = { groupId: group._id as string, + name: group.name, } await publishEvent(Event.USER_GROUP_DELETED, properties) } @@ -36,6 +40,7 @@ async function usersAdded(count: number, group: UserGroup) { const properties: GroupUsersAddedEvent = { count, groupId: group._id as string, + name: group.name, } await publishEvent(Event.USER_GROUP_USERS_ADDED, properties) } @@ -44,6 +49,7 @@ async function usersDeleted(count: number, group: UserGroup) { const properties: GroupUsersDeletedEvent = { count, groupId: group._id as string, + name: group.name, } await publishEvent(Event.USER_GROUP_USERS_REMOVED, properties) } @@ -56,9 +62,11 @@ async function createdOnboarding(groupId: string) { await publishEvent(Event.USER_GROUP_ONBOARDING, properties) } -async function permissionsEdited(roles: UserGroupRoles) { - const properties: UserGroupRoles = { - ...roles, +async function permissionsEdited(group: UserGroup) { + const properties: GroupPermissionsEditedEvent = { + permissions: group.roles!, + name: group.name, + groupId: group._id as string, } await publishEvent(Event.USER_GROUP_PERMISSIONS_EDITED, properties) } diff --git a/packages/backend-core/src/events/publishers/user.ts b/packages/backend-core/src/events/publishers/user.ts index 1fe50149b5..ec43dbbf00 100644 --- a/packages/backend-core/src/events/publishers/user.ts +++ b/packages/backend-core/src/events/publishers/user.ts @@ -19,6 +19,7 @@ import { async function created(user: User, timestamp?: number) { const properties: UserCreatedEvent = { userId: user._id as string, + email: user.email, } await publishEvent(Event.USER_CREATED, properties, timestamp) } @@ -26,6 +27,7 @@ async function created(user: User, timestamp?: number) { async function updated(user: User) { const properties: UserUpdatedEvent = { userId: user._id as string, + email: user.email, } await publishEvent(Event.USER_UPDATED, properties) } @@ -33,6 +35,7 @@ async function updated(user: User) { async function deleted(user: User) { const properties: UserDeletedEvent = { userId: user._id as string, + email: user.email, } await publishEvent(Event.USER_DELETED, properties) } @@ -40,6 +43,7 @@ async function deleted(user: User) { export async function onboardingComplete(user: User) { const properties: UserOnboardingEvent = { userId: user._id as string, + email: user.email, } await publishEvent(Event.USER_ONBOARDING_COMPLETE, properties) } @@ -49,6 +53,7 @@ export async function onboardingComplete(user: User) { async function permissionAdminAssigned(user: User, timestamp?: number) { const properties: UserPermissionAssignedEvent = { userId: user._id as string, + email: user.email, } await publishEvent( Event.USER_PERMISSION_ADMIN_ASSIGNED, @@ -60,6 +65,7 @@ async function permissionAdminAssigned(user: User, timestamp?: number) { async function permissionAdminRemoved(user: User) { const properties: UserPermissionRemovedEvent = { userId: user._id as string, + email: user.email, } await publishEvent(Event.USER_PERMISSION_ADMIN_REMOVED, properties) } @@ -67,6 +73,7 @@ async function permissionAdminRemoved(user: User) { async function permissionBuilderAssigned(user: User, timestamp?: number) { const properties: UserPermissionAssignedEvent = { userId: user._id as string, + email: user.email, } await publishEvent( Event.USER_PERMISSION_BUILDER_ASSIGNED, @@ -78,20 +85,22 @@ async function permissionBuilderAssigned(user: User, timestamp?: number) { async function permissionBuilderRemoved(user: User) { const properties: UserPermissionRemovedEvent = { userId: user._id as string, + email: user.email, } await publishEvent(Event.USER_PERMISSION_BUILDER_REMOVED, properties) } // INVITE -async function invited() { - const properties: UserInvitedEvent = {} +async function invited(email: string) { + const properties: UserInvitedEvent = { email } await publishEvent(Event.USER_INVITED, properties) } async function inviteAccepted(user: User) { const properties: UserInviteAcceptedEvent = { userId: user._id as string, + email: user.email, } await publishEvent(Event.USER_INVITED_ACCEPTED, properties) } @@ -101,6 +110,7 @@ async function inviteAccepted(user: User) { async function passwordForceReset(user: User) { const properties: UserPasswordForceResetEvent = { userId: user._id as string, + email: user.email, } await publishEvent(Event.USER_PASSWORD_FORCE_RESET, properties) } @@ -108,6 +118,7 @@ async function passwordForceReset(user: User) { async function passwordUpdated(user: User) { const properties: UserPasswordUpdatedEvent = { userId: user._id as string, + email: user.email, } await publishEvent(Event.USER_PASSWORD_UPDATED, properties) } @@ -115,6 +126,7 @@ async function passwordUpdated(user: User) { async function passwordResetRequested(user: User) { const properties: UserPasswordResetRequestedEvent = { userId: user._id as string, + email: user.email, } await publishEvent(Event.USER_PASSWORD_RESET_REQUESTED, properties) } @@ -122,6 +134,7 @@ async function passwordResetRequested(user: User) { async function passwordReset(user: User) { const properties: UserPasswordResetEvent = { userId: user._id as string, + email: user.email, } await publishEvent(Event.USER_PASSWORD_RESET, properties) } diff --git a/packages/backend-core/src/utils/utils.ts b/packages/backend-core/src/utils/utils.ts index c608686431..0556a80c74 100644 --- a/packages/backend-core/src/utils/utils.ts +++ b/packages/backend-core/src/utils/utils.ts @@ -227,6 +227,7 @@ export async function getBuildersCount() { */ export async function platformLogout(opts: PlatformLogoutOpts) { const ctx = opts.ctx + const email = ctx.user?.email! const userId = opts.userId const keepActiveSession = opts.keepActiveSession @@ -247,7 +248,7 @@ export async function platformLogout(opts: PlatformLogoutOpts) { const sessionIds = sessions.map(({ sessionId }) => sessionId) await invalidateSessions(userId, { sessionIds, reason: "logout" }) - await events.auth.logout() + await events.auth.logout(email) await userCache.invalidateUser(userId) } diff --git a/packages/types/src/sdk/events/app.ts b/packages/types/src/sdk/events/app.ts index 73d491070f..7b63a4f0cd 100644 --- a/packages/types/src/sdk/events/app.ts +++ b/packages/types/src/sdk/events/app.ts @@ -3,50 +3,61 @@ import { BaseEvent } from "./event" export interface AppCreatedEvent extends BaseEvent { appId: string version: string + name: string } export interface AppUpdatedEvent extends BaseEvent { appId: string version: string + name: string } export interface AppDeletedEvent extends BaseEvent { appId: string + name: string } export interface AppPublishedEvent extends BaseEvent { appId: string + name: string } export interface AppUnpublishedEvent extends BaseEvent { appId: string + name: string } export interface AppFileImportedEvent extends BaseEvent { appId: string + name: string } export interface AppTemplateImportedEvent extends BaseEvent { appId: string templateKey: string + name: string } export interface AppVersionUpdatedEvent extends BaseEvent { appId: string currentVersion: string updatedToVersion: string + name: string } export interface AppVersionRevertedEvent extends BaseEvent { appId: string currentVersion: string revertedToVersion: string + name: string } export interface AppRevertedEvent extends BaseEvent { appId: string + name: string } export interface AppExportedEvent extends BaseEvent { appId: string + name: string } diff --git a/packages/types/src/sdk/events/auth.ts b/packages/types/src/sdk/events/auth.ts index eb9f3148a3..a98e1ca889 100644 --- a/packages/types/src/sdk/events/auth.ts +++ b/packages/types/src/sdk/events/auth.ts @@ -7,10 +7,12 @@ export type SSOType = ConfigType.OIDC | ConfigType.GOOGLE export interface LoginEvent extends BaseEvent { userId: string source: LoginSource + email: string } export interface LogoutEvent extends BaseEvent { userId: string + email: string } export interface SSOCreatedEvent extends BaseEvent { diff --git a/packages/types/src/sdk/events/backup.ts b/packages/types/src/sdk/events/backup.ts index 1dddc109cc..23863cf8ac 100644 --- a/packages/types/src/sdk/events/backup.ts +++ b/packages/types/src/sdk/events/backup.ts @@ -5,6 +5,7 @@ export interface AppBackupRestoreEvent extends BaseEvent { appId: string restoreId: string backupCreatedAt: string + name: string } export interface AppBackupTriggeredEvent extends BaseEvent { @@ -12,4 +13,5 @@ export interface AppBackupTriggeredEvent extends BaseEvent { appId: string trigger: AppBackupTrigger type: AppBackupType + name: string } diff --git a/packages/types/src/sdk/events/event.ts b/packages/types/src/sdk/events/event.ts index 614dd18ded..f7a2051dfc 100644 --- a/packages/types/src/sdk/events/event.ts +++ b/packages/types/src/sdk/events/event.ts @@ -182,8 +182,102 @@ export enum Event { ENVIRONMENT_VARIABLE_UPGRADE_PANEL_OPENED = "environment_variable:upgrade_panel_opened", } -export const AuditedEventFriendlyName = { - [Event.USER_CREATED]: "user created", +export class AuditedEventFriendlyName { + // USER + static USER_CREATED = "User {{ email }} created" + static USER_UPDATED = "User {{ email }} updated" + static USER_DELETED = "User {{ email }} deleted" + static USER_PERMISSION_ADMIN_ASSIGNED = "User {{ email }} admin role assigned" + static USER_PERMISSION_ADMIN_REMOVED = "User {{ email }} admin role removed" + static USER_PERMISSION_BUILDER_ASSIGNED = + "User {{ email }} builder role assigned" + static USER_PERMISSION_BUILDER_REMOVED = + "User {{ email }} builder role removed" + static USER_INVITED = "User {{ email }} invited" + static USER_INVITED_ACCEPTED = "User {{ email }} accepted invite" + static USER_PASSWORD_UPDATED = "User {{ email }} password updated" + static USER_PASSWORD_RESET_REQUESTED = + "User {{ email }} password reset requested" + static USER_PASSWORD_RESET = "User {{ email }} password reset" + static USER_GROUP_CREATED = "User group {{ name }} created" + static USER_GROUP_UPDATED = "User group {{ name }} updated" + static USER_GROUP_DELETED = "User group {{ name }} deleted" + static USER_GROUP_USERS_ADDED = + "User group {{ name }} {{ count }} users added" + static USER_GROUP_USERS_REMOVED = + "User group {{ name }} {{ count }} users removed" + static USER_GROUP_PERMISSIONS_EDITED = + "User group {{ name }} permissions edited" + + // EMAIL + static EMAIL_SMTP_CREATED = "Email configuration created" + static EMAIL_SMTP_UPDATED = "Email configuration updated" + + // AUTH + static AUTH_SSO_CREATED = "SSO configuration created" + static AUTH_SSO_UPDATED = "SSO configuration updated" + static AUTH_SSO_ACTIVATED = "SSO configuration activated" + static AUTH_SSO_DEACTIVATED = "SSO configuration deactivated" + static AUTH_LOGIN = "User {{ email }} logged in" + static AUTH_LOGOUT = "User {{ email }} logged out" + + // ORG + static ORG_NAME_UPDATED = "Organisation name updated" + static ORG_LOGO_UPDATED = "Organisation logo updated" + static ORG_PLATFORM_URL_UPDATED = "Organisation platform URL updated" + + // APP + static APP_CREATED = "App {{ name }} created" + static APP_UPDATED = "App {{ name }} updated" + static APP_DELETED = "App {{ name }} deleted" + static APP_PUBLISHED = "App {{ name }} published" + static APP_UNPUBLISHED = "App {{ name }} unpublished" + static APP_TEMPLATE_IMPORTED = "App {{ name }} template imported" + static APP_FILE_IMPORTED = "App {{ name }} file imported" + static APP_VERSION_UPDATED = "App {{ name }} version updated" + static APP_VERSION_REVERTED = "App {{ name }} version reverted" + static APP_REVERTED = "App {{ name }} reverted" + static APP_EXPORTED = "App {{ name }} exported" + static APP_BACKUP_RESTORED = "App backup {{ name }} restored" + static APP_BACKUP_TRIGGERED = "App backup {{ name }} triggered" + + // DATASOURCE + static DATASOURCE_CREATED = "Datasource created" + static DATASOURCE_UPDATED = "Datasource updated" + static DATASOURCE_DELETED = "Datasource deleted" + + // QUERY + static QUERY_CREATED = "Query created" + static QUERY_UPDATED = "Query updated" + static QUERY_DELETED = "Query deleted" + static QUERY_IMPORT = "Query import" + + // TABLE + static TABLE_CREATED = "Table created" + static TABLE_UPDATED = "Table updated" + static TABLE_DELETED = "Table deleted" + static TABLE_EXPORTED = "Table exported" + static TABLE_IMPORTED = "Table imported" + static TABLE_DATA_IMPORTED = "Data imported to table" + + // ROWS + static ROWS_CREATED = "Rows created" + static ROWS_IMPORTED = "Rows imported" + + // AUTOMATION + static AUTOMATION_CREATED = "Automation created" + static AUTOMATION_DELETED = "Automation deleted" + + // SCREEN + static SCREEN_CREATED = "Screen created" + static SCREEN_DELETED = "Screen deleted" + + // COMPONENT + static COMPONENT_CREATED = "Component created" + static COMPONENT_DELETED = "Component deleted" + + static ENVIRONMENT_VARIABLE_CREATED = "Environment variable created" + static ENVIRONMENT_VARIABLE_DELETED = "Environment variable deleted" } // properties added at the final stage of the event pipeline diff --git a/packages/types/src/sdk/events/user.ts b/packages/types/src/sdk/events/user.ts index 3f8f72801c..1322934d45 100644 --- a/packages/types/src/sdk/events/user.ts +++ b/packages/types/src/sdk/events/user.ts @@ -2,47 +2,60 @@ import { BaseEvent } from "./event" export interface UserCreatedEvent extends BaseEvent { userId: string + email: string } export interface UserUpdatedEvent extends BaseEvent { userId: string + email: string } export interface UserDeletedEvent extends BaseEvent { userId: string + email: string } export interface UserOnboardingEvent extends BaseEvent { userId: string step?: string + email: string } export interface UserPermissionAssignedEvent extends BaseEvent { userId: string + email: string } export interface UserPermissionRemovedEvent extends BaseEvent { userId: string + email: string } -export interface UserInvitedEvent extends BaseEvent {} +export interface UserInvitedEvent extends BaseEvent { + email: string +} export interface UserInviteAcceptedEvent extends BaseEvent { userId: string + email: string } export interface UserPasswordForceResetEvent extends BaseEvent { userId: string + email: string } export interface UserPasswordUpdatedEvent extends BaseEvent { userId: string + email: string } export interface UserPasswordResetRequestedEvent extends BaseEvent { userId: string + email: string } export interface UserPasswordResetEvent extends BaseEvent { userId: string + email: string } diff --git a/packages/types/src/sdk/events/userGroup.ts b/packages/types/src/sdk/events/userGroup.ts index 2ce642e274..57deef4c20 100644 --- a/packages/types/src/sdk/events/userGroup.ts +++ b/packages/types/src/sdk/events/userGroup.ts @@ -2,27 +2,38 @@ import { BaseEvent } from "./event" export interface GroupCreatedEvent extends BaseEvent { groupId: string + name: string } export interface GroupUpdatedEvent extends BaseEvent { groupId: string + name: string } export interface GroupDeletedEvent extends BaseEvent { groupId: string + name: string } export interface GroupUsersAddedEvent extends BaseEvent { count: number groupId: string + name: string } export interface GroupUsersDeletedEvent extends BaseEvent { count: number groupId: string + name: string } export interface GroupAddedOnboardingEvent extends BaseEvent { groupId: string onboarding: boolean } + +export interface GroupPermissionsEditedEvent extends BaseEvent { + permissions: Record + name: string + groupId: string +} diff --git a/packages/worker/src/api/controllers/global/auth.ts b/packages/worker/src/api/controllers/global/auth.ts index e6d3c329d7..7491a47bb3 100644 --- a/packages/worker/src/api/controllers/global/auth.ts +++ b/packages/worker/src/api/controllers/global/auth.ts @@ -54,7 +54,7 @@ export const authenticate = async (ctx: any, next: any) => { async (err: any, user: User, info: any) => { await authInternal(ctx, user, err, info) await context.identity.doInUserContext(user, async () => { - await events.auth.login("local") + await events.auth.login("local", user.email) }) ctx.status = 200 } @@ -208,7 +208,7 @@ export const googleAuth = async (ctx: any, next: any) => { async (err: any, user: User, info: any) => { await authInternal(ctx, user, err, info) await context.identity.doInUserContext(user, async () => { - await events.auth.login("google-internal") + await events.auth.login("google-internal", user.email) }) ctx.redirect("/") } @@ -272,7 +272,7 @@ export const oidcAuth = async (ctx: any, next: any) => { async (err: any, user: any, info: any) => { await authInternal(ctx, user, err, info) await context.identity.doInUserContext(user, async () => { - await events.auth.login("oidc") + await events.auth.login("oidc", user.email) }) ctx.redirect("/") } diff --git a/packages/worker/src/sdk/users/users.ts b/packages/worker/src/sdk/users/users.ts index 8410d0b2e0..617f07d404 100644 --- a/packages/worker/src/sdk/users/users.ts +++ b/packages/worker/src/sdk/users/users.ts @@ -623,7 +623,7 @@ export const invite = async ( } await sendEmail(user.email, EmailTemplatePurpose.INVITATION, opts) response.successful.push({ email: user.email }) - await events.user.invited() + await events.user.invited(user.email) } catch (e) { console.error(`Failed to send email invitation email=${user.email}`, e) response.unsuccessful.push({ From 6ec5e97ce936733466a7953477509557a223af71 Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Fri, 17 Feb 2023 16:26:55 +0000 Subject: [PATCH 013/106] Required work to support the new lucene audit logs search indexing. --- packages/backend-core/src/constants/db.ts | 5 + packages/backend-core/src/constants/misc.ts | 1 + .../backend-core/src/context/mainContext.ts | 12 +- packages/backend-core/src/db/lucene.ts | 39 ++- .../src/api/controllers/row/internalSearch.ts | 10 +- packages/server/src/db/utils.ts | 4 - packages/server/src/db/views/staticViews.ts | 6 +- packages/types/src/sdk/events/event.ts | 222 ++++++++++++------ scripts/link-dependencies.sh | 3 + 9 files changed, 211 insertions(+), 91 deletions(-) diff --git a/packages/backend-core/src/constants/db.ts b/packages/backend-core/src/constants/db.ts index d41098c405..19f493fd8e 100644 --- a/packages/backend-core/src/constants/db.ts +++ b/packages/backend-core/src/constants/db.ts @@ -24,6 +24,11 @@ export enum ViewName { APP_BACKUP_BY_TRIGGER = "by_trigger", } +export const SearchIndexes = { + ROWS: "rows", + AUDIT: "audit", +} + export const DeprecatedViews = { [ViewName.USER_BY_EMAIL]: [ // removed due to inaccuracy in view doc filter logic diff --git a/packages/backend-core/src/constants/misc.ts b/packages/backend-core/src/constants/misc.ts index 0bf3df4094..e25c90575f 100644 --- a/packages/backend-core/src/constants/misc.ts +++ b/packages/backend-core/src/constants/misc.ts @@ -41,5 +41,6 @@ export enum Config { OIDC_LOGOS = "logos_oidc", } +export const MIN_VALID_DATE = new Date(-2147483647000) export const MAX_VALID_DATE = new Date(2147483647000) export const DEFAULT_TENANT_ID = "default" diff --git a/packages/backend-core/src/context/mainContext.ts b/packages/backend-core/src/context/mainContext.ts index 1f14a20778..14b7547ea9 100644 --- a/packages/backend-core/src/context/mainContext.ts +++ b/packages/backend-core/src/context/mainContext.ts @@ -34,17 +34,19 @@ export function getAuditLogDBName(tenantId?: string) { if (!tenantId) { tenantId = getTenantId() } - return `${tenantId}${SEPARATOR}${StaticDatabases.AUDIT_LOGS.name}` + if (tenantId === DEFAULT_TENANT_ID) { + return StaticDatabases.AUDIT_LOGS.name + } else { + return `${tenantId}${SEPARATOR}${StaticDatabases.AUDIT_LOGS.name}` + } } export function baseGlobalDBName(tenantId: string | undefined | null) { - let dbName if (!tenantId || tenantId === DEFAULT_TENANT_ID) { - dbName = StaticDatabases.GLOBAL.name + return StaticDatabases.GLOBAL.name } else { - dbName = `${tenantId}${SEPARATOR}${StaticDatabases.GLOBAL.name}` + return `${tenantId}${SEPARATOR}${StaticDatabases.GLOBAL.name}` } - return dbName } export function isMultiTenant() { diff --git a/packages/backend-core/src/db/lucene.ts b/packages/backend-core/src/db/lucene.ts index 028750797f..374e30a10d 100644 --- a/packages/backend-core/src/db/lucene.ts +++ b/packages/backend-core/src/db/lucene.ts @@ -41,6 +41,8 @@ export class QueryBuilder { sortType: string includeDocs: boolean version?: string + indexBuilder?: () => Promise + noEscaping = false constructor(dbName: string, index: string, base?: SearchFilters) { this.dbName = dbName @@ -66,6 +68,14 @@ export class QueryBuilder { this.includeDocs = true } + disableEscaping() { + this.noEscaping = true + } + + setIndexBuilder(builderFn: () => Promise) { + this.indexBuilder = builderFn + } + setVersion(version?: string) { if (version != null) { this.version = version @@ -176,6 +186,14 @@ export class QueryBuilder { return this } + handleSpaces(input: string) { + if (this.noEscaping) { + return input + } else { + return input.replace(/ /g, "_") + } + } + /** * Preprocesses a value before going into a lucene search. * Transforms strings to lowercase and wraps strings and bools in quotes. @@ -192,7 +210,7 @@ export class QueryBuilder { value = value.toLowerCase ? value.toLowerCase() : value } // Escape characters - if (escape && originalType === "string") { + if (!this.noEscaping && escape && originalType === "string") { value = `${value}`.replace(/[ #+\-&|!(){}\]^"~*?:\\]/g, "\\$&") } @@ -272,7 +290,7 @@ export class QueryBuilder { for (let [key, value] of Object.entries(structure)) { // check for new format - remove numbering if needed key = removeKeyNumbering(key) - key = builder.preprocess(key.replace(/ /g, "_"), { + key = builder.preprocess(builder.handleSpaces(key), { escape: true, }) const expression = queryFn(key, value) @@ -379,7 +397,7 @@ export class QueryBuilder { if (this.sort) { const order = this.sortOrder === "descending" ? "-" : "" const type = `<${this.sortType}>` - body.sort = `${order}${this.sort.replace(/ /g, "_")}${type}` + body.sort = `${order}${this.handleSpaces(this.sort)}${type}` } return body } @@ -388,7 +406,16 @@ export class QueryBuilder { const { url, cookie } = dbCore.getCouchInfo() const fullPath = `${url}/${this.dbName}/_design/database/_search/${this.index}` const body = this.buildSearchBody() - return await runQuery(fullPath, body, cookie) + try { + return await runQuery(fullPath, body, cookie) + } catch (err: any) { + if (err.status === 404 && this.indexBuilder) { + await this.indexBuilder() + return await runQuery(fullPath, body, cookie) + } else { + throw err + } + } } } @@ -407,6 +434,10 @@ const runQuery = async (url: string, body: any, cookie: string) => { Authorization: cookie, }, }) + + if (response.status === 404) { + throw response + } const json = await response.json() let output: any = { diff --git a/packages/server/src/api/controllers/row/internalSearch.ts b/packages/server/src/api/controllers/row/internalSearch.ts index a250fe0429..f2abc91b14 100644 --- a/packages/server/src/api/controllers/row/internalSearch.ts +++ b/packages/server/src/api/controllers/row/internalSearch.ts @@ -1,4 +1,3 @@ -import { SearchIndexes } from "../../../db/utils" import { db as dbCore, context, SearchParams } from "@budibase/backend-core" import { SearchFilters } from "@budibase/types" @@ -7,10 +6,15 @@ export async function paginatedSearch( params: SearchParams ) { const appId = context.getAppId() - return dbCore.paginatedSearch(appId!, SearchIndexes.ROWS, query, params) + return dbCore.paginatedSearch( + appId!, + dbCore.SearchIndexes.ROWS, + query, + params + ) } export async function fullSearch(query: SearchFilters, params: SearchParams) { const appId = context.getAppId() - return dbCore.fullSearch(appId!, SearchIndexes.ROWS, query, params) + return dbCore.fullSearch(appId!, dbCore.SearchIndexes.ROWS, query, params) } diff --git a/packages/server/src/db/utils.ts b/packages/server/src/db/utils.ts index ac5a6162b9..50341e4abc 100644 --- a/packages/server/src/db/utils.ts +++ b/packages/server/src/db/utils.ts @@ -9,10 +9,6 @@ export const AppStatus = { DEPLOYED: "published", } -export const SearchIndexes = { - ROWS: "rows", -} - export const BudibaseInternalDB = { _id: "bb_internal", type: dbCore.BUDIBASE_DATASOURCE_TYPE, diff --git a/packages/server/src/db/views/staticViews.ts b/packages/server/src/db/views/staticViews.ts index 4bccfebeee..674dd20ec7 100644 --- a/packages/server/src/db/views/staticViews.ts +++ b/packages/server/src/db/views/staticViews.ts @@ -1,5 +1,5 @@ -import { context } from "@budibase/backend-core" -import { DocumentType, SEPARATOR, ViewName, SearchIndexes } from "../utils" +import { context, db as dbCore } from "@budibase/backend-core" +import { DocumentType, SEPARATOR, ViewName } from "../utils" import { LinkDocument, Row } from "@budibase/types" const SCREEN_PREFIX = DocumentType.SCREEN + SEPARATOR @@ -91,7 +91,7 @@ async function searchIndex(indexName: string, fnString: string) { export async function createAllSearchIndex() { await searchIndex( - SearchIndexes.ROWS, + dbCore.SearchIndexes.ROWS, function (doc: Row) { function idx(input: Row, prev?: string) { for (let key of Object.keys(input)) { diff --git a/packages/types/src/sdk/events/event.ts b/packages/types/src/sdk/events/event.ts index f7a2051dfc..4fb3e873ae 100644 --- a/packages/types/src/sdk/events/event.ts +++ b/packages/types/src/sdk/events/event.ts @@ -182,102 +182,180 @@ export enum Event { ENVIRONMENT_VARIABLE_UPGRADE_PANEL_OPENED = "environment_variable:upgrade_panel_opened", } -export class AuditedEventFriendlyName { +// all events that are not audited have been added to this record as undefined, this means +// that Typescript can protect us against new events being added and auditing of those +// events not being considered. This might be a little ugly, but provides a level of +// Typescript build protection for the audit log feature, any new event also needs to be +// added to this map, during which the developer will need to consider if it should be +// a user facing event or not. +export const AuditedEventFriendlyName: Record = { // USER - static USER_CREATED = "User {{ email }} created" - static USER_UPDATED = "User {{ email }} updated" - static USER_DELETED = "User {{ email }} deleted" - static USER_PERMISSION_ADMIN_ASSIGNED = "User {{ email }} admin role assigned" - static USER_PERMISSION_ADMIN_REMOVED = "User {{ email }} admin role removed" - static USER_PERMISSION_BUILDER_ASSIGNED = - "User {{ email }} builder role assigned" - static USER_PERMISSION_BUILDER_REMOVED = - "User {{ email }} builder role removed" - static USER_INVITED = "User {{ email }} invited" - static USER_INVITED_ACCEPTED = "User {{ email }} accepted invite" - static USER_PASSWORD_UPDATED = "User {{ email }} password updated" - static USER_PASSWORD_RESET_REQUESTED = - "User {{ email }} password reset requested" - static USER_PASSWORD_RESET = "User {{ email }} password reset" - static USER_GROUP_CREATED = "User group {{ name }} created" - static USER_GROUP_UPDATED = "User group {{ name }} updated" - static USER_GROUP_DELETED = "User group {{ name }} deleted" - static USER_GROUP_USERS_ADDED = - "User group {{ name }} {{ count }} users added" - static USER_GROUP_USERS_REMOVED = - "User group {{ name }} {{ count }} users removed" - static USER_GROUP_PERMISSIONS_EDITED = - "User group {{ name }} permissions edited" + [Event.USER_CREATED]: `User "{{ email }}" created`, + [Event.USER_UPDATED]: `User "{{ email }}" updated`, + [Event.USER_DELETED]: `User "{{ email }}" deleted`, + [Event.USER_PERMISSION_ADMIN_ASSIGNED]: `User "{{ email }}" admin role assigned`, + [Event.USER_PERMISSION_ADMIN_REMOVED]: `User "{{ email }}" admin role removed`, + [Event.USER_PERMISSION_BUILDER_ASSIGNED]: `User "{{ email }}" builder role assigned`, + [Event.USER_PERMISSION_BUILDER_REMOVED]: `User "{{ email }}" builder role removed`, + [Event.USER_INVITED]: `User "{{ email }} invited`, + [Event.USER_INVITED_ACCEPTED]: `User "{{ email }}" accepted invite`, + [Event.USER_PASSWORD_UPDATED]: `User "{{ email }}" password updated`, + [Event.USER_PASSWORD_RESET_REQUESTED]: `User "{{ email }}" password reset requested`, + [Event.USER_PASSWORD_RESET]: `User "{{ email }}" password reset`, + [Event.USER_GROUP_CREATED]: `User group "{{ name }}" created`, + [Event.USER_GROUP_UPDATED]: `User group "{{ name }}" updated`, + [Event.USER_GROUP_DELETED]: `User group "{{ name }}" deleted`, + [Event.USER_GROUP_USERS_ADDED]: `User group "{{ name }}" {{ count }} users added`, + [Event.USER_GROUP_USERS_REMOVED]: `User group "{{ name }}" {{ count }} users removed`, + [Event.USER_GROUP_PERMISSIONS_EDITED]: `User group "{{ name }}" permissions edited`, + [Event.USER_PASSWORD_FORCE_RESET]: undefined, + [Event.USER_GROUP_ONBOARDING]: undefined, + [Event.USER_ONBOARDING_COMPLETE]: undefined, // EMAIL - static EMAIL_SMTP_CREATED = "Email configuration created" - static EMAIL_SMTP_UPDATED = "Email configuration updated" + [Event.EMAIL_SMTP_CREATED]: `Email configuration created`, + [Event.EMAIL_SMTP_UPDATED]: `Email configuration updated`, // AUTH - static AUTH_SSO_CREATED = "SSO configuration created" - static AUTH_SSO_UPDATED = "SSO configuration updated" - static AUTH_SSO_ACTIVATED = "SSO configuration activated" - static AUTH_SSO_DEACTIVATED = "SSO configuration deactivated" - static AUTH_LOGIN = "User {{ email }} logged in" - static AUTH_LOGOUT = "User {{ email }} logged out" + [Event.AUTH_SSO_CREATED]: `SSO configuration created`, + [Event.AUTH_SSO_UPDATED]: `SSO configuration updated`, + [Event.AUTH_SSO_ACTIVATED]: `SSO configuration activated`, + [Event.AUTH_SSO_DEACTIVATED]: `SSO configuration deactivated`, + [Event.AUTH_LOGIN]: `User "{{ email }}" logged in`, + [Event.AUTH_LOGOUT]: `User "{{ email }}" logged out`, // ORG - static ORG_NAME_UPDATED = "Organisation name updated" - static ORG_LOGO_UPDATED = "Organisation logo updated" - static ORG_PLATFORM_URL_UPDATED = "Organisation platform URL updated" + [Event.ORG_NAME_UPDATED]: `Organisation name updated`, + [Event.ORG_LOGO_UPDATED]: `Organisation logo updated`, + [Event.ORG_PLATFORM_URL_UPDATED]: `Organisation platform URL updated`, // APP - static APP_CREATED = "App {{ name }} created" - static APP_UPDATED = "App {{ name }} updated" - static APP_DELETED = "App {{ name }} deleted" - static APP_PUBLISHED = "App {{ name }} published" - static APP_UNPUBLISHED = "App {{ name }} unpublished" - static APP_TEMPLATE_IMPORTED = "App {{ name }} template imported" - static APP_FILE_IMPORTED = "App {{ name }} file imported" - static APP_VERSION_UPDATED = "App {{ name }} version updated" - static APP_VERSION_REVERTED = "App {{ name }} version reverted" - static APP_REVERTED = "App {{ name }} reverted" - static APP_EXPORTED = "App {{ name }} exported" - static APP_BACKUP_RESTORED = "App backup {{ name }} restored" - static APP_BACKUP_TRIGGERED = "App backup {{ name }} triggered" + [Event.APP_CREATED]: `App "{{ name }}" created`, + [Event.APP_UPDATED]: `App "{{ name }}" updated`, + [Event.APP_DELETED]: `App "{{ name }}" deleted`, + [Event.APP_PUBLISHED]: `App "{{ name }}" published`, + [Event.APP_UNPUBLISHED]: `App "{{ name }}" unpublished`, + [Event.APP_TEMPLATE_IMPORTED]: `App "{{ name }}" template imported`, + [Event.APP_FILE_IMPORTED]: `App "{{ name }}" file imported`, + [Event.APP_VERSION_UPDATED]: `App "{{ name }}" version updated`, + [Event.APP_VERSION_REVERTED]: `App "{{ name }}" version reverted`, + [Event.APP_REVERTED]: `App "{{ name }}" reverted`, + [Event.APP_EXPORTED]: `App "{{ name }}" exported`, + [Event.APP_BACKUP_RESTORED]: `App backup "{{ name }}" restored`, + [Event.APP_BACKUP_TRIGGERED]: `App backup "{{ name }}" triggered`, // DATASOURCE - static DATASOURCE_CREATED = "Datasource created" - static DATASOURCE_UPDATED = "Datasource updated" - static DATASOURCE_DELETED = "Datasource deleted" + [Event.DATASOURCE_CREATED]: `Datasource created`, + [Event.DATASOURCE_UPDATED]: `Datasource updated`, + [Event.DATASOURCE_DELETED]: `Datasource deleted`, // QUERY - static QUERY_CREATED = "Query created" - static QUERY_UPDATED = "Query updated" - static QUERY_DELETED = "Query deleted" - static QUERY_IMPORT = "Query import" + [Event.QUERY_CREATED]: `Query created`, + [Event.QUERY_UPDATED]: `Query updated`, + [Event.QUERY_DELETED]: `Query deleted`, + [Event.QUERY_IMPORT]: `Query import`, + [Event.QUERIES_RUN]: undefined, + [Event.QUERY_PREVIEWED]: undefined, // TABLE - static TABLE_CREATED = "Table created" - static TABLE_UPDATED = "Table updated" - static TABLE_DELETED = "Table deleted" - static TABLE_EXPORTED = "Table exported" - static TABLE_IMPORTED = "Table imported" - static TABLE_DATA_IMPORTED = "Data imported to table" + [Event.TABLE_CREATED]: `Table created`, + [Event.TABLE_UPDATED]: `Table updated`, + [Event.TABLE_DELETED]: `Table deleted`, + [Event.TABLE_EXPORTED]: `Table exported`, + [Event.TABLE_IMPORTED]: `Table imported`, + [Event.TABLE_DATA_IMPORTED]: `Data imported to table`, // ROWS - static ROWS_CREATED = "Rows created" - static ROWS_IMPORTED = "Rows imported" + [Event.ROWS_CREATED]: `Rows created`, + [Event.ROWS_IMPORTED]: `Rows imported`, // AUTOMATION - static AUTOMATION_CREATED = "Automation created" - static AUTOMATION_DELETED = "Automation deleted" + [Event.AUTOMATION_CREATED]: `Automation created`, + [Event.AUTOMATION_DELETED]: `Automation deleted`, + [Event.AUTOMATION_TESTED]: undefined, + [Event.AUTOMATIONS_RUN]: undefined, + [Event.AUTOMATION_STEP_CREATED]: undefined, + [Event.AUTOMATION_STEP_DELETED]: undefined, + [Event.AUTOMATION_TRIGGER_UPDATED]: undefined, // SCREEN - static SCREEN_CREATED = "Screen created" - static SCREEN_DELETED = "Screen deleted" + [Event.SCREEN_CREATED]: `Screen created`, + [Event.SCREEN_DELETED]: `Screen deleted`, // COMPONENT - static COMPONENT_CREATED = "Component created" - static COMPONENT_DELETED = "Component deleted" + [Event.COMPONENT_CREATED]: `Component created`, + [Event.COMPONENT_DELETED]: `Component deleted`, - static ENVIRONMENT_VARIABLE_CREATED = "Environment variable created" - static ENVIRONMENT_VARIABLE_DELETED = "Environment variable deleted" + // ENVIRONMENT VARIABLE + [Event.ENVIRONMENT_VARIABLE_CREATED]: `Environment variable created`, + [Event.ENVIRONMENT_VARIABLE_DELETED]: `Environment variable deleted`, + [Event.ENVIRONMENT_VARIABLE_UPGRADE_PANEL_OPENED]: undefined, + + // PLUGIN + [Event.PLUGIN_IMPORTED]: `Plugin imported`, + [Event.PLUGIN_DELETED]: `Plugin deleted`, + [Event.PLUGIN_INIT]: undefined, + + // ROLE - NOT AUDITED + [Event.ROLE_CREATED]: undefined, + [Event.ROLE_UPDATED]: undefined, + [Event.ROLE_DELETED]: undefined, + [Event.ROLE_ASSIGNED]: undefined, + [Event.ROLE_UNASSIGNED]: undefined, + + // LICENSE - NOT AUDITED + [Event.LICENSE_PLAN_CHANGED]: undefined, + [Event.LICENSE_TIER_CHANGED]: undefined, + [Event.LICENSE_ACTIVATED]: undefined, + [Event.LICENSE_PAYMENT_FAILED]: undefined, + [Event.LICENSE_PAYMENT_RECOVERED]: undefined, + [Event.LICENSE_CHECKOUT_OPENED]: undefined, + [Event.LICENSE_CHECKOUT_SUCCESS]: undefined, + [Event.LICENSE_PORTAL_OPENED]: undefined, + + // ACCOUNT - NOT AUDITED + [Event.ACCOUNT_CREATED]: undefined, + [Event.ACCOUNT_DELETED]: undefined, + [Event.ACCOUNT_VERIFIED]: undefined, + + // BACKFILL - NOT AUDITED + [Event.APP_BACKFILL_SUCCEEDED]: undefined, + [Event.APP_BACKFILL_FAILED]: undefined, + [Event.TENANT_BACKFILL_SUCCEEDED]: undefined, + [Event.TENANT_BACKFILL_FAILED]: undefined, + [Event.INSTALLATION_BACKFILL_SUCCEEDED]: undefined, + [Event.INSTALLATION_BACKFILL_FAILED]: undefined, + + // LAYOUT - NOT AUDITED + [Event.LAYOUT_CREATED]: undefined, + [Event.LAYOUT_DELETED]: undefined, + + // VIEW - NOT AUDITED + [Event.VIEW_CREATED]: undefined, + [Event.VIEW_UPDATED]: undefined, + [Event.VIEW_DELETED]: undefined, + [Event.VIEW_EXPORTED]: undefined, + [Event.VIEW_FILTER_CREATED]: undefined, + [Event.VIEW_FILTER_UPDATED]: undefined, + [Event.VIEW_FILTER_DELETED]: undefined, + [Event.VIEW_CALCULATION_CREATED]: undefined, + [Event.VIEW_CALCULATION_UPDATED]: undefined, + [Event.VIEW_CALCULATION_DELETED]: undefined, + + // SERVED - NOT AUDITED + [Event.SERVED_BUILDER]: undefined, + [Event.SERVED_APP]: undefined, + [Event.SERVED_APP_PREVIEW]: undefined, + + // ANALYTICS - NOT AUDITED + [Event.ANALYTICS_OPT_OUT]: undefined, + [Event.ANALYTICS_OPT_IN]: undefined, + + // INSTALLATION - NOT AUDITED + [Event.INSTALLATION_VERSION_CHECKED]: undefined, + [Event.INSTALLATION_VERSION_UPGRADED]: undefined, + [Event.INSTALLATION_VERSION_DOWNGRADED]: undefined, + [Event.INSTALLATION_FIRST_STARTUP]: undefined, } // properties added at the final stage of the event pipeline diff --git a/scripts/link-dependencies.sh b/scripts/link-dependencies.sh index d2a501162b..9926f3dd2b 100755 --- a/scripts/link-dependencies.sh +++ b/scripts/link-dependencies.sh @@ -44,6 +44,9 @@ if [ -d "../budibase-pro" ]; then echo "Linking types to pro" yarn link '@budibase/types' + echo "Linking string-templates to pro" + yarn link '@budibase/string-templates' + cd ../../../budibase echo "Linking pro to worker" From a1b47bbce375d734dcc2cb82d666f86e4e788703 Mon Sep 17 00:00:00 2001 From: Peter Clement Date: Fri, 17 Feb 2023 16:49:41 +0000 Subject: [PATCH 014/106] ensure table is pulling from search endpoint --- packages/bbui/src/Form/Core/Picker.svelte | 1 - .../auditLogs/_components/TimeRenderer.svelte | 12 + .../auditLogs/_components/UserRenderer.svelte | 2 +- .../portal/account/auditLogs/index.svelte | 213 ++++++++++++++---- .../portal/settings/environment/index.svelte | 1 - .../builder/src/stores/portal/auditLogs.js | 2 +- packages/builder/src/stores/portal/index.js | 1 + packages/frontend-core/src/api/auditLogs.js | 6 +- 8 files changed, 188 insertions(+), 50 deletions(-) create mode 100644 packages/builder/src/pages/builder/portal/account/auditLogs/_components/TimeRenderer.svelte diff --git a/packages/bbui/src/Form/Core/Picker.svelte b/packages/bbui/src/Form/Core/Picker.svelte index acd3c5da61..fb0ce00824 100644 --- a/packages/bbui/src/Form/Core/Picker.svelte +++ b/packages/bbui/src/Form/Core/Picker.svelte @@ -32,7 +32,6 @@ export let autocomplete = false export let sort = false export let fetchTerm = null - $: console.log(fieldText) const dispatch = createEventDispatcher() let searchTerm = null diff --git a/packages/builder/src/pages/builder/portal/account/auditLogs/_components/TimeRenderer.svelte b/packages/builder/src/pages/builder/portal/account/auditLogs/_components/TimeRenderer.svelte new file mode 100644 index 0000000000..7ec044604e --- /dev/null +++ b/packages/builder/src/pages/builder/portal/account/auditLogs/_components/TimeRenderer.svelte @@ -0,0 +1,12 @@ + + +
+ {dayjs(row.date).fromNow()} +
diff --git a/packages/builder/src/pages/builder/portal/account/auditLogs/_components/UserRenderer.svelte b/packages/builder/src/pages/builder/portal/account/auditLogs/_components/UserRenderer.svelte index 4baa24403e..c9a69b4316 100644 --- a/packages/builder/src/pages/builder/portal/account/auditLogs/_components/UserRenderer.svelte +++ b/packages/builder/src/pages/builder/portal/account/auditLogs/_components/UserRenderer.svelte @@ -3,4 +3,4 @@ export let row - + diff --git a/packages/builder/src/pages/builder/portal/account/auditLogs/index.svelte b/packages/builder/src/pages/builder/portal/account/auditLogs/index.svelte index a5d403491a..88f042d240 100644 --- a/packages/builder/src/pages/builder/portal/account/auditLogs/index.svelte +++ b/packages/builder/src/pages/builder/portal/account/auditLogs/index.svelte @@ -2,26 +2,28 @@ import { Layout, Table, - Select, Search, Multiselect, notifications, + Icon, + clickOutside, + CoreTextArea, + DatePicker, } from "@budibase/bbui" - import { licensing, users, apps } from "stores/portal" + import { licensing, users, apps, auditLogs } from "stores/portal" import LockedFeature from "../../_components/LockedFeature.svelte" import { createPaginationStore } from "helpers/pagination" - import { getContext, setContext } from "svelte" - import Portal from "svelte-portal" + import { setContext } from "svelte" import ViewDetailsRenderer from "./_components/ViewDetailsRenderer.svelte" import UserRenderer from "./_components/UserRenderer.svelte" + import TimeRenderer from "./_components/TimeRenderer.svelte" - const sidePanel = getContext("side-panel") const schema = { - name: {}, - date: {}, - user: { width: "auto" }, - app: {}, - event: {}, + name: { width: "1fr" }, + date: { width: "1.5fr" }, + user: { width: "0.5fr" }, + app: { width: "1fr" }, + event: { width: "1fr" }, view: { width: "auto", borderLeft: true, displayName: "" }, } @@ -34,18 +36,29 @@ column: "user", component: UserRenderer, }, + { + column: "date", + component: TimeRenderer, + }, ] - let searchTerm = "" - let pageInfo = createPaginationStore() - let prevSearch = undefined + let userSearchTerm = "" + let logSearchTerm = "" + let userPageInfo = createPaginationStore() + let logsPageInfo = createPaginationStore() + + let prevUserSearch = undefined + let prevLogSearch = undefined let selectedUsers = [] + let selectedApps = [] let selectedLog + let sidePanelVisible = false + let startDate, endDate let data = [ { name: "User created", - date: "2021-03-01 12:00:00", + date: "2023-02-14T10:19:52.021Z", user: "Peter Clement", app: "School Admin Panel", event: "User added", @@ -56,30 +69,61 @@ }, ] - $: fetchUsers(page, searchTerm) - $: page = $pageInfo.page + $: fetchUsers(userPage, userSearchTerm) + $: fetchLogs(logsPage, logSearchTerm) + + $: userPage = $userPageInfo.page + $: logsPage = $logsPageInfo.page + $: enrichedList = enrich($users.data || [], selectedUsers) $: sortedList = sort(enrichedList) - const fetchUsers = async (page, search) => { - if ($pageInfo.loading) { + const fetchUsers = async (userPage, search) => { + if ($userPageInfo.loading) { return } // need to remove the page if they've started searching - if (search && !prevSearch) { - pageInfo.reset() - page = undefined + if (search && !prevUserSearch) { + userPageInfo.reset() + userPage = undefined } - prevSearch = search + prevUserSearch = search try { - pageInfo.loading() - await users.search({ page, email: search }) - pageInfo.fetched($users.hasNextPage, $users.nextPage) + userPageInfo.loading() + await users.search({ userPage, email: search }) + userPageInfo.fetched($users.hasNextPage, $users.nextPage) } catch (error) { notifications.error("Error getting user list") } } + const fetchLogs = async (logsPage, search) => { + if ($logsPageInfo.loading) { + return + } + // need to remove the page if they've started searching + if (search && !prevLogSearch) { + logsPageInfo.reset() + logsPage = undefined + } + prevLogSearch = search + try { + logsPageInfo.loading() + await auditLogs.search({ + logsPage, + startDate, + endDate, + metadataSearch: search, + userIds: selectedUsers, + appIds: selectedApps, + }) + logsPageInfo.fetched($auditLogs.hasNextPage, $auditLogs.nextPage) + } catch (error) { + console.log(error) + notifications.error("Error getting audit logs") + } + } + const enrich = (list, selected) => { return list.map(item => { return { @@ -106,7 +150,21 @@ const viewDetails = detail => { selectedLog = detail - sidePanel.open() + sidePanelVisible = true + } + + const downloadLogs = async () => { + try { + await auditLogs.download({ + startDate, + endDate, + metadataSearch: logSearchTerm, + userIds: selectedUsers, + appIds: selectedApps, + }) + } catch (error) { + notifications.error(`Error downloading logs: ` + error.message) + } } setContext("auditLogs", { @@ -123,14 +181,25 @@ $licensing.goToUpgradePage() }} > +
+
Audit Logs { sidePanelVisible = false }} @@ -263,7 +283,6 @@
{ + return { ...state, logs: { ...paged, opts } } }) + return paged } } async function getEventDefinitions() { - return await API.getEventDefinitions() + const events = await API.getEventDefinitions() + + update(state => { + return { ...state, ...events } + }) + + console.log(events) } async function downloadLogs(opts = {}) { From e223fae02a47704814481d0feb6c15a7f4125bcc Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Tue, 21 Feb 2023 12:24:43 +0000 Subject: [PATCH 020/106] Updating types to plurals after discussion about API design. --- packages/types/src/api/web/global/auditLogs.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/types/src/api/web/global/auditLogs.ts b/packages/types/src/api/web/global/auditLogs.ts index ef9927b89a..41bb5f022a 100644 --- a/packages/types/src/api/web/global/auditLogs.ts +++ b/packages/types/src/api/web/global/auditLogs.ts @@ -3,9 +3,9 @@ import { PaginationResponse, PaginationRequest } from "../" import { User, App } from "../../../" export interface AuditLogSearchParams { - userId?: string[] - appId?: string[] - event?: Event[] + userIds?: string[] + appIds?: string[] + events?: Event[] startDate?: string endDate?: string fullSearch?: string From 0f26f55019679014dc9de10872a15eea2edbb3c0 Mon Sep 17 00:00:00 2001 From: Peter Clement Date: Tue, 21 Feb 2023 12:31:21 +0000 Subject: [PATCH 021/106] some style updates for the sidebar --- .../_components/ViewDetailsRenderer.svelte | 2 +- .../portal/account/auditLogs/index.svelte | 61 +++++++++++++++---- packages/frontend-core/src/api/auditLogs.js | 6 +- 3 files changed, 54 insertions(+), 15 deletions(-) diff --git a/packages/builder/src/pages/builder/portal/account/auditLogs/_components/ViewDetailsRenderer.svelte b/packages/builder/src/pages/builder/portal/account/auditLogs/_components/ViewDetailsRenderer.svelte index a222871966..b62ee48cb8 100644 --- a/packages/builder/src/pages/builder/portal/account/auditLogs/_components/ViewDetailsRenderer.svelte +++ b/packages/builder/src/pages/builder/portal/account/auditLogs/_components/ViewDetailsRenderer.svelte @@ -10,4 +10,4 @@ } -Edit +Details diff --git a/packages/builder/src/pages/builder/portal/account/auditLogs/index.svelte b/packages/builder/src/pages/builder/portal/account/auditLogs/index.svelte index 09b8466d8e..821e504774 100644 --- a/packages/builder/src/pages/builder/portal/account/auditLogs/index.svelte +++ b/packages/builder/src/pages/builder/portal/account/auditLogs/index.svelte @@ -55,8 +55,10 @@ let prevLogSearch = undefined let selectedUsers = [] let selectedApps = [] + let selectedEvents = [] let selectedLog let sidePanelVisible = false + let wideSidePanel = false let startDate, endDate $: fetchUsers(userPage, userSearchTerm) @@ -66,7 +68,8 @@ startDate, endDate, selectedUsers, - selectedApps + selectedApps, + selectedEvents ) $: userPage = $userPageInfo.page @@ -100,7 +103,8 @@ startDate, endDate, selectedUsers, - selectedApps + selectedApps, + selectedEvents ) => { if ($logsPageInfo.loading) { return @@ -120,6 +124,7 @@ metadataSearch: search, userIds: selectedUsers, appIds: selectedApps, + events: selectedEvents, }) logsPageInfo.fetched( $auditLogs.logs.hasNextPage, @@ -225,7 +230,7 @@ autocomplete placeholder="All apps" label="App" - getOptionValue={app => "app_dev_" + app.appId} + getOptionValue={app => app.instance._id} getOptionLabel={app => app.name} options={$apps} bind:value={selectedApps} @@ -239,6 +244,7 @@ options={Object.entries($auditLogs.events)} placeholder="All events" label="Event" + bind:value={selectedEvents} />
@@ -266,23 +272,35 @@ {#if selectedLog}
{ sidePanelVisible = false }} >
- Audit Logs - { - sidePanelVisible = false - }} - /> + Audit Log +
+ { + wideSidePanel = !wideSidePanel + }} + /> + { + sidePanelVisible = false + }} + /> +
{ const opts = {} @@ -17,8 +17,8 @@ const buildOpts = ({ opts.metadataSearch = metadataSearch } - if (event) { - opts.event = event + if (events) { + opts.event = events } if (userIds) { From b48acd8cf4ad375eb7ae37d219795eb481421cfc Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Tue, 21 Feb 2023 14:56:38 +0000 Subject: [PATCH 022/106] Some DB type updates (typing dump function) and adding in main audit log event publishers. --- .../src/events/publishers/auditLog.ts | 26 +++++++++++++++++++ .../src/events/publishers/index.ts | 1 + .../types/src/api/web/global/auditLogs.ts | 9 +++++-- packages/types/src/api/web/pagination.ts | 7 +++-- packages/types/src/sdk/db.ts | 15 ++++++++++- packages/types/src/sdk/events/auditLog.ts | 10 +++++++ packages/types/src/sdk/events/event.ts | 8 ++++++ packages/types/src/sdk/events/index.ts | 1 + 8 files changed, 72 insertions(+), 5 deletions(-) create mode 100644 packages/backend-core/src/events/publishers/auditLog.ts create mode 100644 packages/types/src/sdk/events/auditLog.ts diff --git a/packages/backend-core/src/events/publishers/auditLog.ts b/packages/backend-core/src/events/publishers/auditLog.ts new file mode 100644 index 0000000000..b72c135799 --- /dev/null +++ b/packages/backend-core/src/events/publishers/auditLog.ts @@ -0,0 +1,26 @@ +import { + Event, + AuditLogSearchParams, + AuditLogFilterEvent, + AuditLogDownloadEvent, +} from "@budibase/types" +import { publishEvent } from "../events" + +async function filtered(search: AuditLogSearchParams) { + const properties: AuditLogFilterEvent = { + filters: search, + } + await publishEvent(Event.AUDIT_LOG_FILTER, properties) +} + +async function download(search: AuditLogSearchParams) { + const properties: AuditLogDownloadEvent = { + filters: search, + } + await publishEvent(Event.AUDIT_LOG_DOWNLOAD, properties) +} + +export default { + filtered, + download, +} diff --git a/packages/backend-core/src/events/publishers/index.ts b/packages/backend-core/src/events/publishers/index.ts index 34e47b2990..87a34bf3f1 100644 --- a/packages/backend-core/src/events/publishers/index.ts +++ b/packages/backend-core/src/events/publishers/index.ts @@ -21,3 +21,4 @@ export { default as group } from "./group" export { default as plugin } from "./plugin" export { default as backup } from "./backup" export { default as environmentVariable } from "./environmentVariable" +export { default as auditLog } from "./auditLog" diff --git a/packages/types/src/api/web/global/auditLogs.ts b/packages/types/src/api/web/global/auditLogs.ts index 41bb5f022a..8ce0e742d2 100644 --- a/packages/types/src/api/web/global/auditLogs.ts +++ b/packages/types/src/api/web/global/auditLogs.ts @@ -1,5 +1,9 @@ import { Event, AuditedEventFriendlyName } from "../../../sdk" -import { PaginationResponse, PaginationRequest } from "../" +import { + PaginationResponse, + PaginationRequest, + BasicPaginationRequest, +} from "../" import { User, App } from "../../../" export interface AuditLogSearchParams { @@ -9,12 +13,13 @@ export interface AuditLogSearchParams { startDate?: string endDate?: string fullSearch?: string + bookmark?: string } export interface DownloadAuditLogsRequest extends AuditLogSearchParams {} export interface SearchAuditLogsRequest - extends PaginationRequest, + extends BasicPaginationRequest, AuditLogSearchParams {} export enum AuditLogResourceStatus { diff --git a/packages/types/src/api/web/pagination.ts b/packages/types/src/api/web/pagination.ts index ca640d58db..ae4c56971a 100644 --- a/packages/types/src/api/web/pagination.ts +++ b/packages/types/src/api/web/pagination.ts @@ -8,9 +8,12 @@ export enum SortType { number = "number", } -export interface PaginationRequest { - limit?: number +export interface BasicPaginationRequest { bookmark?: string +} + +export interface PaginationRequest extends BasicPaginationRequest { + limit?: number sort?: { order: SortOrder column: string diff --git a/packages/types/src/sdk/db.ts b/packages/types/src/sdk/db.ts index 35d198ccb2..092253d63a 100644 --- a/packages/types/src/sdk/db.ts +++ b/packages/types/src/sdk/db.ts @@ -1,5 +1,6 @@ import Nano from "@budibase/nano" import { AllDocsResponse, AnyDocument, Document } from "../" +import { Writable } from "stream" export type PouchOptions = { inMemory?: boolean @@ -63,6 +64,18 @@ export const isDocument = (doc: any): doc is Document => { return typeof doc === "object" && doc._id && doc._rev } +export interface DatabaseDumpOpts { + filter?: (doc: AnyDocument) => boolean + batch_size?: number + batch_limit?: number + style?: "main_only" | "all_docs" + timeout?: number + doc_ids?: string[] + query_params?: any + view?: string + selector?: any +} + export interface Database { name: string @@ -87,7 +100,7 @@ export interface Database { compact(): Promise // these are all PouchDB related functions that are rarely used - in future // should be replaced by better typed/non-pouch implemented methods - dump(...args: any[]): Promise + dump(stream: Writable, opts?: DatabaseDumpOpts): Promise load(...args: any[]): Promise createIndex(...args: any[]): Promise deleteIndex(...args: any[]): Promise diff --git a/packages/types/src/sdk/events/auditLog.ts b/packages/types/src/sdk/events/auditLog.ts new file mode 100644 index 0000000000..c5e3208536 --- /dev/null +++ b/packages/types/src/sdk/events/auditLog.ts @@ -0,0 +1,10 @@ +import { BaseEvent } from "./event" +import { AuditLogSearchParams } from "../../api" + +export interface AuditLogFilterEvent extends BaseEvent { + filters: AuditLogSearchParams +} + +export interface AuditLogDownloadEvent extends BaseEvent { + filters: AuditLogSearchParams +} diff --git a/packages/types/src/sdk/events/event.ts b/packages/types/src/sdk/events/event.ts index 1be0ea2bdf..119ae4ad7a 100644 --- a/packages/types/src/sdk/events/event.ts +++ b/packages/types/src/sdk/events/event.ts @@ -180,6 +180,10 @@ export enum Event { ENVIRONMENT_VARIABLE_CREATED = "environment_variable:created", ENVIRONMENT_VARIABLE_DELETED = "environment_variable:deleted", ENVIRONMENT_VARIABLE_UPGRADE_PANEL_OPENED = "environment_variable:upgrade_panel_opened", + + // AUDIT LOG + AUDIT_LOG_FILTER = "audit_log:filter", + AUDIT_LOG_DOWNLOAD = "audit_log:download", } // all events that are not audited have been added to this record as undefined, this means @@ -356,6 +360,10 @@ export const AuditedEventFriendlyName: Record = { [Event.INSTALLATION_VERSION_UPGRADED]: undefined, [Event.INSTALLATION_VERSION_DOWNGRADED]: undefined, [Event.INSTALLATION_FIRST_STARTUP]: undefined, + + // AUDIT LOG - NOT AUDITED + [Event.AUDIT_LOG_FILTER]: undefined, + [Event.AUDIT_LOG_DOWNLOAD]: undefined, } // properties added at the final stage of the event pipeline diff --git a/packages/types/src/sdk/events/index.ts b/packages/types/src/sdk/events/index.ts index 009d9beac4..745f84d2a3 100644 --- a/packages/types/src/sdk/events/index.ts +++ b/packages/types/src/sdk/events/index.ts @@ -22,3 +22,4 @@ export * from "./userGroup" export * from "./plugin" export * from "./backup" export * from "./environmentVariable" +export * from "./auditLog" From 1ada790d507b76e4d2cb133a98465dc07b0b1b36 Mon Sep 17 00:00:00 2001 From: adrinr Date: Tue, 21 Feb 2023 15:21:00 +0000 Subject: [PATCH 023/106] Fix postgres update for relationships --- packages/server/src/integrations/base/sql.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/server/src/integrations/base/sql.ts b/packages/server/src/integrations/base/sql.ts index e66795a6db..c722891910 100644 --- a/packages/server/src/integrations/base/sql.ts +++ b/packages/server/src/integrations/base/sql.ts @@ -502,9 +502,7 @@ class InternalBuilder { if (opts.disableReturning) { return query.update(parsedBody) } else { - return query - .update(parsedBody) - .returning(generateSelectStatement(json, knex)) + return query.update(parsedBody).returning("*") } } From e0b3976ee4338b543765bf6952726bae509606df Mon Sep 17 00:00:00 2001 From: adrinr Date: Tue, 21 Feb 2023 15:57:04 +0000 Subject: [PATCH 024/106] Add return select statement back on update --- packages/server/src/integrations/base/sql.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/server/src/integrations/base/sql.ts b/packages/server/src/integrations/base/sql.ts index c722891910..e66795a6db 100644 --- a/packages/server/src/integrations/base/sql.ts +++ b/packages/server/src/integrations/base/sql.ts @@ -502,7 +502,9 @@ class InternalBuilder { if (opts.disableReturning) { return query.update(parsedBody) } else { - return query.update(parsedBody).returning("*") + return query + .update(parsedBody) + .returning(generateSelectStatement(json, knex)) } } From be81767a465af3edd7c90514f42c0b8f28d2b0d0 Mon Sep 17 00:00:00 2001 From: adrinr Date: Tue, 21 Feb 2023 15:57:56 +0000 Subject: [PATCH 025/106] Replace maps for foreach --- packages/server/src/api/controllers/row/ExternalRequest.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/server/src/api/controllers/row/ExternalRequest.ts b/packages/server/src/api/controllers/row/ExternalRequest.ts index 2faff95595..6e79971aa2 100644 --- a/packages/server/src/api/controllers/row/ExternalRequest.ts +++ b/packages/server/src/api/controllers/row/ExternalRequest.ts @@ -293,7 +293,7 @@ export class ExternalRequest { // we're not inserting a doc, will be a bunch of update calls const otherKey: string = field.throughFrom || linkTablePrimary const thisKey: string = field.throughTo || tablePrimary - row[key].map((relationship: any) => { + row[key].forEach((relationship: any) => { manyRelationships.push({ tableId: field.through || field.tableId, isUpdate: false, @@ -309,7 +309,7 @@ export class ExternalRequest { const thisKey: string = "id" // @ts-ignore const otherKey: string = field.fieldName - row[key].map((relationship: any) => { + row[key].forEach((relationship: any) => { manyRelationships.push({ tableId: field.tableId, isUpdate: true, From e0242d08832bfa25167c050780f5ed16b76405b2 Mon Sep 17 00:00:00 2001 From: adrinr Date: Tue, 21 Feb 2023 16:29:18 +0000 Subject: [PATCH 026/106] Fix the many to one updates --- packages/server/src/api/controllers/row/ExternalRequest.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/server/src/api/controllers/row/ExternalRequest.ts b/packages/server/src/api/controllers/row/ExternalRequest.ts index 6e79971aa2..f62e7fe2d0 100644 --- a/packages/server/src/api/controllers/row/ExternalRequest.ts +++ b/packages/server/src/api/controllers/row/ExternalRequest.ts @@ -316,7 +316,7 @@ export class ExternalRequest { key: otherKey, [thisKey]: breakRowIdField(relationship)[0], // leave the ID for enrichment later - [otherKey]: `{{ literal ${tablePrimary} }}`, + [otherKey]: `{{ literal [${table.name}.${tablePrimary}] }}`, }) }) } From 41eb0c3964727861937f36ac30930547c76031f9 Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Tue, 21 Feb 2023 17:22:23 +0000 Subject: [PATCH 027/106] Updating worker db config to have replication available (for audit logs). --- packages/server/src/db/index.ts | 4 ++-- packages/worker/src/db/index.ts | 10 ++++++++-- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/packages/server/src/db/index.ts b/packages/server/src/db/index.ts index fa8027dcc1..157c2f4fb3 100644 --- a/packages/server/src/db/index.ts +++ b/packages/server/src/db/index.ts @@ -1,4 +1,4 @@ -import { init as coreInit } from "@budibase/backend-core" +import * as core from "@budibase/backend-core" import env from "../environment" export function init() { @@ -12,5 +12,5 @@ export function init() { dbConfig.allDbs = true } - coreInit({ db: dbConfig }) + core.init({ db: dbConfig }) } diff --git a/packages/worker/src/db/index.ts b/packages/worker/src/db/index.ts index d74d00d910..157c2f4fb3 100644 --- a/packages/worker/src/db/index.ts +++ b/packages/worker/src/db/index.ts @@ -1,10 +1,16 @@ import * as core from "@budibase/backend-core" import env from "../environment" -export const init = () => { - const dbConfig: any = {} +export function init() { + const dbConfig: any = { + replication: true, + find: true, + } + if (env.isTest() && !env.COUCH_DB_URL) { dbConfig.inMemory = true + dbConfig.allDbs = true } + core.init({ db: dbConfig }) } From 22f42ef898ce57b42cf6ac158cfb748fbc0d445c Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Tue, 21 Feb 2023 19:14:57 +0000 Subject: [PATCH 028/106] Adding new mechanism to get the ipAddress and userAgent of call for audit logs. --- packages/backend-core/src/context/identity.ts | 13 ++++- packages/backend-core/src/events/events.ts | 52 +++++++++++++++---- .../backend-core/src/events/identification.ts | 1 + .../src/middleware/authenticated.ts | 6 +-- packages/backend-core/src/queue/constants.ts | 1 + packages/frontend-core/src/api/auditLogs.js | 6 +-- packages/server/package.json | 1 + packages/server/src/app.ts | 2 + packages/server/yarn.lock | 12 +++++ packages/types/src/sdk/auditLogs.ts | 3 +- packages/types/src/sdk/context.ts | 3 +- .../types/src/sdk/events/identification.ts | 6 +++ packages/worker/package.json | 1 + .../worker/src/api/controllers/global/auth.ts | 6 +-- packages/worker/src/index.ts | 3 ++ packages/worker/yarn.lock | 12 +++++ 16 files changed, 104 insertions(+), 24 deletions(-) diff --git a/packages/backend-core/src/context/identity.ts b/packages/backend-core/src/context/identity.ts index 648dd1b5fd..84de3b68c9 100644 --- a/packages/backend-core/src/context/identity.ts +++ b/packages/backend-core/src/context/identity.ts @@ -5,6 +5,8 @@ import { isCloudAccount, Account, AccountUserContext, + UserContext, + Ctx, } from "@budibase/types" import * as context from "." @@ -16,15 +18,22 @@ export function doInIdentityContext(identity: IdentityContext, task: any) { return context.doInIdentityContext(identity, task) } -export function doInUserContext(user: User, task: any) { - const userContext: any = { +// used in server/worker +export function doInUserContext(user: User, ctx: Ctx, task: any) { + const userContext: UserContext = { ...user, _id: user._id as string, type: IdentityType.USER, + hostInfo: { + ipAddress: ctx.request.ip, + // filled in by koa-useragent package + userAgent: ctx.userAgent._agent.source, + }, } return doInIdentityContext(userContext, task) } +// used in account portal export function doInAccountContext(account: Account, task: any) { const _id = getAccountUserId(account) const tenantId = account.tenantId diff --git a/packages/backend-core/src/events/events.ts b/packages/backend-core/src/events/events.ts index ba4b0a7448..6176fb6724 100644 --- a/packages/backend-core/src/events/events.ts +++ b/packages/backend-core/src/events/events.ts @@ -1,13 +1,37 @@ -import { Event, IdentityType, AuditLogFn } from "@budibase/types" +import { AuditLogFn, Event, IdentityType, HostInfo } from "@budibase/types" import { processors } from "./processors" import identification from "./identification" import { getAppId } from "../context" import * as backfill from "./backfill" +import { createQueue, JobQueue } from "../queue" +import BullQueue from "bull" -let writeAuditLogs: AuditLogFn | undefined +type AuditLogEvent = { + event: Event + properties: any + opts: { + timestamp?: string | number + userId?: string + appId?: string + hostInfo?: HostInfo + } +} + +let auditLogsEnabled = false +let auditLogQueue: BullQueue.Queue export const configure = (fn: AuditLogFn) => { - writeAuditLogs = fn + auditLogsEnabled = true + const writeAuditLogs = fn + auditLogQueue = createQueue(JobQueue.AUDIT_LOG) + return auditLogQueue.process(async job => { + await writeAuditLogs(job.data.event, job.data.properties, { + userId: job.data.opts.userId, + timestamp: job.data.opts.timestamp, + appId: job.data.opts.appId, + hostInfo: job.data.opts.hostInfo, + }) + }) } export const publishEvent = async ( @@ -21,16 +45,22 @@ export const publishEvent = async ( const backfilling = await backfill.isBackfillingEvent(event) // no backfill - send the event and exit if (!backfilling) { - // only audit log actual events, don't include backfills - const userId = identity.type === IdentityType.USER ? identity.id : undefined - if (writeAuditLogs) { - await writeAuditLogs(event, properties, { - userId, - timestamp, - appId: getAppId(), + await processors.processEvent(event, identity, properties, timestamp) + if (auditLogsEnabled) { + // only audit log actual events, don't include backfills + const userId = + identity.type === IdentityType.USER ? identity.id : undefined + // add to event queue, rather than just writing immediately + await auditLogQueue.add({ + event, + properties, + opts: { + userId, + timestamp, + appId: getAppId(), + }, }) } - await processors.processEvent(event, identity, properties, timestamp) return } diff --git a/packages/backend-core/src/events/identification.ts b/packages/backend-core/src/events/identification.ts index 7cade9e14b..e18d96bbe0 100644 --- a/packages/backend-core/src/events/identification.ts +++ b/packages/backend-core/src/events/identification.ts @@ -89,6 +89,7 @@ const getCurrentIdentity = async (): Promise => { installationId, tenantId, environment, + hostInfo: userContext.host, } } else { throw new Error("Unknown identity type") diff --git a/packages/backend-core/src/middleware/authenticated.ts b/packages/backend-core/src/middleware/authenticated.ts index 4bb2aaba76..cce27823c0 100644 --- a/packages/backend-core/src/middleware/authenticated.ts +++ b/packages/backend-core/src/middleware/authenticated.ts @@ -8,7 +8,7 @@ import { getGlobalDB, doInTenant } from "../context" import { decrypt } from "../security/encryption" import * as identity from "../context/identity" import env from "../environment" -import { BBContext, EndpointMatcher } from "@budibase/types" +import { Ctx, EndpointMatcher } from "@budibase/types" const ONE_MINUTE = env.SESSION_UPDATE_PERIOD ? parseInt(env.SESSION_UPDATE_PERIOD) @@ -73,7 +73,7 @@ export default function ( } ) { const noAuthOptions = noAuthPatterns ? buildMatcherRegex(noAuthPatterns) : [] - return async (ctx: BBContext | any, next: any) => { + return async (ctx: Ctx | any, next: any) => { let publicEndpoint = false const version = ctx.request.headers[Header.API_VER] // the path is not authenticated @@ -148,7 +148,7 @@ export default function ( finalise(ctx, { authenticated, user, internal, version, publicEndpoint }) if (user && user.email) { - return identity.doInUserContext(user, next) + return identity.doInUserContext(user, ctx, next) } else { return next() } diff --git a/packages/backend-core/src/queue/constants.ts b/packages/backend-core/src/queue/constants.ts index e8323dacb8..9261ed1176 100644 --- a/packages/backend-core/src/queue/constants.ts +++ b/packages/backend-core/src/queue/constants.ts @@ -1,4 +1,5 @@ export enum JobQueue { AUTOMATION = "automationQueue", APP_BACKUP = "appBackupQueue", + AUDIT_LOG = "auditLogQueue", } diff --git a/packages/frontend-core/src/api/auditLogs.js b/packages/frontend-core/src/api/auditLogs.js index 745bfbc742..ee8f1b5520 100644 --- a/packages/frontend-core/src/api/auditLogs.js +++ b/packages/frontend-core/src/api/auditLogs.js @@ -18,15 +18,15 @@ const buildOpts = ({ } if (events) { - opts.event = events + opts.events = events } if (userIds) { - opts.userId = userIds + opts.userIds = userIds } if (appIds) { - opts.appId = appIds + opts.appIds = appIds } return opts diff --git a/packages/server/package.json b/packages/server/package.json index 3eb133e272..98b69d4b61 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -87,6 +87,7 @@ "koa-send": "5.0.0", "koa-session": "5.12.0", "koa-static": "5.0.0", + "koa-useragent": "^4.1.0", "koa2-ratelimit": "1.1.1", "lodash": "4.17.21", "memorystream": "0.3.1", diff --git a/packages/server/src/app.ts b/packages/server/src/app.ts index 6779b35457..86b2783533 100644 --- a/packages/server/src/app.ts +++ b/packages/server/src/app.ts @@ -33,6 +33,7 @@ import { initialise as initialiseWebsockets } from "./websocket" import { startup } from "./startup" const Sentry = require("@sentry/node") const destroyable = require("server-destroy") +const { userAgent } = require("koa-useragent") // configure events to use the pro audit log write // can't integrate directly into backend-core due to cyclic issues @@ -58,6 +59,7 @@ app.use( ) app.use(middleware.logging) +app.use(userAgent) if (env.isProd()) { env._set("NODE_ENV", "production") diff --git a/packages/server/yarn.lock b/packages/server/yarn.lock index eb0a7c4def..383c3f1bff 100644 --- a/packages/server/yarn.lock +++ b/packages/server/yarn.lock @@ -6976,6 +6976,11 @@ expose-loader@^3.1.0: resolved "https://registry.yarnpkg.com/expose-loader/-/expose-loader-3.1.0.tgz#7a0bdecb345b921ca238a8c4715a4ea7e227213f" integrity sha512-2RExSo0yJiqP+xiUue13jQa2IHE8kLDzTI7b6kn+vUlBVvlzNSiLDzo4e5Pp5J039usvTUnxZ8sUOhv0Kg15NA== +express-useragent@^1.0.15: + version "1.0.15" + resolved "https://registry.yarnpkg.com/express-useragent/-/express-useragent-1.0.15.tgz#cefda5fa4904345d51d3368b117a8dd4124985d9" + integrity sha512-eq5xMiYCYwFPoekffMjvEIk+NWdlQY9Y38OsTyl13IvA728vKT+q/CSERYWzcw93HGBJcIqMIsZC5CZGARPVdg== + ext-list@^2.0.0: version "2.2.2" resolved "https://registry.yarnpkg.com/ext-list/-/ext-list-2.2.2.tgz#0b98e64ed82f5acf0f2931babf69212ef52ddd37" @@ -10236,6 +10241,13 @@ koa-static@5.0.0, koa-static@^5.0.0: debug "^3.1.0" koa-send "^5.0.0" +koa-useragent@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/koa-useragent/-/koa-useragent-4.1.0.tgz#d3f128b552c6da3e5e9e9e9c887b2922b16e4468" + integrity sha512-x/HUDZ1zAmNNh5hA9hHbPm9p3UVg2prlpHzxCXQCzbibrNS0kmj7MkCResCbAbG7ZT6FVxNSMjR94ZGamdMwxA== + dependencies: + express-useragent "^1.0.15" + koa-views@^7.0.1: version "7.0.2" resolved "https://registry.yarnpkg.com/koa-views/-/koa-views-7.0.2.tgz#c96fd9e2143ef00c29dc5160c5ed639891aa723d" diff --git a/packages/types/src/sdk/auditLogs.ts b/packages/types/src/sdk/auditLogs.ts index 9f8eb3825c..dea36b0164 100644 --- a/packages/types/src/sdk/auditLogs.ts +++ b/packages/types/src/sdk/auditLogs.ts @@ -1,9 +1,10 @@ -import { Event } from "./events" +import { Event, HostInfo } from "./events" export type AuditWriteOpts = { appId?: string timestamp?: string | number userId?: string + hostInfo?: HostInfo } export type AuditLogFn = ( diff --git a/packages/types/src/sdk/context.ts b/packages/types/src/sdk/context.ts index b3403df8af..c8345de196 100644 --- a/packages/types/src/sdk/context.ts +++ b/packages/types/src/sdk/context.ts @@ -1,5 +1,5 @@ import { User, Account } from "../documents" -import { IdentityType } from "./events" +import { IdentityType, HostInfo } from "./events" export interface BaseContext { _id: string @@ -16,6 +16,7 @@ export interface UserContext extends BaseContext, User { _id: string tenantId: string account?: Account + hostInfo: HostInfo } export type IdentityContext = BaseContext | AccountUserContext | UserContext diff --git a/packages/types/src/sdk/events/identification.ts b/packages/types/src/sdk/events/identification.ts index 3f4e7ec9d4..bbbf74d33e 100644 --- a/packages/types/src/sdk/events/identification.ts +++ b/packages/types/src/sdk/events/identification.ts @@ -34,6 +34,11 @@ export enum IdentityType { INSTALLATION = "installation", } +export interface HostInfo { + ipAddress: string + userAgent: string +} + export interface Identity { id: string type: IdentityType @@ -41,6 +46,7 @@ export interface Identity { environment: string installationId?: string tenantId?: string + hostInfo: HostInfo } export interface UserIdentity extends Identity { diff --git a/packages/worker/package.json b/packages/worker/package.json index 0fb3abe53b..c1912054c4 100644 --- a/packages/worker/package.json +++ b/packages/worker/package.json @@ -60,6 +60,7 @@ "koa-send": "5.0.1", "koa-session": "5.13.1", "koa-static": "5.0.0", + "koa-useragent": "^4.1.0", "node-fetch": "2.6.7", "nodemailer": "6.7.2", "passport-google-oauth": "2.0.0", diff --git a/packages/worker/src/api/controllers/global/auth.ts b/packages/worker/src/api/controllers/global/auth.ts index 1e55d4de0d..318f69c7ad 100644 --- a/packages/worker/src/api/controllers/global/auth.ts +++ b/packages/worker/src/api/controllers/global/auth.ts @@ -69,7 +69,7 @@ export const login = async (ctx: Ctx, next: any) => { "local", async (err: any, user: User, info: any) => { await passportCallback(ctx, user, err, info) - await context.identity.doInUserContext(user, async () => { + await context.identity.doInUserContext(user, ctx, async () => { await events.auth.login("local", user.email) }) ctx.status = 200 @@ -211,7 +211,7 @@ export const googleCallback = async (ctx: any, next: any) => { { successRedirect: "/", failureRedirect: "/error" }, async (err: any, user: SSOUser, info: any) => { await passportCallback(ctx, user, err, info) - await context.identity.doInUserContext(user, async () => { + await context.identity.doInUserContext(user, ctx, async () => { await events.auth.login("google-internal", user.email) }) ctx.redirect("/") @@ -281,7 +281,7 @@ export const oidcCallback = async (ctx: any, next: any) => { { successRedirect: "/", failureRedirect: "/error" }, async (err: any, user: SSOUser, info: any) => { await passportCallback(ctx, user, err, info) - await context.identity.doInUserContext(user, async () => { + await context.identity.doInUserContext(user, ctx, async () => { await events.auth.login("oidc", user.email) }) ctx.redirect("/") diff --git a/packages/worker/src/index.ts b/packages/worker/src/index.ts index 69cd900637..750ae0055d 100644 --- a/packages/worker/src/index.ts +++ b/packages/worker/src/index.ts @@ -24,6 +24,8 @@ import * as redis from "./utilities/redis" const Sentry = require("@sentry/node") const koaSession = require("koa-session") const logger = require("koa-pino-logger") +const { userAgent } = require("koa-useragent") + import destroyable from "server-destroy" // configure events to use the pro audit log write @@ -48,6 +50,7 @@ app.use(koaBody({ multipart: true })) app.use(koaSession(app)) app.use(middleware.logging) app.use(logger(logging.pinoSettings())) +app.use(userAgent) // authentication app.use(auth.passport.initialize()) diff --git a/packages/worker/yarn.lock b/packages/worker/yarn.lock index 83417a2e84..35af60204e 100644 --- a/packages/worker/yarn.lock +++ b/packages/worker/yarn.lock @@ -3653,6 +3653,11 @@ expect@^28.1.3: jest-message-util "^28.1.3" jest-util "^28.1.3" +express-useragent@^1.0.15: + version "1.0.15" + resolved "https://registry.yarnpkg.com/express-useragent/-/express-useragent-1.0.15.tgz#cefda5fa4904345d51d3368b117a8dd4124985d9" + integrity sha512-eq5xMiYCYwFPoekffMjvEIk+NWdlQY9Y38OsTyl13IvA728vKT+q/CSERYWzcw93HGBJcIqMIsZC5CZGARPVdg== + extend@~3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" @@ -5467,6 +5472,13 @@ koa-static@5.0.0: debug "^3.1.0" koa-send "^5.0.0" +koa-useragent@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/koa-useragent/-/koa-useragent-4.1.0.tgz#d3f128b552c6da3e5e9e9e9c887b2922b16e4468" + integrity sha512-x/HUDZ1zAmNNh5hA9hHbPm9p3UVg2prlpHzxCXQCzbibrNS0kmj7MkCResCbAbG7ZT6FVxNSMjR94ZGamdMwxA== + dependencies: + express-useragent "^1.0.15" + koa@2.13.4, koa@^2.13.4: version "2.13.4" resolved "https://registry.yarnpkg.com/koa/-/koa-2.13.4.tgz#ee5b0cb39e0b8069c38d115139c774833d32462e" From 7bb98291658f2f5ad4261c70870bc2e12fef2eb1 Mon Sep 17 00:00:00 2001 From: Peter Clement Date: Wed, 22 Feb 2023 10:09:15 +0000 Subject: [PATCH 029/106] update sidebar styling and fix bugs --- .../_components/AppColumnRenderer.svelte | 2 +- .../auditLogs/_components/UserRenderer.svelte | 35 +++++++++- .../portal/account/auditLogs/index.svelte | 67 ++++++++++++++----- .../builder/src/stores/portal/auditLogs.js | 2 - packages/frontend-core/src/api/auditLogs.js | 25 ++++--- 5 files changed, 99 insertions(+), 32 deletions(-) diff --git a/packages/builder/src/pages/builder/portal/account/auditLogs/_components/AppColumnRenderer.svelte b/packages/builder/src/pages/builder/portal/account/auditLogs/_components/AppColumnRenderer.svelte index f6665dff28..2ad3997f79 100644 --- a/packages/builder/src/pages/builder/portal/account/auditLogs/_components/AppColumnRenderer.svelte +++ b/packages/builder/src/pages/builder/portal/account/auditLogs/_components/AppColumnRenderer.svelte @@ -2,4 +2,4 @@ export let value -
{value.name}
+
{value?.name || "N/A"}
diff --git a/packages/builder/src/pages/builder/portal/account/auditLogs/_components/UserRenderer.svelte b/packages/builder/src/pages/builder/portal/account/auditLogs/_components/UserRenderer.svelte index 07551da3bc..5d3d8fa28a 100644 --- a/packages/builder/src/pages/builder/portal/account/auditLogs/_components/UserRenderer.svelte +++ b/packages/builder/src/pages/builder/portal/account/auditLogs/_components/UserRenderer.svelte @@ -1,7 +1,8 @@ - +
(showTooltip = true)} + on:focus={() => (showTooltip = true)} + on:mouseleave={() => (showTooltip = false)} +> + +
+{#if showTooltip} +
+ +
+{/if} + + diff --git a/packages/builder/src/pages/builder/portal/account/auditLogs/index.svelte b/packages/builder/src/pages/builder/portal/account/auditLogs/index.svelte index 821e504774..47c93d23d1 100644 --- a/packages/builder/src/pages/builder/portal/account/auditLogs/index.svelte +++ b/packages/builder/src/pages/builder/portal/account/auditLogs/index.svelte @@ -9,6 +9,8 @@ clickOutside, CoreTextArea, DatePicker, + Pagination, + Divider, } from "@budibase/bbui" import { licensing, users, apps, auditLogs } from "stores/portal" import LockedFeature from "../../_components/LockedFeature.svelte" @@ -62,16 +64,15 @@ let startDate, endDate $: fetchUsers(userPage, userSearchTerm) - $: fetchLogs( + $: fetchLogs({ logsPage, logSearchTerm, startDate, endDate, selectedUsers, selectedApps, - selectedEvents - ) - + selectedEvents, + }) $: userPage = $userPageInfo.page $: logsPage = $logsPageInfo.page @@ -97,38 +98,38 @@ } } - const fetchLogs = async ( + const fetchLogs = async ({ logsPage, - search, + logSearchTerm, startDate, endDate, selectedUsers, selectedApps, - selectedEvents - ) => { + selectedEvents, + }) => { if ($logsPageInfo.loading) { return } // need to remove the page if they've started searching - if (search && !prevLogSearch) { + if (logSearchTerm && !prevLogSearch) { logsPageInfo.reset() logsPage = undefined } - prevLogSearch = search + prevLogSearch = logSearchTerm try { logsPageInfo.loading() await auditLogs.search({ - logsPage, + bookmark: logsPage, startDate, endDate, - metadataSearch: search, + fullSearch: logSearchTerm, userIds: selectedUsers, appIds: selectedApps, events: selectedEvents, }) logsPageInfo.fetched( $auditLogs.logs.hasNextPage, - $auditLogs.logs.nextPage + $auditLogs.logs.bookmark ) } catch (error) { console.log(error) @@ -161,6 +162,7 @@ } const viewDetails = detail => { + console.log(detail) selectedLog = detail sidePanelVisible = true } @@ -206,9 +208,15 @@ range={true} label="Date Range" on:change={e => { - if (e.detail[0].length > 1) { + console.log(e) + if (e.detail[0]?.length === 1) { + startDate = e.detail[0][0].toISOString() + } else if (e.detail[0]?.length > 1) { startDate = e.detail[0][0].toISOString() endDate = e.detail[0][1].toISOString() + } else { + startDate = null + endDate = null } }} /> @@ -258,14 +266,23 @@
viewDetails(detail)} {customRenderers} - on:click={viewDetails} data={$auditLogs.logs.data} allowEditColumns={false} allowEditRows={false} allowSelectRows={false} {schema} /> + @@ -298,7 +315,9 @@ /> -
+ + +
.side-panel-header { display: flex; + padding: 20px 10px 10px 10px; gap: var(--spacing-s); justify-content: space-between; align-items: center; } + .pagination { + display: flex; + flex-direction: row; + justify-content: flex-end; + margin-top: var(--spacing-xl); + } + + .side-panel-body { + padding: 10px; + height: 95%; + } #side-panel { position: absolute; right: 0; top: 0; - padding: 24px; + padding-bottom: 24px; background: var(--background); border-left: var(--border-light); width: 320px; @@ -330,7 +361,7 @@ overflow-x: hidden; transform: translateX(100%); transition: transform 130ms ease-in-out; - height: calc(100% - 48px); + height: calc(100% - 25px); z-index: 2; } #side-panel.visible { diff --git a/packages/builder/src/stores/portal/auditLogs.js b/packages/builder/src/stores/portal/auditLogs.js index 3454aab95c..165e4b5ec5 100644 --- a/packages/builder/src/stores/portal/auditLogs.js +++ b/packages/builder/src/stores/portal/auditLogs.js @@ -26,8 +26,6 @@ export function createAuditLogsStore() { update(state => { return { ...state, ...events } }) - - console.log(events) } async function downloadLogs(opts = {}) { diff --git a/packages/frontend-core/src/api/auditLogs.js b/packages/frontend-core/src/api/auditLogs.js index 745bfbc742..867644c23c 100644 --- a/packages/frontend-core/src/api/auditLogs.js +++ b/packages/frontend-core/src/api/auditLogs.js @@ -1,32 +1,39 @@ const buildOpts = ({ + bookmark, userIds, appIds, startDate, endDate, - metadataSearch, + fullSearch, events, }) => { const opts = {} + if (bookmark) { + opts.bookmark = bookmark + } + if (startDate && endDate) { opts.startDate = startDate opts.endDate = endDate + } else if (startDate && !endDate) { + opts.startDate = startDate } - if (metadataSearch) { - opts.metadataSearch = metadataSearch + if (fullSearch) { + opts.fullSearch = fullSearch } - if (events) { - opts.event = events + if (events.length) { + opts.events = events } - if (userIds) { - opts.userId = userIds + if (userIds.length) { + opts.userIds = userIds } - if (appIds) { - opts.appId = appIds + if (appIds.length) { + opts.appIds = appIds } return opts From b9c54b6fe6a2da69a39004851850d967c2f5b299 Mon Sep 17 00:00:00 2001 From: adrinr Date: Wed, 22 Feb 2023 10:54:55 +0000 Subject: [PATCH 030/106] Update many to many --- .../src/api/controllers/row/ExternalRequest.ts | 13 ++++++------- packages/server/src/api/controllers/row/external.ts | 2 +- packages/server/src/integrations/base/sql.ts | 4 +--- 3 files changed, 8 insertions(+), 11 deletions(-) diff --git a/packages/server/src/api/controllers/row/ExternalRequest.ts b/packages/server/src/api/controllers/row/ExternalRequest.ts index f62e7fe2d0..22a4a90865 100644 --- a/packages/server/src/api/controllers/row/ExternalRequest.ts +++ b/packages/server/src/api/controllers/row/ExternalRequest.ts @@ -629,10 +629,7 @@ export class ExternalRequest { * Creating the specific list of fields that we desire, and excluding the ones that are no use to us * is more performant and has the added benefit of protecting against this scenario. */ - buildFields( - table: Table, - includeRelations: IncludeRelationship = IncludeRelationship.INCLUDE - ) { + buildFields(table: Table, includeRelations: boolean) { function extractRealFields(table: Table, existing: string[] = []) { return Object.entries(table.schema) .filter( @@ -691,6 +688,10 @@ export class ExternalRequest { } filters = buildFilters(id, filters || {}, table) const relationships = this.buildRelationships(table) + + const includeSqlRelationships = + config.includeSqlRelationships === IncludeRelationship.INCLUDE + // clean up row on ingress using schema const processed = this.inputProcessing(row, table) row = processed.row @@ -708,9 +709,7 @@ export class ExternalRequest { }, resource: { // have to specify the fields to avoid column overlap (for SQL) - fields: isSql - ? this.buildFields(table, config.includeSqlRelationships) - : [], + fields: isSql ? this.buildFields(table, includeSqlRelationships) : [], }, filters, sort, diff --git a/packages/server/src/api/controllers/row/external.ts b/packages/server/src/api/controllers/row/external.ts index 6120c3cdcb..1b2301f139 100644 --- a/packages/server/src/api/controllers/row/external.ts +++ b/packages/server/src/api/controllers/row/external.ts @@ -58,7 +58,7 @@ export async function patch(ctx: BBContext) { return handleRequest(Operation.UPDATE, tableId, { id: breakRowIdField(id), row: inputs, - includeSqlRelationships: IncludeRelationship.EXCLUDE, + includeSqlRelationships: IncludeRelationship.INCLUDE, }) } diff --git a/packages/server/src/integrations/base/sql.ts b/packages/server/src/integrations/base/sql.ts index e66795a6db..c722891910 100644 --- a/packages/server/src/integrations/base/sql.ts +++ b/packages/server/src/integrations/base/sql.ts @@ -502,9 +502,7 @@ class InternalBuilder { if (opts.disableReturning) { return query.update(parsedBody) } else { - return query - .update(parsedBody) - .returning(generateSelectStatement(json, knex)) + return query.update(parsedBody).returning("*") } } From e350f6b166ca69edfd9dfb24e37f7e47e824f812 Mon Sep 17 00:00:00 2001 From: adrinr Date: Wed, 22 Feb 2023 11:02:32 +0000 Subject: [PATCH 031/106] Undo literal changes --- packages/server/src/api/controllers/row/ExternalRequest.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/server/src/api/controllers/row/ExternalRequest.ts b/packages/server/src/api/controllers/row/ExternalRequest.ts index 22a4a90865..56e54e299e 100644 --- a/packages/server/src/api/controllers/row/ExternalRequest.ts +++ b/packages/server/src/api/controllers/row/ExternalRequest.ts @@ -316,7 +316,7 @@ export class ExternalRequest { key: otherKey, [thisKey]: breakRowIdField(relationship)[0], // leave the ID for enrichment later - [otherKey]: `{{ literal [${table.name}.${tablePrimary}] }}`, + [otherKey]: `{{ literal ${tablePrimary} }}`, }) }) } From ffee41aea320947ae4f50654e3a61b87c82bc202 Mon Sep 17 00:00:00 2001 From: Peter Clement Date: Wed, 22 Feb 2023 12:31:04 +0000 Subject: [PATCH 032/106] custom popover height and sidebar styling --- .../bbui/src/Form/Core/Multiselect.svelte | 2 + packages/bbui/src/Form/Core/Picker.svelte | 3 + packages/bbui/src/Form/Multiselect.svelte | 2 + packages/bbui/src/Form/Select.svelte | 2 + packages/bbui/src/Popover/Popover.svelte | 2 + .../_components/AppColumnRenderer.svelte | 2 +- .../auditLogs/_components/UserRenderer.svelte | 4 +- .../portal/account/auditLogs/index.svelte | 58 ++++++++++++++++--- 8 files changed, 63 insertions(+), 12 deletions(-) diff --git a/packages/bbui/src/Form/Core/Multiselect.svelte b/packages/bbui/src/Form/Core/Multiselect.svelte index a315f44a65..8860fcbf0b 100644 --- a/packages/bbui/src/Form/Core/Multiselect.svelte +++ b/packages/bbui/src/Form/Core/Multiselect.svelte @@ -15,6 +15,7 @@ export let sort = false export let autoWidth = false export let fetchTerm = null + export let customPopoverHeight const dispatch = createEventDispatcher() @@ -91,4 +92,5 @@ onSelectOption={toggleOption} {sort} {autoWidth} + {customPopoverHeight} /> diff --git a/packages/bbui/src/Form/Core/Picker.svelte b/packages/bbui/src/Form/Core/Picker.svelte index ace41aa35b..5cef0f9213 100644 --- a/packages/bbui/src/Form/Core/Picker.svelte +++ b/packages/bbui/src/Form/Core/Picker.svelte @@ -32,6 +32,7 @@ export let autocomplete = false export let sort = false export let fetchTerm = null + export let customPopoverHeight const dispatch = createEventDispatcher() let searchTerm = null @@ -136,6 +137,7 @@ on:close={() => (open = false)} useAnchorWidth={!autoWidth} maxWidth={autoWidth ? 400 : null} + customHeight={customPopoverHeight} >
{ @@ -38,6 +39,7 @@ {getOptionValue} {autoWidth} {autocomplete} + {customPopoverHeight} bind:fetchTerm on:change={onChange} on:click diff --git a/packages/bbui/src/Form/Select.svelte b/packages/bbui/src/Form/Select.svelte index 4f30318282..76fe613c92 100644 --- a/packages/bbui/src/Form/Select.svelte +++ b/packages/bbui/src/Form/Select.svelte @@ -21,6 +21,7 @@ export let sort = false export let tooltip = "" export let autocomplete = false + export let customPopoverHeight const dispatch = createEventDispatcher() const onChange = e => { @@ -53,6 +54,7 @@ {getOptionColour} {isOptionEnabled} {autocomplete} + {customPopoverHeight} on:change={onChange} on:click /> diff --git a/packages/bbui/src/Popover/Popover.svelte b/packages/bbui/src/Popover/Popover.svelte index 8f6ef06591..081e3a34df 100644 --- a/packages/bbui/src/Popover/Popover.svelte +++ b/packages/bbui/src/Popover/Popover.svelte @@ -18,6 +18,7 @@ export let useAnchorWidth = false export let dismissible = true export let offset = 5 + export let customHeight $: target = portalTarget || getContext(Context.PopoverRoot) || ".spectrum" @@ -74,6 +75,7 @@ on:keydown={handleEscape} class="spectrum-Popover is-open" role="presentation" + style="height: {customHeight}" transition:fly|local={{ y: -20, duration: 200 }} > diff --git a/packages/builder/src/pages/builder/portal/account/auditLogs/_components/AppColumnRenderer.svelte b/packages/builder/src/pages/builder/portal/account/auditLogs/_components/AppColumnRenderer.svelte index 2ad3997f79..08260ecc5c 100644 --- a/packages/builder/src/pages/builder/portal/account/auditLogs/_components/AppColumnRenderer.svelte +++ b/packages/builder/src/pages/builder/portal/account/auditLogs/_components/AppColumnRenderer.svelte @@ -2,4 +2,4 @@ export let value -
{value?.name || "N/A"}
+
{value?.name || ""}
diff --git a/packages/builder/src/pages/builder/portal/account/auditLogs/_components/UserRenderer.svelte b/packages/builder/src/pages/builder/portal/account/auditLogs/_components/UserRenderer.svelte index 5d3d8fa28a..1dfb425965 100644 --- a/packages/builder/src/pages/builder/portal/account/auditLogs/_components/UserRenderer.svelte +++ b/packages/builder/src/pages/builder/portal/account/auditLogs/_components/UserRenderer.svelte @@ -18,11 +18,11 @@ on:focus={() => (showTooltip = true)} on:mouseleave={() => (showTooltip = false)} > - +
{#if showTooltip}
- +
{/if} diff --git a/packages/builder/src/pages/builder/portal/account/auditLogs/index.svelte b/packages/builder/src/pages/builder/portal/account/auditLogs/index.svelte index 47c93d23d1..4459eb12a5 100644 --- a/packages/builder/src/pages/builder/portal/account/auditLogs/index.svelte +++ b/packages/builder/src/pages/builder/portal/account/auditLogs/index.svelte @@ -10,6 +10,7 @@ CoreTextArea, DatePicker, Pagination, + Helpers, Divider, } from "@budibase/bbui" import { licensing, users, apps, auditLogs } from "stores/portal" @@ -185,6 +186,11 @@ viewDetails, }) + const copyToClipboard = async value => { + await Helpers.copyToClipboard(value) + notifications.success("Copied") + } + onMount(async () => { await auditLogs.getEventDefinitions() }) @@ -246,6 +252,7 @@
event[0]} getOptionLabel={event => event[1]} @@ -318,6 +325,12 @@
+
copyToClipboard(JSON.stringify(selectedLog.metadata))} + class="copy-icon" + > + +
+ .copy-icon { + right: 16px; + top: 80px; + z-index: 10; + justify-content: center; + align-items: center; + display: flex; + flex-direction: row; + box-sizing: border-box; + + border: 1px solid var(--spectrum-alias-border-color); + border-radius: var(--spectrum-alias-border-radius-regular); + width: 31px; + color: var(--spectrum-alias-text-color); + background-color: var(--spectrum-global-color-gray-75); + transition: background-color + var(--spectrum-global-animation-duration-100, 130ms), + box-shadow var(--spectrum-global-animation-duration-100, 130ms), + border-color var(--spectrum-global-animation-duration-100, 130ms); + height: calc(var(--spectrum-alias-item-height-m) - 2px); + position: absolute; + } + .copy-icon:hover { + cursor: pointer; + color: var(--spectrum-alias-text-color-hover); + background-color: var(--spectrum-global-color-gray-50); + border-color: var(--spectrum-alias-border-color-hover); + } .side-panel-header { display: flex; padding: 20px 10px 10px 10px; @@ -346,7 +387,7 @@ .side-panel-body { padding: 10px; - height: 95%; + height: calc(100% - 67px); } #side-panel { position: absolute; @@ -357,11 +398,11 @@ border-left: var(--border-light); width: 320px; max-width: calc(100vw - 48px - 48px); - overflow: auto; - overflow-x: hidden; transform: translateX(100%); transition: transform 130ms ease-in-out; - height: calc(100% - 25px); + height: calc(100% - 24px); + overflow-y: hidden; + overflow-x: hidden; z-index: 2; } #side-panel.visible { @@ -373,15 +414,14 @@ } #side-panel :global(textarea) { - min-height: 202px !important; + min-height: 100% !important; background-color: var( --spectrum-textfield-m-background-color, var(--spectrum-global-color-gray-50) ); - color: var( - --spectrum-textfield-m-text-color, - var(--spectrum-alias-text-color) - ); + padding-top: var(--spacing-l); + padding-left: var(--spacing-l); + font-size: 13px; } .search :global(.spectrum-InputGroup) { From 63af59a5b0038f1517ac6c8381a5fe5ffe1e3230 Mon Sep 17 00:00:00 2001 From: adrinr Date: Wed, 22 Feb 2023 14:59:42 +0100 Subject: [PATCH 033/106] Handle link fields --- .../src/api/controllers/row/ExternalRequest.ts | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/packages/server/src/api/controllers/row/ExternalRequest.ts b/packages/server/src/api/controllers/row/ExternalRequest.ts index 56e54e299e..a262df8d69 100644 --- a/packages/server/src/api/controllers/row/ExternalRequest.ts +++ b/packages/server/src/api/controllers/row/ExternalRequest.ts @@ -177,9 +177,14 @@ function getEndpoint(tableId: string | undefined, operation: string) { function basicProcessing(row: Row, table: Table): Row { const thisRow: Row = {} // filter the row down to what is actually the row (not joined) - for (let fieldName of Object.keys(table.schema)) { + for (let field of Object.values(table.schema)) { + const fieldName = field.name + const pathValue = row[`${table.name}.${fieldName}`] - const value = pathValue != null ? pathValue : row[fieldName] + const value = + pathValue != null || field.type === FieldTypes.LINK + ? pathValue + : row[fieldName] // all responses include "select col as table.col" so that overlaps are handled if (value != null) { thisRow[fieldName] = value @@ -572,11 +577,18 @@ export class ExternalRequest { if (!linkTable || !linkPrimary) { return } + + const linkSecondary = + linkTable?.primary && + linkTable?.primary?.length > 1 && + linkTable?.primary[1] + const rows = related[key]?.rows || [] const found = rows.find( (row: { [key: string]: any }) => row[linkPrimary] === relationship.id || - row[linkPrimary] === body?.[linkPrimary] + (row[linkPrimary] === body?.[linkPrimary] && + (!linkSecondary || row[linkSecondary] === body?.[linkSecondary])) ) const operation = isUpdate ? Operation.UPDATE : Operation.CREATE if (!found) { From c6dadaa4ff524005a719a6d3fbe00f1e2044fd4c Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Wed, 22 Feb 2023 16:10:54 +0000 Subject: [PATCH 034/106] Some work to make sure the user agent and ip address are always passed correctly to audit logs. --- packages/backend-core/src/events/events.ts | 28 +++++++++---------- .../backend-core/src/events/identification.ts | 2 +- packages/backend-core/src/events/index.ts | 2 +- packages/types/src/sdk/auditLogs.ts | 6 ++++ .../types/src/sdk/events/identification.ts | 2 +- 5 files changed, 23 insertions(+), 17 deletions(-) diff --git a/packages/backend-core/src/events/events.ts b/packages/backend-core/src/events/events.ts index 6176fb6724..d3d32384aa 100644 --- a/packages/backend-core/src/events/events.ts +++ b/packages/backend-core/src/events/events.ts @@ -1,4 +1,10 @@ -import { AuditLogFn, Event, IdentityType, HostInfo } from "@budibase/types" +import { + AuditLogFn, + Event, + IdentityType, + AuditedEventFriendlyName, + AuditLogQueueEvent, +} from "@budibase/types" import { processors } from "./processors" import identification from "./identification" import { getAppId } from "../context" @@ -6,24 +12,17 @@ import * as backfill from "./backfill" import { createQueue, JobQueue } from "../queue" import BullQueue from "bull" -type AuditLogEvent = { - event: Event - properties: any - opts: { - timestamp?: string | number - userId?: string - appId?: string - hostInfo?: HostInfo - } +export function isAudited(event: Event) { + return !!AuditedEventFriendlyName[event] } let auditLogsEnabled = false -let auditLogQueue: BullQueue.Queue +let auditLogQueue: BullQueue.Queue export const configure = (fn: AuditLogFn) => { auditLogsEnabled = true const writeAuditLogs = fn - auditLogQueue = createQueue(JobQueue.AUDIT_LOG) + auditLogQueue = createQueue(JobQueue.AUDIT_LOG) return auditLogQueue.process(async job => { await writeAuditLogs(job.data.event, job.data.properties, { userId: job.data.opts.userId, @@ -46,11 +45,11 @@ export const publishEvent = async ( // no backfill - send the event and exit if (!backfilling) { await processors.processEvent(event, identity, properties, timestamp) - if (auditLogsEnabled) { + if (auditLogsEnabled && isAudited(event)) { // only audit log actual events, don't include backfills const userId = identity.type === IdentityType.USER ? identity.id : undefined - // add to event queue, rather than just writing immediately + // add to the event queue, rather than just writing immediately await auditLogQueue.add({ event, properties, @@ -58,6 +57,7 @@ export const publishEvent = async ( userId, timestamp, appId: getAppId(), + hostInfo: identity.hostInfo, }, }) } diff --git a/packages/backend-core/src/events/identification.ts b/packages/backend-core/src/events/identification.ts index e18d96bbe0..dcb2ebb4ab 100644 --- a/packages/backend-core/src/events/identification.ts +++ b/packages/backend-core/src/events/identification.ts @@ -89,7 +89,7 @@ const getCurrentIdentity = async (): Promise => { installationId, tenantId, environment, - hostInfo: userContext.host, + hostInfo: userContext.hostInfo, } } else { throw new Error("Unknown identity type") diff --git a/packages/backend-core/src/events/index.ts b/packages/backend-core/src/events/index.ts index 7aa4d06e58..15f6dde835 100644 --- a/packages/backend-core/src/events/index.ts +++ b/packages/backend-core/src/events/index.ts @@ -3,7 +3,7 @@ export * as processors from "./processors" export * as analytics from "./analytics" export { default as identification } from "./identification" export * as backfillCache from "./backfill" -export { configure } from "./events" +export { configure, isAudited } from "./events" import { processors } from "./processors" diff --git a/packages/types/src/sdk/auditLogs.ts b/packages/types/src/sdk/auditLogs.ts index dea36b0164..e5d0c77d90 100644 --- a/packages/types/src/sdk/auditLogs.ts +++ b/packages/types/src/sdk/auditLogs.ts @@ -12,3 +12,9 @@ export type AuditLogFn = ( metadata: any, opts: AuditWriteOpts ) => Promise + +export type AuditLogQueueEvent = { + event: Event + properties: any + opts: AuditWriteOpts +} diff --git a/packages/types/src/sdk/events/identification.ts b/packages/types/src/sdk/events/identification.ts index bbbf74d33e..8b6b7ddf44 100644 --- a/packages/types/src/sdk/events/identification.ts +++ b/packages/types/src/sdk/events/identification.ts @@ -46,7 +46,7 @@ export interface Identity { environment: string installationId?: string tenantId?: string - hostInfo: HostInfo + hostInfo?: HostInfo } export interface UserIdentity extends Identity { From f00994af7f015d4792e14450178f23a0d55c7f94 Mon Sep 17 00:00:00 2001 From: adrinr Date: Wed, 22 Feb 2023 17:18:05 +0100 Subject: [PATCH 035/106] Fix wrong relationship mapping --- .../server/src/api/controllers/row/ExternalRequest.ts | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/packages/server/src/api/controllers/row/ExternalRequest.ts b/packages/server/src/api/controllers/row/ExternalRequest.ts index a262df8d69..1510e31881 100644 --- a/packages/server/src/api/controllers/row/ExternalRequest.ts +++ b/packages/server/src/api/controllers/row/ExternalRequest.ts @@ -384,6 +384,15 @@ export class ExternalRequest { ) { continue } + + if ( + relationship.from && + row[fromColumn] === undefined && + row[relationship.from] === null + ) { + continue + } + let linked = basicProcessing(row, linkedTable) if (!linked._id) { continue From 647e643439d12899b9a00293db0d8e91f84f7505 Mon Sep 17 00:00:00 2001 From: Peter Clement Date: Wed, 22 Feb 2023 17:25:24 +0000 Subject: [PATCH 036/106] start download work --- .../portal/account/auditLogs/index.svelte | 27 +++++++++++++++---- packages/frontend-core/src/api/auditLogs.js | 6 ++--- 2 files changed, 25 insertions(+), 8 deletions(-) diff --git a/packages/builder/src/pages/builder/portal/account/auditLogs/index.svelte b/packages/builder/src/pages/builder/portal/account/auditLogs/index.svelte index 4459eb12a5..125a67a03d 100644 --- a/packages/builder/src/pages/builder/portal/account/auditLogs/index.svelte +++ b/packages/builder/src/pages/builder/portal/account/auditLogs/index.svelte @@ -21,6 +21,7 @@ import UserRenderer from "./_components/UserRenderer.svelte" import TimeRenderer from "./_components/TimeRenderer.svelte" import AppColumnRenderer from "./_components/AppColumnRenderer.svelte" + import download from "downloadjs" const schema = { date: { width: "0.8fr" }, @@ -167,16 +168,29 @@ selectedLog = detail sidePanelVisible = true } + async function exportView() { + try { + const data = await API.exportView({ + viewName: view, + format: exportFormat, + }) + } catch (error) { + notifications.error(`Unable to export ${exportFormat.toUpperCase()} data`) + } + } const downloadLogs = async () => { try { - await auditLogs.download({ + let response = await auditLogs.downloadLogs({ startDate, endDate, - metadataSearch: logSearchTerm, + fullSearch: logSearchTerm, userIds: selectedUsers, appIds: selectedApps, + events: selectedEvents, }) + + // DO SOMETHING HERE??????????? } catch (error) { notifications.error(`Error downloading logs: ` + error.message) } @@ -193,6 +207,7 @@ onMount(async () => { await auditLogs.getEventDefinitions() + await licensing.init() }) @@ -214,7 +229,6 @@ range={true} label="Date Range" on:change={e => { - console.log(e) if (e.detail[0]?.length === 1) { startDate = e.detail[0][0].toISOString() } else if (e.detail[0]?.length > 1) { @@ -263,8 +277,11 @@ />
-
- downloadLogs()} name="Download" /> +
downloadLogs()} + style="padding-bottom: var(--spacing-s)" + > +
diff --git a/packages/frontend-core/src/api/auditLogs.js b/packages/frontend-core/src/api/auditLogs.js index 867644c23c..08e14328a1 100644 --- a/packages/frontend-core/src/api/auditLogs.js +++ b/packages/frontend-core/src/api/auditLogs.js @@ -8,7 +8,7 @@ const buildOpts = ({ events, }) => { const opts = {} - + if (bookmark) { opts.bookmark = bookmark } @@ -35,7 +35,7 @@ const buildOpts = ({ if (appIds.length) { opts.appIds = appIds } - + console.log(opts) return opts } @@ -58,7 +58,7 @@ export const buildAuditLogsEndpoints = API => ({ downloadLogs: async opts => { return await API.post({ - url: `/api/global/auditlogs/definitions`, + url: `/api/global/auditlogs/download`, body: buildOpts(opts), }) }, From 01076bd35f896d12a539dcb8b39ad858fe3c87be Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Wed, 22 Feb 2023 18:50:27 +0000 Subject: [PATCH 037/106] Getting downloading working correctly, some minor UI updates, adding a new middleware for converting a query string to a body (useful for when a GET has to be used). --- .../src/middleware/downloadBody.ts | 22 ++++++++ packages/backend-core/src/middleware/index.ts | 1 + .../portal/account/auditLogs/index.svelte | 50 +++++++++---------- .../builder/src/stores/portal/auditLogs.js | 6 +-- packages/frontend-core/src/api/auditLogs.js | 10 ++-- .../api/routes/global/tests/auditLogs.spec.ts | 5 ++ 6 files changed, 60 insertions(+), 34 deletions(-) create mode 100644 packages/backend-core/src/middleware/downloadBody.ts create mode 100644 packages/worker/src/api/routes/global/tests/auditLogs.spec.ts diff --git a/packages/backend-core/src/middleware/downloadBody.ts b/packages/backend-core/src/middleware/downloadBody.ts new file mode 100644 index 0000000000..a7050e08c5 --- /dev/null +++ b/packages/backend-core/src/middleware/downloadBody.ts @@ -0,0 +1,22 @@ +import { Ctx } from "@budibase/types" + +/** + * Expects a standard "query" query string property which is the JSON body + * of the request, which has to be sent via query string due to the requirement + * of making an endpoint a GET request e.g. downloading a file stream. + */ +export default function (ctx: Ctx, next: any) { + const queryString = ctx.request.query?.query as string | undefined + if (!queryString) { + return next() + } + const decoded = decodeURIComponent(queryString) + let json + try { + json = JSON.parse(decoded) + } catch (err) { + return next() + } + ctx.request.body = json + return next() +} diff --git a/packages/backend-core/src/middleware/index.ts b/packages/backend-core/src/middleware/index.ts index de609f9a3e..0c4c2f6b94 100644 --- a/packages/backend-core/src/middleware/index.ts +++ b/packages/backend-core/src/middleware/index.ts @@ -17,4 +17,5 @@ export { default as builderOrAdmin } from "./builderOrAdmin" export { default as builderOnly } from "./builderOnly" export { default as logging } from "./logging" export { default as errorHandling } from "./errorHandling" +export { default as downloadBody } from "./downloadBody" export * as joiValidator from "./joi-validator" diff --git a/packages/builder/src/pages/builder/portal/account/auditLogs/index.svelte b/packages/builder/src/pages/builder/portal/account/auditLogs/index.svelte index 125a67a03d..944ed87d1a 100644 --- a/packages/builder/src/pages/builder/portal/account/auditLogs/index.svelte +++ b/packages/builder/src/pages/builder/portal/account/auditLogs/index.svelte @@ -21,13 +21,13 @@ import UserRenderer from "./_components/UserRenderer.svelte" import TimeRenderer from "./_components/TimeRenderer.svelte" import AppColumnRenderer from "./_components/AppColumnRenderer.svelte" - import download from "downloadjs" + import { cloneDeep } from "lodash" const schema = { date: { width: "0.8fr" }, user: { width: "0.5fr" }, - app: { width: "1fr", fieldName: "name" }, - name: { width: "1fr" }, + app: { width: "0.75fr", fieldName: "name" }, + name: { width: "1.5fr" }, view: { width: "auto", borderLeft: true, displayName: "" }, } @@ -134,8 +134,7 @@ $auditLogs.logs.bookmark ) } catch (error) { - console.log(error) - notifications.error("Error getting audit logs") + notifications.error(`Error getting audit logs - ${error}`) } } @@ -164,24 +163,13 @@ } const viewDetails = detail => { - console.log(detail) selectedLog = detail sidePanelVisible = true } - async function exportView() { - try { - const data = await API.exportView({ - viewName: view, - format: exportFormat, - }) - } catch (error) { - notifications.error(`Unable to export ${exportFormat.toUpperCase()} data`) - } - } const downloadLogs = async () => { try { - let response = await auditLogs.downloadLogs({ + window.location = auditLogs.getDownloadUrl({ startDate, endDate, fullSearch: logSearchTerm, @@ -189,8 +177,6 @@ appIds: selectedApps, events: selectedEvents, }) - - // DO SOMETHING HERE??????????? } catch (error) { notifications.error(`Error downloading logs: ` + error.message) } @@ -205,6 +191,20 @@ notifications.success("Copied") } + function cleanupMetadata(log) { + const cloned = cloneDeep(log) + cloned.userId = cloned.user._id + if (cloned.app) { + cloned.appId = cloned.app.appId + } + // remove props that are confused/not returned in download + delete cloned._id + delete cloned._rev + delete cloned.app + delete cloned.user + return cloned + } + onMount(async () => { await auditLogs.getEventDefinitions() await licensing.init() @@ -277,15 +277,15 @@ />
+
+ +
+
downloadLogs()} style="padding-bottom: var(--spacing-s)" > - -
- -
- +
@@ -352,7 +352,7 @@ disabled minHeight={"300px"} height={"100%"} - value={JSON.stringify(selectedLog.metadata, null, 2)} + value={JSON.stringify(cleanupMetadata(selectedLog), null, 2)} /> diff --git a/packages/builder/src/stores/portal/auditLogs.js b/packages/builder/src/stores/portal/auditLogs.js index 165e4b5ec5..9abf8ec11b 100644 --- a/packages/builder/src/stores/portal/auditLogs.js +++ b/packages/builder/src/stores/portal/auditLogs.js @@ -28,15 +28,15 @@ export function createAuditLogsStore() { }) } - async function downloadLogs(opts = {}) { - return await API.downloadLogs(opts) + function getDownloadUrl(opts = {}) { + return API.getDownloadUrl(opts) } return { subscribe, search, getEventDefinitions, - downloadLogs, + getDownloadUrl, } } diff --git a/packages/frontend-core/src/api/auditLogs.js b/packages/frontend-core/src/api/auditLogs.js index 08e14328a1..b8ad16a722 100644 --- a/packages/frontend-core/src/api/auditLogs.js +++ b/packages/frontend-core/src/api/auditLogs.js @@ -8,7 +8,7 @@ const buildOpts = ({ events, }) => { const opts = {} - + if (bookmark) { opts.bookmark = bookmark } @@ -56,10 +56,8 @@ export const buildAuditLogsEndpoints = API => ({ }) }, - downloadLogs: async opts => { - return await API.post({ - url: `/api/global/auditlogs/download`, - body: buildOpts(opts), - }) + getDownloadUrl: opts => { + const query = encodeURIComponent(JSON.stringify(opts)) + return `/api/global/auditlogs/download?query=${query}` }, }) diff --git a/packages/worker/src/api/routes/global/tests/auditLogs.spec.ts b/packages/worker/src/api/routes/global/tests/auditLogs.spec.ts new file mode 100644 index 0000000000..5e7ed31263 --- /dev/null +++ b/packages/worker/src/api/routes/global/tests/auditLogs.spec.ts @@ -0,0 +1,5 @@ +import { mocks } from "@budibase/backend-core/tests" + +mocks.licenses.useEnvironmentVariables() + +describe("/api/global/auditlogs", () => {}) From 83649f1959e35d894b50cc44097c9a2f9520e749 Mon Sep 17 00:00:00 2001 From: adrinr Date: Wed, 22 Feb 2023 22:40:50 +0100 Subject: [PATCH 038/106] Setup o2m and m2m relationships --- .tool-versions | 2 +- .../api/controllers/row/ExternalRequest.ts | 32 ++--- .../src/integration-test/postgres.spec.ts | 134 +++++++++++------- 3 files changed, 100 insertions(+), 68 deletions(-) diff --git a/.tool-versions b/.tool-versions index 8a1af3c071..6ee8cc60be 100644 --- a/.tool-versions +++ b/.tool-versions @@ -1,2 +1,2 @@ nodejs 14.19.3 -python 3.11.1 \ No newline at end of file +python 3.10.0 \ No newline at end of file diff --git a/packages/server/src/api/controllers/row/ExternalRequest.ts b/packages/server/src/api/controllers/row/ExternalRequest.ts index 1510e31881..79a598edf0 100644 --- a/packages/server/src/api/controllers/row/ExternalRequest.ts +++ b/packages/server/src/api/controllers/row/ExternalRequest.ts @@ -142,7 +142,11 @@ function cleanupConfig(config: RunConfig, table: Table): RunConfig { return config } -function generateIdForRow(row: Row | undefined, table: Table): string { +function generateIdForRow( + row: Row | undefined, + table: Table, + isLinked: boolean = false +): string { const primary = table.primary if (!row || !primary) { return "" @@ -151,7 +155,10 @@ function generateIdForRow(row: Row | undefined, table: Table): string { let idParts = [] for (let field of primary) { // need to handle table name + field or just field, depending on if relationships used - const fieldValue = row[`${table.name}.${field}`] || row[field] + let fieldValue = row[`${table.name}.${field}`] + if (!fieldValue && !isLinked) { + fieldValue = row[field] + } if (fieldValue) { idParts.push(fieldValue) } @@ -174,23 +181,20 @@ function getEndpoint(tableId: string | undefined, operation: string) { } } -function basicProcessing(row: Row, table: Table): Row { +function basicProcessing(row: Row, table: Table, isLinked: boolean): Row { const thisRow: Row = {} // filter the row down to what is actually the row (not joined) for (let field of Object.values(table.schema)) { const fieldName = field.name const pathValue = row[`${table.name}.${fieldName}`] - const value = - pathValue != null || field.type === FieldTypes.LINK - ? pathValue - : row[fieldName] + const value = pathValue != null || isLinked ? pathValue : row[fieldName] // all responses include "select col as table.col" so that overlaps are handled if (value != null) { thisRow[fieldName] = value } } - thisRow._id = generateIdForRow(row, table) + thisRow._id = generateIdForRow(row, table, isLinked) thisRow.tableId = table._id thisRow._rev = "rev" return processFormulas(table, thisRow) @@ -385,15 +389,7 @@ export class ExternalRequest { continue } - if ( - relationship.from && - row[fromColumn] === undefined && - row[relationship.from] === null - ) { - continue - } - - let linked = basicProcessing(row, linkedTable) + let linked = basicProcessing(row, linkedTable, true) if (!linked._id) { continue } @@ -441,7 +437,7 @@ export class ExternalRequest { ) continue } - const thisRow = fixArrayTypes(basicProcessing(row, table), table) + const thisRow = fixArrayTypes(basicProcessing(row, table, false), table) if (thisRow._id == null) { throw "Unable to generate row ID for SQL rows" } diff --git a/packages/server/src/integration-test/postgres.spec.ts b/packages/server/src/integration-test/postgres.spec.ts index c688600e8d..cc8760023f 100644 --- a/packages/server/src/integration-test/postgres.spec.ts +++ b/packages/server/src/integration-test/postgres.spec.ts @@ -23,11 +23,19 @@ jest.setTimeout(30000) jest.unmock("pg") +interface RandomForeignKeyConfig { + createOne2Many?: boolean + createMany2One?: number + createMany2Many?: number +} + describe("row api - postgres", () => { let makeRequest: MakeRequestResponse, postgresDatasource: Datasource, primaryPostgresTable: Table, - auxPostgresTable: Table + o2mInfo: { table: Table; fieldName: string }, + m2oInfo: { table: Table; fieldName: string }, + m2mInfo: { table: Table; fieldName: string } let host: string let port: number @@ -67,31 +75,46 @@ describe("row api - postgres", () => { }, }) - auxPostgresTable = await config.createTable({ - name: generator.word({ length: 10 }), - type: "external", - primary: ["id"], - schema: { - id: { - name: "id", - type: FieldType.AUTO, - constraints: { - presence: true, + async function createAuxTable(prefix: string) { + return await config.createTable({ + name: `${prefix}_${generator.word({ length: 6 })}`, + type: "external", + primary: ["id"], + schema: { + id: { + name: "id", + type: FieldType.AUTO, + constraints: { + presence: true, + }, + }, + title: { + name: "title", + type: FieldType.STRING, + constraints: { + presence: true, + }, }, }, - title: { - name: "title", - type: FieldType.STRING, - constraints: { - presence: true, - }, - }, - }, - sourceId: postgresDatasource._id, - }) + sourceId: postgresDatasource._id, + }) + } + + o2mInfo = { + table: await createAuxTable("o2m"), + fieldName: "oneToManyRelation", + } + m2oInfo = { + table: await createAuxTable("m2o"), + fieldName: "manyToOneRelation", + } + m2mInfo = { + table: await createAuxTable("m2m"), + fieldName: "manyToManyRelation", + } primaryPostgresTable = await config.createTable({ - name: generator.word({ length: 10 }), + name: `p_${generator.word({ length: 6 })}`, type: "external", primary: ["id"], schema: { @@ -117,25 +140,45 @@ describe("row api - postgres", () => { name: "value", type: FieldType.NUMBER, }, - linkedField: { + oneToManyRelation: { type: FieldType.LINK, constraints: { type: "array", presence: false, }, - fieldName: "foreignField", - name: "linkedField", + fieldName: o2mInfo.fieldName, + name: "oneToManyRelation", relationshipType: RelationshipTypes.ONE_TO_MANY, - tableId: auxPostgresTable._id, + tableId: o2mInfo.table._id, + }, + manyToOneRelation: { + type: FieldType.LINK, + constraints: { + type: "array", + presence: false, + }, + fieldName: m2oInfo.fieldName, + name: "manyToOneRelation", + relationshipType: RelationshipTypes.MANY_TO_ONE, + tableId: m2oInfo.table._id, + }, + manyToManyRelation: { + type: FieldType.LINK, + constraints: { + type: "array", + presence: false, + }, + fieldName: m2mInfo.fieldName, + name: "manyToManyRelation", + relationshipType: RelationshipTypes.MANY_TO_MANY, + tableId: m2mInfo.table._id, }, }, sourceId: postgresDatasource._id, }) }) - afterAll(async () => { - await config.end() - }) + afterAll(config.end) function generateRandomPrimaryRowData() { return { @@ -153,19 +196,20 @@ describe("row api - postgres", () => { async function createPrimaryRow(opts: { rowData: PrimaryRowData - createForeignRow?: boolean + createForeignRows?: RandomForeignKeyConfig }) { let { rowData } = opts let foreignRow: Row | undefined - if (opts?.createForeignRow) { + + if (opts?.createForeignRows?.createOne2Many) { foreignRow = await config.createRow({ - tableId: auxPostgresTable._id, + tableId: o2mInfo.table._id, title: generator.name(), }) rowData = { ...rowData, - [`fk_${auxPostgresTable.name}_foreignField`]: foreignRow.id, + [`fk_${o2mInfo.table.name}_${o2mInfo.fieldName}`]: foreignRow.id, } } @@ -197,9 +241,7 @@ describe("row api - postgres", () => { async function populatePrimaryRows( count: number, - opts?: { - createForeignRow?: boolean - } + opts?: RandomForeignKeyConfig ) { return await Promise.all( Array(count) @@ -210,7 +252,7 @@ describe("row api - postgres", () => { rowData, ...(await createPrimaryRow({ rowData, - createForeignRow: opts?.createForeignRow, + createForeignRows: opts, })), } }) @@ -295,7 +337,7 @@ describe("row api - postgres", () => { describe("given than a row exists", () => { let row: Row beforeEach(async () => { - let rowResponse = _.sample(await populatePrimaryRows(10))! + let rowResponse = _.sample(await populatePrimaryRows(1))! row = rowResponse.row }) @@ -422,7 +464,7 @@ describe("row api - postgres", () => { let foreignRow: Row beforeEach(async () => { let [createdRow] = await populatePrimaryRows(1, { - createForeignRow: true, + createOne2Many: true, }) row = createdRow.row foreignRow = createdRow.foreignRow! @@ -437,16 +479,10 @@ describe("row api - postgres", () => { ...row, _id: expect.any(String), _rev: expect.any(String), + [`fk_${o2mInfo.table.name}_${o2mInfo.fieldName}`]: foreignRow.id, }) - expect(res.body.foreignField).toBeUndefined() - - expect( - res.body[`fk_${auxPostgresTable.name}_foreignField`] - ).toBeDefined() - expect(res.body[`fk_${auxPostgresTable.name}_foreignField`]).toBe( - foreignRow.id - ) + expect(res.body[o2mInfo.fieldName]).toBeUndefined() }) }) }) @@ -672,7 +708,7 @@ describe("row api - postgres", () => { beforeEach(async () => { const rowsInfo = await createPrimaryRow({ rowData: generateRandomPrimaryRowData(), - createForeignRow: true, + createForeignRows: { createOne2Many: true }, }) row = rowsInfo.row @@ -687,7 +723,7 @@ describe("row api - postgres", () => { expect(foreignRow).toBeDefined() expect(res.body).toEqual({ ...row, - linkedField: [ + [o2mInfo.fieldName]: [ { ...foreignRow, }, From 70689c03690ba9440df4c0f8bee3c0d7ceaa074d Mon Sep 17 00:00:00 2001 From: adrinr Date: Thu, 23 Feb 2023 00:06:57 +0100 Subject: [PATCH 039/106] Fix tests --- .../src/integration-test/postgres.spec.ts | 257 ++++++++++++++---- 1 file changed, 204 insertions(+), 53 deletions(-) diff --git a/packages/server/src/integration-test/postgres.spec.ts b/packages/server/src/integration-test/postgres.spec.ts index cc8760023f..1707e596fd 100644 --- a/packages/server/src/integration-test/postgres.spec.ts +++ b/packages/server/src/integration-test/postgres.spec.ts @@ -23,19 +23,25 @@ jest.setTimeout(30000) jest.unmock("pg") -interface RandomForeignKeyConfig { - createOne2Many?: boolean - createMany2One?: number - createMany2Many?: number +interface ForeignTableInfo { + table: Table + fieldName: string + relationshipType: RelationshipTypes +} + +interface ForeignRowsInfo { + row: Row + foreignKey: string + relationshipType: RelationshipTypes } describe("row api - postgres", () => { let makeRequest: MakeRequestResponse, postgresDatasource: Datasource, primaryPostgresTable: Table, - o2mInfo: { table: Table; fieldName: string }, - m2oInfo: { table: Table; fieldName: string }, - m2mInfo: { table: Table; fieldName: string } + o2mInfo: ForeignTableInfo, + m2oInfo: ForeignTableInfo, + m2mInfo: ForeignTableInfo let host: string let port: number @@ -103,14 +109,17 @@ describe("row api - postgres", () => { o2mInfo = { table: await createAuxTable("o2m"), fieldName: "oneToManyRelation", + relationshipType: RelationshipTypes.ONE_TO_MANY, } m2oInfo = { table: await createAuxTable("m2o"), fieldName: "manyToOneRelation", + relationshipType: RelationshipTypes.MANY_TO_ONE, } m2mInfo = { table: await createAuxTable("m2m"), fieldName: "manyToManyRelation", + relationshipType: RelationshipTypes.MANY_TO_MANY, } primaryPostgresTable = await config.createTable({ @@ -196,21 +205,43 @@ describe("row api - postgres", () => { async function createPrimaryRow(opts: { rowData: PrimaryRowData - createForeignRows?: RandomForeignKeyConfig + createForeignRows?: { + createOne2Many?: boolean + createMany2One?: number + createMany2Many?: number + } }) { let { rowData } = opts - let foreignRow: Row | undefined + let foreignRows: ForeignRowsInfo[] = [] - if (opts?.createForeignRows?.createOne2Many) { - foreignRow = await config.createRow({ - tableId: o2mInfo.table._id, + async function createForeignRow(tableInfo: ForeignTableInfo) { + const foreignRow = await config.createRow({ + tableId: tableInfo.table._id, title: generator.name(), }) + const foreignKey = `fk_${tableInfo.table.name}_${tableInfo.fieldName}` rowData = { ...rowData, - [`fk_${o2mInfo.table.name}_${o2mInfo.fieldName}`]: foreignRow.id, + [foreignKey]: foreignRow.id, } + foreignRows.push({ + row: foreignRow, + foreignKey, + relationshipType: tableInfo.relationshipType, + }) + } + + if (opts?.createForeignRows?.createOne2Many) { + await createForeignRow(o2mInfo) + } + + for (let i = 0; i < (opts?.createForeignRows?.createMany2One || 0); i++) { + await createForeignRow(m2oInfo) + } + + for (let i = 0; i < (opts?.createForeignRows?.createMany2Many || 0); i++) { + await createForeignRow(m2mInfo) } const row = await config.createRow({ @@ -218,7 +249,7 @@ describe("row api - postgres", () => { ...rowData, }) - return { row, foreignRow } + return { row, foreignRows } } async function createDefaultPgTable() { @@ -241,7 +272,11 @@ describe("row api - postgres", () => { async function populatePrimaryRows( count: number, - opts?: RandomForeignKeyConfig + opts?: { + createOne2Many?: boolean + createMany2One?: number + createMany2Many?: number + } ) { return await Promise.all( Array(count) @@ -461,28 +496,134 @@ describe("row api - postgres", () => { describe("given a row with relation data", () => { let row: Row - let foreignRow: Row - beforeEach(async () => { - let [createdRow] = await populatePrimaryRows(1, { - createOne2Many: true, + let rowData: { + name: string + description: string + value: number + } + let foreignRows: ForeignRowsInfo[] + + describe("with all relationship types", () => { + beforeEach(async () => { + let [createdRow] = await populatePrimaryRows(1, { + createOne2Many: true, + createMany2One: 3, + createMany2Many: 2, + }) + row = createdRow.row + rowData = createdRow.rowData + foreignRows = createdRow.foreignRows + }) + + it("only one to many foreign keys are retrieved", async () => { + const res = await getRow(primaryPostgresTable._id, row.id) + + expect(res.status).toBe(200) + + const one2ManyForeignRows = foreignRows.filter( + x => x.relationshipType === RelationshipTypes.ONE_TO_MANY + ) + expect(one2ManyForeignRows).toHaveLength(1) + + expect(res.body).toEqual({ + ...rowData, + id: row.id, + tableId: row.tableId, + _id: expect.any(String), + _rev: expect.any(String), + [one2ManyForeignRows[0].foreignKey]: one2ManyForeignRows[0].row.id, + }) + + expect(res.body[o2mInfo.fieldName]).toBeUndefined() }) - row = createdRow.row - foreignRow = createdRow.foreignRow! }) - it("only foreign keys are retrieved", async () => { - const res = await getRow(primaryPostgresTable._id, row.id) - - expect(res.status).toBe(200) - - expect(res.body).toEqual({ - ...row, - _id: expect.any(String), - _rev: expect.any(String), - [`fk_${o2mInfo.table.name}_${o2mInfo.fieldName}`]: foreignRow.id, + describe("with only one to many", () => { + beforeEach(async () => { + let [createdRow] = await populatePrimaryRows(1, { + createOne2Many: true, + }) + row = createdRow.row + rowData = createdRow.rowData + foreignRows = createdRow.foreignRows }) - expect(res.body[o2mInfo.fieldName]).toBeUndefined() + it("only one to many foreign keys are retrieved", async () => { + const res = await getRow(primaryPostgresTable._id, row.id) + + expect(res.status).toBe(200) + + expect(foreignRows).toHaveLength(1) + + expect(res.body).toEqual({ + ...rowData, + id: row.id, + tableId: row.tableId, + _id: expect.any(String), + _rev: expect.any(String), + [foreignRows[0].foreignKey]: foreignRows[0].row.id, + }) + + expect(res.body[o2mInfo.fieldName]).toBeUndefined() + }) + }) + + describe("with only many to one", () => { + beforeEach(async () => { + let [createdRow] = await populatePrimaryRows(1, { + createMany2One: 3, + }) + row = createdRow.row + rowData = createdRow.rowData + foreignRows = createdRow.foreignRows + }) + + it("only one to many foreign keys are retrieved", async () => { + const res = await getRow(primaryPostgresTable._id, row.id) + + expect(res.status).toBe(200) + + expect(foreignRows).toHaveLength(3) + + expect(res.body).toEqual({ + ...rowData, + id: row.id, + tableId: row.tableId, + _id: expect.any(String), + _rev: expect.any(String), + }) + + expect(res.body[o2mInfo.fieldName]).toBeUndefined() + }) + }) + + describe("with only many to many", () => { + beforeEach(async () => { + let [createdRow] = await populatePrimaryRows(1, { + createMany2Many: 2, + }) + row = createdRow.row + rowData = createdRow.rowData + foreignRows = createdRow.foreignRows + }) + + it("only one to many foreign keys are retrieved", async () => { + const res = await getRow(primaryPostgresTable._id, row.id) + + expect(res.status).toBe(200) + + expect(foreignRows).toHaveLength(2) + + expect(res.body).toEqual({ + ...rowData, + id: row.id, + tableId: row.tableId, + _id: expect.any(String), + _rev: expect.any(String), + }) + + expect(res.body[o2mInfo.fieldName]).toBeUndefined() + }) }) }) }) @@ -703,31 +844,41 @@ describe("row api - postgres", () => { const getAll = (tableId: string | undefined, rowId: string | undefined) => makeRequest("get", `/api/${tableId}/${rowId}/enrich`) describe("given a row with relation data", () => { - let row: Row, foreignRow: Row | undefined + let row: Row, rowData: PrimaryRowData, foreignRows: ForeignRowsInfo[] - beforeEach(async () => { - const rowsInfo = await createPrimaryRow({ - rowData: generateRandomPrimaryRowData(), - createForeignRows: { createOne2Many: true }, + describe("only with one to many data", () => { + beforeEach(async () => { + rowData = generateRandomPrimaryRowData() + const rowsInfo = await createPrimaryRow({ + rowData, + createForeignRows: { createOne2Many: true }, + }) + + row = rowsInfo.row + foreignRows = rowsInfo.foreignRows }) - row = rowsInfo.row - foreignRow = rowsInfo.foreignRow - }) + it("enrich populates the foreign field", async () => { + const res = await getAll(primaryPostgresTable._id, row.id) - it("enrich populates the foreign field", async () => { - const res = await getAll(primaryPostgresTable._id, row.id) + expect(res.status).toBe(200) - expect(res.status).toBe(200) - - expect(foreignRow).toBeDefined() - expect(res.body).toEqual({ - ...row, - [o2mInfo.fieldName]: [ - { - ...foreignRow, - }, - ], + expect(foreignRows).toHaveLength(1) + expect(res.body).toEqual({ + ...rowData, + [foreignRows[0].foreignKey]: foreignRows[0].row.id, + [o2mInfo.fieldName]: [ + { + ...foreignRows[0].row, + _id: expect.any(String), + _rev: expect.any(String), + }, + ], + id: row.id, + tableId: row.tableId, + _id: expect.any(String), + _rev: expect.any(String), + }) }) }) }) @@ -750,7 +901,7 @@ describe("row api - postgres", () => { const rowsCount = 6 let rows: { row: Row - foreignRow: Row | undefined + foreignRows: ForeignRowsInfo[] rowData: PrimaryRowData }[] beforeEach(async () => { From 9e0d003038b594219abaa130d77807145541c47f Mon Sep 17 00:00:00 2001 From: adrinr Date: Thu, 23 Feb 2023 10:28:24 +0100 Subject: [PATCH 040/106] Fix creation --- packages/server/src/api/controllers/row/ExternalRequest.ts | 1 + packages/server/src/integrations/base/sql.ts | 4 +--- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/packages/server/src/api/controllers/row/ExternalRequest.ts b/packages/server/src/api/controllers/row/ExternalRequest.ts index 79a598edf0..74d48cb93e 100644 --- a/packages/server/src/api/controllers/row/ExternalRequest.ts +++ b/packages/server/src/api/controllers/row/ExternalRequest.ts @@ -741,6 +741,7 @@ export class ExternalRequest { table, }, } + // can't really use response right now const response = await getDatasourceAndQuery(json) // handle many to many relationships now if we know the ID (could be auto increment) diff --git a/packages/server/src/integrations/base/sql.ts b/packages/server/src/integrations/base/sql.ts index c722891910..6871d7b0ba 100644 --- a/packages/server/src/integrations/base/sql.ts +++ b/packages/server/src/integrations/base/sql.ts @@ -415,9 +415,7 @@ class InternalBuilder { if (opts.disableReturning) { return query.insert(parsedBody) } else { - return query - .insert(parsedBody) - .returning(generateSelectStatement(json, knex)) + return query.insert(parsedBody).returning("*") } } From 7868fc657d5bf31c4cc7a9bef5eb2b77bfb2bf34 Mon Sep 17 00:00:00 2001 From: adrinr Date: Thu, 23 Feb 2023 10:39:16 +0100 Subject: [PATCH 041/106] Fix many-to-one tests --- .../src/integration-test/postgres.spec.ts | 115 +++++++++++++++--- 1 file changed, 95 insertions(+), 20 deletions(-) diff --git a/packages/server/src/integration-test/postgres.spec.ts b/packages/server/src/integration-test/postgres.spec.ts index 1707e596fd..b9f356ded1 100644 --- a/packages/server/src/integration-test/postgres.spec.ts +++ b/packages/server/src/integration-test/postgres.spec.ts @@ -23,18 +23,6 @@ jest.setTimeout(30000) jest.unmock("pg") -interface ForeignTableInfo { - table: Table - fieldName: string - relationshipType: RelationshipTypes -} - -interface ForeignRowsInfo { - row: Row - foreignKey: string - relationshipType: RelationshipTypes -} - describe("row api - postgres", () => { let makeRequest: MakeRequestResponse, postgresDatasource: Datasource, @@ -86,10 +74,12 @@ describe("row api - postgres", () => { name: `${prefix}_${generator.word({ length: 6 })}`, type: "external", primary: ["id"], + primaryDisplay: "title", schema: { id: { name: "id", type: FieldType.AUTO, + autocolumn: true, constraints: { presence: true, }, @@ -130,6 +120,7 @@ describe("row api - postgres", () => { id: { name: "id", type: FieldType.AUTO, + autocolumn: true, constraints: { presence: true, }, @@ -159,6 +150,7 @@ describe("row api - postgres", () => { name: "oneToManyRelation", relationshipType: RelationshipTypes.ONE_TO_MANY, tableId: o2mInfo.table._id, + main: true, }, manyToOneRelation: { type: FieldType.LINK, @@ -170,6 +162,7 @@ describe("row api - postgres", () => { name: "manyToOneRelation", relationshipType: RelationshipTypes.MANY_TO_ONE, tableId: m2oInfo.table._id, + main: true, }, manyToManyRelation: { type: FieldType.LINK, @@ -181,6 +174,7 @@ describe("row api - postgres", () => { name: "manyToManyRelation", relationshipType: RelationshipTypes.MANY_TO_MANY, tableId: m2mInfo.table._id, + main: true, }, }, sourceId: postgresDatasource._id, @@ -203,6 +197,17 @@ describe("row api - postgres", () => { value: number } + type ForeignTableInfo = { + table: Table + fieldName: string + relationshipType: RelationshipTypes + } + + type ForeignRowsInfo = { + row: Row + relationshipType: RelationshipTypes + } + async function createPrimaryRow(opts: { rowData: PrimaryRowData createForeignRows?: { @@ -211,33 +216,61 @@ describe("row api - postgres", () => { createMany2Many?: number } }) { - let { rowData } = opts + let { rowData } = opts as any let foreignRows: ForeignRowsInfo[] = [] async function createForeignRow(tableInfo: ForeignTableInfo) { + const foreignKey = `fk_${tableInfo.table.name}_${tableInfo.fieldName}` + const foreignRow = await config.createRow({ tableId: tableInfo.table._id, title: generator.name(), }) - const foreignKey = `fk_${tableInfo.table.name}_${tableInfo.fieldName}` rowData = { ...rowData, [foreignKey]: foreignRow.id, } foreignRows.push({ row: foreignRow, - foreignKey, + relationshipType: tableInfo.relationshipType, }) } if (opts?.createForeignRows?.createOne2Many) { - await createForeignRow(o2mInfo) + const foreignKey = `fk_${o2mInfo.table.name}_${o2mInfo.fieldName}` + + const foreignRow = await config.createRow({ + tableId: o2mInfo.table._id, + title: generator.name(), + }) + + rowData = { + ...rowData, + [foreignKey]: foreignRow.id, + } + foreignRows.push({ + row: foreignRow, + relationshipType: o2mInfo.relationshipType, + }) } for (let i = 0; i < (opts?.createForeignRows?.createMany2One || 0); i++) { - await createForeignRow(m2oInfo) + const foreignRow = await config.createRow({ + tableId: m2oInfo.table._id, + title: generator.name(), + }) + + rowData = { + ...rowData, + [m2oInfo.fieldName]: rowData[m2oInfo.fieldName] || [], + } + rowData[m2oInfo.fieldName].push(foreignRow._id) + foreignRows.push({ + row: foreignRow, + relationshipType: RelationshipTypes.MANY_TO_ONE, + }) } for (let i = 0; i < (opts?.createForeignRows?.createMany2Many || 0); i++) { @@ -531,7 +564,8 @@ describe("row api - postgres", () => { tableId: row.tableId, _id: expect.any(String), _rev: expect.any(String), - [one2ManyForeignRows[0].foreignKey]: one2ManyForeignRows[0].row.id, + [`fk_${o2mInfo.table.name}_${o2mInfo.fieldName}`]: + one2ManyForeignRows[0].row.id, }) expect(res.body[o2mInfo.fieldName]).toBeUndefined() @@ -561,7 +595,8 @@ describe("row api - postgres", () => { tableId: row.tableId, _id: expect.any(String), _rev: expect.any(String), - [foreignRows[0].foreignKey]: foreignRows[0].row.id, + [`fk_${o2mInfo.table.name}_${o2mInfo.fieldName}`]: + foreignRows[0].row.id, }) expect(res.body[o2mInfo.fieldName]).toBeUndefined() @@ -866,7 +901,8 @@ describe("row api - postgres", () => { expect(foreignRows).toHaveLength(1) expect(res.body).toEqual({ ...rowData, - [foreignRows[0].foreignKey]: foreignRows[0].row.id, + [`fk_${o2mInfo.table.name}_${o2mInfo.fieldName}`]: + foreignRows[0].row.id, [o2mInfo.fieldName]: [ { ...foreignRows[0].row, @@ -881,6 +917,45 @@ describe("row api - postgres", () => { }) }) }) + + describe("only with many to one data", () => { + beforeEach(async () => { + rowData = generateRandomPrimaryRowData() + const rowsInfo = await createPrimaryRow({ + rowData, + createForeignRows: { + createMany2One: 2, + }, + }) + + row = rowsInfo.row + foreignRows = rowsInfo.foreignRows + }) + + it("enrich populates the foreign field", async () => { + const res = await getAll(primaryPostgresTable._id, row.id) + + expect(res.status).toBe(200) + + expect(res.body).toEqual({ + ...rowData, + [m2oInfo.fieldName]: [ + { + ...foreignRows[0].row, + [`fk_${m2oInfo.table.name}_${m2oInfo.fieldName}`]: row.id, + }, + { + ...foreignRows[1].row, + [`fk_${m2oInfo.table.name}_${m2oInfo.fieldName}`]: row.id, + }, + ], + id: row.id, + tableId: row.tableId, + _id: expect.any(String), + _rev: expect.any(String), + }) + }) + }) }) }) From 5207f5108035d01cfed3ab4f0f9d242d9149f8fa Mon Sep 17 00:00:00 2001 From: adrinr Date: Thu, 23 Feb 2023 10:50:18 +0100 Subject: [PATCH 042/106] Test enrich for all relationship types --- .../src/integration-test/postgres.spec.ts | 91 ++++++++++--------- 1 file changed, 47 insertions(+), 44 deletions(-) diff --git a/packages/server/src/integration-test/postgres.spec.ts b/packages/server/src/integration-test/postgres.spec.ts index b9f356ded1..df0e4bac15 100644 --- a/packages/server/src/integration-test/postgres.spec.ts +++ b/packages/server/src/integration-test/postgres.spec.ts @@ -274,7 +274,20 @@ describe("row api - postgres", () => { } for (let i = 0; i < (opts?.createForeignRows?.createMany2Many || 0); i++) { - await createForeignRow(m2mInfo) + const foreignRow = await config.createRow({ + tableId: m2mInfo.table._id, + title: generator.name(), + }) + + rowData = { + ...rowData, + [m2mInfo.fieldName]: rowData[m2mInfo.fieldName] || [], + } + rowData[m2mInfo.fieldName].push(foreignRow._id) + foreignRows.push({ + row: foreignRow, + relationshipType: RelationshipTypes.MANY_TO_MANY, + }) } const row = await config.createRow({ @@ -513,7 +526,7 @@ describe("row api - postgres", () => { let rows: { row: Row; rowData: PrimaryRowData }[] beforeEach(async () => { - rows = await populatePrimaryRows(10) + rows = await populatePrimaryRows(5) }) it("a single row can be retrieved successfully", async () => { @@ -881,50 +894,15 @@ describe("row api - postgres", () => { describe("given a row with relation data", () => { let row: Row, rowData: PrimaryRowData, foreignRows: ForeignRowsInfo[] - describe("only with one to many data", () => { - beforeEach(async () => { - rowData = generateRandomPrimaryRowData() - const rowsInfo = await createPrimaryRow({ - rowData, - createForeignRows: { createOne2Many: true }, - }) - - row = rowsInfo.row - foreignRows = rowsInfo.foreignRows - }) - - it("enrich populates the foreign field", async () => { - const res = await getAll(primaryPostgresTable._id, row.id) - - expect(res.status).toBe(200) - - expect(foreignRows).toHaveLength(1) - expect(res.body).toEqual({ - ...rowData, - [`fk_${o2mInfo.table.name}_${o2mInfo.fieldName}`]: - foreignRows[0].row.id, - [o2mInfo.fieldName]: [ - { - ...foreignRows[0].row, - _id: expect.any(String), - _rev: expect.any(String), - }, - ], - id: row.id, - tableId: row.tableId, - _id: expect.any(String), - _rev: expect.any(String), - }) - }) - }) - - describe("only with many to one data", () => { + describe("with all relationship types", () => { beforeEach(async () => { rowData = generateRandomPrimaryRowData() const rowsInfo = await createPrimaryRow({ rowData, createForeignRows: { - createMany2One: 2, + createOne2Many: true, + createMany2One: 3, + createMany2Many: 2, }, }) @@ -932,22 +910,47 @@ describe("row api - postgres", () => { foreignRows = rowsInfo.foreignRows }) - it("enrich populates the foreign field", async () => { + it("enrich populates the foreign fields", async () => { const res = await getAll(primaryPostgresTable._id, row.id) expect(res.status).toBe(200) + const foreignRowsByType = _.groupBy( + foreignRows, + x => x.relationshipType + ) expect(res.body).toEqual({ ...rowData, + [`fk_${o2mInfo.table.name}_${o2mInfo.fieldName}`]: + foreignRowsByType[RelationshipTypes.ONE_TO_MANY][0].row.id, + [o2mInfo.fieldName]: [ + { + ...foreignRowsByType[RelationshipTypes.ONE_TO_MANY][0].row, + _id: expect.any(String), + _rev: expect.any(String), + }, + ], [m2oInfo.fieldName]: [ { - ...foreignRows[0].row, + ...foreignRowsByType[RelationshipTypes.MANY_TO_ONE][0].row, [`fk_${m2oInfo.table.name}_${m2oInfo.fieldName}`]: row.id, }, { - ...foreignRows[1].row, + ...foreignRowsByType[RelationshipTypes.MANY_TO_ONE][1].row, [`fk_${m2oInfo.table.name}_${m2oInfo.fieldName}`]: row.id, }, + { + ...foreignRowsByType[RelationshipTypes.MANY_TO_ONE][2].row, + [`fk_${m2oInfo.table.name}_${m2oInfo.fieldName}`]: row.id, + }, + ], + [m2mInfo.fieldName]: [ + { + ...foreignRowsByType[RelationshipTypes.MANY_TO_MANY][0].row, + }, + { + ...foreignRowsByType[RelationshipTypes.MANY_TO_MANY][1].row, + }, ], id: row.id, tableId: row.tableId, From 6efb0f4997986a419952996c0f1edd8e42c4a6c8 Mon Sep 17 00:00:00 2001 From: Peter Clement Date: Thu, 23 Feb 2023 10:57:50 +0000 Subject: [PATCH 043/106] update table width --- .../builder/portal/account/auditLogs/index.svelte | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/packages/builder/src/pages/builder/portal/account/auditLogs/index.svelte b/packages/builder/src/pages/builder/portal/account/auditLogs/index.svelte index 944ed87d1a..34c50f3354 100644 --- a/packages/builder/src/pages/builder/portal/account/auditLogs/index.svelte +++ b/packages/builder/src/pages/builder/portal/account/auditLogs/index.svelte @@ -1,3 +1,7 @@ +