diff --git a/AUTHORS.md b/.github/AUTHORS.md similarity index 100% rename from AUTHORS.md rename to .github/AUTHORS.md diff --git a/CODE_OF_CONDUCT.md b/.github/CODE_OF_CONDUCT.md similarity index 100% rename from CODE_OF_CONDUCT.md rename to .github/CODE_OF_CONDUCT.md diff --git a/CONTRIBUTING.md b/.github/CONTRIBUTING.md similarity index 99% rename from CONTRIBUTING.md rename to .github/CONTRIBUTING.md index 72ad1fb6e9..e49b3b37ab 100644 --- a/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -186,7 +186,7 @@ Or if you are in the builder you can run `yarn cy:test`. ### Other Useful Information -* The contributors are listed in [AUTHORS.md](https://github.com/budibase/server/blob/master/AUTHORS.md) (add yourself). +* The contributors are listed in [AUTHORS.md](https://github.com/Budibase/budibase/blob/master/.github/AUTHORS.md) (add yourself). * This project uses a modified version of the MPLv2 license, see [LICENSE](https://github.com/budibase/server/blob/master/LICENSE). diff --git a/README.md b/README.md index 5056479db9..50ef3dc855 100644 --- a/README.md +++ b/README.md @@ -116,7 +116,7 @@ You can also follow a quick tutorial on [how to build a CRM with Budibase](https ## ❗ Code of Conduct -Budibase is dedicated to providing a welcoming, diverse, and harrassment-free experience for everyone. We expect everyone in the Budibase community to abide by our [**Code of Conduct**](https://github.com/Budibase/budibase/blob/master/CODE_OF_CONDUCT.md). Please read it. +Budibase is dedicated to providing a welcoming, diverse, and harrassment-free experience for everyone. We expect everyone in the Budibase community to abide by our [**Code of Conduct**](https://github.com/Budibase/budibase/blob/master/.github/CODE_OF_CONDUCT.md). Please read it. ## 🙌 Contributing to Budibase @@ -134,7 +134,7 @@ Budibase is a monorepo managed by lerna. Lerna manages the building and publishi - [packages/server](https://github.com/Budibase/budibase/tree/master/packages/server) - The budibase server. This Koa app is responsible for serving the JS for the builder and budibase apps, as well as providing the API for interaction with the database and file system. -For more information, see [CONTRIBUTING.md](./CONTRIBUTING.md) +For more information, see [CONTRIBUTING.md](https://github.com/Budibase/budibase/blob/master/.github/CONTRIBUTING.md) ## 📝 License diff --git a/package.json b/package.json index 5ff26bfa91..d58e36517d 100644 --- a/package.json +++ b/package.json @@ -14,7 +14,7 @@ "prettier-plugin-svelte": "^1.4.0", "rimraf": "^3.0.2", "rollup-plugin-replace": "^2.2.0", - "svelte": "^3.28.0" + "svelte": "^3.30.0" }, "scripts": { "bootstrap": "lerna bootstrap", @@ -26,7 +26,7 @@ "nuke": "rimraf ~/.budibase && npm run restore", "clean": "lerna clean", "kill-port": "kill-port 4001", - "dev": "npm run kill-port && node ./scripts/symlinkDev.js && lerna run --parallel dev:builder --concurrency 1", + "dev": "yarn run kill-port && node ./scripts/symlinkDev.js && lerna run --parallel dev:builder --concurrency 1", "test": "lerna run test", "lint": "eslint packages", "lint:fix": "eslint --fix packages", diff --git a/packages/builder/cypress/integration/createTable.spec.js b/packages/builder/cypress/integration/createTable.spec.js index fdad39b956..27560aaeb9 100644 --- a/packages/builder/cypress/integration/createTable.spec.js +++ b/packages/builder/cypress/integration/createTable.spec.js @@ -60,7 +60,7 @@ context("Create a Table", () => { }) it("deletes a table", () => { - cy.contains(".nav-item", "dog").get(".actions").invoke("show").click() + cy.get(".actions").first().invoke("show").click() cy.get("[data-cy=delete-table]").click() cy.contains("Delete Table").click() cy.contains("dog").should("not.exist") diff --git a/packages/builder/cypress/integration/createUser.spec.js b/packages/builder/cypress/integration/createUser.spec.js index b1f737068b..a5f9934dd7 100644 --- a/packages/builder/cypress/integration/createUser.spec.js +++ b/packages/builder/cypress/integration/createUser.spec.js @@ -9,9 +9,9 @@ context('Create a User', () => { // https://on.cypress.io/interacting-with-elements it('should create a user', () => { - cy.createUser('bbuser', 'test', 'POWER_USER') + cy.createUser("bbuser@test.com", "test", "ADMIN") - // Check to make sure user was created! - cy.get("input[disabled]").should('have.value', 'bbuser') + // // Check to make sure user was created! + cy.contains("bbuser").should('be.visible') }) }) diff --git a/packages/builder/cypress/setup.js b/packages/builder/cypress/setup.js index f56374ea35..7f20eff88c 100644 --- a/packages/builder/cypress/setup.js +++ b/packages/builder/cypress/setup.js @@ -16,6 +16,9 @@ process.env.BUDIBASE_API_KEY = "6BE826CB-6B30-4AEC-8777-2E90464633DE" process.env.NODE_ENV = "cypress" process.env.ENABLE_ANALYTICS = "false" +// Stop info logs polluting test outputs +process.env.LOG_LEVEL = "error" + async function run(dir) { process.env.BUDIBASE_DIR = resolve(dir) require("dotenv").config({ path: resolve(dir, ".env") }) diff --git a/packages/builder/cypress/support/commands.js b/packages/builder/cypress/support/commands.js index 15564083ba..94faa124a8 100644 --- a/packages/builder/cypress/support/commands.js +++ b/packages/builder/cypress/support/commands.js @@ -44,9 +44,9 @@ Cypress.Commands.add("createApp", name => { cy.contains("Next").click() - cy.get("input[name=username]") + cy.get("input[name=email]") .click() - .type("test") + .type("test@test.com") cy.get("input[name=password]") .click() .type("test") @@ -111,25 +111,28 @@ Cypress.Commands.add("addRow", values => { }) }) -Cypress.Commands.add("createUser", (username, password, accessLevel) => { +Cypress.Commands.add("createUser", (email, password, role) => { // Create User - cy.get(".toprightnav > .settings").click() cy.contains("Users").click() - cy.get("[name=Name]") - .first() - .type(username) - cy.get("[name=Password]") - .first() - .type(password) - cy.get("select") - .first() - .select(accessLevel) + cy.contains("Create New Row").click() - // Save - cy.get(".inputs") - .contains("Create") - .click() + cy.get(".modal").within(() => { + cy.get("input") + .first() + .type(password) + cy.get("input") + .eq(1) + .type(email) + cy.get("select") + .first() + .select(role) + + // Save + cy.get(".buttons") + .contains("Create Row") + .click() + }) }) Cypress.Commands.add("addHeadlineComponent", text => { diff --git a/packages/builder/package.json b/packages/builder/package.json index 4254e3c7f6..542c35205e 100644 --- a/packages/builder/package.json +++ b/packages/builder/package.json @@ -63,7 +63,7 @@ } }, "dependencies": { - "@budibase/bbui": "^1.50.2", + "@budibase/bbui": "^1.52.2", "@budibase/client": "^0.3.8", "@budibase/colorpicker": "^1.0.1", "@budibase/svelte-ag-grid": "^0.0.16", @@ -81,8 +81,8 @@ "shortid": "^2.2.15", "svelte-loading-spinners": "^0.1.1", "svelte-portal": "^0.1.0", - "yup": "^0.29.2", - "uuid": "^8.3.1" + "uuid": "^8.3.1", + "yup": "^0.29.2" }, "devDependencies": { "@babel/core": "^7.5.5", @@ -90,6 +90,7 @@ "@babel/preset-env": "^7.5.5", "@babel/runtime": "^7.5.5", "@rollup/plugin-alias": "^3.0.1", + "@rollup/plugin-commonjs": "^16.0.0", "@rollup/plugin-json": "^4.0.3", "@sveltech/routify": "1.7.11", "@testing-library/jest-dom": "^5.11.0", @@ -104,9 +105,9 @@ "rimraf": "^3.0.2", "rollup": "^2.11.2", "rollup-plugin-alias": "^1.5.2", - "rollup-plugin-commonjs": "^10.0.0", "rollup-plugin-copy": "^3.0.0", "rollup-plugin-css-only": "^2.1.0", + "rollup-plugin-html": "^0.2.1", "rollup-plugin-livereload": "^1.0.0", "rollup-plugin-node-builtins": "^2.1.2", "rollup-plugin-node-globals": "^1.4.0", @@ -115,7 +116,7 @@ "rollup-plugin-terser": "^7.0.2", "rollup-plugin-url": "^2.2.2", "start-server-and-test": "^1.11.0", - "svelte": "^3.29.0", + "svelte": "^3.30.0", "svelte-jester": "^1.0.6" }, "gitHead": "115189f72a850bfb52b65ec61d932531bf327072" diff --git a/packages/builder/rollup.config.js b/packages/builder/rollup.config.js index 93c36026e4..2d5ec52f52 100644 --- a/packages/builder/rollup.config.js +++ b/packages/builder/rollup.config.js @@ -1,7 +1,7 @@ import alias from "@rollup/plugin-alias" import svelte from "rollup-plugin-svelte" import resolve from "rollup-plugin-node-resolve" -import commonjs from "rollup-plugin-commonjs" +import commonjs from "@rollup/plugin-commonjs" import url from "rollup-plugin-url" import livereload from "rollup-plugin-livereload" import { terser } from "rollup-plugin-terser" @@ -11,106 +11,12 @@ import copy from "rollup-plugin-copy" import css from "rollup-plugin-css-only" import replace from "rollup-plugin-replace" import json from "@rollup/plugin-json" +import html from "rollup-plugin-html" import path from "path" const production = !process.env.ROLLUP_WATCH - -const lodash_fp_exports = [ - "flow", - "pipe", - "union", - "reduce", - "isUndefined", - "cloneDeep", - "split", - "some", - "map", - "filter", - "isEmpty", - "countBy", - "includes", - "last", - "find", - "constant", - "take", - "first", - "intersection", - "mapValues", - "isNull", - "has", - "isInteger", - "isNumber", - "isString", - "isBoolean", - "isDate", - "isArray", - "isObject", - "clone", - "values", - "keyBy", - "isNaN", - "keys", - "orderBy", - "concat", - "reverse", - "difference", - "merge", - "flatten", - "each", - "pull", - "join", - "defaultCase", - "uniqBy", - "every", - "uniqWith", - "isFunction", - "groupBy", - "differenceBy", - "intersectionBy", - "isEqual", - "max", - "sortBy", - "assign", - "uniq", - "trimChars", - "trimCharsStart", - "isObjectLike", - "flattenDeep", - "indexOf", - "isPlainObject", - "toNumber", - "takeRight", - "toPairs", - "remove", - "findIndex", - "compose", - "get", - "tap", -] - -const lodash_exports = [ - "flow", - "join", - "replace", - "trim", - "dropRight", - "takeRight", - "head", - "reduce", - "tail", - "startsWith", - "findIndex", - "merge", - "assign", - "each", - "find", - "orderBy", - "union", -] - const outputpath = "../server/builder" - const coreExternal = [ "lodash", "lodash/fp", @@ -170,10 +76,6 @@ export default { { src: "src/index.html", dest: outputpath }, { src: "src/favicon.png", dest: outputpath }, { src: "assets", dest: outputpath }, - { - src: "node_modules/@budibase/client/dist/budibase-client.esm.mjs", - dest: outputpath, - }, { src: "node_modules/@budibase/bbui/dist/bbui.css", dest: outputpath, @@ -224,13 +126,7 @@ export default { ) }, }), - commonjs({ - namedExports: { - "lodash/fp": lodash_fp_exports, - lodash: lodash_exports, - shortid: ["generate"], - }, - }), + commonjs(), url({ limit: 0, include: ["**/*.woff2", "**/*.png"], @@ -248,5 +144,6 @@ export default { // instead of npm run dev), minify production && terser(), json(), + html(), ], } diff --git a/packages/builder/src/builderStore/fetchBindableProperties.js b/packages/builder/src/builderStore/fetchBindableProperties.js index 9a193112fb..962fb80ebf 100644 --- a/packages/builder/src/builderStore/fetchBindableProperties.js +++ b/packages/builder/src/builderStore/fetchBindableProperties.js @@ -24,7 +24,7 @@ import { cloneDeep, difference } from "lodash/fp" * @returns {Array.} */ export default function({ componentInstanceId, screen, components, tables }) { - const walkResult = walk({ + const result = walk({ // cloning so we are free to mutate props (e.g. by adding _contexts) instance: cloneDeep(screen.props), targetId: componentInstanceId, @@ -33,13 +33,10 @@ export default function({ componentInstanceId, screen, components, tables }) { }) return [ - ...walkResult.bindableInstances - .filter(isInstanceInSharedContext(walkResult)) - .map(componentInstanceToBindable(walkResult)), - - ...(walkResult.target?._contexts - .map(contextToBindables(tables, walkResult)) - .flat() ?? []), + ...result.bindableInstances + .filter(isInstanceInSharedContext(result)) + .map(componentInstanceToBindable), + ...(result.target?._contexts.map(contextToBindables(tables)).flat() ?? []), ] } @@ -53,26 +50,18 @@ const isInstanceInSharedContext = walkResult => i => // turns a component instance prop into binding expressions // used by the UI -const componentInstanceToBindable = walkResult => i => { - const lastContext = - i.instance._contexts.length && - i.instance._contexts[i.instance._contexts.length - 1] - const contextParentPath = lastContext - ? getParentPath(walkResult, lastContext) - : "" - +const componentInstanceToBindable = i => { return { type: "instance", instance: i.instance, // how the binding expression persists, and is used in the app at runtime - runtimeBinding: `${contextParentPath}${i.instance._id}.${i.prop}`, + runtimeBinding: `${i.instance._id}`, // how the binding exressions looks to the user of the builder readableBinding: `${i.instance._instanceName}`, } } -const contextToBindables = (tables, walkResult) => context => { - const contextParentPath = getParentPath(walkResult, context) +const contextToBindables = tables => context => { const tableId = context.table?.tableId ?? context.table const table = tables.find(table => table._id === tableId) let schema = @@ -98,7 +87,7 @@ const contextToBindables = (tables, walkResult) => context => { fieldSchema, instance: context.instance, // how the binding expression persists, and is used in the app at runtime - runtimeBinding: `${contextParentPath}data.${runtimeBoundKey}`, + runtimeBinding: `${context.instance._id}.${runtimeBoundKey}`, // how the binding expressions looks to the user of the builder readableBinding: `${context.instance._instanceName}.${table.name}.${key}`, // table / view info @@ -118,20 +107,6 @@ const contextToBindables = (tables, walkResult) => context => { ) } -const getParentPath = (walkResult, context) => { - // describes the number of "parent" in the path - // clone array first so original array is not mtated - const contextParentNumber = [...walkResult.target._contexts] - .reverse() - .indexOf(context) - - return ( - new Array(contextParentNumber).fill("parent").join(".") + - // trailing . if has parents - (contextParentNumber ? "." : "") - ) -} - const walk = ({ instance, targetId, components, tables, result }) => { if (!result) { result = { diff --git a/packages/builder/src/builderStore/getNewComponentName.js b/packages/builder/src/builderStore/getNewComponentName.js index a69bec21ad..98ca05b827 100644 --- a/packages/builder/src/builderStore/getNewComponentName.js +++ b/packages/builder/src/builderStore/getNewComponentName.js @@ -2,6 +2,8 @@ import { walkProps } from "./storeUtils" import { get_capitalised_name } from "../helpers" import { get } from "svelte/store" import { allScreens } from "builderStore" +import { FrontendTypes } from "../constants" +import { currentAsset } from "." export default function(component, state) { const capitalised = get_capitalised_name( @@ -19,14 +21,16 @@ export default function(component, state) { }) } - // check page first - findMatches(state.pages[state.currentPageName].props) + // check layouts first + for (let layout of state.layouts) { + findMatches(layout.props) + } // if viewing screen, check current screen for duplicate - if (state.currentFrontEndType === "screen") { - findMatches(state.currentPreviewItem.props) + if (state.currentFrontEndType === FrontendTypes.SCREEN) { + findMatches(get(currentAsset).props) } else { - // viewing master page - need to find against all screens + // viewing a layout - need to find against all screens for (let screen of get(allScreens)) { findMatches(screen.props) } diff --git a/packages/builder/src/builderStore/index.js b/packages/builder/src/builderStore/index.js index ae77889404..887ef733e4 100644 --- a/packages/builder/src/builderStore/index.js +++ b/packages/builder/src/builderStore/index.js @@ -4,37 +4,74 @@ import { getAutomationStore } from "./store/automation/" import { getThemeStore } from "./store/theme" import { derived } from "svelte/store" import analytics from "analytics" +import { LAYOUT_NAMES } from "../constants" +import { makePropsSafe } from "components/userInterface/assetParsing/createProps" export const store = getFrontendStore() export const backendUiStore = getBackendUiStore() export const automationStore = getAutomationStore() export const themeStore = getThemeStore() +export const currentAsset = derived(store, $store => { + const layout = $store.layouts + ? $store.layouts.find(layout => layout._id === $store.currentAssetId) + : null + + if (layout) return layout + + const screen = $store.screens + ? $store.screens.find(screen => screen._id === $store.currentAssetId) + : null + + if (screen) return screen + + return null +}) + +export const selectedComponent = derived( + [store, currentAsset], + ([$store, $currentAsset]) => { + if (!$currentAsset || !$store.selectedComponentId) return null + + function traverse(node, callback) { + if (node._id === $store.selectedComponentId) return callback(node) + + if (node._children) { + node._children.forEach(child => traverse(child, callback)) + } + + if (node.props) { + traverse(node.props, callback) + } + } + + let component + traverse($currentAsset, found => { + const componentIdentifier = found._component ?? found.props._component + const componentDef = componentIdentifier.startsWith("##") + ? found + : $store.components[componentIdentifier] + + component = makePropsSafe(componentDef, found) + }) + + return component + } +) + +export const currentAssetName = derived(store, () => { + return currentAsset.name +}) + +// leave this as before for consistency export const allScreens = derived(store, $store => { - let screens = [] - if ($store.pages == null) { - return screens - } - for (let page of Object.values($store.pages)) { - screens = screens.concat(page._screens) - } - return screens + return $store.screens }) -export const currentScreens = derived(store, $store => { - const currentScreens = $store.pages[$store.currentPageName]?._screens - if (currentScreens == null) { - return [] - } - return Array.isArray(currentScreens) - ? currentScreens - : Object.values(currentScreens) -}) - -export const selectedPage = derived(store, $store => { - if (!$store.pages) return null - - return $store.pages[$store.currentPageName || "main"] +export const mainLayout = derived(store, $store => { + return $store.layouts?.find( + layout => layout._id === LAYOUT_NAMES.MASTER.PRIVATE + ) }) export const initialise = async () => { diff --git a/packages/builder/src/builderStore/replaceBindings.js b/packages/builder/src/builderStore/replaceBindings.js index aa57301261..0bf9f485c9 100644 --- a/packages/builder/src/builderStore/replaceBindings.js +++ b/packages/builder/src/builderStore/replaceBindings.js @@ -12,10 +12,7 @@ export function readableToRuntimeBinding(bindableProperties, textWithBindings) { return boundValue === `{{ ${readableBinding} }}` }) if (binding) { - result = textWithBindings.replace( - boundValue, - `{{ ${binding.runtimeBinding} }}` - ) + result = result.replace(boundValue, `{{ ${binding.runtimeBinding} }}`) } }) return result diff --git a/packages/builder/src/builderStore/store/frontend.js b/packages/builder/src/builderStore/store/frontend.js index 778c7f7be5..5bb10a24c2 100644 --- a/packages/builder/src/builderStore/store/frontend.js +++ b/packages/builder/src/builderStore/store/frontend.js @@ -4,34 +4,36 @@ import { createProps, getBuiltin, makePropsSafe, -} from "components/userInterface/pagesParsing/createProps" -import { allScreens, backendUiStore, selectedPage } from "builderStore" -import { generate_screen_css } from "../generate_css" +} from "components/userInterface/assetParsing/createProps" +import { + allScreens, + backendUiStore, + currentAsset, + mainLayout, + selectedComponent, +} from "builderStore" import { fetchComponentLibDefinitions } from "../loadComponentLibraries" import api from "../api" -import { DEFAULT_PAGES_OBJECT } from "../../constants" +import { FrontendTypes } from "../../constants" import getNewComponentName from "../getNewComponentName" import analytics from "analytics" import { findChildComponentType, generateNewIdsForComponent, getComponentDefinition, - getParent, + findParent, } from "../storeUtils" const INITIAL_FRONTEND_STATE = { apps: [], name: "", description: "", - pages: DEFAULT_PAGES_OBJECT, - mainUi: {}, - unauthenticatedUi: {}, + layouts: [], + screens: [], components: [], - currentPreviewItem: null, - currentComponentInfo: null, currentFrontEndType: "none", - currentPageName: "", - currentComponentProps: null, + currentAssetId: "", + selectedComponentId: "", errors: [], hasAppPackage: false, libraries: null, @@ -43,52 +45,13 @@ export const getFrontendStore = () => { const store = writable({ ...INITIAL_FRONTEND_STATE }) store.actions = { - // TODO: REFACTOR initialise: async pkg => { + const { layouts, screens, application } = pkg + store.update(state => { - state.appId = pkg.application._id + state.appId = application._id return state }) - const screens = await api.get("/api/screens").then(r => r.json()) - - const mainScreens = screens.filter(screen => - screen._id.includes(pkg.pages.main._id) - ), - unauthScreens = screens.filter(screen => - screen._id.includes(pkg.pages.unauthenticated._id) - ) - pkg.pages = { - main: { - ...pkg.pages.main, - _screens: mainScreens, - }, - unauthenticated: { - ...pkg.pages.unauthenticated, - _screens: unauthScreens, - }, - } - - // if the app has just been created - // we need to build the CSS and save - if (pkg.justCreated) { - for (let pageName of ["main", "unauthenticated"]) { - const page = pkg.pages[pageName] - store.actions.screens.regenerateCss(page) - for (let screen of page._screens) { - store.actions.screens.regenerateCss(screen) - } - - await api.post(`/api/pages/${page._id}`, { - page: { - componentLibraries: pkg.application.componentLibraries, - ...page, - }, - screens: page._screens, - }) - } - } - - pkg.justCreated = false const components = await fetchComponentLibDefinitions(pkg.application._id) @@ -99,7 +62,8 @@ export const getFrontendStore = () => { name: pkg.application.name, description: pkg.application.description, appId: pkg.application._id, - pages: pkg.pages, + layouts, + screens, hasAppPackage: true, builtins: [getBuiltin("##builtin/screenslot")], appInstance: pkg.application.instance, @@ -107,20 +71,6 @@ export const getFrontendStore = () => { await backendUiStore.actions.database.select(pkg.application.instance) }, - selectPageOrScreen: type => { - store.update(state => { - state.currentFrontEndType = type - - const page = get(selectedPage) - - const pageOrScreen = type === "page" ? page : page._screens[0] - - state.currentComponentInfo = pageOrScreen ? pageOrScreen.props : null - state.currentPreviewItem = pageOrScreen - state.currentView = "detail" - return state - }) - }, routing: { fetch: async () => { const response = await api.get("/api/routing") @@ -133,167 +83,170 @@ export const getFrontendStore = () => { }, }, screens: { - select: screenId => { + select: async screenId => { + let promise store.update(state => { const screen = get(allScreens).find(screen => screen._id === screenId) - state.currentPreviewItem = screen - state.currentFrontEndType = "screen" + if (!screen) return state + + state.currentFrontEndType = FrontendTypes.SCREEN + state.currentAssetId = screenId state.currentView = "detail" - store.actions.screens.regenerateCssForCurrentScreen() - const safeProps = makePropsSafe( - state.components[screen.props._component], - screen.props - ) - screen.props = safeProps - state.currentComponentInfo = safeProps + promise = store.actions.screens.regenerateCss(screen) + state.selectedComponentId = screen.props?._id return state }) + await promise }, create: async screen => { - let savePromise + screen = await store.actions.screens.save(screen) store.update(state => { - state.currentPreviewItem = screen - state.currentComponentInfo = screen.props - state.currentFrontEndType = "screen" - - if (state.currentPreviewItem) { - store.actions.screens.regenerateCss(state.currentPreviewItem) - } - - savePromise = store.actions.screens.save(screen) + state.currentAssetId = screen._id + state.selectedComponentId = screen.props._id + state.currentFrontEndType = FrontendTypes.SCREEN return state }) - - await savePromise + return screen }, save: async screen => { - const page = get(selectedPage) - const currentPageScreens = page._screens - const creatingNewScreen = screen._id === undefined + const response = await api.post(`/api/screens`, screen) + screen = await response.json() - let savePromise - const response = await api.post(`/api/screens/${page._id}`, screen) - const json = await response.json() - screen._rev = json.rev - screen._id = json.id - const foundScreen = page._screens.findIndex(el => el._id === screen._id) - if (foundScreen !== -1) { - page._screens.splice(foundScreen, 1) - } - page._screens.push(screen) - - // TODO: should carry out all server updates to screen in a single call store.update(state => { - page._screens = currentPageScreens + const foundScreen = state.screens.findIndex( + el => el._id === screen._id + ) + if (foundScreen !== -1) { + state.screens.splice(foundScreen, 1) + } + state.screens.push(screen) if (creatingNewScreen) { - state.currentPreviewItem = screen const safeProps = makePropsSafe( state.components[screen.props._component], screen.props ) - state.currentComponentInfo = safeProps + state.selectedComponentId = safeProps._id screen.props = safeProps } - savePromise = store.actions.pages.save() - return state }) - if (savePromise) await savePromise + return screen }, - regenerateCss: screen => { - screen._css = generate_screen_css([screen.props]) + regenerateCss: async asset => { + const response = await api.post("/api/css/generate", asset) + asset._css = (await response.json())?.css }, - regenerateCssForCurrentScreen: () => { - const { currentPreviewItem } = get(store) - if (currentPreviewItem) { - store.actions.screens.regenerateCss(currentPreviewItem) + regenerateCssForCurrentScreen: async () => { + const asset = get(currentAsset) + if (asset) { + await store.actions.screens.regenerateCss(asset) } }, delete: async screens => { - let deletePromise - const screensToDelete = Array.isArray(screens) ? screens : [screens] + const screenDeletePromises = [] store.update(state => { - const currentPage = get(selectedPage) - for (let screenToDelete of screensToDelete) { - // Remove screen from current page as well - // TODO: Should be done server side - currentPage._screens = currentPage._screens.filter( - scr => scr._id !== screenToDelete._id + state.screens = state.screens.filter( + screen => screen._id !== screenToDelete._id ) - - deletePromise = api.delete( - `/api/screens/${screenToDelete._id}/${screenToDelete._rev}` + screenDeletePromises.push( + api.delete( + `/api/screens/${screenToDelete._id}/${screenToDelete._rev}` + ) ) + if (screenToDelete._id === state.currentAssetId) { + state.currentAssetId = "" + } } return state }) - await deletePromise + await Promise.all(screenDeletePromises) }, }, preview: { saveSelected: async () => { const state = get(store) - if (state.currentFrontEndType !== "page") { - await store.actions.screens.save(state.currentPreviewItem) + const selectedAsset = get(currentAsset) + + if (state.currentFrontEndType !== FrontendTypes.LAYOUT) { + await store.actions.screens.save(selectedAsset) + } else { + await store.actions.layouts.save(selectedAsset) } - await store.actions.pages.save() }, }, - pages: { - select: pageName => { + layouts: { + select: async layoutId => { store.update(state => { - const currentPage = state.pages[pageName] + const layout = store.actions.layouts.find(layoutId) - state.currentFrontEndType = "page" + state.currentFrontEndType = FrontendTypes.LAYOUT state.currentView = "detail" - state.currentPageName = pageName - // This is the root of many problems. - // Uncaught (in promise) TypeError: Cannot read property '_component' of undefined - // it appears that the currentPage sometimes has _props instead of props - // why - const safeProps = makePropsSafe( - state.components[currentPage.props._component], - currentPage.props - ) - state.currentComponentInfo = safeProps - currentPage.props = safeProps - state.currentPreviewItem = state.pages[pageName] - store.actions.screens.regenerateCssForCurrentScreen() - - for (let screen of get(allScreens)) { - screen._css = generate_screen_css([screen.props]) - } + state.currentAssetId = layout._id + state.selectedComponentId = layout.props?._id return state }) - }, - save: async page => { - const storeContents = get(store) - const pageName = storeContents.currentPageName || "main" - const pageToSave = page || storeContents.pages[pageName] + let cssPromises = [] + cssPromises.push(store.actions.screens.regenerateCssForCurrentScreen()) - // TODO: revisit. This sends down a very weird payload - const response = await api.post(`/api/pages/${pageToSave._id}`, { - page: { - componentLibraries: storeContents.pages.componentLibraries, - ...pageToSave, - }, - screens: pageToSave._screens, - }) + for (let screen of get(allScreens)) { + cssPromises.push(store.actions.screens.regenerateCss(screen)) + } + await Promise.all(cssPromises) + }, + save: async layout => { + const layoutToSave = cloneDeep(layout) + delete layoutToSave._css + + const response = await api.post(`/api/layouts`, layoutToSave) const json = await response.json() - if (!json.ok) throw new Error("Error updating page") + store.update(state => { + const layoutIdx = state.layouts.findIndex( + stateLayout => stateLayout._id === json._id + ) + + if (layoutIdx >= 0) { + // update existing layout + state.layouts.splice(layoutIdx, 1, json) + } else { + // save new layout + state.layouts.push(json) + } + + state.currentAssetId = json._id + return state + }) + }, + find: layoutId => { + if (!layoutId) { + return get(mainLayout) + } + const storeContents = get(store) + return storeContents.layouts.find(layout => layout._id === layoutId) + }, + delete: async layoutToDelete => { + const response = await api.delete( + `/api/layouts/${layoutToDelete._id}/${layoutToDelete._rev}` + ) + + if (response.status !== 200) { + const json = await response.json() + throw new Error(json.message) + } store.update(state => { - state.pages[pageName]._rev = json.rev + state.layouts = state.layouts.filter( + layout => layout._id !== layoutToDelete._id + ) return state }) }, @@ -301,17 +254,19 @@ export const getFrontendStore = () => { components: { select: component => { store.update(state => { - const componentDef = component._component.startsWith("##") - ? component - : state.components[component._component] - state.currentComponentInfo = makePropsSafe(componentDef, component) + state.selectedComponentId = component._id state.currentView = "component" return state }) }, create: (componentToAdd, presetProps) => { + const selectedAsset = get(currentAsset) + store.update(state => { function findSlot(component_array) { + if (!component_array) { + return false + } for (let component of component_array) { if (component._component === "##builtin/screenslot") { return true @@ -324,7 +279,7 @@ export const getFrontendStore = () => { if ( componentToAdd.startsWith("##") && - findSlot(state.pages[state.currentPageName].props._children) + findSlot(selectedAsset?.props._children) ) { return state } @@ -340,29 +295,34 @@ export const getFrontendStore = () => { _instanceName: instanceName, }) - const currentComponent = - state.components[state.currentComponentInfo._component] + const selected = get(selectedComponent) - const targetParent = currentComponent.children - ? state.currentComponentInfo - : getParent( - state.currentPreviewItem.props, - state.currentComponentInfo - ) + const currentComponentDefinition = + state.components[selected._component] - // Don't continue if there's no parent - if (!targetParent) { - return state + const allowsChildren = currentComponentDefinition.children + + // Determine where to put the new component. + let targetParent + if (allowsChildren) { + // Child of the selected component + targetParent = selected + } else { + // Sibling of selected component + targetParent = findParent(selectedAsset.props, selected) } - targetParent._children = targetParent._children.concat( - newComponent.props - ) + // Don't continue if there's no parent + if (!targetParent) return state + + // Push the new component + targetParent._children.push(newComponent.props) store.actions.preview.saveSelected() state.currentView = "component" - state.currentComponentInfo = newComponent.props + state.selectedComponentId = newComponent.props._id + analytics.captureEvent("Added Component", { name: newComponent.props._component, }) @@ -370,14 +330,12 @@ export const getFrontendStore = () => { }) }, copy: (component, cut = false) => { + const selectedAsset = get(currentAsset) store.update(state => { state.componentToPaste = cloneDeep(component) state.componentToPaste.isCut = cut if (cut) { - const parent = getParent( - state.currentPreviewItem.props, - component._id - ) + const parent = findParent(selectedAsset.props, component._id) parent._children = parent._children.filter( child => child._id !== component._id ) @@ -387,7 +345,9 @@ export const getFrontendStore = () => { return state }) }, - paste: (targetComponent, mode) => { + paste: async (targetComponent, mode) => { + const selectedAsset = get(currentAsset) + let promises = [] store.update(state => { if (!state.componentToPaste) return state @@ -406,54 +366,56 @@ export const getFrontendStore = () => { return state } - const parent = getParent( - state.currentPreviewItem.props, - targetComponent - ) + const parent = findParent(selectedAsset.props, targetComponent) const targetIndex = parent._children.indexOf(targetComponent) const index = mode === "above" ? targetIndex : targetIndex + 1 parent._children.splice(index, 0, cloneDeep(componentToPaste)) - store.actions.screens.regenerateCssForCurrentScreen() - store.actions.preview.saveSelected() + promises.push(store.actions.screens.regenerateCssForCurrentScreen()) + promises.push(store.actions.preview.saveSelected()) store.actions.components.select(componentToPaste) return state }) + await Promise.all(promises) }, - updateStyle: (type, name, value) => { - store.update(state => { - if (!state.currentComponentInfo._styles) { - state.currentComponentInfo._styles = {} - } - state.currentComponentInfo._styles[type][name] = value + updateStyle: async (type, name, value) => { + let promises = [] + const selected = get(selectedComponent) - store.actions.screens.regenerateCssForCurrentScreen() + store.update(state => { + if (!selected._styles) { + selected._styles = {} + } + selected._styles[type][name] = value + + promises.push(store.actions.screens.regenerateCssForCurrentScreen()) // save without messing with the store - store.actions.preview.saveSelected() + promises.push(store.actions.preview.saveSelected()) return state }) + await Promise.all(promises) }, updateProp: (name, value) => { store.update(state => { - let current_component = state.currentComponentInfo + let current_component = get(selectedComponent) current_component[name] = value - state.currentComponentInfo = current_component + state.selectedComponentId = current_component._id store.actions.preview.saveSelected() return state }) }, findRoute: component => { // Gets all the components to needed to construct a path. - const tempStore = get(store) + const selectedAsset = get(currentAsset) let pathComponents = [] let parent = component let root = false while (!root) { - parent = getParent(tempStore.currentPreviewItem.props, parent) + parent = findParent(selectedAsset.props, parent) if (!parent) { root = true } else { @@ -461,7 +423,7 @@ export const getFrontendStore = () => { } } - // Remove root entry since it's the screen or page layout. + // Remove root entry since it's the screen or layout. // Reverse array since we need the correct order of the IDs const reversedComponents = pathComponents.reverse().slice(1) @@ -476,12 +438,13 @@ export const getFrontendStore = () => { }, links: { save: async (url, title) => { - let savePromise + let promises = [] + const layout = get(mainLayout) store.update(state => { - // Try to extract a nav component from the master screen + // Try to extract a nav component from the master layout const nav = findChildComponentType( - state.pages.main, - "@budibase/standard-components/Navigation" + layout, + "@budibase/standard-components/navigation" ) if (nav) { let newLink @@ -513,18 +476,18 @@ export const getFrontendStore = () => { }).props } - // Save page and regenerate all CSS because otherwise weird things happen + // Save layout and regenerate all CSS because otherwise weird things happen nav._children = [...nav._children, newLink] - state.currentPageName = "main" - store.actions.screens.regenerateCss(state.pages.main) - for (let screen of state.pages.main._screens) { - store.actions.screens.regenerateCss(screen) + state.currentAssetId = layout._id + promises.push(store.actions.screens.regenerateCss(layout)) + for (let screen of get(allScreens)) { + promises.push(store.actions.screens.regenerateCss(screen)) } - savePromise = store.actions.pages.save() + promises.push(store.actions.layouts.save(layout)) } return state }) - await savePromise + await Promise.all(promises) }, }, }, diff --git a/packages/builder/src/builderStore/store/screenTemplates/newRowScreen.js b/packages/builder/src/builderStore/store/screenTemplates/newRowScreen.js index 1e699dad95..74f9b55fc8 100644 --- a/packages/builder/src/builderStore/store/screenTemplates/newRowScreen.js +++ b/packages/builder/src/builderStore/store/screenTemplates/newRowScreen.js @@ -18,7 +18,7 @@ export default function(tables) { }) } -export const newRowUrl = table => sanitizeUrl(`/${table.name}/new`) +export const newRowUrl = table => sanitizeUrl(`/${table.name}/new/row`) export const NEW_ROW_TEMPLATE = "NEW_ROW_TEMPLATE" function generateTitleContainer(table) { diff --git a/packages/builder/src/builderStore/store/screenTemplates/utils/Component.js b/packages/builder/src/builderStore/store/screenTemplates/utils/Component.js index 0a40c62dc7..bd03fc7cdc 100644 --- a/packages/builder/src/builderStore/store/screenTemplates/utils/Component.js +++ b/packages/builder/src/builderStore/store/screenTemplates/utils/Component.js @@ -14,9 +14,6 @@ export class Component extends BaseStructure { active: {}, selected: {}, }, - _code: "", - className: "", - onLoad: [], type: "", _instanceName: "", _children: [], diff --git a/packages/builder/src/builderStore/store/screenTemplates/utils/Screen.js b/packages/builder/src/builderStore/store/screenTemplates/utils/Screen.js index 523296e959..00bd43ec2c 100644 --- a/packages/builder/src/builderStore/store/screenTemplates/utils/Screen.js +++ b/packages/builder/src/builderStore/store/screenTemplates/utils/Screen.js @@ -4,6 +4,7 @@ export class Screen extends BaseStructure { constructor() { super(true) this._json = { + layoutId: "layout_private_master", props: { _id: "", _component: "", @@ -18,7 +19,7 @@ export class Screen extends BaseStructure { }, routing: { route: "", - accessLevelId: "", + roleId: "BASIC", }, name: "screen-id", } diff --git a/packages/builder/src/builderStore/storeUtils.js b/packages/builder/src/builderStore/storeUtils.js index 9c9d1ef940..4ee2dd7ccc 100644 --- a/packages/builder/src/builderStore/storeUtils.js +++ b/packages/builder/src/builderStore/storeUtils.js @@ -1,15 +1,21 @@ -import { getBuiltin } from "components/userInterface/pagesParsing/createProps" +import { getBuiltin } from "components/userInterface/assetParsing/createProps" import { uuid } from "./uuid" import getNewComponentName from "./getNewComponentName" -export const getParent = (rootProps, child) => { +/** + * Find the parent component of the passed in child. + * @param {Object} rootProps - props to search for the parent in + * @param {String|Object} child - id of the child or the child itself to find the parent of + */ +export const findParent = (rootProps, child) => { let parent - walkProps(rootProps, (p, breakWalk) => { + walkProps(rootProps, (props, breakWalk) => { if ( - p._children && - (p._children.includes(child) || p._children.some(c => c._id === child)) + props._children && + (props._children.includes(child) || + props._children.some(c => c._id === child)) ) { - parent = p + parent = props breakWalk() } }) diff --git a/packages/builder/src/components/automation/SetupPanel/AutomationBlockSetup.svelte b/packages/builder/src/components/automation/SetupPanel/AutomationBlockSetup.svelte index 8bb4dc36dd..7e26b2155e 100644 --- a/packages/builder/src/components/automation/SetupPanel/AutomationBlockSetup.svelte +++ b/packages/builder/src/components/automation/SetupPanel/AutomationBlockSetup.svelte @@ -62,6 +62,8 @@ {:else if value.customType === 'password'} + {:else if value.customType === 'email'} + {:else if value.customType === 'table'} {:else if value.customType === 'row'} diff --git a/packages/builder/src/components/backend/DataTable/RowFieldControl.svelte b/packages/builder/src/components/backend/DataTable/RowFieldControl.svelte index f974e521c4..8b1c2e18e6 100644 --- a/packages/builder/src/components/backend/DataTable/RowFieldControl.svelte +++ b/packages/builder/src/components/backend/DataTable/RowFieldControl.svelte @@ -1,14 +1,26 @@ {#if type === 'options'} @@ -29,6 +41,17 @@ {:else if type === 'link'} +{:else if type === 'longform'} +
+ + +
{:else} - + {/if} diff --git a/packages/builder/src/components/backend/DataTable/api.js b/packages/builder/src/components/backend/DataTable/api.js index 496db35b3f..629405a9fc 100644 --- a/packages/builder/src/components/backend/DataTable/api.js +++ b/packages/builder/src/components/backend/DataTable/api.js @@ -7,8 +7,8 @@ export async function createUser(user) { } export async function saveRow(row, tableId) { - const SAVE_ROWS_URL = `/api/${tableId}/rows` - const response = await api.post(SAVE_ROWS_URL, row) + const SAVE_ROW_URL = `/api/${tableId}/rows` + const response = await api.post(SAVE_ROW_URL, row) return await response.json() } diff --git a/packages/builder/src/components/backend/DataTable/modals/CreateEditColumn.svelte b/packages/builder/src/components/backend/DataTable/modals/CreateEditColumn.svelte index 866e574bca..ee72b36053 100644 --- a/packages/builder/src/components/backend/DataTable/modals/CreateEditColumn.svelte +++ b/packages/builder/src/components/backend/DataTable/modals/CreateEditColumn.svelte @@ -2,6 +2,7 @@ import { Input, Button, TextButton, Select, Toggle } from "@budibase/bbui" import { cloneDeep } from "lodash/fp" import { backendUiStore } from "builderStore" + import { TableNames, UNEDITABLE_USER_FIELDS } from "constants" import { FIELDS } from "constants/backend" import { notifier } from "builderStore/store/notifications" import ValuesList from "components/common/ValuesList.svelte" @@ -30,6 +31,9 @@ table => table._id !== $backendUiStore.draftTable._id ) $: required = !!field?.constraints?.presence || primaryDisplay + $: uneditable = + $backendUiStore.selectedTable?._id === TableNames.USERS && + UNEDITABLE_USER_FIELDS.includes(field.name) async function saveColumn() { backendUiStore.update(state => { @@ -87,7 +91,7 @@
- + - - {#if editMode} - - {:else} - - {/if} -
- - diff --git a/packages/builder/src/components/settings/tabs/Users.svelte b/packages/builder/src/components/settings/tabs/Users.svelte deleted file mode 100644 index 3d4a44fc73..0000000000 --- a/packages/builder/src/components/settings/tabs/Users.svelte +++ /dev/null @@ -1,114 +0,0 @@ - - -
-
- -
- - - - -
-
-
- - {#await fetchUsersPromise} - Loading... - {:then users} -
    - {#each users as user} -
  • - -
  • - {:else} -
  • No Users found
  • - {/each} -
- {:catch err} - Something went wrong when trying to fetch users. Please refresh (CMD + R / - CTRL + R) the page and try again. - {/await} -
-
- - diff --git a/packages/builder/src/components/settings/tabs/index.js b/packages/builder/src/components/settings/tabs/index.js index 6e34141d09..2f0e958112 100644 --- a/packages/builder/src/components/settings/tabs/index.js +++ b/packages/builder/src/components/settings/tabs/index.js @@ -1,6 +1,5 @@ export { default as General } from "./General.svelte" export { default as Integrations } from "./Integrations.svelte" export { default as Permissions } from "./Permissions.svelte" -export { default as Users } from "./Users.svelte" export { default as APIKeys } from "./APIKeys.svelte" export { default as DangerZone } from "./DangerZone.svelte" diff --git a/packages/builder/src/components/start/CreateAppModal.svelte b/packages/builder/src/components/start/CreateAppModal.svelte index 049b21c995..b88397b6c4 100644 --- a/packages/builder/src/components/start/CreateAppModal.svelte +++ b/packages/builder/src/components/start/CreateAppModal.svelte @@ -52,13 +52,13 @@ applicationName: string().required("Your application must have a name."), }, { - username: string().required("Your application needs a first user."), + email: string() + .email() + .required("Your application needs a first user."), password: string().required( "Please enter a password for your first user." ), - accessLevelId: string().required( - "You need to select an access level for your user." - ), + roleId: string().required("You need to select a role for your user."), }, ] @@ -79,9 +79,7 @@ if (hasKey) { validationSchemas.shift() - validationSchemas = validationSchemas steps.shift() - steps = steps } // Handles form navigation @@ -155,19 +153,17 @@ const pkg = await applicationPkg.json() if (applicationPkg.ok) { backendUiStore.actions.reset() - pkg.justCreated = true await store.actions.initialise(pkg) - automationStore.actions.fetch() + await automationStore.actions.fetch() } else { throw new Error(pkg) } // Create user const user = { - name: $createAppStore.values.username, - username: $createAppStore.values.username, + email: $createAppStore.values.email, password: $createAppStore.values.password, - accessLevelId: $createAppStore.values.accessLevelId, + roleId: $createAppStore.values.roleId, } const userResp = await api.post(`/api/users`, user) const json = await userResp.json() diff --git a/packages/builder/src/components/start/Steps/User.svelte b/packages/builder/src/components/start/Steps/User.svelte index edc1fdf40b..397a06be94 100644 --- a/packages/builder/src/components/start/Steps/User.svelte +++ b/packages/builder/src/components/start/Steps/User.svelte @@ -2,18 +2,18 @@ import { Input, Select } from "@budibase/bbui" export let validationErrors - let blurred = { username: false, password: false } + let blurred = { email: false, password: false }

Create your first User

(blurred.username = true)} - label="Username" - name="username" - placeholder="Username" - type="name" - error={blurred.username && validationErrors.username} /> + on:input={() => (blurred.email = true)} + label="Email" + name="email" + placeholder="Email" + type="email" + error={blurred.email && validationErrors.email} /> (blurred.password = true)} label="Password" @@ -21,7 +21,7 @@ placeholder="Password" type="password" error={blurred.password && validationErrors.password} /> - diff --git a/packages/builder/src/components/userInterface/AppPreview/CurrentItemPreview.svelte b/packages/builder/src/components/userInterface/AppPreview/CurrentItemPreview.svelte index b3ec41b2a2..ccb0153e45 100644 --- a/packages/builder/src/components/userInterface/AppPreview/CurrentItemPreview.svelte +++ b/packages/builder/src/components/userInterface/AppPreview/CurrentItemPreview.svelte @@ -1,146 +1,79 @@
- {#if hasComponent && $store.currentPreviewItem} - ', - _appId: "inst_app_2cc_ca3383f896034e9295345c05f7dfca0c", _instanceName: "Rick Astley Video", _children: [], }, @@ -102,7 +92,64 @@ exports.HOME_SCREEN = { }, routing: { route: "/", - accessLevelId: BUILTIN_LEVEL_IDS.BASIC, + roleId: BUILTIN_ROLE_IDS.BASIC, }, - name: "d834fea2-1b3e-4320-ab34-f9009f5ecc59", -} + name: "home-screen", +}) + +exports.createLoginScreen = app => ({ + description: "", + url: "", + layoutId: BASE_LAYOUT_PROP_IDS.PUBLIC, + props: { + _instanceName: "LoginScreenContainer", + _id: "5beb4c7b-3c8b-49b2-b8b3-d447dc76dda7", + _component: "@budibase/standard-components/container", + _styles: { + normal: { + flex: "1 1 auto", + display: "flex", + "flex-direction": "column", + "justify-content": "center", + "align-items": "center", + }, + hover: {}, + active: {}, + selected: {}, + }, + type: "div", + _children: [ + { + _id: "781e497e-2e7c-11eb-adc1-0242ac120002", + _component: "@budibase/standard-components/login", + _styles: { + normal: { + padding: "64px", + background: "rgba(255, 255, 255, 0.4)", + "border-radius": "0.5rem", + "margin-top": "0px", + "box-shadow": + "0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04)", + "font-size": "16px", + "font-family": "Inter", + flex: "0 1 auto", + }, + hover: {}, + active: {}, + selected: {}, + }, + logo: + "https://d33wubrfki0l68.cloudfront.net/aac32159d7207b5085e74a7ef67afbb7027786c5/2b1fd/img/logo/bb-emblem.svg", + title: `Log in to ${app.name}`, + buttonText: "Log In", + _children: [], + _instanceName: "Login", + }, + ], + }, + routing: { + route: "/", + roleId: BUILTIN_ROLE_IDS.PUBLIC, + }, + name: "login-screen", +}) diff --git a/packages/server/src/db/utils.js b/packages/server/src/db/utils.js index 4edb27a416..ea4ab27b0c 100644 --- a/packages/server/src/db/utils.js +++ b/packages/server/src/db/utils.js @@ -10,16 +10,17 @@ const DocumentTypes = { AUTOMATION: "au", LINK: "li", APP: "app", - ACCESS_LEVEL: "ac", + ROLE: "role", WEBHOOK: "wh", INSTANCE: "inst", - PAGE: "page", + LAYOUT: "layout", SCREEN: "screen", } const ViewNames = { LINK: "by_link", ROUTING: "screen_routes", + USERS: "ta_users", } exports.ViewNames = ViewNames @@ -80,13 +81,12 @@ exports.generateTableID = () => { exports.getRowParams = (tableId = null, rowId = null, otherProps = {}) => { if (tableId == null) { return getDocParams(DocumentTypes.ROW, null, otherProps) - } else { - const endOfKey = - rowId == null - ? `${tableId}${SEPARATOR}` - : `${tableId}${SEPARATOR}${rowId}` - return getDocParams(DocumentTypes.ROW, endOfKey, otherProps) } + + const endOfKey = + rowId == null ? `${tableId}${SEPARATOR}` : `${tableId}${SEPARATOR}${rowId}` + + return getDocParams(DocumentTypes.ROW, endOfKey, otherProps) } /** @@ -101,17 +101,21 @@ exports.generateRowID = tableId => { /** * Gets parameters for retrieving users, this is a utility function for the getDocParams function. */ -exports.getUserParams = (username = null, otherProps = {}) => { - return getDocParams(DocumentTypes.USER, username, otherProps) +exports.getUserParams = (email = "", otherProps = {}) => { + return getDocParams( + DocumentTypes.ROW, + `${ViewNames.USERS}${SEPARATOR}${DocumentTypes.USER}${SEPARATOR}${email}`, + otherProps + ) } /** * Generates a new user ID based on the passed in username. - * @param {string} username The username which the ID is going to be built up of. + * @param {string} email The email which the ID is going to be built up of. * @returns {string} The new user ID which the user doc can be stored under. */ -exports.generateUserID = username => { - return `${DocumentTypes.USER}${SEPARATOR}${username}` +exports.generateUserID = email => { + return `${DocumentTypes.ROW}${SEPARATOR}${ViewNames.USERS}${SEPARATOR}${DocumentTypes.USER}${SEPARATOR}${email}` } /** @@ -165,18 +169,48 @@ exports.getAppParams = (appId = null, otherProps = {}) => { } /** - * Generates a new access level ID. - * @returns {string} The new access level ID which the access level doc can be stored under. + * Generates a new role ID. + * @returns {string} The new role ID which the role doc can be stored under. */ -exports.generateAccessLevelID = () => { - return `${DocumentTypes.ACCESS_LEVEL}${SEPARATOR}${newid()}` +exports.generateRoleID = () => { + return `${DocumentTypes.ROLE}${SEPARATOR}${newid()}` } /** - * Gets parameters for retrieving an access level, this is a utility function for the getDocParams function. + * Gets parameters for retrieving a role, this is a utility function for the getDocParams function. */ -exports.getAccessLevelParams = (accessLevelId = null, otherProps = {}) => { - return getDocParams(DocumentTypes.ACCESS_LEVEL, accessLevelId, otherProps) +exports.getRoleParams = (roleId = null, otherProps = {}) => { + return getDocParams(DocumentTypes.ROLE, roleId, otherProps) +} + +/** + * Generates a new layout ID. + * @returns {string} The new layout ID which the layout doc can be stored under. + */ +exports.generateLayoutID = id => { + return `${DocumentTypes.LAYOUT}${SEPARATOR}${id || newid()}` +} + +/** + * Gets parameters for retrieving layout, this is a utility function for the getDocParams function. + */ +exports.getLayoutParams = (layoutId = null, otherProps = {}) => { + return getDocParams(DocumentTypes.LAYOUT, layoutId, otherProps) +} + +/** + * Generates a new screen ID. + * @returns {string} The new screen ID which the screen doc can be stored under. + */ +exports.generateScreenID = () => { + return `${DocumentTypes.SCREEN}${SEPARATOR}${newid()}` +} + +/** + * Gets parameters for retrieving screens, this is a utility function for the getDocParams function. + */ +exports.getScreenParams = (screenId = null, otherProps = {}) => { + return getDocParams(DocumentTypes.SCREEN, screenId, otherProps) } /** @@ -187,36 +221,6 @@ exports.generateWebhookID = () => { return `${DocumentTypes.WEBHOOK}${SEPARATOR}${newid()}` } -/** - * Generates a new page ID. - * @returns {string} The new page ID which the page doc can be stored under. - */ -exports.generatePageID = () => { - return `${DocumentTypes.PAGE}${SEPARATOR}${newid()}` -} - -/** - * Gets parameters for retrieving pages, this is a utility function for the getDocParams function. - */ -exports.getPageParams = (pageId = null, otherProps = {}) => { - return getDocParams(DocumentTypes.PAGE, pageId, otherProps) -} - -/** - * Generates a new screen ID. - * @returns {string} The new screen ID which the screen doc can be stored under. - */ -exports.generateScreenID = pageId => { - return `${DocumentTypes.SCREEN}${SEPARATOR}${pageId}${SEPARATOR}${newid()}` -} - -/** - * Gets parameters for retrieving screens for a particular page, this is a utility function for the getDocParams function. - */ -exports.getScreenParams = (pageId = null, otherProps = {}) => { - return getDocParams(DocumentTypes.SCREEN, pageId, otherProps) -} - /** * Gets parameters for retrieving a webhook, this is a utility function for the getDocParams function. */ diff --git a/packages/server/src/events/AutomationEmitter.js b/packages/server/src/events/AutomationEmitter.js new file mode 100644 index 0000000000..fbfc445e2c --- /dev/null +++ b/packages/server/src/events/AutomationEmitter.js @@ -0,0 +1,51 @@ +const { rowEmission, tableEmission } = require("./utils") +const mainEmitter = require("./index") + +// max number of automations that can chain on top of each other +const MAX_AUTOMATION_CHAIN = 5 + +/** + * Special emitter which takes the count of automation runs which have occurred and blocks an + * automation from running if it has reached the maximum number of chained automations runs. + * This essentially "fakes" the normal emitter to add some functionality in-between to stop automations + * from getting stuck endlessly chaining. + */ +class AutomationEmitter { + constructor(chainCount) { + this.chainCount = chainCount + this.metadata = { + automationChainCount: chainCount, + } + } + + emitRow(eventName, appId, row, table = null) { + // don't emit even if we've reached max automation chain + if (this.chainCount >= MAX_AUTOMATION_CHAIN) { + return + } + rowEmission({ + emitter: mainEmitter, + eventName, + appId, + row, + table, + metadata: this.metadata, + }) + } + + emitTable(eventName, appId, table = null) { + // don't emit even if we've reached max automation chain + if (this.chainCount > MAX_AUTOMATION_CHAIN) { + return + } + tableEmission({ + emitter: mainEmitter, + eventName, + appId, + table, + metadata: this.metadata, + }) + } +} + +module.exports = AutomationEmitter diff --git a/packages/server/src/events/index.js b/packages/server/src/events/index.js index 237e212293..6fd97487d6 100644 --- a/packages/server/src/events/index.js +++ b/packages/server/src/events/index.js @@ -1,4 +1,5 @@ const EventEmitter = require("events").EventEmitter +const { rowEmission, tableEmission } = require("./utils") /** * keeping event emitter in one central location as it might be used for things other than @@ -12,36 +13,11 @@ const EventEmitter = require("events").EventEmitter */ class BudibaseEmitter extends EventEmitter { emitRow(eventName, appId, row, table = null) { - let event = { - row, - appId, - tableId: row.tableId, - } - if (table) { - event.table = table - } - event.id = row._id - if (row._rev) { - event.revision = row._rev - } - this.emit(eventName, event) + rowEmission({ emitter: this, eventName, appId, row, table }) } emitTable(eventName, appId, table = null) { - const tableId = table._id - let event = { - table: { - ...table, - tableId: tableId, - }, - appId, - tableId: tableId, - } - event.id = tableId - if (table._rev) { - event.revision = table._rev - } - this.emit(eventName, event) + tableEmission({ emitter: this, eventName, appId, table }) } } diff --git a/packages/server/src/events/utils.js b/packages/server/src/events/utils.js new file mode 100644 index 0000000000..2d43139d27 --- /dev/null +++ b/packages/server/src/events/utils.js @@ -0,0 +1,38 @@ +exports.rowEmission = ({ emitter, eventName, appId, row, table, metadata }) => { + let event = { + row, + appId, + tableId: row.tableId, + } + if (table) { + event.table = table + } + event.id = row._id + if (row._rev) { + event.revision = row._rev + } + if (metadata) { + event.metadata = metadata + } + emitter.emit(eventName, event) +} + +exports.tableEmission = ({ emitter, eventName, appId, table, metadata }) => { + const tableId = table._id + let event = { + table: { + ...table, + tableId: tableId, + }, + appId, + tableId: tableId, + } + event.id = tableId + if (table._rev) { + event.revision = table._rev + } + if (metadata) { + event.metadata = metadata + } + emitter.emit(eventName, event) +} diff --git a/packages/server/src/middleware/authenticated.js b/packages/server/src/middleware/authenticated.js index 497c24699d..277c2b28db 100644 --- a/packages/server/src/middleware/authenticated.js +++ b/packages/server/src/middleware/authenticated.js @@ -1,9 +1,6 @@ const jwt = require("jsonwebtoken") const STATUS_CODES = require("../utilities/statusCodes") -const { - getAccessLevel, - BUILTIN_LEVELS, -} = require("../utilities/security/accessLevels") +const { getRole, BUILTIN_ROLES } = require("../utilities/security/roles") const { AuthTypes } = require("../constants") const { getAppId, getCookieName, setCookie, isClient } = require("../utilities") @@ -35,7 +32,7 @@ module.exports = async (ctx, next) => { ctx.appId = appId ctx.user = { appId, - accessLevel: BUILTIN_LEVELS.PUBLIC, + role: BUILTIN_ROLES.PUBLIC, } await next() return @@ -49,7 +46,7 @@ module.exports = async (ctx, next) => { ctx.user = { ...jwtPayload, appId: appId, - accessLevel: await getAccessLevel(appId, jwtPayload.accessLevelId), + role: await getRole(appId, jwtPayload.roleId), } } catch (err) { ctx.throw(err.status || STATUS_CODES.FORBIDDEN, err.text) diff --git a/packages/server/src/middleware/authorized.js b/packages/server/src/middleware/authorized.js index 5f4b78b97e..f18cf3b5c8 100644 --- a/packages/server/src/middleware/authorized.js +++ b/packages/server/src/middleware/authorized.js @@ -1,4 +1,4 @@ -const { BUILTIN_LEVEL_IDS } = require("../utilities/security/accessLevels") +const { BUILTIN_ROLE_IDS } = require("../utilities/security/roles") const { PermissionTypes, doesHavePermission, @@ -7,7 +7,7 @@ const env = require("../environment") const { apiKeyTable } = require("../db/dynamoClient") const { AuthTypes } = require("../constants") -const ADMIN_ACCESS = [BUILTIN_LEVEL_IDS.ADMIN, BUILTIN_LEVEL_IDS.BUILDER] +const ADMIN_ROLES = [BUILTIN_ROLE_IDS.ADMIN, BUILTIN_ROLE_IDS.BUILDER] const LOCAL_PASS = new RegExp(["webhooks/trigger", "webhooks/schema"].join("|")) @@ -47,9 +47,9 @@ module.exports = (permType, permLevel = null) => async (ctx, next) => { ctx.throw(403, "User not found") } - const accessLevel = ctx.user.accessLevel + const role = ctx.user.role const permissions = ctx.user.permissions - if (ADMIN_ACCESS.indexOf(accessLevel._id) !== -1) { + if (ADMIN_ROLES.indexOf(role._id) !== -1) { return next() } diff --git a/packages/server/src/utilities/builder/compileStaticAssets.js b/packages/server/src/utilities/builder/compileStaticAssets.js new file mode 100644 index 0000000000..763fccd35a --- /dev/null +++ b/packages/server/src/utilities/builder/compileStaticAssets.js @@ -0,0 +1,83 @@ +const { + ensureDir, + constants, + copyFile, + writeFile, + readdir, + readFile, + existsSync, +} = require("fs-extra") +const { join } = require("../centralPath") +const { budibaseAppsDir } = require("../budibaseDir") + +const CSS_DIRECTORY = "css" + +/** + * Compile all the non-db static web assets that are required for the running of + * a budibase application. This includes CSS, the JSON structure of the DOM and + * the client library, a script responsible for reading the JSON structure + * and rendering the application. + * @param {string} appId id of the application we want to compile static assets for + * @param {array|object} assets a list of screens or screen layouts for which the CSS should be extracted and stored. + */ +module.exports = async (appId, assets) => { + const publicPath = join(budibaseAppsDir(), appId, "public") + await ensureDir(publicPath) + for (let asset of Array.isArray(assets) ? assets : [assets]) { + await buildCssBundle(publicPath, asset) + await copyClientLib(publicPath) + // remove props that shouldn't be present when written to DB + if (asset._css) { + delete asset._css + } + } + return assets +} + +/** + * Reads the _css property of all screens and the screen layouts, and creates a singular CSS + * bundle for the app at /public/bundle.css + * @param {String} publicPath - path to the public assets directory of the budibase application + * @param {Object} asset a single screen or screen layout which is being updated + */ +const buildCssBundle = async (publicPath, asset) => { + const cssPath = join(publicPath, CSS_DIRECTORY) + let cssString = "" + + // create a singular CSS file for this asset + const assetCss = asset._css ? asset._css.trim() : "" + if (assetCss.length !== 0) { + await ensureDir(cssPath) + await writeFile(join(cssPath, asset._id), assetCss) + } + + // bundle up all the CSS in the directory into one top level CSS file + if (existsSync(cssPath)) { + const cssFiles = await readdir(cssPath) + for (let filename of cssFiles) { + const css = await readFile(join(cssPath, filename)) + cssString += css + } + } + + await writeFile(join(publicPath, "bundle.css"), cssString) +} + +/** + * Copy the budibase client library and sourcemap from NPM to /public/. + * The client library is then served as a static asset when the budibase application + * is running in preview or prod + * @param {String} publicPath - path to write the client library to + */ +const copyClientLib = async publicPath => { + const sourcepath = require.resolve("@budibase/client") + const destPath = join(publicPath, "budibase-client.js") + + await copyFile(sourcepath, destPath, constants.COPYFILE_FICLONE) + + await copyFile( + sourcepath + ".map", + destPath + ".map", + constants.COPYFILE_FICLONE + ) +} diff --git a/packages/server/src/utilities/builder/compileStaticAssetsForPage.js b/packages/server/src/utilities/builder/compileStaticAssetsForPage.js deleted file mode 100644 index c91ba24bb3..0000000000 --- a/packages/server/src/utilities/builder/compileStaticAssetsForPage.js +++ /dev/null @@ -1,102 +0,0 @@ -const { ensureDir, constants, copyFile, writeFile } = require("fs-extra") -const { join } = require("../centralPath") -const { budibaseAppsDir } = require("../budibaseDir") - -/** - * Compile all the non-db static web assets that are required for the running of - * a budibase application. This includes CSS, the JSON structure of the DOM and - * the client library, a script responsible for reading the JSON structure - * and rendering the application. - * @param {} appId - id of the application we want to compile static assets for - * @param {*} pageName - name of the page that the assets will be served for - * @param {*} pkg - app package information/metadata - */ -module.exports = async (appId, pageName, pkg) => { - const pagePath = join(budibaseAppsDir(), appId, "public", pageName) - - pkg.screens = pkg.screens || [] - - await ensureDir(pagePath) - - await buildPageCssBundle(pagePath, pkg) - - await buildFrontendAppDefinition(pagePath, pkg) - - await copyClientLib(pagePath) -} - -/** - * Reads the _css property of a page and its screens, and creates a singular CSS - * bundle for the page at /public//bundle.css - * @param {String} publicPagePath - path to the public assets directory of the budibase application - * @param {Object} pkg - app package information - * @param {"main" | "unauthenticated"} pageName - the pagename of the page we are compiling CSS for. - */ -const buildPageCssBundle = async (publicPagePath, pkg) => { - let cssString = "" - - for (let screen of pkg.screens || []) { - if (!screen._css) continue - if (screen._css.trim().length === 0) { - delete screen._css - continue - } - cssString += screen._css - } - - if (pkg.page._css) cssString += pkg.page._css - - writeFile(join(publicPagePath, "bundle.css"), cssString) -} - -/** - * Copy the budibase client library and sourcemap from NPM to /public/. - * The client library is then served as a static asset when the budibase application - * is running in preview or prod - * @param {String} pagePath - path to write the client library to - */ -const copyClientLib = async pagePath => { - const sourcepath = require.resolve("@budibase/client") - const destPath = join(pagePath, "budibase-client.js") - - await copyFile(sourcepath, destPath, constants.COPYFILE_FICLONE) - - await copyFile( - sourcepath + ".map", - destPath + ".map", - constants.COPYFILE_FICLONE - ) -} - -/** - * Build the frontend definition for a budibase application. This includes all page and screen information, - * and is injected into the budibase client library to tell it how to start constructing - * the DOM from components defined in the frontendDefinition. - * @param {String} pagePath - path to the public folder of the page where the definition will be written - * @param {Object} pkg - app package information from which the frontendDefinition will be built. - */ -const buildFrontendAppDefinition = async (pagePath, pkg) => { - const filename = join(pagePath, "clientFrontendDefinition.js") - - // Delete CSS code from the page and screens so it's not injected - delete pkg.page._css - - for (let screen of pkg.screens) { - if (screen._css) { - delete pkg.page._css - } - } - - const clientUiDefinition = JSON.stringify({ - page: pkg.page, - screens: pkg.screens, - libraries: ["@budibase/standard-components"], - }) - - await writeFile( - filename, - ` - window['##BUDIBASE_FRONTEND_DEFINITION##'] = ${clientUiDefinition}; - ` - ) -} diff --git a/packages/builder/src/builderStore/generate_css.js b/packages/server/src/utilities/builder/generateCss.js similarity index 72% rename from packages/builder/src/builderStore/generate_css.js rename to packages/server/src/utilities/builder/generateCss.js index 2bb5a3bd2e..c3d72c741f 100644 --- a/packages/builder/src/builderStore/generate_css.js +++ b/packages/server/src/utilities/builder/generateCss.js @@ -1,21 +1,21 @@ -export const generate_screen_css = component_arr => { +exports.generateAssetCss = component_arr => { let styles = "" for (const { _styles, _id, _children, _component } of component_arr) { let [componentName] = _component.match(/[a-z]*$/) Object.keys(_styles).forEach(selector => { - const cssString = generate_css(_styles[selector]) + const cssString = exports.generateCss(_styles[selector]) if (cssString) { - styles += apply_class(_id, componentName, cssString, selector) + styles += exports.applyClass(_id, componentName, cssString, selector) } }) if (_children && _children.length) { - styles += generate_screen_css(_children) + "\n" + styles += exports.generateAssetCss(_children) + "\n" } } return styles.trim() } -export const generate_css = style => { +exports.generateCss = style => { let cssString = Object.entries(style).reduce((str, [key, value]) => { if (typeof value === "string") { if (value) { @@ -33,7 +33,7 @@ export const generate_css = style => { return (cssString || "").trim() } -export const apply_class = (id, name = "element", styles, selector) => { +exports.applyClass = (id, name = "element", styles, selector) => { if (selector === "normal") { return `.${name}-${id} {\n${styles}\n}` } else { diff --git a/packages/server/src/utilities/builder/setBuilderToken.js b/packages/server/src/utilities/builder/setBuilderToken.js index f3adf079ad..ed374a1d8e 100644 --- a/packages/server/src/utilities/builder/setBuilderToken.js +++ b/packages/server/src/utilities/builder/setBuilderToken.js @@ -1,4 +1,4 @@ -const { BUILTIN_LEVEL_IDS } = require("../security/accessLevels") +const { BUILTIN_ROLE_IDS } = require("../security/roles") const { BUILTIN_PERMISSION_NAMES } = require("../security/permissions") const env = require("../../environment") const CouchDB = require("../../db") @@ -10,7 +10,7 @@ const APP_PREFIX = DocumentTypes.APP + SEPARATOR module.exports = async (ctx, appId, version) => { const builderUser = { userId: "BUILDER", - accessLevelId: BUILTIN_LEVEL_IDS.BUILDER, + roleId: BUILTIN_ROLE_IDS.BUILDER, permissions: [BUILTIN_PERMISSION_NAMES.ADMIN], version, } diff --git a/packages/server/src/utilities/mustache.js b/packages/server/src/utilities/mustache.js new file mode 100644 index 0000000000..0428bdc03d --- /dev/null +++ b/packages/server/src/utilities/mustache.js @@ -0,0 +1,73 @@ +const handlebars = require("handlebars") + +handlebars.registerHelper("object", value => { + return new handlebars.SafeString(JSON.stringify(value)) +}) + +/** + * When running mustache statements to execute on the context of the automation it possible user's may input mustache + * in a few different forms, some of which are invalid but are logically valid. An example of this would be the mustache + * statement "{{steps[0].revision}}" here it is obvious the user is attempting to access an array or object using array + * like operators. These are not supported by Mustache and therefore the statement will fail. This function will clean up + * the mustache statement so it instead reads as "{{steps.0.revision}}" which is valid and will work. It may also be expanded + * to include any other mustache statement cleanup that has been deemed necessary for the system. + * + * @param {string} string The string which *may* contain mustache statements, it is OK if it does not contain any. + * @returns {string} The string that was input with cleaned up mustache statements as required. + */ +function cleanMustache(string) { + let charToReplace = { + "[": ".", + "]": "", + } + let regex = new RegExp(/{{[^}}]*}}/g) + let matches = string.match(regex) + if (matches == null) { + return string + } + for (let match of matches) { + let baseIdx = string.indexOf(match) + for (let key of Object.keys(charToReplace)) { + let idxChar = match.indexOf(key) + if (idxChar !== -1) { + string = + string.slice(baseIdx, baseIdx + idxChar) + + charToReplace[key] + + string.slice(baseIdx + idxChar + 1) + } + } + } + return string +} + +/** + * Given an input object this will recurse through all props to try and update + * any handlebars/mustache statements within. + * @param {object|array} inputs The input structure which is to be recursed, it is important to note that + * if the structure contains any cycles then this will fail. + * @param {object} context The context that handlebars should fill data from. + * @returns {object|array} The structure input, as fully updated as possible. + */ +function recurseMustache(inputs, context) { + // JSON stringify will fail if there are any cycles, stops infinite recursion + try { + JSON.stringify(inputs) + } catch (err) { + throw "Unable to process inputs to JSON, cannot recurse" + } + for (let key of Object.keys(inputs)) { + let val = inputs[key] + if (typeof val === "string") { + val = cleanMustache(inputs[key]) + const template = handlebars.compile(val) + inputs[key] = template(context) + } + // this covers objects and arrays + else if (typeof val === "object") { + inputs[key] = recurseMustache(inputs[key], context) + } + } + return inputs +} + +exports.recurseMustache = recurseMustache diff --git a/packages/server/src/utilities/security/accessLevels.js b/packages/server/src/utilities/security/accessLevels.js deleted file mode 100644 index 344dd20930..0000000000 --- a/packages/server/src/utilities/security/accessLevels.js +++ /dev/null @@ -1,150 +0,0 @@ -const CouchDB = require("../../db") -const { cloneDeep } = require("lodash/fp") - -const BUILTIN_IDS = { - ADMIN: "ADMIN", - POWER: "POWER_USER", - BASIC: "BASIC", - PUBLIC: "PUBLIC", - BUILDER: "BUILDER", -} - -function AccessLevel(id, name, inherits) { - this._id = id - this.name = name - if (inherits) { - this.inherits = inherits - } -} - -exports.BUILTIN_LEVELS = { - ADMIN: new AccessLevel(BUILTIN_IDS.ADMIN, "Admin", BUILTIN_IDS.POWER), - POWER: new AccessLevel(BUILTIN_IDS.POWER, "Power", BUILTIN_IDS.BASIC), - BASIC: new AccessLevel(BUILTIN_IDS.BASIC, "Basic", BUILTIN_IDS.PUBLIC), - PUBLIC: new AccessLevel(BUILTIN_IDS.PUBLIC, "Public"), - BUILDER: new AccessLevel(BUILTIN_IDS.BUILDER, "Builder"), -} - -exports.BUILTIN_LEVEL_ID_ARRAY = Object.values(exports.BUILTIN_LEVELS).map( - level => level._id -) - -exports.BUILTIN_LEVEL_NAME_ARRAY = Object.values(exports.BUILTIN_LEVELS).map( - level => level.name -) - -function isBuiltin(accessLevel) { - return exports.BUILTIN_LEVEL_ID_ARRAY.indexOf(accessLevel) !== -1 -} - -/** - * Gets the access level object, this is mainly useful for two purposes, to check if the level exists and - * to check if the access level inherits any others. - * @param {string} appId The app in which to look for the access level. - * @param {string|null} accessLevelId The level ID to lookup. - * @returns {Promise} The access level object, which may contain an "inherits" property. - */ -exports.getAccessLevel = async (appId, accessLevelId) => { - if (!accessLevelId) { - return null - } - let accessLevel - if (isBuiltin(accessLevelId)) { - accessLevel = cloneDeep( - Object.values(exports.BUILTIN_LEVELS).find( - level => level._id === accessLevelId - ) - ) - } else { - const db = new CouchDB(appId) - accessLevel = await db.get(accessLevelId) - } - return accessLevel -} - -/** - * Returns an ordered array of the user's inherited access level IDs, this can be used - * to determine if a user can access something that requires a specific access level. - * @param {string} appId The ID of the application from which access levels should be obtained. - * @param {string} userAccessLevelId The user's access level, this can be found in their access token. - * @returns {Promise} returns an ordered array of the access levels, with the first being their - * highest level of access and the last being the lowest level. - */ -exports.getUserAccessLevelHierarchy = async (appId, userAccessLevelId) => { - // special case, if they don't have a level then they are a public user - if (!userAccessLevelId) { - return [BUILTIN_IDS.PUBLIC] - } - let accessLevelIds = [userAccessLevelId] - let userAccess = await exports.getAccessLevel(appId, userAccessLevelId) - // check if inherited makes it possible - while ( - userAccess && - userAccess.inherits && - accessLevelIds.indexOf(userAccess.inherits) === -1 - ) { - accessLevelIds.push(userAccess.inherits) - // go to get the inherited incase it inherits anything - userAccess = await exports.getAccessLevel(appId, userAccess.inherits) - } - // add the user's actual level at the end (not at start as that stops iteration - return accessLevelIds -} - -class AccessController { - constructor(appId) { - this.appId = appId - this.userHierarchies = {} - } - - async hasAccess(tryingAccessLevelId, userAccessLevelId) { - // special cases, the screen has no access level, the access levels are the same or the user - // is currently in the builder - if ( - tryingAccessLevelId == null || - tryingAccessLevelId === "" || - tryingAccessLevelId === userAccessLevelId || - userAccessLevelId === BUILTIN_IDS.BUILDER - ) { - return true - } - let accessLevelIds = this.userHierarchies[userAccessLevelId] - if (!accessLevelIds) { - accessLevelIds = await exports.getUserAccessLevelHierarchy( - this.appId, - userAccessLevelId - ) - this.userHierarchies[userAccessLevelId] = userAccessLevelId - } - - return accessLevelIds.indexOf(tryingAccessLevelId) !== -1 - } - - async checkScreensAccess(screens, userAccessLevelId) { - let accessibleScreens = [] - // don't want to handle this with Promise.all as this would mean all custom access levels would be - // retrieved at same time, it is likely a custom levels will be re-used and therefore want - // to work in sync for performance save - for (let screen of screens) { - const accessible = await this.checkScreenAccess(screen, userAccessLevelId) - if (accessible) { - accessibleScreens.push(accessible) - } - } - return accessibleScreens - } - - async checkScreenAccess(screen, userAccessLevelId) { - const accessLevelId = - screen && screen.routing ? screen.routing.accessLevelId : null - if (await this.hasAccess(accessLevelId, userAccessLevelId)) { - return screen - } - return null - } -} - -exports.AccessController = AccessController -exports.BUILTIN_LEVEL_IDS = BUILTIN_IDS -exports.isBuiltin = isBuiltin -exports.AccessLevel = AccessLevel diff --git a/packages/server/src/utilities/security/roles.js b/packages/server/src/utilities/security/roles.js new file mode 100644 index 0000000000..8a2b343c7a --- /dev/null +++ b/packages/server/src/utilities/security/roles.js @@ -0,0 +1,143 @@ +const CouchDB = require("../../db") +const { cloneDeep } = require("lodash/fp") + +const BUILTIN_IDS = { + ADMIN: "ADMIN", + POWER: "POWER_USER", + BASIC: "BASIC", + PUBLIC: "PUBLIC", + BUILDER: "BUILDER", +} + +function Role(id, name, inherits) { + this._id = id + this.name = name + if (inherits) { + this.inherits = inherits + } +} + +exports.BUILTIN_ROLES = { + ADMIN: new Role(BUILTIN_IDS.ADMIN, "Admin", BUILTIN_IDS.POWER), + POWER: new Role(BUILTIN_IDS.POWER, "Power", BUILTIN_IDS.BASIC), + BASIC: new Role(BUILTIN_IDS.BASIC, "Basic", BUILTIN_IDS.PUBLIC), + PUBLIC: new Role(BUILTIN_IDS.PUBLIC, "Public"), + BUILDER: new Role(BUILTIN_IDS.BUILDER, "Builder"), +} + +exports.BUILTIN_ROLE_ID_ARRAY = Object.values(exports.BUILTIN_ROLES).map( + level => level._id +) + +exports.BUILTIN_ROLE_NAME_ARRAY = Object.values(exports.BUILTIN_ROLES).map( + level => level.name +) + +function isBuiltin(role) { + return exports.BUILTIN_ROLE_ID_ARRAY.indexOf(role) !== -1 +} + +/** + * Gets the role object, this is mainly useful for two purposes, to check if the level exists and + * to check if the role inherits any others. + * @param {string} appId The app in which to look for the role. + * @param {string|null} roleId The level ID to lookup. + * @returns {Promise} The role object, which may contain an "inherits" property. + */ +exports.getRole = async (appId, roleId) => { + if (!roleId) { + return null + } + let role + if (isBuiltin(roleId)) { + role = cloneDeep( + Object.values(exports.BUILTIN_ROLES).find(role => role._id === roleId) + ) + } else { + const db = new CouchDB(appId) + role = await db.get(roleId) + } + return role +} + +/** + * Returns an ordered array of the user's inherited role IDs, this can be used + * to determine if a user can access something that requires a specific role. + * @param {string} appId The ID of the application from which roles should be obtained. + * @param {string} userRoleId The user's role ID, this can be found in their access token. + * @returns {Promise} returns an ordered array of the roles, with the first being their + * highest level of access and the last being the lowest level. + */ +exports.getUserRoleHierarchy = async (appId, userRoleId) => { + // special case, if they don't have a role then they are a public user + if (!userRoleId) { + return [BUILTIN_IDS.PUBLIC] + } + let roleIds = [userRoleId] + let userRole = await exports.getRole(appId, userRoleId) + // check if inherited makes it possible + while ( + userRole && + userRole.inherits && + roleIds.indexOf(userRole.inherits) === -1 + ) { + roleIds.push(userRole.inherits) + // go to get the inherited incase it inherits anything + userRole = await exports.getRole(appId, userRole.inherits) + } + return roleIds +} + +class AccessController { + constructor(appId) { + this.appId = appId + this.userHierarchies = {} + } + + async hasAccess(tryingRoleId, userRoleId) { + // special cases, the screen has no role, the roles are the same or the user + // is currently in the builder + if ( + tryingRoleId == null || + tryingRoleId === "" || + tryingRoleId === userRoleId || + tryingRoleId === BUILTIN_IDS.BUILDER + ) { + return true + } + let roleIds = this.userHierarchies[userRoleId] + if (!roleIds) { + roleIds = await exports.getUserRoleHierarchy(this.appId, userRoleId) + this.userHierarchies[userRoleId] = roleIds + } + + return roleIds.indexOf(tryingRoleId) !== -1 + } + + async checkScreensAccess(screens, userRoleId) { + let accessibleScreens = [] + // don't want to handle this with Promise.all as this would mean all custom roles would be + // retrieved at same time, it is likely a custom role will be re-used and therefore want + // to work in sync for performance save + for (let screen of screens) { + const accessible = await this.checkScreenAccess(screen, userRoleId) + if (accessible) { + accessibleScreens.push(accessible) + } + } + return accessibleScreens + } + + async checkScreenAccess(screen, userRoleId) { + const roleId = screen && screen.routing ? screen.routing.roleId : null + if (await this.hasAccess(roleId, userRoleId)) { + return screen + } + return null + } +} + +exports.AccessController = AccessController +exports.BUILTIN_ROLE_IDS = BUILTIN_IDS +exports.isBuiltin = isBuiltin +exports.Role = Role diff --git a/packages/server/yarn.lock b/packages/server/yarn.lock index 5e7317cd19..30a0ba2d40 100644 --- a/packages/server/yarn.lock +++ b/packages/server/yarn.lock @@ -15,18 +15,18 @@ "@babel/highlight" "^7.10.4" "@babel/core@^7.1.0": - version "7.11.6" - resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.11.6.tgz#3a9455dc7387ff1bac45770650bc13ba04a15651" - integrity sha512-Wpcv03AGnmkgm6uS6k8iwhIwTrcP0m17TL1n1sy7qD0qelDu4XNeW0dN0mHfa+Gei211yDaLoEe/VlbXQzM4Bg== + version "7.12.9" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.12.9.tgz#fd450c4ec10cdbb980e2928b7aa7a28484593fc8" + integrity sha512-gTXYh3M5wb7FRXQy+FErKFAv90BnlOuNn1QkCK2lREoPAjrQCO49+HVSrFoe5uakFAF5eenS75KbO2vQiLrTMQ== dependencies: "@babel/code-frame" "^7.10.4" - "@babel/generator" "^7.11.6" - "@babel/helper-module-transforms" "^7.11.0" - "@babel/helpers" "^7.10.4" - "@babel/parser" "^7.11.5" - "@babel/template" "^7.10.4" - "@babel/traverse" "^7.11.5" - "@babel/types" "^7.11.5" + "@babel/generator" "^7.12.5" + "@babel/helper-module-transforms" "^7.12.1" + "@babel/helpers" "^7.12.5" + "@babel/parser" "^7.12.7" + "@babel/template" "^7.12.7" + "@babel/traverse" "^7.12.9" + "@babel/types" "^7.12.7" convert-source-map "^1.7.0" debug "^4.1.0" gensync "^1.0.0-beta.1" @@ -36,12 +36,12 @@ semver "^5.4.1" source-map "^0.5.0" -"@babel/generator@^7.11.5", "@babel/generator@^7.11.6", "@babel/generator@^7.4.0": - version "7.11.6" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.11.6.tgz#b868900f81b163b4d464ea24545c61cbac4dc620" - integrity sha512-DWtQ1PV3r+cLbySoHrwn9RWEgKMBLLma4OBQloPRyDYvc5msJM9kvTLo1YnlJd1P/ZuKbdli3ijr5q3FvAF3uA== +"@babel/generator@^7.12.5", "@babel/generator@^7.4.0": + version "7.12.5" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.12.5.tgz#a2c50de5c8b6d708ab95be5e6053936c1884a4de" + integrity sha512-m16TQQJ8hPt7E+OS/XVQg/7U184MLXtvuGbCdA7na61vha+ImkyyNM/9DDA0unYCVZn3ZOhng+qz48/KBOT96A== dependencies: - "@babel/types" "^7.11.5" + "@babel/types" "^7.12.5" jsesc "^2.5.1" source-map "^0.5.0" @@ -61,62 +61,63 @@ dependencies: "@babel/types" "^7.10.4" -"@babel/helper-member-expression-to-functions@^7.10.4": - version "7.11.0" - resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.11.0.tgz#ae69c83d84ee82f4b42f96e2a09410935a8f26df" - integrity sha512-JbFlKHFntRV5qKw3YC0CvQnDZ4XMwgzzBbld7Ly4Mj4cbFy3KywcR8NtNctRToMWJOVvLINJv525Gd6wwVEx/Q== +"@babel/helper-member-expression-to-functions@^7.12.1": + version "7.12.7" + resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.12.7.tgz#aa77bd0396ec8114e5e30787efa78599d874a855" + integrity sha512-DCsuPyeWxeHgh1Dus7APn7iza42i/qXqiFPWyBDdOFtvS581JQePsc1F/nD+fHrcswhLlRc2UpYS1NwERxZhHw== dependencies: - "@babel/types" "^7.11.0" + "@babel/types" "^7.12.7" -"@babel/helper-module-imports@^7.10.4": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.10.4.tgz#4c5c54be04bd31670a7382797d75b9fa2e5b5620" - integrity sha512-nEQJHqYavI217oD9+s5MUBzk6x1IlvoS9WTPfgG43CbMEeStE0v+r+TucWdx8KFGowPGvyOkDT9+7DHedIDnVw== +"@babel/helper-module-imports@^7.12.1": + version "7.12.5" + resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.12.5.tgz#1bfc0229f794988f76ed0a4d4e90860850b54dfb" + integrity sha512-SR713Ogqg6++uexFRORf/+nPXMmWIn80TALu0uaFb+iQIUoR7bOC7zBWyzBs5b3tBBJXuyD0cRu1F15GyzjOWA== dependencies: - "@babel/types" "^7.10.4" + "@babel/types" "^7.12.5" -"@babel/helper-module-transforms@^7.11.0": - version "7.11.0" - resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.11.0.tgz#b16f250229e47211abdd84b34b64737c2ab2d359" - integrity sha512-02EVu8COMuTRO1TAzdMtpBPbe6aQ1w/8fePD2YgQmxZU4gpNWaL9gK3Jp7dxlkUlUCJOTaSeA+Hrm1BRQwqIhg== +"@babel/helper-module-transforms@^7.12.1": + version "7.12.1" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.12.1.tgz#7954fec71f5b32c48e4b303b437c34453fd7247c" + integrity sha512-QQzehgFAZ2bbISiCpmVGfiGux8YVFXQ0abBic2Envhej22DVXV9nCFaS5hIQbkyo1AdGb+gNME2TSh3hYJVV/w== dependencies: - "@babel/helper-module-imports" "^7.10.4" - "@babel/helper-replace-supers" "^7.10.4" - "@babel/helper-simple-access" "^7.10.4" + "@babel/helper-module-imports" "^7.12.1" + "@babel/helper-replace-supers" "^7.12.1" + "@babel/helper-simple-access" "^7.12.1" "@babel/helper-split-export-declaration" "^7.11.0" + "@babel/helper-validator-identifier" "^7.10.4" "@babel/template" "^7.10.4" - "@babel/types" "^7.11.0" + "@babel/traverse" "^7.12.1" + "@babel/types" "^7.12.1" lodash "^4.17.19" "@babel/helper-optimise-call-expression@^7.10.4": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.10.4.tgz#50dc96413d594f995a77905905b05893cd779673" - integrity sha512-n3UGKY4VXwXThEiKrgRAoVPBMqeoPgHVqiHZOanAJCG9nQUL2pLRQirUzl0ioKclHGpGqRgIOkgcIJaIWLpygg== + version "7.12.7" + resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.12.7.tgz#7f94ae5e08721a49467346aa04fd22f750033b9c" + integrity sha512-I5xc9oSJ2h59OwyUqjv95HRyzxj53DAubUERgQMrpcCEYQyToeHA+NEcUEsVWB4j53RDeskeBJ0SgRAYHDBckw== dependencies: - "@babel/types" "^7.10.4" + "@babel/types" "^7.12.7" "@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.8.0": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz#2f75a831269d4f677de49986dff59927533cf375" integrity sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg== -"@babel/helper-replace-supers@^7.10.4": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.10.4.tgz#d585cd9388ea06e6031e4cd44b6713cbead9e6cf" - integrity sha512-sPxZfFXocEymYTdVK1UNmFPBN+Hv5mJkLPsYWwGBxZAxaWfFu+xqp7b6qWD0yjNuNL2VKc6L5M18tOXUP7NU0A== +"@babel/helper-replace-supers@^7.12.1": + version "7.12.5" + resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.12.5.tgz#f009a17543bbbbce16b06206ae73b63d3fca68d9" + integrity sha512-5YILoed0ZyIpF4gKcpZitEnXEJ9UoDRki1Ey6xz46rxOzfNMAhVIJMoune1hmPVxh40LRv1+oafz7UsWX+vyWA== dependencies: - "@babel/helper-member-expression-to-functions" "^7.10.4" + "@babel/helper-member-expression-to-functions" "^7.12.1" "@babel/helper-optimise-call-expression" "^7.10.4" - "@babel/traverse" "^7.10.4" - "@babel/types" "^7.10.4" + "@babel/traverse" "^7.12.5" + "@babel/types" "^7.12.5" -"@babel/helper-simple-access@^7.10.4": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.10.4.tgz#0f5ccda2945277a2a7a2d3a821e15395edcf3461" - integrity sha512-0fMy72ej/VEvF8ULmX6yb5MtHG4uH4Dbd6I/aHDb/JVg0bbivwt9Wg+h3uMvX+QSFtwr5MeItvazbrc4jtRAXw== +"@babel/helper-simple-access@^7.12.1": + version "7.12.1" + resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.12.1.tgz#32427e5aa61547d38eb1e6eaf5fd1426fdad9136" + integrity sha512-OxBp7pMrjVewSSC8fXDFrHrBcJATOOFssZwv16F3/6Xtc138GHybBfPbm9kfiqQHKhYQrlamWILwlDCeyMFEaA== dependencies: - "@babel/template" "^7.10.4" - "@babel/types" "^7.10.4" + "@babel/types" "^7.12.1" "@babel/helper-split-export-declaration@^7.11.0": version "7.11.0" @@ -130,14 +131,14 @@ resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.4.tgz#a78c7a7251e01f616512d31b10adcf52ada5e0d2" integrity sha512-3U9y+43hz7ZM+rzG24Qe2mufW5KhvFg/NhnNph+i9mgCtdTCtMJuI1TMkrIUiK7Ix4PYlRF9I5dhqaLYA/ADXw== -"@babel/helpers@^7.10.4": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.10.4.tgz#2abeb0d721aff7c0a97376b9e1f6f65d7a475044" - integrity sha512-L2gX/XeUONeEbI78dXSrJzGdz4GQ+ZTA/aazfUsFaWjSe95kiCuOZ5HsXvkiw3iwF+mFHSRUfJU8t6YavocdXA== +"@babel/helpers@^7.12.5": + version "7.12.5" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.12.5.tgz#1a1ba4a768d9b58310eda516c449913fe647116e" + integrity sha512-lgKGMQlKqA8meJqKsW6rUnc4MdUk35Ln0ATDqdM1a/UpARODdI4j5Y5lVfUScnSNkJcdCRAaWkspykNoFg9sJA== dependencies: "@babel/template" "^7.10.4" - "@babel/traverse" "^7.10.4" - "@babel/types" "^7.10.4" + "@babel/traverse" "^7.12.5" + "@babel/types" "^7.12.5" "@babel/highlight@^7.10.4": version "7.10.4" @@ -148,10 +149,10 @@ chalk "^2.0.0" js-tokens "^4.0.0" -"@babel/parser@^7.1.0", "@babel/parser@^7.10.4", "@babel/parser@^7.11.5", "@babel/parser@^7.4.3": - version "7.11.5" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.11.5.tgz#c7ff6303df71080ec7a4f5b8c003c58f1cf51037" - integrity sha512-X9rD8qqm695vgmeaQ4fvz/o3+Wk4ZzQvSHkDBgpYKxpD4qTAUm88ZKtHkVqIOsYFFbIQ6wQYhC6q7pjqVK0E0Q== +"@babel/parser@^7.1.0", "@babel/parser@^7.12.7", "@babel/parser@^7.4.3": + version "7.12.7" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.12.7.tgz#fee7b39fe809d0e73e5b25eecaf5780ef3d73056" + integrity sha512-oWR02Ubp4xTLCAqPRiNIuMVgNO5Aif/xpXtabhzW2HWUD47XJsAB4Zd/Rg30+XeQA3juXigV7hlquOTmwqLiwg== "@babel/plugin-syntax-object-rest-spread@^7.0.0": version "7.8.3" @@ -161,54 +162,45 @@ "@babel/helper-plugin-utils" "^7.8.0" "@babel/runtime@^7.7.2": - version "7.12.1" - resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.12.1.tgz#b4116a6b6711d010b2dad3b7b6e43bf1b9954740" - integrity sha512-J5AIf3vPj3UwXaAzb5j1xM4WAQDX3EMgemF8rjCP3SoW09LfRKAXQKt6CoVYl230P6iWdRcBbnLDDdnqWxZSCA== + version "7.12.5" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.12.5.tgz#410e7e487441e1b360c29be715d870d9b985882e" + integrity sha512-plcc+hbExy3McchJCEQG3knOsuh3HH+Prx1P6cLIkET/0dLuQDEnrT+s27Axgc9bqfsmNUNHfscgMUdBpC9xfg== dependencies: regenerator-runtime "^0.13.4" -"@babel/template@^7.10.4", "@babel/template@^7.4.0": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.10.4.tgz#3251996c4200ebc71d1a8fc405fba940f36ba278" - integrity sha512-ZCjD27cGJFUB6nmCB1Enki3r+L5kJveX9pq1SvAUKoICy6CZ9yD8xO086YXdYhvNjBdnekm4ZnaP5yC8Cs/1tA== +"@babel/template@^7.10.4", "@babel/template@^7.12.7", "@babel/template@^7.4.0": + version "7.12.7" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.12.7.tgz#c817233696018e39fbb6c491d2fb684e05ed43bc" + integrity sha512-GkDzmHS6GV7ZeXfJZ0tLRBhZcMcY0/Lnb+eEbXDBfCAcZCjrZKe6p3J4we/D24O9Y8enxWAg1cWwof59yLh2ow== dependencies: "@babel/code-frame" "^7.10.4" - "@babel/parser" "^7.10.4" - "@babel/types" "^7.10.4" + "@babel/parser" "^7.12.7" + "@babel/types" "^7.12.7" -"@babel/traverse@^7.1.0", "@babel/traverse@^7.10.4", "@babel/traverse@^7.11.5", "@babel/traverse@^7.4.3": - version "7.11.5" - resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.11.5.tgz#be777b93b518eb6d76ee2e1ea1d143daa11e61c3" - integrity sha512-EjiPXt+r7LiCZXEfRpSJd+jUMnBd4/9OUv7Nx3+0u9+eimMwJmG0Q98lw4/289JCoxSE8OolDMNZaaF/JZ69WQ== +"@babel/traverse@^7.1.0", "@babel/traverse@^7.12.1", "@babel/traverse@^7.12.5", "@babel/traverse@^7.12.9", "@babel/traverse@^7.4.3": + version "7.12.9" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.12.9.tgz#fad26c972eabbc11350e0b695978de6cc8e8596f" + integrity sha512-iX9ajqnLdoU1s1nHt36JDI9KG4k+vmI8WgjK5d+aDTwQbL2fUnzedNedssA645Ede3PM2ma1n8Q4h2ohwXgMXw== dependencies: "@babel/code-frame" "^7.10.4" - "@babel/generator" "^7.11.5" + "@babel/generator" "^7.12.5" "@babel/helper-function-name" "^7.10.4" "@babel/helper-split-export-declaration" "^7.11.0" - "@babel/parser" "^7.11.5" - "@babel/types" "^7.11.5" + "@babel/parser" "^7.12.7" + "@babel/types" "^7.12.7" debug "^4.1.0" globals "^11.1.0" lodash "^4.17.19" -"@babel/types@^7.0.0", "@babel/types@^7.10.4", "@babel/types@^7.11.0", "@babel/types@^7.11.5", "@babel/types@^7.3.0", "@babel/types@^7.4.0": - version "7.11.5" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.11.5.tgz#d9de577d01252d77c6800cee039ee64faf75662d" - integrity sha512-bvM7Qz6eKnJVFIn+1LPtjlBFPVN5jNDc1XmN15vWe7Q3DPBufWWsLiIvUu7xW87uTG6QoggpIDnUgLQvPheU+Q== +"@babel/types@^7.0.0", "@babel/types@^7.10.4", "@babel/types@^7.11.0", "@babel/types@^7.12.1", "@babel/types@^7.12.5", "@babel/types@^7.12.7", "@babel/types@^7.3.0", "@babel/types@^7.4.0": + version "7.12.7" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.12.7.tgz#6039ff1e242640a29452c9ae572162ec9a8f5d13" + integrity sha512-MNyI92qZq6jrQkXvtIiykvl4WtoRrVV9MPn+ZfsoEENjiWcBQ3ZSHrkxnJWgWtLX3XXqX5hrSQ+X69wkmesXuQ== dependencies: "@babel/helper-validator-identifier" "^7.10.4" lodash "^4.17.19" to-fast-properties "^2.0.0" -"@budibase/client@^0.3.8": - version "0.3.8" - resolved "https://registry.yarnpkg.com/@budibase/client/-/client-0.3.8.tgz#75df7e97e8f0d9b58c00e2bb0d3b4a55f8d04735" - integrity sha512-tnFdmCdXKS+uZGoipr69Wa0oVoFHmyoV0ydihI6q0gKQH0KutypVHAaul2qPB8t5a/mTZopC//2WdmCeX1GKVg== - dependencies: - deep-equal "^2.0.1" - mustache "^4.0.1" - regexparam "^1.3.0" - "@cnakazawa/watch@^1.0.3": version "1.0.4" resolved "https://registry.yarnpkg.com/@cnakazawa/watch/-/watch-1.0.4.tgz#f864ae85004d0fcab6f50be9141c4da368d1656a" @@ -252,33 +244,16 @@ global-agent "^2.0.2" global-tunnel-ng "^2.7.1" -"@hapi/address@^4.1.0": - version "4.1.0" - resolved "https://registry.yarnpkg.com/@hapi/address/-/address-4.1.0.tgz#d60c5c0d930e77456fdcde2598e77302e2955e1d" - integrity sha512-SkszZf13HVgGmChdHo/PxchnSaCJ6cetVqLzyciudzZRT0jcOouIF/Q93mgjw8cce+D+4F4C1Z/WrfFN+O3VHQ== - dependencies: - "@hapi/hoek" "^9.0.0" - "@hapi/bourne@^2.0.0": version "2.0.0" resolved "https://registry.yarnpkg.com/@hapi/bourne/-/bourne-2.0.0.tgz#5bb2193eb685c0007540ca61d166d4e1edaf918d" integrity sha512-WEezM1FWztfbzqIUbsDzFRVMxSoLy3HugVcux6KDDtTqzPsLE8NDRHfXvev66aH1i2oOKKar3/XDjbvh/OUBdg== -"@hapi/formula@^2.0.0": - version "2.0.0" - resolved "https://registry.yarnpkg.com/@hapi/formula/-/formula-2.0.0.tgz#edade0619ed58c8e4f164f233cda70211e787128" - integrity sha512-V87P8fv7PI0LH7LiVi8Lkf3x+KCO7pQozXRssAHNXXL9L1K+uyu4XypLXwxqVDKgyQai6qj3/KteNlrqDx4W5A== - "@hapi/hoek@^9.0.0": version "9.1.0" resolved "https://registry.yarnpkg.com/@hapi/hoek/-/hoek-9.1.0.tgz#6c9eafc78c1529248f8f4d92b0799a712b6052c6" integrity sha512-i9YbZPN3QgfighY/1X1Pu118VUz2Fmmhd6b2n0/O8YVgGGfw0FbUYoA97k7FkpGJ+pLCFEDLUmAPPV4D1kpeFw== -"@hapi/pinpoint@^2.0.0": - version "2.0.0" - resolved "https://registry.yarnpkg.com/@hapi/pinpoint/-/pinpoint-2.0.0.tgz#805b40d4dbec04fc116a73089494e00f073de8df" - integrity sha512-vzXR5MY7n4XeIvLpfl3HtE3coZYO4raKXW766R6DZw/6aLqR26iuZ109K7a0NtF2Db0jxqh7xz2AxkUwpUFybw== - "@hapi/topo@^5.0.0": version "5.0.0" resolved "https://registry.yarnpkg.com/@hapi/topo/-/topo-5.0.0.tgz#c19af8577fa393a06e9c77b60995af959be721e7" @@ -736,98 +711,114 @@ path-to-regexp "1.x" urijs "^1.19.2" -"@sendgrid/client@^7.2.6": - version "7.2.6" - resolved "https://registry.yarnpkg.com/@sendgrid/client/-/client-7.2.6.tgz#28374927b5d9b3b351b9426f4a218d23d590c958" - integrity sha512-AOB3IVlB76SMYdaLEtWGm6/GwrOv0xlAOkyCqk5+XifJRqL2pl8a9lfxFZ9BEnWrdqPJPJ1/omopj0P7d5ZPmw== +"@sendgrid/client@^7.4.0": + version "7.4.0" + resolved "https://registry.yarnpkg.com/@sendgrid/client/-/client-7.4.0.tgz#07c26936f88ade43fb845ce00b37d882999c0a04" + integrity sha512-KAZlEb1P8sATgBN+7hXgzaRF94nF9KQgDxQ6zUT1BV0kEsNtJQ2cs35sCtWt6AKKJrL0xPI/MsfcAJqom4YQBg== dependencies: - "@sendgrid/helpers" "^7.2.6" + "@sendgrid/helpers" "^7.4.0" axios "^0.19.2" -"@sendgrid/helpers@^7.2.6": - version "7.2.6" - resolved "https://registry.yarnpkg.com/@sendgrid/helpers/-/helpers-7.2.6.tgz#5d15b8914940147c0635c9a3d2a93fed8c73dc71" - integrity sha512-J2xniPBOVo4ASzx+xc735OovHGj/v9oNrDo1Bb5fwTg/kmUxWxeoKZRkB+KLdciwmTtVrZjYLdQB3pMFIe9lAw== +"@sendgrid/helpers@^7.4.0": + version "7.4.0" + resolved "https://registry.yarnpkg.com/@sendgrid/helpers/-/helpers-7.4.0.tgz#be98730c89c190c8873e2f25d868a13d26b75b25" + integrity sha512-IQI2vemiJB0+X6bEp4HRG+0/wrzR2RDGnB5rwfq1CsPDrUFdJfxbE2zbGx//1GnlNwAtbHyc93ejU1m0KZr86w== dependencies: - chalk "^2.0.1" deepmerge "^4.2.2" "@sendgrid/mail@^7.1.1": - version "7.2.6" - resolved "https://registry.yarnpkg.com/@sendgrid/mail/-/mail-7.2.6.tgz#8f6a398ad75fb1ed7a35a9bb18cbdac111637ef6" - integrity sha512-eP9MuqEZIgt4bHaoufWqKGUY4Bo7FUgST3WGNYIDXIe1rP2dV6/JR7Ac2Dl9iW22gy15nc58fLGIGa41XbwtuA== + version "7.4.0" + resolved "https://registry.yarnpkg.com/@sendgrid/mail/-/mail-7.4.0.tgz#126de0f0fc7c62d5d609140261fd598b6291fee3" + integrity sha512-SAARsfbl50OEJ99LYGKfgrYiV5O6+23aeGJuEBTHHSwRZ6KhD3n1BjPeIejbqgbqYLZJfNLxyU3o5xRdJPp3zg== dependencies: - "@sendgrid/client" "^7.2.6" - "@sendgrid/helpers" "^7.2.6" + "@sendgrid/client" "^7.4.0" + "@sendgrid/helpers" "^7.4.0" -"@sentry/core@5.25.0": - version "5.25.0" - resolved "https://registry.yarnpkg.com/@sentry/core/-/core-5.25.0.tgz#525ad37f9e8a95603768e3b74b437d5235a51578" - integrity sha512-hY6Zmo7t/RV+oZuvXHP6nyAj/QnZr2jW0e7EbL5YKMV8q0vlnjcE0LgqFXme726OJemoLk67z+sQOJic/Ztehg== +"@sentry/core@5.27.6": + version "5.27.6" + resolved "https://registry.yarnpkg.com/@sentry/core/-/core-5.27.6.tgz#3ceeb58acd857f1e17d52d3087bfecb506adc1f7" + integrity sha512-izCS5iyc6HAfpW1AsGXLAKetx82C1Sq1siAh97tOlSK58PVJAEH/WMiej9WuZJxCDTOtj94QtoLflssrZyAtFg== dependencies: - "@sentry/hub" "5.25.0" - "@sentry/minimal" "5.25.0" - "@sentry/types" "5.25.0" - "@sentry/utils" "5.25.0" + "@sentry/hub" "5.27.6" + "@sentry/minimal" "5.27.6" + "@sentry/types" "5.27.6" + "@sentry/utils" "5.27.6" tslib "^1.9.3" -"@sentry/hub@5.25.0": - version "5.25.0" - resolved "https://registry.yarnpkg.com/@sentry/hub/-/hub-5.25.0.tgz#6932535604cafaee1ac7f361b0e7c2ce8f7e7bc3" - integrity sha512-kOlOiJV8wMX50lYpzMlOXBoH7MNG0Ho4RTusdZnXZBaASq5/ljngDJkLr6uylNjceZQP21wzipCQajsJMYB7EQ== +"@sentry/hub@5.27.6": + version "5.27.6" + resolved "https://registry.yarnpkg.com/@sentry/hub/-/hub-5.27.6.tgz#a94adbe32c45dda7ad5adf742b82e0a022eb9c2f" + integrity sha512-bOMky3iu7zEghSaWmTayfme5tCpUok841qDCGxGKuyAtOhBDsgGNS/ApNEEDF2fyX0oo4G1cHYPWhX90ZFf/xA== dependencies: - "@sentry/types" "5.25.0" - "@sentry/utils" "5.25.0" + "@sentry/types" "5.27.6" + "@sentry/utils" "5.27.6" tslib "^1.9.3" -"@sentry/minimal@5.25.0": - version "5.25.0" - resolved "https://registry.yarnpkg.com/@sentry/minimal/-/minimal-5.25.0.tgz#447b5406b45c8c436c461abea4474d6a849ed975" - integrity sha512-9JFKuW7U+1vPO86k3+XRtJyooiVZsVOsFFO4GulBzepi3a0ckNyPgyjUY1saLH+cEHx18hu8fGgajvI8ANUF2g== +"@sentry/minimal@5.27.6": + version "5.27.6" + resolved "https://registry.yarnpkg.com/@sentry/minimal/-/minimal-5.27.6.tgz#783012ed94668be168f2b521e0ea6295c76ce2b0" + integrity sha512-pKhzVQX9nL4m1dcnb2i2Y47IWVNs+K3wiYLgCB9hl9+ApxppfOc+fquiFoCloST3IuaD4yly2TtbOJgAMWcMxQ== dependencies: - "@sentry/hub" "5.25.0" - "@sentry/types" "5.25.0" + "@sentry/hub" "5.27.6" + "@sentry/types" "5.27.6" tslib "^1.9.3" "@sentry/node@^5.19.2": - version "5.25.0" - resolved "https://registry.yarnpkg.com/@sentry/node/-/node-5.25.0.tgz#f3c3300e1d8d77025fadac02ede4f4da7a037c73" - integrity sha512-zxoUVdAFTeK9kdEGY95TMs6g8Zx/P55HxG4gHD80BG/XIEvWiGPcGCLOspO4IdGqYXkGS74KfBOIXmmCawWwLg== + version "5.27.6" + resolved "https://registry.yarnpkg.com/@sentry/node/-/node-5.27.6.tgz#a9ab20bf305d802914b41040ef3b328c2b681120" + integrity sha512-ogKL4F3wSZuzNeHOGKPqQPbZ87Bd/dC8wk7Rwbui3SIMgtoUmO3rSOR4Edwar6mf330cA6CY9roylWdcaSqmZA== dependencies: - "@sentry/core" "5.25.0" - "@sentry/hub" "5.25.0" - "@sentry/tracing" "5.25.0" - "@sentry/types" "5.25.0" - "@sentry/utils" "5.25.0" + "@sentry/core" "5.27.6" + "@sentry/hub" "5.27.6" + "@sentry/tracing" "5.27.6" + "@sentry/types" "5.27.6" + "@sentry/utils" "5.27.6" cookie "^0.4.1" https-proxy-agent "^5.0.0" lru_map "^0.3.3" tslib "^1.9.3" -"@sentry/tracing@5.25.0": - version "5.25.0" - resolved "https://registry.yarnpkg.com/@sentry/tracing/-/tracing-5.25.0.tgz#1cfbcf085a7a3b679f417058d09590298ddaa255" - integrity sha512-KcyHEGFpqSDubHrdWT/vF2hKkjw/ts6NpJ6tPDjBXUNz98BHdAyMKtLOFTCeJFply7/s5fyiAYu44M+M6IG3Bw== +"@sentry/tracing@5.27.6": + version "5.27.6" + resolved "https://registry.yarnpkg.com/@sentry/tracing/-/tracing-5.27.6.tgz#34a827c6e7a819b0eb0e409063203209abd19dad" + integrity sha512-ms3vprEId+hi8hcqtf8weqsNGASaDXAZzIOT4g2gASGpwLb5hLuScpM8z6Yhu5FGjb8DektlW5OrXJSsStIozw== dependencies: - "@sentry/hub" "5.25.0" - "@sentry/minimal" "5.25.0" - "@sentry/types" "5.25.0" - "@sentry/utils" "5.25.0" + "@sentry/hub" "5.27.6" + "@sentry/minimal" "5.27.6" + "@sentry/types" "5.27.6" + "@sentry/utils" "5.27.6" tslib "^1.9.3" -"@sentry/types@5.25.0": - version "5.25.0" - resolved "https://registry.yarnpkg.com/@sentry/types/-/types-5.25.0.tgz#3bcf95e118d655d3f4e8bfa5f0be2e1fe4ea5307" - integrity sha512-8M4PREbcar+15wrtEqcwfcU33SS+2wBSIOd/NrJPXJPTYxi49VypCN1mZBDyWkaK+I+AuQwI3XlRPCfsId3D1A== +"@sentry/types@5.27.6": + version "5.27.6" + resolved "https://registry.yarnpkg.com/@sentry/types/-/types-5.27.6.tgz#b5054eafcb8ac11d4bc4787c7bc7fc113cad8b80" + integrity sha512-XOW9W8DrMk++4Hk7gWi9o5VR0o/GrqGfTKyFsHSIjqt2hL6kiMPvKeb2Hhmp7Iq37N2bDmRdWpM5m+68S2Jk6w== -"@sentry/utils@5.25.0": - version "5.25.0" - resolved "https://registry.yarnpkg.com/@sentry/utils/-/utils-5.25.0.tgz#b132034be66d7381d30879d2a9e09216fed28342" - integrity sha512-Hz5spdIkMSRH5NR1YFOp5qbsY5Ud2lKhEQWlqxcVThMG5YNUc10aYv5ijL19v0YkrC2rqPjCRm7GrVtzOc7bXQ== +"@sentry/utils@5.27.6": + version "5.27.6" + resolved "https://registry.yarnpkg.com/@sentry/utils/-/utils-5.27.6.tgz#cd8486469ae9716a21a4bc7e828e5aeee0ed9727" + integrity sha512-/QMVLv+zrTfiIj2PU+SodSbSzD5MmamMOaljkDsRIVsj6gpkm1/VG1g2+40TZ0FbQ4hCW2F+iR7cnqzZBNmchA== dependencies: - "@sentry/types" "5.25.0" + "@sentry/types" "5.27.6" tslib "^1.9.3" +"@sideway/address@^4.1.0": + version "4.1.0" + resolved "https://registry.yarnpkg.com/@sideway/address/-/address-4.1.0.tgz#0b301ada10ac4e0e3fa525c90615e0b61a72b78d" + integrity sha512-wAH/JYRXeIFQRsxerIuLjgUu2Xszam+O5xKeatJ4oudShOOirfmsQ1D6LL54XOU2tizpCYku+s1wmU0SYdpoSA== + dependencies: + "@hapi/hoek" "^9.0.0" + +"@sideway/formula@^3.0.0": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@sideway/formula/-/formula-3.0.0.tgz#fe158aee32e6bd5de85044be615bc08478a0a13c" + integrity sha512-vHe7wZ4NOXVfkoRb8T5otiENVlT7a3IAiw7H5M2+GO+9CDgcVUUsX1zalAztCmwyOr2RUTGJdgB+ZvSVqmdHmg== + +"@sideway/pinpoint@^2.0.0": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@sideway/pinpoint/-/pinpoint-2.0.0.tgz#cff8ffadc372ad29fd3f78277aeb29e632cc70df" + integrity sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ== + "@sindresorhus/is@^0.14.0": version "0.14.0" resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-0.14.0.tgz#9fb3a3cf3132328151f353de4632e01e52102bea" @@ -846,9 +837,9 @@ defer-to-connect "^1.0.1" "@types/babel__core@^7.1.0": - version "7.1.10" - resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.1.10.tgz#ca58fc195dd9734e77e57c6f2df565623636ab40" - integrity sha512-x8OM8XzITIMyiwl5Vmo2B1cR1S1Ipkyv4mdlbJjMa1lmuKvKY9FrBbEANIaMlnWn5Rf7uO+rC/VgYabNkE17Hw== + version "7.1.12" + resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.1.12.tgz#4d8e9e51eb265552a7e4f1ff2219ab6133bdfb2d" + integrity sha512-wMTHiiTiBAAPebqaPiPDLFA4LYPKr6Ph0Xq/6rq1Ur3v66HXyG+clfR9CNETkD7MQS8ZHvpQOtA53DLws5WAEQ== dependencies: "@babel/parser" "^7.1.0" "@babel/types" "^7.0.0" @@ -864,9 +855,9 @@ "@babel/types" "^7.0.0" "@types/babel__template@*": - version "7.0.3" - resolved "https://registry.yarnpkg.com/@types/babel__template/-/babel__template-7.0.3.tgz#b8aaeba0a45caca7b56a5de9459872dde3727214" - integrity sha512-uCoznIPDmnickEi6D0v11SBpW0OuVqHJCa7syXqQHy5uktSCreIlt0iglsCnmvz8yCb38hGcWeseA8cWJSwv5Q== + version "7.4.0" + resolved "https://registry.yarnpkg.com/@types/babel__template/-/babel__template-7.4.0.tgz#0c888dd70b3ee9eebb6e4f200e809da0076262be" + integrity sha512-NTPErx4/FiPCGScH7foPyr+/1Dkzkni+rHiYHHoTjvwou7AQzJkNeD60A9CXRy+ZEN2B1bggmkTMCDb+Mv5k+A== dependencies: "@babel/parser" "^7.1.0" "@babel/types" "^7.0.0" @@ -897,9 +888,9 @@ "@types/node" "*" "@types/fs-extra@^9.0.1": - version "9.0.2" - resolved "https://registry.yarnpkg.com/@types/fs-extra/-/fs-extra-9.0.2.tgz#e1e1b578c48e8d08ae7fc36e552b94c6f4621609" - integrity sha512-jp0RI6xfZpi5JL8v7WQwpBEQTq63RqW2kxwTZt+m27LcJqQdPVU1yGnT1ZI4EtCDynQQJtIGyQahkiCGCS7e+A== + version "9.0.4" + resolved "https://registry.yarnpkg.com/@types/fs-extra/-/fs-extra-9.0.4.tgz#12553138cf0438db9a31cdc8b0a3aa9332eb67aa" + integrity sha512-50GO5ez44lxK5MDH90DYHFFfqxH7+fTqEEnvguQRzJ/tY9qFrMSHLiYHite+F3SNmf7+LHC1eMXojuD+E3Qcyg== dependencies: "@types/node" "*" @@ -924,14 +915,14 @@ "@types/istanbul-lib-report" "*" "@types/node@*": - version "14.11.8" - resolved "https://registry.yarnpkg.com/@types/node/-/node-14.11.8.tgz#fe2012f2355e4ce08bca44aeb3abbb21cf88d33f" - integrity sha512-KPcKqKm5UKDkaYPTuXSx8wEP7vE9GnuaXIZKijwRYcePpZFDVuy2a57LarFKiORbHOuTOOwYzxVxcUzsh2P2Pw== + version "14.14.10" + resolved "https://registry.yarnpkg.com/@types/node/-/node-14.14.10.tgz#5958a82e41863cfc71f2307b3748e3491ba03785" + integrity sha512-J32dgx2hw8vXrSbu4ZlVhn1Nm3GbeCFNw2FWL8S5QKucHGY0cyNwjdQdO+KMBZ4wpmC7KhLCiNsdk1RFRIYUQQ== "@types/node@^12.0.12": - version "12.12.67" - resolved "https://registry.yarnpkg.com/@types/node/-/node-12.12.67.tgz#4f86badb292e822e3b13730a1f9713ed2377f789" - integrity sha512-R48tgL2izApf+9rYNH+3RBMbRpPeW3N8f0I9HMhggeq4UXwBDqumJ14SDs4ctTMhG11pIOduZ4z3QWGOiMc9Vg== + version "12.19.7" + resolved "https://registry.yarnpkg.com/@types/node/-/node-12.19.7.tgz#cf8b6ac088dd9182ac9a1d765f787a8d12490c04" + integrity sha512-zvjOU1g4CpPilbTDUATnZCUb/6lARMRAqzT7ILwl1P3YvU2leEcZ2+fw9+Jrw/paXB1CgQyXTrN4hWDtqT9O2A== "@types/normalize-package-data@^2.4.0": version "2.4.0" @@ -961,9 +952,9 @@ "@types/yargs-parser" "*" "@types/yargs@^15.0.5": - version "15.0.8" - resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-15.0.8.tgz#7644904cad7427eb704331ea9bf1ee5499b82e23" - integrity sha512-b0BYzFUzBpOhPjpl1wtAHU994jBeKF4TKVlT7ssFv44T617XNcPdRoG4AzHLVshLzlrF7i3lTelH7UbuNYV58Q== + version "15.0.10" + resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-15.0.10.tgz#0fe3c8173a0d5c3e780b389050140c3f5ea6ea74" + integrity sha512-z8PNtlhrj7eJNLmrAivM7rjBESG6JwC5xP3RVk12i/8HVP7Xnx/sEmERnRImyEuUaJfO942X0qMOYsoupaJbZQ== dependencies: "@types/yargs-parser" "*" @@ -1060,9 +1051,9 @@ acorn@^7.1.1: integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A== agent-base@6: - version "6.0.1" - resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-6.0.1.tgz#808007e4e5867decb0ab6ab2f928fbdb5a596db4" - integrity sha512-01q25QQDwLSsyfhrKbn8yuur+JNw0H+0Y4JiGIKd3z9aYk/w/2kxD/Upc+t2ZBBSUNff50VjPsSW2YxM8QYKVg== + version "6.0.2" + resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-6.0.2.tgz#49fff58577cfee3f37176feab4c22e00f86d7f77" + integrity sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ== dependencies: debug "4" @@ -1247,11 +1238,6 @@ array-equal@^1.0.0: resolved "https://registry.yarnpkg.com/array-equal/-/array-equal-1.0.0.tgz#8c2a5ef2472fd9ea742b04c77a75093ba2757c93" integrity sha1-jCpe8kcv2ep0KwTHenUJO6J1fJM= -array-filter@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/array-filter/-/array-filter-1.0.0.tgz#baf79e62e6ef4c2a4c0b831232daffec251f9d83" - integrity sha1-uveeYubvTCpMC4MSMtr/7CUfnYM= - array-unique@^0.3.2: version "0.3.2" resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428" @@ -1324,17 +1310,10 @@ 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== -available-typed-arrays@^1.0.0, available-typed-arrays@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/available-typed-arrays/-/available-typed-arrays-1.0.2.tgz#6b098ca9d8039079ee3f77f7b783c4480ba513f5" - integrity sha512-XWX3OX8Onv97LMk/ftVyBibpGwY5a8SmuxZPzeOxqmuEqUCOM9ZE+uIaD1VNJ5QnvU2UQusvmKbuM1FR8QWGfQ== - dependencies: - array-filter "^1.0.0" - aws-sdk@^2.767.0: - version "2.771.0" - resolved "https://registry.yarnpkg.com/aws-sdk/-/aws-sdk-2.771.0.tgz#ff4beb0a04d6ab1ae962c85dfb42e3e9bfe2b93b" - integrity sha512-fqNGusCwkdemx3yFqvQbU1+xq/PB2wGq7EQIrrTZx/zxfXUp+7+PnrHzXtViCRghN0tylLghBfWYD4VcVcqi7g== + version "2.799.0" + resolved "https://registry.yarnpkg.com/aws-sdk/-/aws-sdk-2.799.0.tgz#8b1a64c1a9f8ccf5794eb07bdd8051e4cb6adcfd" + integrity sha512-NYAoiNU+bJXhlJsC0rFqrmD5t5ho7/VxldmziP6HLPYHfOCI9Uvk6UVjfPmhLWPm0mHnIxhsHqmsNGyjhHNYmw== dependencies: buffer "4.9.2" events "1.1.1" @@ -1352,9 +1331,9 @@ aws-sign2@~0.7.0: integrity sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg= aws4@^1.8.0: - version "1.10.1" - resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.10.1.tgz#e1e82e4f3e999e2cfd61b161280d16a111f86428" - integrity sha512-zg7Hz2k5lI8kb7U32998pRRFin7zJlkfezGJjUc2heaD4Pw2wObakCDVzkKztTm/Ln7eiVvYsjqak0Ed4LkMDA== + version "1.11.0" + resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.11.0.tgz#d61f46d83b2519250e2784daf5b09479a8b41c59" + integrity sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA== axios@^0.19.2: version "0.19.2" @@ -1416,10 +1395,10 @@ base62@^1.1.0: resolved "https://registry.yarnpkg.com/base62/-/base62-1.2.8.tgz#1264cb0fb848d875792877479dbe8bae6bae3428" integrity sha512-V6YHUbjLxN1ymqNLb1DPHoU1CpfdL7d2YTIp5W3U4hhoG4hhxNmsFDs66M9EXxBiSEke5Bt5dwdfMwwZF70iLA== -base64-js@^1.0.2: - version "1.3.1" - resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.3.1.tgz#58ece8cb75dd07e71ed08c736abc5fac4dbf8df1" - integrity sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g== +base64-js@^1.0.2, base64-js@^1.3.1: + version "1.5.1" + resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" + integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== base@^0.11.1: version "0.11.2" @@ -1501,9 +1480,9 @@ bmp-js@^0.1.0: integrity sha1-4Fpj95amwf8l9Hcex62twUjAcjM= boolean@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/boolean/-/boolean-3.0.1.tgz#35ecf2b4a2ee191b0b44986f14eb5f052a5cbb4f" - integrity sha512-HRZPIjPcbwAVQvOTxR4YE3o8Xs98NqbbL1iEZDCz7CL8ql0Lt5iOyJFxfnAB0oFs8Oh02F/lLlg30Mexv46LjA== + version "3.0.2" + resolved "https://registry.yarnpkg.com/boolean/-/boolean-3.0.2.tgz#df1baa18b6a2b0e70840475e1d93ec8fe75b2570" + integrity sha512-RwywHlpCRc3/Wh81MiCKun4ydaIFyW5Ea6JbL6sRCVx5q5irDw7pMXBUFYF/jArQ6YrG36q0kpovc9P/Kd3I4g== boxen@^4.2.0: version "4.2.0" @@ -1627,12 +1606,12 @@ buffer@4.9.2: isarray "^1.0.0" buffer@^5.1.0, buffer@^5.2.0, buffer@^5.2.1, buffer@^5.5.0, buffer@^5.6.0: - version "5.6.0" - resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.6.0.tgz#a31749dc7d81d84db08abf937b6b8c4033f62786" - integrity sha512-/gDYp/UtU0eA1ys8bOs9J6a+E/KWIY+DZ+Q2WESNUA0jFRsJOc0SNUO6xJ5SGA1xueg3NL65W6s+NY5l9cunuw== + version "5.7.1" + resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.7.1.tgz#ba62e7c13133053582197160851a8f648e99eed0" + integrity sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ== dependencies: - base64-js "^1.0.2" - ieee754 "^1.1.4" + base64-js "^1.3.1" + ieee754 "^1.1.13" builder-util-runtime@8.7.2: version "8.7.2" @@ -1787,9 +1766,9 @@ chmodr@^1.2.0: integrity sha512-Y5uI7Iq/Az6HgJEL6pdw7THVd7jbVOTPwsmcPOBjQL8e3N+pz872kzK5QxYGEy21iRys+iHWV0UZQXDFJo1hyA== chokidar@^3.2.2: - version "3.4.2" - resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.4.2.tgz#38dc8e658dec3809741eb3ef7bb0a47fe424232d" - integrity sha512-IZHaDeBeI+sZJRX7lGcXsdzgvZqKv6sECqsbErJA4mHWfpRrD8B97kSFN4cQz6nGBGiuFia1MKR4d6c1o8Cv7A== + version "3.4.3" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.4.3.tgz#c1df38231448e45ca4ac588e6c79573ba6a57d5b" + integrity sha512-DtM3g7juCXQxFVSNPNByEC2+NImtBuxQQvWlHunpJIS5Ocr0lG306cC7FCi7cEA0fzmybPUIl4txBIobk1gGOQ== dependencies: anymatch "~3.1.1" braces "~3.0.2" @@ -1797,7 +1776,7 @@ chokidar@^3.2.2: is-binary-path "~2.1.0" is-glob "~4.0.1" normalize-path "~3.0.0" - readdirp "~3.4.0" + readdirp "~3.5.0" optionalDependencies: fsevents "~2.1.2" @@ -2042,9 +2021,9 @@ copy-descriptor@^0.1.0: integrity sha1-Z29us8OZl8LuGsOpJP1hJHSPV40= core-js@^3.6.5: - version "3.6.5" - resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.6.5.tgz#7395dc273af37fb2e50e9bd3d9fe841285231d1a" - integrity sha512-vZVEEwZoIsI+vPEuoF9Iqf5H7/M3eeQqWlQnYa8FSKKePuYTf5MWnxb5SDAzCa60b3JBRS5g9b+Dq7b1y/RCrA== + version "3.8.0" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.8.0.tgz#0fc2d4941cadf80538b030648bb64d230b4da0ce" + integrity sha512-W2VYNB0nwQQE7tKS7HzXd7r2y/y2SVJl4ga6oH/dnaLFzM0o2lB2P3zCkWj5Wc/zyMYjtgd5Hmhk0ObkQFZOIA== core-util-is@1.0.2, core-util-is@^1.0.2, core-util-is@~1.0.0: version "1.0.2" @@ -2124,10 +2103,10 @@ dateformat@^3.0.3: resolved "https://registry.yarnpkg.com/dateformat/-/dateformat-3.0.3.tgz#a6e37499a4d9a9cf85ef5872044d62901c9889ae" integrity sha512-jyCETtSl3VMZMWeRo7iY1FL19ges1t55hMo5yaam4Jrsm5EPL89UQkoQRyiI+Yf4k8r2ZpdngkV8hr1lIdjb3Q== -debug@4, debug@^4.0.1, debug@^4.1.0, debug@^4.1.1: - version "4.2.0" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.2.0.tgz#7f150f93920e94c58f5574c2fd01a3110effe7f1" - integrity sha512-IX2ncY78vDTjZMFUdmsvIRFY2Cf4FnD0wRs+nQwJU8Lu99/tPFdb0VybiiMTPe3I6rQmwsqQqRBvxU+bZ/I8sg== +debug@4, debug@^4.0.1, debug@^4.1.0, debug@^4.1.1, debug@^4.3.0: + version "4.3.1" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.1.tgz#f0d229c505e0c6d8c49ac553d1b13dc183f6b2ee" + integrity sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ== dependencies: ms "2.1.2" @@ -2146,19 +2125,12 @@ debug@^2.2.0, debug@^2.3.3, debug@^2.6.9: ms "2.0.0" debug@^3.1.0, debug@^3.2.6: - version "3.2.6" - resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b" - integrity sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ== + version "3.2.7" + resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.7.tgz#72580b7e9145fb39b6676f9c5e5fb100b934179a" + integrity sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ== dependencies: ms "^2.1.1" -debug@^4.3.0: - version "4.3.1" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.1.tgz#f0d229c505e0c6d8c49ac553d1b13dc183f6b2ee" - integrity sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ== - dependencies: - ms "2.1.2" - decamelize@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" @@ -2229,26 +2201,6 @@ decompress@^4.2.1: pify "^2.3.0" strip-dirs "^2.0.0" -deep-equal@^2.0.1: - version "2.0.4" - resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-2.0.4.tgz#6b0b407a074666033169df3acaf128e1c6f3eab6" - integrity sha512-BUfaXrVoCfgkOQY/b09QdO9L3XNoF2XH0A3aY9IQwQL/ZjLOe8FQgCNVl1wiolhsFo8kFdO9zdPViCPbmaJA5w== - dependencies: - es-abstract "^1.18.0-next.1" - es-get-iterator "^1.1.0" - is-arguments "^1.0.4" - is-date-object "^1.0.2" - is-regex "^1.1.1" - isarray "^2.0.5" - object-is "^1.1.3" - object-keys "^1.1.1" - object.assign "^4.1.1" - regexp.prototype.flags "^1.3.0" - side-channel "^1.0.3" - which-boxed-primitive "^1.0.1" - which-collection "^1.0.1" - which-typed-array "^1.1.2" - deep-equal@~1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-1.0.1.tgz#f5d260292b660e084eff4cdbc9f08ad3247448b5" @@ -2635,7 +2587,7 @@ error-ex@^1.3.1: dependencies: is-arrayish "^0.2.1" -es-abstract@^1.17.0-next.1, es-abstract@^1.17.2, es-abstract@^1.17.4, es-abstract@^1.17.5: +es-abstract@^1.17.0-next.1, es-abstract@^1.17.2: version "1.17.7" resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.17.7.tgz#a4de61b2f66989fc7421676c1cb9787573ace54c" integrity sha512-VBl/gnfcJ7OercKA9MVaegWsBHFjV492syMudcnQZvt/Dw8ezpcOHYZXa/J96O8vx+g4x65YKhxOwDUh63aS5g== @@ -2652,38 +2604,6 @@ es-abstract@^1.17.0-next.1, es-abstract@^1.17.2, es-abstract@^1.17.4, es-abstrac string.prototype.trimend "^1.0.1" string.prototype.trimstart "^1.0.1" -es-abstract@^1.18.0-next.0, es-abstract@^1.18.0-next.1: - version "1.18.0-next.1" - resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.18.0-next.1.tgz#6e3a0a4bda717e5023ab3b8e90bec36108d22c68" - integrity sha512-I4UGspA0wpZXWENrdA0uHbnhte683t3qT/1VFH9aX2dA5PPSf6QW5HHXf5HImaqPmjXaVeVk4RGWnaylmV7uAA== - dependencies: - es-to-primitive "^1.2.1" - function-bind "^1.1.1" - has "^1.0.3" - has-symbols "^1.0.1" - is-callable "^1.2.2" - is-negative-zero "^2.0.0" - is-regex "^1.1.1" - object-inspect "^1.8.0" - object-keys "^1.1.1" - object.assign "^4.1.1" - string.prototype.trimend "^1.0.1" - string.prototype.trimstart "^1.0.1" - -es-get-iterator@^1.1.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/es-get-iterator/-/es-get-iterator-1.1.1.tgz#b93ddd867af16d5118e00881396533c1c6647ad9" - integrity sha512-qorBw8Y7B15DVLaJWy6WdEV/ZkieBcu6QCq/xzWzGOKJqgG1j754vXRfZ3NY7HSShneqU43mPB4OkQBTkvHhFw== - dependencies: - call-bind "^1.0.0" - get-intrinsic "^1.0.1" - has-symbols "^1.0.1" - is-arguments "^1.0.4" - is-map "^2.0.1" - is-set "^2.0.1" - is-string "^1.0.5" - isarray "^2.0.5" - es-to-primitive@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.2.1.tgz#e55cd4c9cdc188bcefb03b366c736323fc5c898a" @@ -2736,6 +2656,11 @@ escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5: resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= +escape-string-regexp@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz#a30304e99daa32e23b2fd20f51babd07cffca344" + integrity sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w== + escape-string-regexp@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" @@ -3352,16 +3277,16 @@ functional-red-black-tree@^1.0.1: integrity sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc= gensync@^1.0.0-beta.1: - version "1.0.0-beta.1" - resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.1.tgz#58f4361ff987e5ff6e1e7a210827aa371eaac269" - integrity sha512-r8EC6NO1sngH/zdD9fiRDLdcgnbayXah+mLgManTaIZJqEC1MZstmnox8KpnI2/fxQwrp5OpCOYWLp4rBl4Jcg== + version "1.0.0-beta.2" + resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0" + integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg== get-caller-file@^2.0.1, get-caller-file@^2.0.5: version "2.0.5" resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== -get-intrinsic@^1.0.0, get-intrinsic@^1.0.1: +get-intrinsic@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.0.1.tgz#94a9768fcbdd0595a1c9273aacf4c89d075631be" integrity sha512-ZnWP+AmS1VUaLgTRy47+zKtjTxz+0xMpx3I52i+aalBK1QP19ggLF3Db89KJX7kjfOfP2eoa01qc++GwPgufPg== @@ -3655,9 +3580,9 @@ hosted-git-info@^2.1.4: integrity sha512-f/wzC2QaWBs7t9IYqB4T3sR1xviIViXJRJTWBlx2Gf3g0Xi5vI7Yy4koXQ1c9OYDGHN9sBy1DQ2AB8fqZBWhUg== hosted-git-info@^3.0.5: - version "3.0.5" - resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-3.0.5.tgz#bea87905ef7317442e8df3087faa3c842397df03" - integrity sha512-i4dpK6xj9BIpVOTboXIlKG9+8HMKggcrMX7WA24xZtKwX0TPelq/rbaS5rCKeNX8sJXZJGdSxpnEGtta+wismQ== + version "3.0.7" + resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-3.0.7.tgz#a30727385ea85acfcee94e0aad9e368c792e036c" + integrity sha512-fWqc0IcuXs+BmE9orLDyVykAG9GJtGLGuZAAqgcckPgv5xad4AcXGIv8galtQvlwutxSlaMcdw7BUtq2EIvqCQ== dependencies: lru-cache "^6.0.0" @@ -3759,11 +3684,16 @@ iconv-lite@^0.6.2: dependencies: safer-buffer ">= 2.1.2 < 3.0.0" -ieee754@1.1.13, ieee754@^1.1.4: +ieee754@1.1.13: version "1.1.13" resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.13.tgz#ec168558e95aa181fd87d37f55c32bbcb6708b84" integrity sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg== +ieee754@^1.1.13, ieee754@^1.1.4: + version "1.2.1" + resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" + integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== + ignore-by-default@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/ignore-by-default/-/ignore-by-default-1.0.1.tgz#48ca6d72f6c6a3af00a9ad4ae6876be3889e2b09" @@ -3790,9 +3720,9 @@ immediate@~3.0.5: integrity sha1-nbHb0Pr43m++D13V5Wu2BigN5ps= import-fresh@^3.0.0: - version "3.2.1" - resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.2.1.tgz#633ff618506e793af5ac91bf48b72677e15cbe66" - integrity sha512-6e1q1cnWP2RXD9/keSkxHScg508CdXqXWgWBaETNhyuBFz+kUZlKboh+ISK+bU++DmbHimVBrOz/zzPe0sZ3sQ== + version "3.2.2" + resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.2.2.tgz#fc129c160c5d68235507f4331a6baad186bdbc3e" + integrity sha512-cTPNrlvJT6twpYy+YmKUKrTSjWFs3bjYjAhCwm+z4EOCubZxAuO+hHpRN64TqjEaYSHs7tJAE0w1CKMGmsG/lw== dependencies: parent-module "^1.0.0" resolve-from "^4.0.0" @@ -3899,21 +3829,11 @@ is-accessor-descriptor@^1.0.0: dependencies: kind-of "^6.0.0" -is-arguments@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/is-arguments/-/is-arguments-1.0.4.tgz#3faf966c7cba0ff437fb31f6250082fcf0448cf3" - integrity sha512-xPh0Rmt8NE65sNzvyUmWgI1tz3mKq74lGA0mL8LYZcoIzKOzDh6HmrYm3d18k60nHerC8A9Km8kYu87zfSFnLA== - is-arrayish@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" integrity sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0= -is-bigint@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-bigint/-/is-bigint-1.0.0.tgz#73da8c33208d00f130e9b5e15d23eac9215601c4" - integrity sha512-t5mGUXC/xRheCK431ylNiSkGGpBp8bHENBcENTkDT6ppwPzEVxNGZRvgvmOEfbWkFhA7D2GEuE2mmQTr78sl2g== - is-binary-path@~2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09" @@ -3921,11 +3841,6 @@ is-binary-path@~2.1.0: dependencies: binary-extensions "^2.0.0" -is-boolean-object@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/is-boolean-object/-/is-boolean-object-1.0.1.tgz#10edc0900dd127697a92f6f9807c7617d68ac48e" - integrity sha512-TqZuVwa/sppcrhUCAYkGBk7w0yxfQQnxq28fjkO53tnK9FQXmdwz2JS5+GjsWQ6RByES1K40nI+yDic5c9/aAQ== - is-buffer@^1.1.5: version "1.1.6" resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" @@ -3948,6 +3863,13 @@ is-class-hotfix@~0.0.6: resolved "https://registry.yarnpkg.com/is-class-hotfix/-/is-class-hotfix-0.0.6.tgz#a527d31fb23279281dde5f385c77b5de70a72435" integrity sha512-0n+pzCC6ICtVr/WXnN2f03TK/3BfXY7me4cjCAqT8TYXEl0+JBRoqBo94JJHXcyDSLUeWbNX8Fvy5g5RJdAstQ== +is-core-module@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.1.0.tgz#a4cc031d9b1aca63eecbd18a650e13cb4eeab946" + integrity sha512-YcV7BgVMRFRua2FqQzKtTDMz8iCuLEyGKjr70q8Zm1yy2qKcurbFEd79PAdHV77oL3NrAaOVQIbMmiHQCHB7ZA== + dependencies: + has "^1.0.3" + is-data-descriptor@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz#0b5ee648388e2c860282e793f1856fec3f301b56" @@ -3962,7 +3884,7 @@ is-data-descriptor@^1.0.0: dependencies: kind-of "^6.0.0" -is-date-object@^1.0.1, is-date-object@^1.0.2: +is-date-object@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.2.tgz#bda736f2cd8fd06d32844e7743bfa7494c3bfd7e" integrity sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g== @@ -3985,6 +3907,11 @@ is-descriptor@^1.0.0, is-descriptor@^1.0.2: is-data-descriptor "^1.0.0" kind-of "^6.0.2" +is-docker@^2.0.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/is-docker/-/is-docker-2.1.1.tgz#4125a88e44e450d384e09047ede71adc2d144156" + integrity sha512-ZOoqiXfEwtGknTiuDEy8pN2CfE3TxMHprvNer1mXiqwkOT77Rw3YVrUQ52EqAOU3QAWDQ+bQdx7HJzrv7LS2Hw== + 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" @@ -4042,31 +3969,16 @@ is-installed-globally@^0.3.1: global-dirs "^2.0.1" is-path-inside "^3.0.1" -is-map@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/is-map/-/is-map-2.0.1.tgz#520dafc4307bb8ebc33b813de5ce7c9400d644a1" - integrity sha512-T/S49scO8plUiAOA2DBTBG3JHpn1yiw0kRp6dgiZ0v2/6twi5eiB0rHtHFH9ZIrvlWc6+4O+m4zg5+Z833aXgw== - is-natural-number@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/is-natural-number/-/is-natural-number-4.0.1.tgz#ab9d76e1db4ced51e35de0c72ebecf09f734cde8" integrity sha1-q5124dtM7VHjXeDHLr7PCfc0zeg= -is-negative-zero@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.0.tgz#9553b121b0fac28869da9ed459e20c7543788461" - integrity sha1-lVOxIbD6wohp2p7UWeIMdUN4hGE= - is-npm@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/is-npm/-/is-npm-4.0.0.tgz#c90dd8380696df87a7a6d823c20d0b12bbe3c84d" integrity sha512-96ECIfh9xtDDlPylNPXhzjsykHsMJZ18ASpaWzQyBr4YRTcVjUvzaHayDAES2oU/3KpljhHUjtSRNiDwi0F0ig== -is-number-object@^1.0.3: - version "1.0.4" - resolved "https://registry.yarnpkg.com/is-number-object/-/is-number-object-1.0.4.tgz#36ac95e741cf18b283fc1ddf5e83da798e3ec197" - integrity sha512-zohwelOAur+5uXtk8O3GPQ1eAcu4ZX3UwxQhUlfFFMNpUd83gXgjbhJh6HmB6LUNV/ieOLQuDwJO3dWJosUeMw== - is-number@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/is-number/-/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195" @@ -4118,21 +4030,11 @@ is-retry-allowed@^1.1.0: resolved "https://registry.yarnpkg.com/is-retry-allowed/-/is-retry-allowed-1.2.0.tgz#d778488bd0a4666a3be8a1482b9f2baafedea8b4" integrity sha512-RUbUeKwvm3XG2VYamhJL1xFktgjvPzL0Hq8C+6yrWIswDy3BIXGqCxhxkc30N9jqK311gVU137K8Ei55/zVJRg== -is-set@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/is-set/-/is-set-2.0.1.tgz#d1604afdab1724986d30091575f54945da7e5f43" - integrity sha512-eJEzOtVyenDs1TMzSQ3kU3K+E0GUS9sno+F0OBT97xsgcJsF9nXMBtkT9/kut5JEpM7oL7X/0qxR17K3mcwIAA== - is-stream@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" integrity sha1-EtSj3U5o4Lec6428hBc66A2RykQ= -is-string@^1.0.4, is-string@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/is-string/-/is-string-1.0.5.tgz#40493ed198ef3ff477b8c7f92f644ec82a5cd3a6" - integrity sha512-buY6VNRjhQMiF1qWDouloZlQbRhDPCebwxSjxMjxgemYT46YMd2NR0/H+fBhEfWX4A/w9TBJ+ol+okqJKFE6vQ== - is-symbol@^1.0.2: version "1.0.3" resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.3.tgz#38e1014b9e6329be0de9d24a414fd7441ec61937" @@ -4149,16 +4051,6 @@ is-type-of@^1.0.0: is-class-hotfix "~0.0.6" isstream "~0.1.2" -is-typed-array@^1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/is-typed-array/-/is-typed-array-1.1.3.tgz#a4ff5a5e672e1a55f99c7f54e59597af5c1df04d" - integrity sha512-BSYUBOK/HJibQ30wWkWold5txYwMUXQct9YHAQJr8fSwvZoiglcqB0pd7vEN23+Tsi9IUEjztdOSzl4qLVYGTQ== - dependencies: - available-typed-arrays "^1.0.0" - es-abstract "^1.17.4" - foreach "^2.0.5" - has-symbols "^1.0.1" - is-typedarray@^1.0.0, is-typedarray@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" @@ -4169,16 +4061,6 @@ is-utf8@^0.2.0: resolved "https://registry.yarnpkg.com/is-utf8/-/is-utf8-0.2.1.tgz#4b0da1442104d1b336340e80797e865cf39f7d72" integrity sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI= -is-weakmap@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/is-weakmap/-/is-weakmap-2.0.1.tgz#5008b59bdc43b698201d18f62b37b2ca243e8cf2" - integrity sha512-NSBR4kH5oVj1Uwvv970ruUkCV7O1mzgVFO4/rev2cLRda9Tm9HrL70ZPut4rOHgY0FNrUu9BCbXA2sdQ+x0chA== - -is-weakset@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/is-weakset/-/is-weakset-2.0.1.tgz#e9a0af88dbd751589f5e50d80f4c98b780884f83" - integrity sha512-pi4vhbhVHGLxohUw7PhGsueT4vRGFoXhP7+RGN0jKIv9+8PWYCQTqtADngrxOm2g46hoH0+g8uZZBzMrvVGDmw== - is-windows@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d" @@ -4189,6 +4071,13 @@ is-wsl@^1.1.0: resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-1.1.0.tgz#1f16e4aa22b04d1336b66188a66af3c600c3a66d" integrity sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0= +is-wsl@^2.1.1: + version "2.2.0" + resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-2.2.0.tgz#74a4c76e77ca9fd3f932f290c17ea326cd157271" + integrity sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww== + dependencies: + is-docker "^2.0.0" + is-yarn-global@^0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/is-yarn-global/-/is-yarn-global-0.3.0.tgz#d502d3382590ea3004893746754c89139973e232" @@ -4204,11 +4093,6 @@ isarray@1.0.0, isarray@^1.0.0, isarray@~1.0.0: resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE= -isarray@^2.0.5: - version "2.0.5" - resolved "https://registry.yarnpkg.com/isarray/-/isarray-2.0.5.tgz#8af1e4c1221244cc62459faf38940d4e644a5723" - integrity sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw== - isbinaryfile@^4.0.6: version "4.0.6" resolved "https://registry.yarnpkg.com/isbinaryfile/-/isbinaryfile-4.0.6.tgz#edcb62b224e2b4710830b67498c8e4e5a4d2610b" @@ -4670,15 +4554,15 @@ jmespath@0.15.0, jmespath@^0.15.0: integrity sha1-o/Iiqarp+Wb10nx5ZRDigJF2Qhc= joi@^17.2.1: - version "17.2.1" - resolved "https://registry.yarnpkg.com/joi/-/joi-17.2.1.tgz#e5140fdf07e8fecf9bc977c2832d1bdb1e3f2a0a" - integrity sha512-YT3/4Ln+5YRpacdmfEfrrKh50/kkgX3LgBltjqnlMPIYiZ4hxXZuVJcxmsvxsdeHg9soZfE3qXxHC2tMpCCBOA== + version "17.3.0" + resolved "https://registry.yarnpkg.com/joi/-/joi-17.3.0.tgz#f1be4a6ce29bc1716665819ac361dfa139fff5d2" + integrity sha512-Qh5gdU6niuYbUIUV5ejbsMiiFmBdw8Kcp8Buj2JntszCkCfxJ9Cz76OtHxOZMPXrt5810iDIXs+n1nNVoquHgg== dependencies: - "@hapi/address" "^4.1.0" - "@hapi/formula" "^2.0.0" "@hapi/hoek" "^9.0.0" - "@hapi/pinpoint" "^2.0.0" "@hapi/topo" "^5.0.0" + "@sideway/address" "^4.1.0" + "@sideway/formula" "^3.0.0" + "@sideway/pinpoint" "^2.0.0" joycon@^2.2.5: version "2.2.5" @@ -4795,11 +4679,11 @@ jsonfile@^4.0.0: graceful-fs "^4.1.6" jsonfile@^6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-6.0.1.tgz#98966cba214378c8c84b82e085907b40bf614179" - integrity sha512-jR2b5v7d2vIOust+w3wtFKZIfpC2pnRmFAhAC/BuweZFQR8qZzxH1OyrQ10HmdVYiXWkYUqPVsz91cG7EL2FBg== + version "6.1.0" + resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-6.1.0.tgz#bc55b2634793c679ec6403094eb13698a6ec0aae" + integrity sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ== dependencies: - universalify "^1.0.0" + universalify "^2.0.0" optionalDependencies: graceful-fs "^4.1.6" @@ -5560,9 +5444,9 @@ mute-stream@0.0.8: integrity sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA== nan@^2.12.1: - version "2.14.1" - resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.1.tgz#d7be34dfa3105b91494c3147089315eff8874b01" - integrity sha512-isWHgVjnFjh2x2yuJ/tj3JbwoHu3UC2dX5G/88Cm24yB6YopVgxvBObDY7n5xW6ExmFhJpSEQqFPvq9zaXc8Jw== + version "2.14.2" + resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.2.tgz#f5376400695168f4cc694ac9393d0c9585eeea19" + integrity sha512-M2ufzIiINKCuDfBSAUr1vWQ+vuVcA9kqx8JJUsbQi6yf1uGRyb7HfpdfUr5qLXf3B/t8dPvcjhKMmlfnP47EzQ== nanomatch@^1.2.9: version "1.2.13" @@ -5658,9 +5542,9 @@ node-notifier@^5.4.2: which "^1.3.0" nodemon@^2.0.4: - version "2.0.4" - resolved "https://registry.yarnpkg.com/nodemon/-/nodemon-2.0.4.tgz#55b09319eb488d6394aa9818148c0c2d1c04c416" - integrity sha512-Ltced+hIfTmaS28Zjv1BM552oQ3dbwPqI4+zI0SLgq+wpJhSyqgYude/aZa/3i31VCQWMfXJVxvu86abcam3uQ== + version "2.0.6" + resolved "https://registry.yarnpkg.com/nodemon/-/nodemon-2.0.6.tgz#1abe1937b463aaf62f0d52e2b7eaadf28cc2240d" + integrity sha512-4I3YDSKXg6ltYpcnZeHompqac4E6JeAMpGm8tJnB9Y3T0ehasLa4139dJOcCrB93HHrUMsCrKtoAlXTqT5n4AQ== dependencies: chokidar "^3.2.2" debug "^3.2.6" @@ -5670,8 +5554,8 @@ nodemon@^2.0.4: semver "^5.7.1" supports-color "^5.5.0" touch "^3.1.0" - undefsafe "^2.0.2" - update-notifier "^4.0.0" + undefsafe "^2.0.3" + update-notifier "^4.1.0" nopt@~1.0.10: version "1.0.10" @@ -5765,14 +5649,6 @@ object-inspect@^1.8.0: resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.8.0.tgz#df807e5ecf53a609cc6bfe93eac3cc7be5b3a9d0" integrity sha512-jLdtEOB112fORuypAyl/50VRVIBIdVQOSUUGQHzJ4xBSbit81zRarz7GThkEFZy1RceYrWYcPcBFPQwHyAc1gA== -object-is@^1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/object-is/-/object-is-1.1.3.tgz#2e3b9e65560137455ee3bd62aec4d90a2ea1cc81" - integrity sha512-teyqLvFWzLkq5B9ki8FVWA902UER2qkxmdA4nLf+wjOLAWgxzCWZNCxpDq9MvE8MmhWNr+I8w3BN49Vx36Y6Xg== - dependencies: - define-properties "^1.1.3" - es-abstract "^1.18.0-next.1" - object-keys@^1.0.12, object-keys@^1.0.6, object-keys@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" @@ -5786,12 +5662,12 @@ object-visit@^1.0.0: isobject "^3.0.0" object.assign@^4.1.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.1.tgz#303867a666cdd41936ecdedfb1f8f3e32a478cdd" - integrity sha512-VT/cxmx5yaoHSOTSyrCygIDFco+RsibY2NM0a4RdEeY/4KgqezwFtK1yr3U67xYhqJSlASm2pKhLVzPj2lr4bA== + version "4.1.2" + resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.2.tgz#0ed54a342eceb37b38ff76eb831a0e788cb63940" + integrity sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ== dependencies: + call-bind "^1.0.0" define-properties "^1.1.3" - es-abstract "^1.18.0-next.0" has-symbols "^1.0.1" object-keys "^1.1.1" @@ -5841,6 +5717,14 @@ only@~0.0.2: resolved "https://registry.yarnpkg.com/only/-/only-0.0.2.tgz#2afde84d03e50b9a8edc444e30610a70295edfb4" integrity sha1-Kv3oTQPlC5qO3EROMGEKcCle37Q= +open@^7.3.0: + version "7.3.0" + resolved "https://registry.yarnpkg.com/open/-/open-7.3.0.tgz#45461fdee46444f3645b6e14eb3ca94b82e1be69" + integrity sha512-mgLwQIx2F/ye9SmbrUkurZCnkoXyXyu9EbHtJZrICjVAJfyMArdHp3KkixGdZx1ZHFPNIwl0DDM1dFFqXbTLZw== + dependencies: + is-docker "^2.0.0" + is-wsl "^2.1.1" + optionator@^0.8.1, optionator@^0.8.3: version "0.8.3" resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.3.tgz#84fa1d036fe9d3c7e21d99884b601167ec8fb495" @@ -6458,12 +6342,12 @@ progress@^2.0.0, progress@^2.0.3: integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA== prompts@^2.0.1: - version "2.3.2" - resolved "https://registry.yarnpkg.com/prompts/-/prompts-2.3.2.tgz#480572d89ecf39566d2bd3fe2c9fccb7c4c0b068" - integrity sha512-Q06uKs2CkNYVID0VqwfAl9mipo99zkBv/n2JtWY89Yxa3ZabWSrs0e2KTudKVa3peLUvYXMefDqIleLPVUBZMA== + version "2.4.0" + resolved "https://registry.yarnpkg.com/prompts/-/prompts-2.4.0.tgz#4aa5de0723a231d1ee9121c40fdf663df73f61d7" + integrity sha512-awZAKrk3vN6CroQukBL+R9051a4R3zCZBlJm/HBfrSZ8iTpYix3VX1vU4mveiLpiwmOJT4wokTF9m6HUk4KqWQ== dependencies: kleur "^3.0.3" - sisteransi "^1.0.4" + sisteransi "^1.0.5" proto-list@~1.2.1: version "1.2.4" @@ -6514,9 +6398,9 @@ punycode@^2.1.0, punycode@^2.1.1: integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== pupa@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/pupa/-/pupa-2.0.1.tgz#dbdc9ff48ffbea4a26a069b6f9f7abb051008726" - integrity sha512-hEJH0s8PXLY/cdXh66tNEQGndDrIKNqNC5xmrysZy3i5C3oEoLna7YAOad+7u125+zH1HNXUmGEkrhb3c2VriA== + version "2.1.1" + resolved "https://registry.yarnpkg.com/pupa/-/pupa-2.1.1.tgz#f5e8fd4afc2c5d97828faa523549ed8744a20d62" + integrity sha512-l1jNAspIBSFqbT+y+5FosojNpVpF94nlI+wDUpqP9enwOTfHx9f0gh5nB96vl+6yTpsJsypeNrwfzPrKuHB41A== dependencies: escape-goat "^2.0.0" @@ -6673,10 +6557,10 @@ readable-stream@~0.0.2: resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-0.0.4.tgz#f32d76e3fb863344a548d79923007173665b3b8d" integrity sha1-8y124/uGM0SlSNeZIwBxc2ZbO40= -readdirp@~3.4.0: - version "3.4.0" - resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.4.0.tgz#9fdccdf9e9155805449221ac645e8303ab5b9ada" - integrity sha512-0xe001vZBnJEK+uKcj8qOhyAKPzIT+gStxWr3LCB0DwcXR5NZJ3IaC+yGnHCYzB/S7ov3m3EEbZI2zeNvX+hGQ== +readdirp@~3.5.0: + version "3.5.0" + resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.5.0.tgz#9ba74c019b15d365278d2e91bb8c48d7b4d42c9e" + integrity sha512-cMhu7c/8rdhkHXWsY+osBhfSy0JikwpHK/5+imo+LpeasTF8ouErHrlYkwT0++njiyuDvc7OFY5T3ukvZ8qmFQ== dependencies: picomatch "^2.2.1" @@ -6720,28 +6604,15 @@ regex-not@^1.0.0, regex-not@^1.0.2: extend-shallow "^3.0.2" safe-regex "^1.1.0" -regexp.prototype.flags@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.3.0.tgz#7aba89b3c13a64509dabcf3ca8d9fbb9bdf5cb75" - integrity sha512-2+Q0C5g951OlYlJz6yu5/M33IcsESLlLfsyIaLJaG4FA2r4yP8MvVMJUUP/fVBkSpbbbZlS5gynbEWLipiiXiQ== - dependencies: - define-properties "^1.1.3" - es-abstract "^1.17.0-next.1" - -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" integrity sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw== registry-auth-token@^4.0.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/registry-auth-token/-/registry-auth-token-4.2.0.tgz#1d37dffda72bbecd0f581e4715540213a65eb7da" - integrity sha512-P+lWzPrsgfN+UEpDS3U8AQKg/UjZX6mQSJueZj3EK+vNESoqBSpBUD3gmu4sF9lOsjXWjF11dQKUqemf3veq1w== + version "4.2.1" + resolved "https://registry.yarnpkg.com/registry-auth-token/-/registry-auth-token-4.2.1.tgz#6d7b4006441918972ccd5fedcd41dc322c79b250" + integrity sha512-6gkSb4U6aWJB4SF2ZvLb76yCBjcvufXBqvvEx1HbmKPkutswjW1xNVRY0+daljIYRbogN7O0etYSlbiaEQyMyw== dependencies: rc "^1.2.8" @@ -6868,10 +6739,11 @@ resolve@1.1.7: integrity sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs= resolve@^1.10.0, resolve@^1.3.2: - version "1.17.0" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.17.0.tgz#b25941b54968231cc2d1bb76a79cb7f2c0bf8444" - integrity sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w== + version "1.19.0" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.19.0.tgz#1af5bf630409734a067cae29318aac7fa29a267c" + integrity sha512-rArEXAgsBG4UgRGcynxWIWKFvh/XZCcS8UJdHhwy91zwAvCZIbcs+vAbflgBnNjYMs/i/i+/Ux6IZhML1yPvxg== dependencies: + is-core-module "^2.1.0" path-parse "^1.0.6" responselike@1.0.2, responselike@^1.0.2: @@ -7117,20 +6989,12 @@ shellwords@^0.1.1: resolved "https://registry.yarnpkg.com/shellwords/-/shellwords-0.1.1.tgz#d6b9181c1a48d397324c84871efbcfc73fc0654b" integrity sha512-vFwSUfQvqybiICwZY5+DAWIPLKsWO31Q91JSKl3UYv+K5c2QRPzn0qzec6QPu1Qc9eHYItiP3NdJqNVqetYAww== -side-channel@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.3.tgz#cdc46b057550bbab63706210838df5d4c19519c3" - integrity sha512-A6+ByhlLkksFoUepsGxfj5x1gTSrs+OydsRptUxeNCabQpCFUvcwIczgOigI8vhY/OJCnPnyE9rGiwgvr9cS1g== - dependencies: - es-abstract "^1.18.0-next.0" - object-inspect "^1.8.0" - signal-exit@^3.0.0, signal-exit@^3.0.2: version "3.0.3" resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.3.tgz#a1410c2edd8f077b08b4e253c8eacfcaf057461c" integrity sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA== -sisteransi@^1.0.4: +sisteransi@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/sisteransi/-/sisteransi-1.0.5.tgz#134d681297756437cc05ca01370d3a7a571075ed" integrity sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg== @@ -7341,9 +7205,11 @@ sshpk@^1.7.0: tweetnacl "~0.14.0" stack-utils@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/stack-utils/-/stack-utils-1.0.2.tgz#33eba3897788558bebfc2db059dc158ec36cebb8" - integrity sha512-MTX+MeG5U994cazkjd/9KNAapsHnibjMLnfXodlkXw76JEea0UiNzrqidzo1emMwk7w5Qhc9jd4Bn9TBb1MFwA== + version "1.0.3" + resolved "https://registry.yarnpkg.com/stack-utils/-/stack-utils-1.0.3.tgz#db7a475733b5b8bf6521907b18891d29006f7751" + integrity sha512-WldO+YmqhEpjp23eHZRhOT1NQF51STsbxZ+/AdpFD+EhheFxAe5d0WoK4DQVJkSHacPrJJX3OqRAl9CgHf78pg== + dependencies: + escape-string-regexp "^2.0.0" stat-mode@^1.0.0: version "1.0.0" @@ -7405,20 +7271,20 @@ string-width@^4.0.0, string-width@^4.1.0, string-width@^4.2.0: strip-ansi "^6.0.0" string.prototype.trimend@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.1.tgz#85812a6b847ac002270f5808146064c995fb6913" - integrity sha512-LRPxFUaTtpqYsTeNKaFOw3R4bxIzWOnbQ837QfBylo8jIxtcbK/A/sMV7Q+OAV/vWo+7s25pOE10KYSjaSO06g== + version "1.0.3" + resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.3.tgz#a22bd53cca5c7cf44d7c9d5c732118873d6cd18b" + integrity sha512-ayH0pB+uf0U28CtjlLvL7NaohvR1amUvVZk+y3DYb0Ey2PUV5zPkkKy9+U1ndVEIXO8hNg18eIv9Jntbii+dKw== dependencies: + call-bind "^1.0.0" define-properties "^1.1.3" - es-abstract "^1.17.5" string.prototype.trimstart@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.1.tgz#14af6d9f34b053f7cfc89b72f8f2ee14b9039a54" - integrity sha512-XxZn+QpvrBI1FOcg6dIpxUPgWCPuNXvMD72aaRaUQv1eD4e/Qy8i/hFTe0BUmD60p/QA6bh1avmuPTfNjqVWRw== + version "1.0.3" + resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.3.tgz#9b4cb590e123bb36564401d59824298de50fd5aa" + integrity sha512-oBIBUy5lea5tt0ovtOFiEQaBkoBBkyJhZXzJYrSmDo5IUUqbOPvVezuRs/agBIdZ2p2Eo1FD6bD9USyBLfl3xg== dependencies: + call-bind "^1.0.0" define-properties "^1.1.3" - es-abstract "^1.17.5" string_decoder@^1.1.1: version "1.3.0" @@ -7570,10 +7436,10 @@ supports-color@^7.1.0: dependencies: has-flag "^4.0.0" -svelte@^3.29.4: - version "3.29.4" - resolved "https://registry.yarnpkg.com/svelte/-/svelte-3.29.4.tgz#d0f80cb58109ef52963855c23496f7153bb2eb7e" - integrity sha512-oW0fGHlyFFMvzRtIvOs84b0fOc0gmZNQcL5Is3hxuTpvaYX3pfd8oHy4KnOvbq4Ca6SG6AHdRMk7OhApTo0NqA== +svelte@^3.30.0: + version "3.30.0" + resolved "https://registry.yarnpkg.com/svelte/-/svelte-3.30.0.tgz#cbde341e96bf34f4ac73c8f14f8a014e03bfb7d6" + integrity sha512-z+hdIACb9TROGvJBQWcItMtlr4s0DBUgJss6qWrtFkOoIInkG+iAMo/FJZQFyDBQZc+dul2+TzYSi/tpTT5/Ag== symbol-tree@^3.2.2: version "3.2.4" @@ -7591,14 +7457,14 @@ table@^5.2.3: string-width "^3.0.0" tar-fs@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/tar-fs/-/tar-fs-2.1.0.tgz#d1cdd121ab465ee0eb9ccde2d35049d3f3daf0d5" - integrity sha512-9uW5iDvrIMCVpvasdFHW0wJPez0K4JnMZtsuIeDI7HyMGJNxmDZDOCQROr7lXyS+iL/QMpj07qcjGYTSdRFXUg== + version "2.1.1" + resolved "https://registry.yarnpkg.com/tar-fs/-/tar-fs-2.1.1.tgz#489a15ab85f1f0befabb370b7de4f9eb5cbe8784" + integrity sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng== dependencies: chownr "^1.1.1" mkdirp-classic "^0.5.2" pump "^3.0.0" - tar-stream "^2.0.0" + tar-stream "^2.1.4" tar-stream@^1.5.2: version "1.6.2" @@ -7613,7 +7479,7 @@ tar-stream@^1.5.2: to-buffer "^1.1.1" xtend "^4.0.0" -tar-stream@^2.0.0: +tar-stream@^2.1.4: version "2.1.4" resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-2.1.4.tgz#c4fb1a11eb0da29b893a5b25476397ba2d053bfa" integrity sha512-o3pS2zlG4gxr67GmFYBLlq+dM8gyRGUOvsrHclSkvtVtQbjV0s/+ZE8OpICbaj8clrX3tjeHngYGP7rweaBnuw== @@ -7633,9 +7499,9 @@ temp-file@^3.3.7: fs-extra "^8.1.0" term-size@^2.1.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/term-size/-/term-size-2.2.0.tgz#1f16adedfe9bdc18800e1776821734086fcc6753" - integrity sha512-a6sumDlzyHVJWb8+YofY4TW112G6p2FCPEAFk+59gIYHv3XHRhm9ltVQ9kli4hNWeQBwSpe8cRN25x0ROunMOw== + version "2.2.1" + resolved "https://registry.yarnpkg.com/term-size/-/term-size-2.2.1.tgz#2a6a54840432c2fb6320fea0f415531e90189f54" + integrity sha512-wK0Ri4fOGjv/XPy8SBHZChl8CM7uMc5VML7SqiQ0zG7+J5Vr+RMQDoHa2CNT6KHUnTGIXH34UDMkPzAUyapBZg== test-exclude@^5.2.3: version "5.2.3" @@ -7902,9 +7768,9 @@ typedarray@^0.0.6: integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c= uglify-js@^3.1.4: - version "3.11.4" - resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.11.4.tgz#b47b7ae99d4bd1dca65b53aaa69caa0909e6fadf" - integrity sha512-FyYnoxVL1D6+jDGQpbK5jW6y/2JlVfRfEeQ67BPCUg5wfCjaKOpr2XeceE4QL+MkhxliLtf5EbrMDZgzpt2CNw== + version "3.12.0" + resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.12.0.tgz#b943f129275c41d435eb54b643bbffee71dccf57" + integrity sha512-8lBMSkFZuAK7gGF8LswsXmir8eX8d2AAMOnxSDWjKBx/fBR6MypQjs78m6ML9zQVp1/hD4TBdfeMZMC7nW1TAA== unbzip2-stream@^1.0.9: version "1.4.3" @@ -7914,7 +7780,7 @@ unbzip2-stream@^1.0.9: buffer "^5.2.1" through "^2.3.8" -undefsafe@^2.0.2: +undefsafe@^2.0.3: version "2.0.3" resolved "https://registry.yarnpkg.com/undefsafe/-/undefsafe-2.0.3.tgz#6b166e7094ad46313b2202da7ecc2cd7cc6e7aae" integrity sha512-nrXZwwXrD/T/JXeygJqdCO6NZZ1L66HrxM/Z7mIq2oPanoN0F1nLx3lwJMu6AwJY69hdixaFQOuoYsMjE5/C2A== @@ -7948,6 +7814,11 @@ universalify@^1.0.0: resolved "https://registry.yarnpkg.com/universalify/-/universalify-1.0.0.tgz#b61a1da173e8435b2fe3c67d29b9adf8594bd16d" integrity sha512-rb6X1W158d7pRQBg5gkR8uPaSfiids68LTJQYOtEUhoJUWBdaQHsuT/EUduxXYxcrt4r5PJ4fuHW1MHT6p0qug== +universalify@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/universalify/-/universalify-2.0.0.tgz#75a4984efedc4b08975c5aeb73f530d02df25717" + integrity sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ== + unpipe@1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" @@ -7970,7 +7841,7 @@ unset-value@^1.0.0: has-value "^0.3.1" isobject "^3.0.0" -update-notifier@^4.0.0, update-notifier@^4.1.1: +update-notifier@^4.1.0, update-notifier@^4.1.1: version "4.1.3" resolved "https://registry.yarnpkg.com/update-notifier/-/update-notifier-4.1.3.tgz#be86ee13e8ce48fb50043ff72057b5bd598e1ea3" integrity sha512-Yld6Z0RyCYGB6ckIjffGOSOmHXj1gMeE7aROz4MG+XMkmixBX4jUngrGXNYz7wPKBmtoD4MnBa2Anu7RSKht/A== @@ -8074,9 +7945,9 @@ uuid@^3.3.2: integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A== v8-compile-cache@^2.0.3: - version "2.1.1" - resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.1.1.tgz#54bc3cdd43317bca91e35dcaf305b1a7237de745" - integrity sha512-8OQ9CL+VWyt3JStj7HX7/ciTL2V3Rl1Wf5OL+SNTm0yK1KvtReVulksyeRnCANHHuUxHlQig+JJDlUhBt1NQDQ== + version "2.2.0" + resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.2.0.tgz#9471efa3ef9128d2f7c6a7ca39c4dd6b5055b132" + integrity sha512-gTpR5XQNKFwOd4clxfnhaqvfqMpqEwr4tOtCyz4MtYZX2JYhfr1JvBFKdS+7K/9rfpZR3VLX+YWBbKoxCgS43Q== validate-npm-package-license@^3.0.1: version "3.0.4" @@ -8159,44 +8030,11 @@ whatwg-url@^7.0.0: tr46 "^1.0.1" webidl-conversions "^4.0.2" -which-boxed-primitive@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/which-boxed-primitive/-/which-boxed-primitive-1.0.1.tgz#cbe8f838ebe91ba2471bb69e9edbda67ab5a5ec1" - integrity sha512-7BT4TwISdDGBgaemWU0N0OU7FeAEJ9Oo2P1PHRm/FCWoEi2VLWC9b6xvxAA3C/NMpxg3HXVgi0sMmGbNUbNepQ== - dependencies: - is-bigint "^1.0.0" - is-boolean-object "^1.0.0" - is-number-object "^1.0.3" - is-string "^1.0.4" - is-symbol "^1.0.2" - -which-collection@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/which-collection/-/which-collection-1.0.1.tgz#70eab71ebbbd2aefaf32f917082fc62cdcb70906" - integrity sha512-W8xeTUwaln8i3K/cY1nGXzdnVZlidBcagyNFtBdD5kxnb4TvGKR7FfSIS3mYpwWS1QUCutfKz8IY8RjftB0+1A== - dependencies: - is-map "^2.0.1" - is-set "^2.0.1" - is-weakmap "^2.0.1" - is-weakset "^2.0.1" - which-module@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a" integrity sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho= -which-typed-array@^1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.2.tgz#e5f98e56bda93e3dac196b01d47c1156679c00b2" - integrity sha512-KT6okrd1tE6JdZAy3o2VhMoYPh3+J6EMZLyrxBQsZflI1QCZIxMrIYLkosd8Twf+YfknVIHmYQPgJt238p8dnQ== - dependencies: - available-typed-arrays "^1.0.2" - es-abstract "^1.17.5" - foreach "^2.0.5" - function-bind "^1.1.1" - has-symbols "^1.0.1" - is-typed-array "^1.1.3" - which@^1.2.9, which@^1.3.0: version "1.3.1" resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" diff --git a/packages/standard-components/.gitignore b/packages/standard-components/.gitignore index 3aebfd3c7b..a785d2cb49 100644 --- a/packages/standard-components/.gitignore +++ b/packages/standard-components/.gitignore @@ -1,5 +1,4 @@ .DS_Store node_modules -yarn.lock package-lock.json dist/ diff --git a/packages/standard-components/components.json b/packages/standard-components/components.json index a766d3084c..7da618224e 100644 --- a/packages/standard-components/components.json +++ b/packages/standard-components/components.json @@ -13,18 +13,12 @@ "embed": "string" } }, - "Navigation": { + "navigation": { "name": "Navigation", "description": "A basic header navigation component", "children": true, "props": { - "logoUrl": "string", - "title": "string", - "backgroundColor": "string", - "color": "string", - "borderWidth": "string", - "borderColor": "string", - "borderStyle": "string" + "logoUrl": "string" } }, "button": { @@ -32,7 +26,6 @@ "description": "an html diff --git a/packages/standard-components/src/Card.svelte b/packages/standard-components/src/Card.svelte index bfb0e0072f..74121590e3 100644 --- a/packages/standard-components/src/Card.svelte +++ b/packages/standard-components/src/Card.svelte @@ -1,5 +1,9 @@ -
- {#if showImage}{/if} +
+ {#if showImage} + + {/if}

{heading}

{description}

- {linkText} + {linkText}
@@ -68,7 +82,7 @@ a { margin: 0.5rem 0; text-decoration: none; - color: var(--color); + color: var(--linkColor); font-weight: 600; } diff --git a/packages/standard-components/src/CardHorizontal.svelte b/packages/standard-components/src/CardHorizontal.svelte index e3c010e507..5d7596e296 100644 --- a/packages/standard-components/src/CardHorizontal.svelte +++ b/packages/standard-components/src/CardHorizontal.svelte @@ -1,5 +1,8 @@ -
- {#if showImage}{/if} +
+ {#if showImage} + + {/if}

{heading}

@@ -34,7 +38,9 @@
@@ -90,7 +96,7 @@ a { margin: 0.5rem 0 0 0; text-decoration: none; - color: var(--color); + color: var(--linkColor); font-weight: 600; font-size: 0.85rem; margin: 0; diff --git a/packages/standard-components/src/CardStat.svelte b/packages/standard-components/src/CardStat.svelte new file mode 100644 index 0000000000..e5e40ad862 --- /dev/null +++ b/packages/standard-components/src/CardStat.svelte @@ -0,0 +1,49 @@ + + +
+

{title}

+

{value}

+

{label}

+
+ + diff --git a/packages/standard-components/src/Chart/ApexChart.svelte b/packages/standard-components/src/Chart/ApexChart.svelte deleted file mode 100644 index 5bf319e7ea..0000000000 --- a/packages/standard-components/src/Chart/ApexChart.svelte +++ /dev/null @@ -1,18 +0,0 @@ - - -{#if options} -
-{:else if options === false} -
Invalid chart options
-{/if} - - diff --git a/packages/standard-components/src/Checkbox.svelte b/packages/standard-components/src/Checkbox.svelte deleted file mode 100644 index 75e41bb897..0000000000 --- a/packages/standard-components/src/Checkbox.svelte +++ /dev/null @@ -1,11 +0,0 @@ - - - diff --git a/packages/standard-components/src/Container.svelte b/packages/standard-components/src/Container.svelte index 0e4ff6f49b..22139d7d7e 100644 --- a/packages/standard-components/src/Container.svelte +++ b/packages/standard-components/src/Container.svelte @@ -1,50 +1,62 @@ {#if type === 'div'} -
+
+ +
{:else if type === 'header'} -
+
+ +
{:else if type === 'main'} -
+
+ +
{:else if type === 'footer'} -