diff --git a/packages/builder/src/pages/builder/portal/manage/users/_components/UpdateRolesModal.svelte b/packages/builder/src/pages/builder/portal/manage/users/_components/UpdateRolesModal.svelte
index 436ba28bba..59045a1198 100644
--- a/packages/builder/src/pages/builder/portal/manage/users/_components/UpdateRolesModal.svelte
+++ b/packages/builder/src/pages/builder/portal/manage/users/_components/UpdateRolesModal.svelte
@@ -9,7 +9,9 @@
const dispatch = createEventDispatcher()
const roles = app.roles
- let options = roles.map(role => role._id).filter(id => id !== "PUBLIC")
+ let options = roles
+ .filter(role => role._id !== "PUBLIC")
+ .map(role => ({ value: role._id, label: role.name }))
let selectedRole = user?.roles?.[app?._id]
async function updateUserRoles() {
@@ -46,5 +48,7 @@
on:change
{options}
label="Role"
+ getOptionLabel={role => role.name}
+ getOptionValue={role => role._id}
/>
diff --git a/packages/builder/src/stores/portal/index.js b/packages/builder/src/stores/portal/index.js
index 5bebb2aa7a..e2736cfa58 100644
--- a/packages/builder/src/stores/portal/index.js
+++ b/packages/builder/src/stores/portal/index.js
@@ -4,3 +4,4 @@ export { admin } from "./admin"
export { apps } from "./apps"
export { email } from "./email"
export { auth } from "./auth"
+export { oidc } from "./oidc"
diff --git a/packages/builder/src/stores/portal/oidc.js b/packages/builder/src/stores/portal/oidc.js
new file mode 100644
index 0000000000..d8d06f12a9
--- /dev/null
+++ b/packages/builder/src/stores/portal/oidc.js
@@ -0,0 +1,33 @@
+import { writable } from "svelte/store"
+import api from "builderStore/api"
+
+const OIDC_CONFIG = {
+ logo: undefined,
+ name: undefined,
+ uuid: undefined,
+}
+
+export function createOidcStore() {
+ const store = writable(OIDC_CONFIG)
+ const { set, subscribe } = store
+
+ async function init() {
+ const res = await api.get(`/api/admin/configs/publicOidc`)
+ const json = await res.json()
+
+ if (json.status === 400) {
+ set(OIDC_CONFIG)
+ } else {
+ // Just use the first config for now. We will be support multiple logins buttons later on.
+ set(...json)
+ }
+ }
+
+ return {
+ subscribe,
+ set,
+ init,
+ }
+}
+
+export const oidc = createOidcStore()
diff --git a/packages/builder/src/stores/portal/organisation.js b/packages/builder/src/stores/portal/organisation.js
index 7e6a777cd4..71c0be4b4d 100644
--- a/packages/builder/src/stores/portal/organisation.js
+++ b/packages/builder/src/stores/portal/organisation.js
@@ -6,6 +6,8 @@ const DEFAULT_CONFIG = {
logoUrl: undefined,
docsUrl: undefined,
company: "Budibase",
+ oidc: undefined,
+ google: undefined,
}
export function createOrganisationStore() {
diff --git a/packages/cli/package.json b/packages/cli/package.json
index 6c953baa73..d04901f56b 100644
--- a/packages/cli/package.json
+++ b/packages/cli/package.json
@@ -1,6 +1,6 @@
{
"name": "@budibase/cli",
- "version": "0.9.82",
+ "version": "0.9.83-alpha.0",
"description": "Budibase CLI, for developers, self hosting and migrations.",
"main": "src/index.js",
"bin": {
@@ -24,7 +24,7 @@
"docker-compose": "^0.23.6",
"inquirer": "^8.0.0",
"lookpath": "^1.1.0",
- "pkg": "^4.4.9",
+ "pkg": "^5.3.0",
"posthog-node": "1.0.7",
"randomstring": "^1.1.5"
},
diff --git a/packages/cli/yarn.lock b/packages/cli/yarn.lock
index 57676a85d2..cc4fcf413a 100644
--- a/packages/cli/yarn.lock
+++ b/packages/cli/yarn.lock
@@ -23,17 +23,19 @@
chalk "^2.0.0"
js-tokens "^4.0.0"
-"@babel/parser@^7.9.4":
- version "7.13.11"
- resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.13.11.tgz#f93ebfc99d21c1772afbbaa153f47e7ce2f50b88"
- integrity sha512-PhuoqeHoO9fc4ffMEVk4qb/w/s2iOSWohvbHxLtxui0eBg3Lg5gN1U8wp1V1u61hOWkPQJJyJzGH6Y+grwkq8Q==
+"@babel/parser@7.13.13":
+ version "7.13.13"
+ resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.13.13.tgz#42f03862f4aed50461e543270916b47dd501f0df"
+ integrity sha512-OhsyMrqygfk5v8HmWwOzlYjJrtLaFhF34MrfG/Z73DgYCI6ojNUTUp2TYbtnjo8PegeJp12eamsNettCQjKjVw==
-"@babel/runtime@^7.9.2":
- version "7.13.10"
- resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.13.10.tgz#47d42a57b6095f4468da440388fdbad8bebf0d7d"
- integrity sha512-4QPkjJq6Ns3V/RgpEahRk+AGfL0eO6RHHtTWoNNr5mO49G6B5+X6d6THgWEAvTrznU5xYpbAlVKRYcsCgh/Akw==
+"@babel/types@7.13.12":
+ version "7.13.12"
+ resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.13.12.tgz#edbf99208ef48852acdff1c8a681a1e4ade580cd"
+ integrity sha512-K4nY2xFN4QMvQwkQ+zmBDp6ANMbVNw6BbxWmYA4qNjhR9W+Lj/8ky5MEY2Me5r+B2c6/v6F53oMndG+f9s3IiA==
dependencies:
- regenerator-runtime "^0.13.4"
+ "@babel/helper-validator-identifier" "^7.12.11"
+ lodash "^4.17.19"
+ to-fast-properties "^2.0.0"
"@eslint/eslintrc@^0.4.0":
version "0.4.0"
@@ -81,7 +83,14 @@ acorn@^7.4.0:
resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa"
integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==
-ajv@^6.10.0, ajv@^6.12.3, ajv@^6.12.4:
+agent-base@6:
+ 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"
+
+ajv@^6.10.0, ajv@^6.12.4:
version "6.12.6"
resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4"
integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==
@@ -113,6 +122,16 @@ ansi-escapes@^4.2.1:
dependencies:
type-fest "^0.11.0"
+ansi-regex@^2.0.0:
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df"
+ integrity sha1-w7M6te42DYbg5ijwRorn7yfWVN8=
+
+ansi-regex@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998"
+ integrity sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=
+
ansi-regex@^5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.0.tgz#388539f55179bf39339c81af30a654d69f87cb75"
@@ -132,6 +151,19 @@ ansi-styles@^4.0.0, ansi-styles@^4.1.0:
dependencies:
color-convert "^2.0.1"
+aproba@^1.0.3:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a"
+ integrity sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==
+
+are-we-there-yet@~1.1.2:
+ version "1.1.5"
+ resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz#4b35c2944f062a8bfcda66410760350fe9ddfc21"
+ integrity sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w==
+ dependencies:
+ delegates "^1.0.0"
+ readable-stream "^2.0.6"
+
argparse@^1.0.7:
version "1.0.10"
resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911"
@@ -149,37 +181,15 @@ array-uniq@1.0.2:
resolved "https://registry.yarnpkg.com/array-uniq/-/array-uniq-1.0.2.tgz#5fcc373920775723cfd64d65c64bef53bf9eba6d"
integrity sha1-X8w3OSB3VyPP1k1lxkvvU7+eum0=
-asn1@~0.2.3:
- version "0.2.4"
- resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.4.tgz#8d2475dfab553bb33e77b54e59e880bb8ce23136"
- integrity sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==
- dependencies:
- safer-buffer "~2.1.0"
-
-assert-plus@1.0.0, assert-plus@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525"
- integrity sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=
-
astral-regex@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-2.0.0.tgz#483143c567aeed4785759c0865786dc77d7d2e31"
integrity sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==
-asynckit@^0.4.0:
- version "0.4.0"
- resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79"
- integrity sha1-x57Zf380y48robyXkLzDZkdLS3k=
-
-aws-sign2@~0.7.0:
- version "0.7.0"
- resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8"
- integrity sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=
-
-aws4@^1.8.0:
- version "1.11.0"
- resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.11.0.tgz#d61f46d83b2519250e2784daf5b09479a8b41c59"
- integrity sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==
+at-least-node@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/at-least-node/-/at-least-node-1.0.0.tgz#602cd4b46e844ad4effc92a8011a3c46e0238dc2"
+ integrity sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==
axios-retry@^3.1.9:
version "3.1.9"
@@ -200,12 +210,19 @@ balanced-match@^1.0.0:
resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767"
integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c=
-bcrypt-pbkdf@^1.0.0:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz#a4301d389b6a43f9b67ff3ca11a3f6637e360e9e"
- integrity sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=
+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==
+
+bl@^4.0.3:
+ version "4.1.0"
+ resolved "https://registry.yarnpkg.com/bl/-/bl-4.1.0.tgz#451535264182bec2fbbc83a62ab98cf11d9f7b3a"
+ integrity sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==
dependencies:
- tweetnacl "^0.14.3"
+ buffer "^5.5.0"
+ inherits "^2.0.4"
+ readable-stream "^3.4.0"
brace-expansion@^1.1.7:
version "1.1.11"
@@ -222,21 +239,19 @@ braces@^3.0.1:
dependencies:
fill-range "^7.0.1"
-byline@^5.0.0:
- version "5.0.0"
- resolved "https://registry.yarnpkg.com/byline/-/byline-5.0.0.tgz#741c5216468eadc457b03410118ad77de8c1ddb1"
- integrity sha1-dBxSFkaOrcRXsDQQEYrXfejB3bE=
+buffer@^5.5.0:
+ version "5.7.1"
+ resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.7.1.tgz#ba62e7c13133053582197160851a8f648e99eed0"
+ integrity sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==
+ dependencies:
+ base64-js "^1.3.1"
+ ieee754 "^1.1.13"
callsites@^3.0.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73"
integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==
-caseless@~0.12.0:
- version "0.12.0"
- resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc"
- integrity sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=
-
chalk@^2.0.0:
version "2.4.2"
resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424"
@@ -246,14 +261,6 @@ chalk@^2.0.0:
escape-string-regexp "^1.0.5"
supports-color "^5.3.0"
-chalk@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/chalk/-/chalk-3.0.0.tgz#3f73c2bf526591f574cc492c51e2456349f844e4"
- integrity sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==
- dependencies:
- ansi-styles "^4.1.0"
- supports-color "^7.1.0"
-
chalk@^4.0.0, chalk@^4.1.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.0.tgz#4e14870a618d9e2edd97dd8345fd9d9dc315646a"
@@ -272,6 +279,11 @@ charenc@0.0.2:
resolved "https://registry.yarnpkg.com/charenc/-/charenc-0.0.2.tgz#c0a1d2f3a7092e03774bfa83f14c0fc5790a8667"
integrity sha1-wKHS86cJLgN3S/qD8UwPxXkKhmc=
+chownr@^1.1.1:
+ version "1.1.4"
+ resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.4.tgz#6fc9d7b42d32a583596337666e7d08084da2cc6b"
+ integrity sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==
+
cli-cursor@^3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-3.1.0.tgz#264305a7ae490d1d03bf0c9ba7c925d1753af307"
@@ -284,6 +296,20 @@ cli-width@^3.0.0:
resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-3.0.0.tgz#a2f48437a2caa9a22436e794bf071ec9e61cedf6"
integrity sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==
+cliui@^7.0.2:
+ version "7.0.4"
+ resolved "https://registry.yarnpkg.com/cliui/-/cliui-7.0.4.tgz#a0265ee655476fc807aea9df3df8df7783808b4f"
+ integrity sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==
+ dependencies:
+ string-width "^4.2.0"
+ strip-ansi "^6.0.0"
+ wrap-ansi "^7.0.0"
+
+code-point-at@^1.0.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77"
+ integrity sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=
+
color-convert@^1.9.0:
version "1.9.3"
resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8"
@@ -308,13 +334,6 @@ color-name@~1.1.4:
resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2"
integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==
-combined-stream@^1.0.6, combined-stream@~1.0.6:
- version "1.0.8"
- resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f"
- integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==
- dependencies:
- delayed-stream "~1.0.0"
-
commander@^7.1.0:
version "7.1.0"
resolved "https://registry.yarnpkg.com/commander/-/commander-7.1.0.tgz#f2eaecf131f10e36e07d894698226e36ae0eb5ff"
@@ -330,7 +349,12 @@ concat-map@0.0.1:
resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=
-core-util-is@1.0.2, core-util-is@~1.0.0:
+console-control-strings@^1.0.0, console-control-strings@~1.1.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e"
+ integrity sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=
+
+core-util-is@~1.0.0:
version "1.0.2"
resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7"
integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=
@@ -349,29 +373,39 @@ crypt@0.0.2:
resolved "https://registry.yarnpkg.com/crypt/-/crypt-0.0.2.tgz#88d7ff7ec0dfb86f713dc87bbb42d044d3e6c41b"
integrity sha1-iNf/fsDfuG9xPch7u0LQRNPmxBs=
-dashdash@^1.12.0:
- version "1.14.1"
- resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0"
- integrity sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=
- dependencies:
- assert-plus "^1.0.0"
-
-debug@^4.0.1, debug@^4.1.1:
+debug@4, debug@^4.0.1, debug@^4.1.1:
version "4.3.1"
resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.1.tgz#f0d229c505e0c6d8c49ac553d1b13dc183f6b2ee"
integrity sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==
dependencies:
ms "2.1.2"
+decompress-response@^4.2.0:
+ version "4.2.1"
+ resolved "https://registry.yarnpkg.com/decompress-response/-/decompress-response-4.2.1.tgz#414023cc7a302da25ce2ec82d0d5238ccafd8986"
+ integrity sha512-jOSne2qbyE+/r8G1VU+G/82LBs2Fs4LAsTiLSHOCOMZQl2OKZ6i8i4IyHemTe+/yIXOtTcRQMzPcgyhoFlqPkw==
+ dependencies:
+ mimic-response "^2.0.0"
+
+deep-extend@^0.6.0:
+ version "0.6.0"
+ resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac"
+ integrity sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==
+
deep-is@^0.1.3, deep-is@~0.1.3:
version "0.1.3"
resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34"
integrity sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=
-delayed-stream@~1.0.0:
+delegates@^1.0.0:
version "1.0.0"
- resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619"
- integrity sha1-3zrhmayt+31ECqrgsp4icrJOxhk=
+ resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a"
+ integrity sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=
+
+detect-libc@^1.0.3:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b"
+ integrity sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=
dir-glob@^3.0.1:
version "3.0.1"
@@ -392,19 +426,18 @@ doctrine@^3.0.0:
dependencies:
esutils "^2.0.2"
-ecc-jsbn@~0.1.1:
- version "0.1.2"
- resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz#3a83a904e54353287874c564b7549386849a98c9"
- integrity sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=
- dependencies:
- jsbn "~0.1.0"
- safer-buffer "^2.1.0"
-
emoji-regex@^8.0.0:
version "8.0.0"
resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37"
integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==
+end-of-stream@^1.1.0, end-of-stream@^1.4.1:
+ version "1.4.4"
+ resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0"
+ integrity sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==
+ dependencies:
+ once "^1.4.0"
+
enquirer@^2.3.5:
version "2.3.6"
resolved "https://registry.yarnpkg.com/enquirer/-/enquirer-2.3.6.tgz#2a7fe5dd634a1e4125a975ec994ff5456dc3734d"
@@ -412,18 +445,23 @@ enquirer@^2.3.5:
dependencies:
ansi-colors "^4.1.1"
+escalade@^3.1.1:
+ version "3.1.1"
+ resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40"
+ integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==
+
escape-string-regexp@^1.0.5:
version "1.0.5"
resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=
-escodegen@^1.14.1:
- version "1.14.3"
- resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-1.14.3.tgz#4e7b81fba61581dc97582ed78cab7f0e8d63f503"
- integrity sha512-qFcX0XJkdg+PB3xjZZG/wKSuT1PnQWx57+TVSjIMmILd2yC/6ByYElPwJnslDsuWuSAp4AwJGumarAAmJch5Kw==
+escodegen@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-2.0.0.tgz#5e32b12833e8aa8fa35e1bf0befa89380484c7dd"
+ integrity sha512-mmHKys/C8BFUGI+MAWNcSYoORYLMdPzjrknd2Vc+bUsjN5bXcr8EhrNB+UTqfL1y3I9c4fw2ihgtMPQLBRiQxw==
dependencies:
esprima "^4.0.1"
- estraverse "^4.2.0"
+ estraverse "^5.2.0"
esutils "^2.0.2"
optionator "^0.8.1"
optionalDependencies:
@@ -525,7 +563,7 @@ esrecurse@^4.3.0:
dependencies:
estraverse "^5.2.0"
-estraverse@^4.1.1, estraverse@^4.2.0:
+estraverse@^4.1.1:
version "4.3.0"
resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d"
integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==
@@ -545,11 +583,6 @@ expand-template@^2.0.3:
resolved "https://registry.yarnpkg.com/expand-template/-/expand-template-2.0.3.tgz#6e14b3fcee0f3a6340ecb57d2e8918692052a47c"
integrity sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==
-extend@~3.0.2:
- version "3.0.2"
- resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa"
- integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==
-
external-editor@^3.0.3:
version "3.1.0"
resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-3.1.0.tgz#cb03f740befae03ea4d283caed2741a83f335495"
@@ -559,16 +592,6 @@ external-editor@^3.0.3:
iconv-lite "^0.4.24"
tmp "^0.0.33"
-extsprintf@1.3.0:
- version "1.3.0"
- resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05"
- integrity sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=
-
-extsprintf@^1.2.0:
- version "1.4.0"
- resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.0.tgz#e2689f8f356fad62cca65a3a91c5df5f9551692f"
- integrity sha1-4mifjzVvrWLMplo6kcXfX5VRaS8=
-
fast-deep-equal@^3.1.1:
version "3.1.3"
resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525"
@@ -642,20 +665,6 @@ follow-redirects@^1.10.0:
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.13.3.tgz#e5598ad50174c1bc4e872301e82ac2cd97f90267"
integrity sha512-DUgl6+HDzB0iEptNQEXLx/KhTmDb8tZUHSeLqpnjpknR70H0nC2t9N73BK6fN4hOvJ84pKlIQVQ4k5FFlBedKA==
-forever-agent@~0.6.1:
- version "0.6.1"
- resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91"
- integrity sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=
-
-form-data@~2.3.2:
- version "2.3.3"
- resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.3.tgz#dcce52c05f644f298c6a7ab936bd724ceffbf3a6"
- integrity sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==
- dependencies:
- asynckit "^0.4.0"
- combined-stream "^1.0.6"
- mime-types "^2.1.12"
-
from2@^2.3.0:
version "2.3.0"
resolved "https://registry.yarnpkg.com/from2/-/from2-2.3.0.tgz#8bfb5502bde4a4d36cfdeea007fcca21d7e382af"
@@ -664,14 +673,20 @@ from2@^2.3.0:
inherits "^2.0.1"
readable-stream "^2.0.0"
-fs-extra@^8.1.0:
- version "8.1.0"
- resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-8.1.0.tgz#49d43c45a88cd9677668cb7be1b46efdb8d2e1c0"
- integrity sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==
+fs-constants@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/fs-constants/-/fs-constants-1.0.0.tgz#6be0de9be998ce16af8afc24497b9ee9b7ccd9ad"
+ integrity sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==
+
+fs-extra@^9.1.0:
+ version "9.1.0"
+ resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-9.1.0.tgz#5954460c764a8da2094ba3554bf839e6b9a7c86d"
+ integrity sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==
dependencies:
+ at-least-node "^1.0.0"
graceful-fs "^4.2.0"
- jsonfile "^4.0.0"
- universalify "^0.1.0"
+ jsonfile "^6.0.1"
+ universalify "^2.0.0"
fs.realpath@^1.0.0:
version "1.0.0"
@@ -688,12 +703,29 @@ functional-red-black-tree@^1.0.1:
resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327"
integrity sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=
-getpass@^0.1.1:
- version "0.1.7"
- resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa"
- integrity sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=
+gauge@~2.7.3:
+ version "2.7.4"
+ resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7"
+ integrity sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=
dependencies:
- assert-plus "^1.0.0"
+ aproba "^1.0.3"
+ console-control-strings "^1.0.0"
+ has-unicode "^2.0.0"
+ object-assign "^4.1.0"
+ signal-exit "^3.0.0"
+ string-width "^1.0.1"
+ strip-ansi "^3.0.1"
+ wide-align "^1.1.0"
+
+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==
+
+github-from-package@0.0.0:
+ version "0.0.0"
+ resolved "https://registry.yarnpkg.com/github-from-package/-/github-from-package-0.0.0.tgz#97fb5d96bfde8973313f20e8288ef9a167fa64ce"
+ integrity sha1-l/tdlr/eiXMxPyDoKI75oWf6ZM4=
glob-parent@^5.0.0, glob-parent@^5.1.0:
version "5.1.2"
@@ -728,10 +760,10 @@ globals@^13.6.0:
dependencies:
type-fest "^0.20.2"
-globby@^11.0.0:
- version "11.0.2"
- resolved "https://registry.yarnpkg.com/globby/-/globby-11.0.2.tgz#1af538b766a3b540ebfb58a32b2e2d5897321d83"
- integrity sha512-2ZThXDvvV8fYFRVIxnrMQBipZQDr7MxKAmQK1vujaj9/7eF0efG7BPUKJ7jP7G5SLF37xKDXvO4S/KKLj/Z0og==
+globby@^11.0.3:
+ version "11.0.4"
+ resolved "https://registry.yarnpkg.com/globby/-/globby-11.0.4.tgz#2cbaff77c2f2a62e71e9b2813a67b97a3a3001a5"
+ integrity sha512-9O4MVG9ioZJ08ffbcyVYyLOJLk5JQ688pJ4eMGLpdWLHq/Wr1D9BlriLQyL0E+jbkuePVZXYFj47QM/v093wHg==
dependencies:
array-union "^2.1.0"
dir-glob "^3.0.1"
@@ -745,19 +777,6 @@ graceful-fs@^4.1.6, graceful-fs@^4.2.0:
resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.6.tgz#ff040b2b0853b23c3d31027523706f1885d76bee"
integrity sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ==
-har-schema@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92"
- integrity sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=
-
-har-validator@~5.1.3:
- version "5.1.5"
- resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-5.1.5.tgz#1f0803b9f8cb20c0fa13822df1ecddb36bde1efd"
- integrity sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==
- dependencies:
- ajv "^6.12.3"
- har-schema "^2.0.0"
-
has-flag@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd"
@@ -768,6 +787,11 @@ has-flag@^4.0.0:
resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b"
integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==
+has-unicode@^2.0.0:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9"
+ integrity sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=
+
has@^1.0.3:
version "1.0.3"
resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796"
@@ -775,14 +799,13 @@ has@^1.0.3:
dependencies:
function-bind "^1.1.1"
-http-signature@~1.2.0:
- version "1.2.0"
- resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1"
- integrity sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=
+https-proxy-agent@^5.0.0:
+ version "5.0.0"
+ resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz#e2a90542abb68a762e0a0850f6c9edadfd8506b2"
+ integrity sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==
dependencies:
- assert-plus "^1.0.0"
- jsprim "^1.2.2"
- sshpk "^1.7.0"
+ agent-base "6"
+ debug "4"
iconv-lite@^0.4.24:
version "0.4.24"
@@ -791,6 +814,11 @@ iconv-lite@^0.4.24:
dependencies:
safer-buffer ">= 2.1.2 < 3"
+ieee754@^1.1.13:
+ version "1.2.1"
+ resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352"
+ integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==
+
ignore@^4.0.6:
version "4.0.6"
resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc"
@@ -822,11 +850,16 @@ inflight@^1.0.4:
once "^1.3.0"
wrappy "1"
-inherits@2, inherits@^2.0.1, inherits@~2.0.3:
+inherits@2, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.3:
version "2.0.4"
resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c"
integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
+ini@~1.3.0:
+ version "1.3.8"
+ resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.8.tgz#a29da425b48806f34767a4efce397269af28432c"
+ integrity sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==
+
inquirer@^8.0.0:
version "8.0.0"
resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-8.0.0.tgz#957a46db1abcf0fdd2ab82deb7470e90afc7d0ac"
@@ -846,10 +879,10 @@ inquirer@^8.0.0:
strip-ansi "^6.0.0"
through "^2.3.6"
-into-stream@^5.1.1:
- version "5.1.1"
- resolved "https://registry.yarnpkg.com/into-stream/-/into-stream-5.1.1.tgz#f9a20a348a11f3c13face22763f2d02e127f4db8"
- integrity sha512-krrAJ7McQxGGmvaYbB7Q1mcA+cRwg9Ij2RfWIeVesNBgVDZmzY/Fa4IpZUT3bmdRzMzdf/mzltCG2Dq99IZGBA==
+into-stream@^6.0.0:
+ version "6.0.0"
+ resolved "https://registry.yarnpkg.com/into-stream/-/into-stream-6.0.0.tgz#4bfc1244c0128224e18b8870e85b2de8e66c6702"
+ integrity sha512-XHbaOAvP+uFKUFsOgoNPRjLkwB+I22JFPFe5OjTkQ0nwgj6+pSjb4NmB6VMxaPshLiOf+zcpOCBQuLwC1KHhZA==
dependencies:
from2 "^2.3.0"
p-is-promise "^3.0.0"
@@ -871,6 +904,18 @@ is-extglob@^2.1.1:
resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2"
integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=
+is-fullwidth-code-point@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb"
+ integrity sha1-754xOG8DGn8NZDr4L95QxFfvAMs=
+ dependencies:
+ number-is-nan "^1.0.0"
+
+is-fullwidth-code-point@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f"
+ integrity sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=
+
is-fullwidth-code-point@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d"
@@ -893,11 +938,6 @@ 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-typedarray@~1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a"
- integrity sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=
-
isarray@~1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11"
@@ -908,11 +948,6 @@ isexe@^2.0.0:
resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10"
integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=
-isstream@~0.1.2:
- version "0.1.2"
- resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a"
- integrity sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=
-
join-component@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/join-component/-/join-component-1.1.0.tgz#b8417b750661a392bee2c2537c68b2a9d4977cd5"
@@ -931,11 +966,6 @@ js-yaml@^3.13.1:
argparse "^1.0.7"
esprima "^4.0.0"
-jsbn@~0.1.0:
- version "0.1.1"
- resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513"
- integrity sha1-peZUwuWi3rXyAdls77yoDA7y9RM=
-
json-schema-traverse@^0.4.1:
version "0.4.1"
resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660"
@@ -946,38 +976,20 @@ json-schema-traverse@^1.0.0:
resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz#ae7bcb3656ab77a73ba5c49bf654f38e6b6860e2"
integrity sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==
-json-schema@0.2.3:
- version "0.2.3"
- resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13"
- integrity sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=
-
json-stable-stringify-without-jsonify@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651"
integrity sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=
-json-stringify-safe@~5.0.1:
- version "5.0.1"
- resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb"
- integrity sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=
-
-jsonfile@^4.0.0:
- version "4.0.0"
- resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb"
- integrity sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=
+jsonfile@^6.0.1:
+ version "6.1.0"
+ resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-6.1.0.tgz#bc55b2634793c679ec6403094eb13698a6ec0aae"
+ integrity sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==
+ dependencies:
+ universalify "^2.0.0"
optionalDependencies:
graceful-fs "^4.1.6"
-jsprim@^1.2.2:
- version "1.4.1"
- resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.1.tgz#313e66bc1e5cc06e438bc1b7499c2e5c56acb6a2"
- integrity sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=
- dependencies:
- assert-plus "1.0.0"
- extsprintf "1.3.0"
- json-schema "0.2.3"
- verror "1.10.0"
-
levn@^0.4.1:
version "0.4.1"
resolved "https://registry.yarnpkg.com/levn/-/levn-0.4.1.tgz#ae4562c007473b932a6200d403268dd2fffc6ade"
@@ -994,7 +1006,7 @@ levn@~0.3.0:
prelude-ls "~1.1.2"
type-check "~0.3.2"
-lodash@^4.17.20, lodash@^4.17.21:
+lodash@^4.17.19, lodash@^4.17.20, lodash@^4.17.21:
version "4.17.21"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c"
integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==
@@ -1033,23 +1045,16 @@ micromatch@^4.0.2:
braces "^3.0.1"
picomatch "^2.0.5"
-mime-db@1.46.0:
- version "1.46.0"
- resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.46.0.tgz#6267748a7f799594de3cbc8cde91def349661cee"
- integrity sha512-svXaP8UQRZ5K7or+ZmfNhg2xX3yKDMUzqadsSqi4NCH/KomcH75MAMYAGVlvXn4+b/xOPhS3I2uHKRUzvjY7BQ==
-
-mime-types@^2.1.12, mime-types@~2.1.19:
- version "2.1.29"
- resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.29.tgz#1d4ab77da64b91f5f72489df29236563754bb1b2"
- integrity sha512-Y/jMt/S5sR9OaqteJtslsFZKWOIIqMACsJSiHghlCAyhf7jfVYjKBmLiX8OgpWeW+fjJ2b+Az69aPFPkUOY6xQ==
- dependencies:
- mime-db "1.46.0"
-
mimic-fn@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b"
integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==
+mimic-response@^2.0.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-2.1.0.tgz#d13763d35f613d09ec37ebb30bac0469c0ee8f43"
+ integrity sha512-wXqjST+SLt7R009ySCglWBCFpjUygmCIfD790/kVbiGmUgfYGuB14PiTd5DwVxSV4NcYHjzMkoj5LjQZwTQLEA==
+
minimatch@^3.0.4:
version "3.0.4"
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083"
@@ -1057,17 +1062,15 @@ minimatch@^3.0.4:
dependencies:
brace-expansion "^1.1.7"
-minimist@^1.2.5:
+minimist@^1.2.0, minimist@^1.2.3, minimist@^1.2.5:
version "1.2.5"
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602"
integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==
-mkdirp@^0.5.1:
- version "0.5.5"
- resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.5.tgz#d91cefd62d1436ca0f41620e251288d420099def"
- integrity sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==
- dependencies:
- minimist "^1.2.5"
+mkdirp-classic@^0.5.2, mkdirp-classic@^0.5.3:
+ version "0.5.3"
+ resolved "https://registry.yarnpkg.com/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz#fa10c9115cc6d8865be221ba47ee9bed78601113"
+ integrity sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==
ms@2.1.2:
version "2.1.2"
@@ -1079,30 +1082,67 @@ ms@^2.1.3:
resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2"
integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==
-multistream@^2.1.1:
- version "2.1.1"
- resolved "https://registry.yarnpkg.com/multistream/-/multistream-2.1.1.tgz#629d3a29bd76623489980d04519a2c365948148c"
- integrity sha512-xasv76hl6nr1dEy3lPvy7Ej7K/Lx3O/FCvwge8PeVJpciPPoNCbaANcNiBug3IpdvTveZUcAV0DJzdnUDMesNQ==
+multistream@^4.1.0:
+ version "4.1.0"
+ resolved "https://registry.yarnpkg.com/multistream/-/multistream-4.1.0.tgz#7bf00dfd119556fbc153cff3de4c6d477909f5a8"
+ integrity sha512-J1XDiAmmNpRCBfIWJv+n0ymC4ABcf/Pl+5YvC5B/D2f/2+8PtHvCNxMPKiQcZyi922Hq69J2YOpb1pTywfifyw==
dependencies:
- inherits "^2.0.1"
- readable-stream "^2.0.5"
+ once "^1.4.0"
+ readable-stream "^3.6.0"
mute-stream@0.0.8:
version "0.0.8"
resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.8.tgz#1630c42b2251ff81e2a283de96a5497ea92e5e0d"
integrity sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==
+napi-build-utils@^1.0.1:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/napi-build-utils/-/napi-build-utils-1.0.2.tgz#b1fddc0b2c46e380a0b7a76f984dd47c41a13806"
+ integrity sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==
+
natural-compare@^1.4.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7"
integrity sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=
-oauth-sign@~0.9.0:
- version "0.9.0"
- resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455"
- integrity sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==
+node-abi@^2.7.0:
+ version "2.30.0"
+ resolved "https://registry.yarnpkg.com/node-abi/-/node-abi-2.30.0.tgz#8be53bf3e7945a34eea10e0fc9a5982776cf550b"
+ integrity sha512-g6bZh3YCKQRdwuO/tSZZYJAw622SjsRfJ2X0Iy4sSOHZ34/sPPdVBn8fev2tj7njzLwuqPw9uMtGsGkO5kIQvg==
+ dependencies:
+ semver "^5.4.1"
-once@^1.3.0:
+node-fetch@^2.6.1:
+ version "2.6.1"
+ resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.1.tgz#045bd323631f76ed2e2b55573394416b639a0052"
+ integrity sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==
+
+noop-logger@^0.1.1:
+ version "0.1.1"
+ resolved "https://registry.yarnpkg.com/noop-logger/-/noop-logger-0.1.1.tgz#94a2b1633c4f1317553007d8966fd0e841b6a4c2"
+ integrity sha1-lKKxYzxPExdVMAfYlm/Q6EG2pMI=
+
+npmlog@^4.0.1:
+ version "4.1.2"
+ resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b"
+ integrity sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==
+ dependencies:
+ are-we-there-yet "~1.1.2"
+ console-control-strings "~1.1.0"
+ gauge "~2.7.3"
+ set-blocking "~2.0.0"
+
+number-is-nan@^1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d"
+ integrity sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=
+
+object-assign@^4.1.0:
+ version "4.1.1"
+ resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
+ integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=
+
+once@^1.3.0, once@^1.3.1, once@^1.4.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E=
@@ -1140,7 +1180,7 @@ optionator@^0.9.1:
type-check "^0.4.0"
word-wrap "^1.2.3"
-os-tmpdir@^1.0.1, os-tmpdir@~1.0.2:
+os-tmpdir@~1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274"
integrity sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=
@@ -1177,51 +1217,44 @@ path-type@^4.0.0:
resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b"
integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==
-performance-now@^2.1.0:
- version "2.1.0"
- resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b"
- integrity sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=
-
picomatch@^2.0.5, picomatch@^2.2.1:
version "2.2.2"
resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.2.2.tgz#21f333e9b6b8eaff02468f5146ea406d345f4dad"
integrity sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==
-pkg-fetch@^2.6.9:
- version "2.6.9"
- resolved "https://registry.yarnpkg.com/pkg-fetch/-/pkg-fetch-2.6.9.tgz#c18c5fa9604c57a3df3d9630afb64e176bc8732d"
- integrity sha512-EnVR8LRILXBvaNP+wJOSY02c3+qDDfyEyR+aqAHLhcc9PBnbxFT9UZ1+If49goPQzQPn26TzF//fc6KXZ0aXEg==
+pkg-fetch@3.1.1:
+ version "3.1.1"
+ resolved "https://registry.yarnpkg.com/pkg-fetch/-/pkg-fetch-3.1.1.tgz#8f94115d926e71359ed96c211fe022b7a2452f8d"
+ integrity sha512-3GfpNwbwoTxge2TrVp6Oyz/FZJOoxF1r0+1YikOhnBXa2Di/VOJKtUObFHap76BFnyFo1fwh5vARWFR9TzLKUg==
dependencies:
- "@babel/runtime" "^7.9.2"
- byline "^5.0.0"
- chalk "^3.0.0"
- expand-template "^2.0.3"
- fs-extra "^8.1.0"
- minimist "^1.2.5"
+ chalk "^4.1.0"
+ fs-extra "^9.1.0"
+ https-proxy-agent "^5.0.0"
+ node-fetch "^2.6.1"
progress "^2.0.3"
- request "^2.88.0"
- request-progress "^3.0.0"
- semver "^6.3.0"
- unique-temp-dir "^1.0.0"
+ semver "^7.3.5"
+ yargs "^16.2.0"
-pkg@^4.4.9:
- version "4.4.9"
- resolved "https://registry.yarnpkg.com/pkg/-/pkg-4.4.9.tgz#be04f8d03795772b7c4394724ae7252d7c2a4519"
- integrity sha512-FK4GqHtcCY2PPPVaKViU0NyRzpo6gCS7tPKN5b7AkElqjAOCH1bsRKgohEnxThr6DWfTGByGqba2YHGR/BqbmA==
+pkg@^5.3.0:
+ version "5.3.0"
+ resolved "https://registry.yarnpkg.com/pkg/-/pkg-5.3.0.tgz#27b5a0afd7cd2b85199cc1ab95e6d19ac5ae3fcd"
+ integrity sha512-/DGG+QcSPraMAIxaoGCNqb2A6Xkm2jBQMsj2mjb4ag236ByTY9Xhpikvj5ixwlSQV0euuJw4fphKCd5YHRPS8w==
dependencies:
- "@babel/parser" "^7.9.4"
- "@babel/runtime" "^7.9.2"
- chalk "^3.0.0"
- escodegen "^1.14.1"
- fs-extra "^8.1.0"
- globby "^11.0.0"
- into-stream "^5.1.1"
+ "@babel/parser" "7.13.13"
+ "@babel/types" "7.13.12"
+ chalk "^4.1.0"
+ escodegen "^2.0.0"
+ fs-extra "^9.1.0"
+ globby "^11.0.3"
+ into-stream "^6.0.0"
minimist "^1.2.5"
- multistream "^2.1.1"
- pkg-fetch "^2.6.9"
+ multistream "^4.1.0"
+ pkg-fetch "3.1.1"
+ prebuild-install "6.0.1"
progress "^2.0.3"
- resolve "^1.15.1"
+ resolve "^1.20.0"
stream-meter "^1.0.4"
+ tslib "2.1.0"
posthog-node@1.0.7:
version "1.0.7"
@@ -1237,6 +1270,27 @@ posthog-node@1.0.7:
remove-trailing-slash "^0.1.1"
uuid "^8.3.2"
+prebuild-install@6.0.1:
+ version "6.0.1"
+ resolved "https://registry.yarnpkg.com/prebuild-install/-/prebuild-install-6.0.1.tgz#5902172f7a40eb67305b96c2a695db32636ee26d"
+ integrity sha512-7GOJrLuow8yeiyv75rmvZyeMGzl8mdEX5gY69d6a6bHWmiPevwqFw+tQavhK0EYMaSg3/KD24cWqeQv1EWsqDQ==
+ dependencies:
+ detect-libc "^1.0.3"
+ expand-template "^2.0.3"
+ github-from-package "0.0.0"
+ minimist "^1.2.3"
+ mkdirp-classic "^0.5.3"
+ napi-build-utils "^1.0.1"
+ node-abi "^2.7.0"
+ noop-logger "^0.1.1"
+ npmlog "^4.0.1"
+ pump "^3.0.0"
+ rc "^1.2.7"
+ simple-get "^3.0.3"
+ tar-fs "^2.0.0"
+ tunnel-agent "^0.6.0"
+ which-pm-runs "^1.0.0"
+
prelude-ls@^1.2.1:
version "1.2.1"
resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396"
@@ -1257,21 +1311,19 @@ progress@^2.0.0, progress@^2.0.3:
resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8"
integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==
-psl@^1.1.28:
- version "1.8.0"
- resolved "https://registry.yarnpkg.com/psl/-/psl-1.8.0.tgz#9326f8bcfb013adcc005fdff056acce020e51c24"
- integrity sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==
+pump@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64"
+ integrity sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==
+ dependencies:
+ end-of-stream "^1.1.0"
+ once "^1.3.1"
-punycode@^2.1.0, punycode@^2.1.1:
+punycode@^2.1.0:
version "2.1.1"
resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec"
integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==
-qs@~6.5.2:
- version "6.5.2"
- resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36"
- integrity sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==
-
queue-microtask@^1.2.2:
version "1.2.2"
resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.2.tgz#abf64491e6ecf0f38a6502403d4cda04f372dfd3"
@@ -1284,7 +1336,17 @@ randomstring@^1.1.5:
dependencies:
array-uniq "1.0.2"
-readable-stream@^2.0.0, readable-stream@^2.0.5, readable-stream@^2.1.4:
+rc@^1.2.7:
+ version "1.2.8"
+ resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed"
+ integrity sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==
+ dependencies:
+ deep-extend "^0.6.0"
+ ini "~1.3.0"
+ minimist "^1.2.0"
+ strip-json-comments "~2.0.1"
+
+readable-stream@^2.0.0, readable-stream@^2.0.6, readable-stream@^2.1.4:
version "2.3.7"
resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57"
integrity sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==
@@ -1297,10 +1359,14 @@ readable-stream@^2.0.0, readable-stream@^2.0.5, readable-stream@^2.1.4:
string_decoder "~1.1.1"
util-deprecate "~1.0.1"
-regenerator-runtime@^0.13.4:
- version "0.13.7"
- resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz#cac2dacc8a1ea675feaabaeb8ae833898ae46f55"
- integrity sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew==
+readable-stream@^3.1.1, readable-stream@^3.4.0, readable-stream@^3.6.0:
+ version "3.6.0"
+ resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.0.tgz#337bbda3adc0706bd3e024426a286d4b4b2c9198"
+ integrity sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==
+ dependencies:
+ inherits "^2.0.3"
+ string_decoder "^1.1.1"
+ util-deprecate "^1.0.1"
regexpp@^3.1.0:
version "3.1.0"
@@ -1312,38 +1378,10 @@ remove-trailing-slash@^0.1.1:
resolved "https://registry.yarnpkg.com/remove-trailing-slash/-/remove-trailing-slash-0.1.1.tgz#be2285a59f39c74d1bce4f825950061915e3780d"
integrity sha512-o4S4Qh6L2jpnCy83ysZDau+VORNvnFw07CKSAymkd6ICNVEPisMyzlc00KlvvicsxKck94SEwhDnMNdICzO+tA==
-request-progress@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/request-progress/-/request-progress-3.0.0.tgz#4ca754081c7fec63f505e4faa825aa06cd669dbe"
- integrity sha1-TKdUCBx/7GP1BeT6qCWqBs1mnb4=
- dependencies:
- throttleit "^1.0.0"
-
-request@^2.88.0:
- version "2.88.2"
- resolved "https://registry.yarnpkg.com/request/-/request-2.88.2.tgz#d73c918731cb5a87da047e207234146f664d12b3"
- integrity sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==
- dependencies:
- aws-sign2 "~0.7.0"
- aws4 "^1.8.0"
- caseless "~0.12.0"
- combined-stream "~1.0.6"
- extend "~3.0.2"
- forever-agent "~0.6.1"
- form-data "~2.3.2"
- har-validator "~5.1.3"
- http-signature "~1.2.0"
- is-typedarray "~1.0.0"
- isstream "~0.1.2"
- json-stringify-safe "~5.0.1"
- mime-types "~2.1.19"
- oauth-sign "~0.9.0"
- performance-now "^2.1.0"
- qs "~6.5.2"
- safe-buffer "^5.1.2"
- tough-cookie "~2.5.0"
- tunnel-agent "^0.6.0"
- uuid "^3.3.2"
+require-directory@^2.1.1:
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42"
+ integrity sha1-jGStX9MNqxyXbiNE/+f3kqam30I=
require-from-string@^2.0.2:
version "2.0.2"
@@ -1355,7 +1393,7 @@ resolve-from@^4.0.0:
resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6"
integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==
-resolve@^1.15.1:
+resolve@^1.20.0:
version "1.20.0"
resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.20.0.tgz#629a013fb3f70755d6f0b7935cc1c2c5378b1975"
integrity sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==
@@ -1402,7 +1440,7 @@ rxjs@^6.6.6:
dependencies:
tslib "^1.9.0"
-safe-buffer@^5.0.1, safe-buffer@^5.1.2:
+safe-buffer@^5.0.1, safe-buffer@~5.2.0:
version "5.2.1"
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6"
integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==
@@ -1412,15 +1450,15 @@ safe-buffer@~5.1.0, safe-buffer@~5.1.1:
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d"
integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==
-"safer-buffer@>= 2.1.2 < 3", safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@~2.1.0:
+"safer-buffer@>= 2.1.2 < 3":
version "2.1.2"
resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a"
integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==
-semver@^6.3.0:
- version "6.3.0"
- resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d"
- integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==
+semver@^5.4.1:
+ version "5.7.1"
+ resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7"
+ integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==
semver@^7.2.1:
version "7.3.4"
@@ -1429,6 +1467,18 @@ semver@^7.2.1:
dependencies:
lru-cache "^6.0.0"
+semver@^7.3.5:
+ version "7.3.5"
+ resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.5.tgz#0b621c879348d8998e4b0e4be94b3f12e6018ef7"
+ integrity sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==
+ dependencies:
+ lru-cache "^6.0.0"
+
+set-blocking@~2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7"
+ integrity sha1-BF+XgtARrppoA93TgrJDkrPYkPc=
+
shebang-command@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea"
@@ -1441,11 +1491,25 @@ shebang-regex@^3.0.0:
resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172"
integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==
-signal-exit@^3.0.2:
+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==
+simple-concat@^1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/simple-concat/-/simple-concat-1.0.1.tgz#f46976082ba35c2263f1c8ab5edfe26c41c9552f"
+ integrity sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==
+
+simple-get@^3.0.3:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/simple-get/-/simple-get-3.1.0.tgz#b45be062435e50d159540b576202ceec40b9c6b3"
+ integrity sha512-bCR6cP+aTdScaQCnQKbPKtJOKDp/hj9EDLJo3Nw4y1QksqaovlW/bnptB6/c1e+qmNIDHRK+oXFDdEqBT8WzUA==
+ dependencies:
+ decompress-response "^4.2.0"
+ once "^1.3.1"
+ simple-concat "^1.0.0"
+
slash@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634"
@@ -1470,21 +1534,6 @@ sprintf-js@~1.0.2:
resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c"
integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=
-sshpk@^1.7.0:
- version "1.16.1"
- resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.16.1.tgz#fb661c0bef29b39db40769ee39fa70093d6f6877"
- integrity sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==
- dependencies:
- asn1 "~0.2.3"
- assert-plus "^1.0.0"
- bcrypt-pbkdf "^1.0.0"
- dashdash "^1.12.0"
- ecc-jsbn "~0.1.1"
- getpass "^0.1.1"
- jsbn "~0.1.0"
- safer-buffer "^2.0.2"
- tweetnacl "~0.14.0"
-
stream-meter@^1.0.4:
version "1.0.4"
resolved "https://registry.yarnpkg.com/stream-meter/-/stream-meter-1.0.4.tgz#52af95aa5ea760a2491716704dbff90f73afdd1d"
@@ -1492,6 +1541,23 @@ stream-meter@^1.0.4:
dependencies:
readable-stream "^2.1.4"
+string-width@^1.0.1:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3"
+ integrity sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=
+ dependencies:
+ code-point-at "^1.0.0"
+ is-fullwidth-code-point "^1.0.0"
+ strip-ansi "^3.0.0"
+
+"string-width@^1.0.2 || 2":
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e"
+ integrity sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==
+ dependencies:
+ is-fullwidth-code-point "^2.0.0"
+ strip-ansi "^4.0.0"
+
string-width@^4.1.0, string-width@^4.2.0:
version "4.2.2"
resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.2.tgz#dafd4f9559a7585cfba529c6a0a4f73488ebd4c5"
@@ -1501,6 +1567,13 @@ string-width@^4.1.0, string-width@^4.2.0:
is-fullwidth-code-point "^3.0.0"
strip-ansi "^6.0.0"
+string_decoder@^1.1.1:
+ version "1.3.0"
+ resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e"
+ integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==
+ dependencies:
+ safe-buffer "~5.2.0"
+
string_decoder@~1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8"
@@ -1508,6 +1581,20 @@ string_decoder@~1.1.1:
dependencies:
safe-buffer "~5.1.0"
+strip-ansi@^3.0.0, strip-ansi@^3.0.1:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf"
+ integrity sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=
+ dependencies:
+ ansi-regex "^2.0.0"
+
+strip-ansi@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f"
+ integrity sha1-qEeQIusaw2iocTibY1JixQXuNo8=
+ dependencies:
+ ansi-regex "^3.0.0"
+
strip-ansi@^6.0.0:
version "6.0.0"
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.0.tgz#0b1571dd7669ccd4f3e06e14ef1eed26225ae532"
@@ -1520,6 +1607,11 @@ strip-json-comments@^3.1.0, strip-json-comments@^3.1.1:
resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006"
integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==
+strip-json-comments@~2.0.1:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a"
+ integrity sha1-PFMZQukIwml8DsNEhYwobHygpgo=
+
supports-color@^5.3.0:
version "5.5.0"
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f"
@@ -1544,16 +1636,32 @@ table@^6.0.4:
slice-ansi "^4.0.0"
string-width "^4.2.0"
+tar-fs@^2.0.0:
+ 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.1.4"
+
+tar-stream@^2.1.4:
+ version "2.2.0"
+ resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-2.2.0.tgz#acad84c284136b060dc3faa64474aa9aebd77287"
+ integrity sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==
+ dependencies:
+ bl "^4.0.3"
+ end-of-stream "^1.4.1"
+ fs-constants "^1.0.0"
+ inherits "^2.0.3"
+ readable-stream "^3.1.1"
+
text-table@^0.2.0:
version "0.2.0"
resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4"
integrity sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=
-throttleit@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/throttleit/-/throttleit-1.0.0.tgz#9e785836daf46743145a5984b6268d828528ac6c"
- integrity sha1-nnhYNtr0Z0MUWlmEtiaNgoUorGw=
-
through@^2.3.6:
version "2.3.8"
resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5"
@@ -1566,6 +1674,11 @@ tmp@^0.0.33:
dependencies:
os-tmpdir "~1.0.2"
+to-fast-properties@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e"
+ integrity sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=
+
to-regex-range@^5.0.1:
version "5.0.1"
resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4"
@@ -1573,13 +1686,10 @@ to-regex-range@^5.0.1:
dependencies:
is-number "^7.0.0"
-tough-cookie@~2.5.0:
- version "2.5.0"
- resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.5.0.tgz#cd9fb2a0aa1d5a12b473bd9fb96fa3dcff65ade2"
- integrity sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==
- dependencies:
- psl "^1.1.28"
- punycode "^2.1.1"
+tslib@2.1.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.1.0.tgz#da60860f1c2ecaa5703ab7d39bc05b6bf988b97a"
+ integrity sha512-hcVC3wYEziELGGmEEXue7D75zbwIIVUMWAVbHItGPx0ziyXxrOMQx4rQEVEV45Ut/1IotuEvwqPopzIOkDMf0A==
tslib@^1.9.0:
version "1.14.1"
@@ -1593,11 +1703,6 @@ tunnel-agent@^0.6.0:
dependencies:
safe-buffer "^5.0.1"
-tweetnacl@^0.14.3, tweetnacl@~0.14.0:
- version "0.14.5"
- resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64"
- integrity sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=
-
type-check@^0.4.0, type-check@~0.4.0:
version "0.4.0"
resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1"
@@ -1627,24 +1732,10 @@ type-fest@^0.8.1:
resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.8.1.tgz#09e249ebde851d3b1e48d27c105444667f17b83d"
integrity sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==
-uid2@0.0.3:
- version "0.0.3"
- resolved "https://registry.yarnpkg.com/uid2/-/uid2-0.0.3.tgz#483126e11774df2f71b8b639dcd799c376162b82"
- integrity sha1-SDEm4Rd03y9xuLY53NeZw3YWK4I=
-
-unique-temp-dir@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/unique-temp-dir/-/unique-temp-dir-1.0.0.tgz#6dce95b2681ca003eebfb304a415f9cbabcc5385"
- integrity sha1-bc6VsmgcoAPuv7MEpBX5y6vMU4U=
- dependencies:
- mkdirp "^0.5.1"
- os-tmpdir "^1.0.1"
- uid2 "0.0.3"
-
-universalify@^0.1.0:
- version "0.1.2"
- resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66"
- integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==
+universalify@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/universalify/-/universalify-2.0.0.tgz#75a4984efedc4b08975c5aeb73f530d02df25717"
+ integrity sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==
uri-js@^4.2.2:
version "4.4.1"
@@ -1653,16 +1744,11 @@ uri-js@^4.2.2:
dependencies:
punycode "^2.1.0"
-util-deprecate@~1.0.1:
+util-deprecate@^1.0.1, util-deprecate@~1.0.1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=
-uuid@^3.3.2:
- version "3.4.0"
- resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee"
- integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==
-
uuid@^8.3.2:
version "8.3.2"
resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2"
@@ -1673,14 +1759,10 @@ v8-compile-cache@^2.0.3:
resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz#2de19618c66dc247dcfb6f99338035d8245a2cee"
integrity sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==
-verror@1.10.0:
- version "1.10.0"
- resolved "https://registry.yarnpkg.com/verror/-/verror-1.10.0.tgz#3a105ca17053af55d6e270c1f8288682e18da400"
- integrity sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=
- dependencies:
- assert-plus "^1.0.0"
- core-util-is "1.0.2"
- extsprintf "^1.2.0"
+which-pm-runs@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/which-pm-runs/-/which-pm-runs-1.0.0.tgz#670b3afbc552e0b55df6b7780ca74615f23ad1cb"
+ integrity sha1-Zws6+8VS4LVd9rd4DKdGFfI60cs=
which@^2.0.1:
version "2.0.2"
@@ -1689,17 +1771,56 @@ which@^2.0.1:
dependencies:
isexe "^2.0.0"
+wide-align@^1.1.0:
+ version "1.1.3"
+ resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.3.tgz#ae074e6bdc0c14a431e804e624549c633b000457"
+ integrity sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==
+ dependencies:
+ string-width "^1.0.2 || 2"
+
word-wrap@^1.2.3, word-wrap@~1.2.3:
version "1.2.3"
resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c"
integrity sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==
+wrap-ansi@^7.0.0:
+ version "7.0.0"
+ resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43"
+ integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==
+ dependencies:
+ ansi-styles "^4.0.0"
+ string-width "^4.1.0"
+ strip-ansi "^6.0.0"
+
wrappy@1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=
+y18n@^5.0.5:
+ version "5.0.8"
+ resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55"
+ integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==
+
yallist@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72"
integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==
+
+yargs-parser@^20.2.2:
+ version "20.2.9"
+ resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee"
+ integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==
+
+yargs@^16.2.0:
+ version "16.2.0"
+ resolved "https://registry.yarnpkg.com/yargs/-/yargs-16.2.0.tgz#1c82bf0f6b6a66eafce7ef30e376f49a12477f66"
+ integrity sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==
+ dependencies:
+ cliui "^7.0.2"
+ escalade "^3.1.1"
+ get-caller-file "^2.0.5"
+ require-directory "^2.1.1"
+ string-width "^4.2.0"
+ y18n "^5.0.5"
+ yargs-parser "^20.2.2"
diff --git a/packages/client/package.json b/packages/client/package.json
index f80a81104a..2d2496b135 100644
--- a/packages/client/package.json
+++ b/packages/client/package.json
@@ -1,6 +1,6 @@
{
"name": "@budibase/client",
- "version": "0.9.82",
+ "version": "0.9.83-alpha.0",
"license": "MPL-2.0",
"module": "dist/budibase-client.js",
"main": "dist/budibase-client.js",
@@ -18,9 +18,9 @@
"dev:builder": "rollup -cw"
},
"dependencies": {
- "@budibase/bbui": "^0.9.82",
- "@budibase/standard-components": "^0.9.82",
- "@budibase/string-templates": "^0.9.82",
+ "@budibase/bbui": "^0.9.83-alpha.0",
+ "@budibase/standard-components": "^0.9.83-alpha.0",
+ "@budibase/string-templates": "^0.9.83-alpha.0",
"regexparam": "^1.3.0",
"shortid": "^2.2.15",
"svelte-spa-router": "^3.0.5"
diff --git a/packages/client/src/api/app.js b/packages/client/src/api/app.js
index 61c23ef6a6..c5ee305cda 100644
--- a/packages/client/src/api/app.js
+++ b/packages/client/src/api/app.js
@@ -3,8 +3,8 @@ import API from "./api"
/**
* Fetches screen definition for an app.
*/
-export const fetchAppDefinition = async appId => {
+export const fetchAppPackage = async appId => {
return await API.get({
- url: `/api/applications/${appId}/definition`,
+ url: `/api/applications/${appId}/appPackage`,
})
}
diff --git a/packages/client/src/components/ClientApp.svelte b/packages/client/src/components/ClientApp.svelte
index 014bea89b3..1076c0f568 100644
--- a/packages/client/src/components/ClientApp.svelte
+++ b/packages/client/src/components/ClientApp.svelte
@@ -13,6 +13,7 @@
authStore,
routeStore,
builderStore,
+ appStore,
} from "../store"
import { TableNames, ActionTypes } from "../constants"
import SettingsBar from "./preview/SettingsBar.svelte"
@@ -70,6 +71,9 @@
}
}
}
+
+ $: themeClass =
+ $builderStore.theme || $appStore.application?.theme || "spectrum--light"
{#if dataLoaded}
@@ -77,7 +81,7 @@
id="spectrum-root"
lang="en"
dir="ltr"
- class="spectrum spectrum--medium spectrum--light"
+ class="spectrum spectrum--medium {themeClass}"
>
{#if permissionError}
@@ -126,6 +130,28 @@
}
#app-root {
position: relative;
+ border: 1px solid var(--spectrum-global-color-gray-300);
+ }
+
+ /* Custom scrollbars */
+ :global(::-webkit-scrollbar) {
+ width: 8px;
+ height: 8px;
+ }
+ :global(::-webkit-scrollbar-track) {
+ background: var(--spectrum-alias-background-color-default);
+ }
+ :global(::-webkit-scrollbar-thumb) {
+ background-color: var(--spectrum-global-color-gray-400);
+ border-radius: 4px;
+ }
+ :global(::-webkit-scrollbar-corner) {
+ background: var(--spectrum-alias-background-color-default);
+ }
+ :global(*) {
+ scrollbar-width: thin;
+ scrollbar-color: var(--spectrum-global-color-gray-400)
+ var(--spectrum-alias-background-color-default);
}
.error {
diff --git a/packages/client/src/components/Component.svelte b/packages/client/src/components/Component.svelte
index 4440e83845..8c7437e523 100644
--- a/packages/client/src/components/Component.svelte
+++ b/packages/client/src/components/Component.svelte
@@ -8,11 +8,18 @@
import { hashString } from "../utils/hash"
import Manifest from "@budibase/standard-components/manifest.json"
import { Placeholder } from "@budibase/standard-components"
+ import {
+ getActiveConditions,
+ reduceConditionActions,
+ } from "../utils/conditions"
export let instance = {}
- // Props that will be passed to the component instance
- let componentProps
+ // The enriched component settings
+ let enrichedSettings
+
+ // Any prop overrides that need to be applied due to conditional UI
+ let conditionalSettings
// Props are hashed when inside the builder preview and used as a key, so that
// components fully remount whenever any props change
@@ -28,6 +35,9 @@
let lastContextKey
let lastInstanceKey
+ // Visibility flag used by conditional UI
+ let visible = true
+
// Get contexts
const context = getContext("context")
const insideScreenslot = !!getContext("screenslot")
@@ -54,6 +64,8 @@
$builderStore.inBuilder &&
$builderStore.selectedComponentId === instance._id
$: interactive = $builderStore.previewType === "layout" || insideScreenslot
+ $: evaluateConditions(enrichedSettings?._conditions)
+ $: componentSettings = { ...enrichedSettings, ...conditionalSettings }
// Update component context
$: componentStore.set({
@@ -62,14 +74,14 @@
styles: { ...instance._styles, id, empty, interactive },
empty,
selected,
- props: componentProps,
+ props: componentSettings,
name,
})
const getRawProps = instance => {
let validProps = {}
Object.entries(instance)
- .filter(([name]) => !name.startsWith("_"))
+ .filter(([name]) => name === "_conditions" || !name.startsWith("_"))
.forEach(([key, value]) => {
validProps[key] = value
})
@@ -123,34 +135,55 @@
return
}
let propsChanged = false
- if (!componentProps) {
- componentProps = {}
+ if (!enrichedSettings) {
+ enrichedSettings = {}
propsChanged = true
}
Object.keys(enrichedProps).forEach(key => {
- if (!propsAreSame(enrichedProps[key], componentProps[key])) {
+ if (!propsAreSame(enrichedProps[key], enrichedSettings[key])) {
propsChanged = true
- componentProps[key] = enrichedProps[key]
+ enrichedSettings[key] = enrichedProps[key]
}
})
// Update the hash if we're in the builder so we can fully remount this
// component
if (get(builderStore).inBuilder && propsChanged) {
- propsHash = hashString(JSON.stringify(componentProps))
+ propsHash = hashString(JSON.stringify(enrichedSettings))
}
}
+
+ const evaluateConditions = conditions => {
+ if (!conditions?.length) {
+ return
+ }
+
+ // Default visible to false if there is a show condition
+ let nextVisible = !conditions.find(condition => condition.action === "show")
+
+ // Execute conditions and determine settings and visibility changes
+ const activeConditions = getActiveConditions(conditions)
+ const result = reduceConditionActions(activeConditions)
+ if (result.visible != null) {
+ nextVisible = result.visible
+ }
+
+ // Update state from condition results
+ conditionalSettings = result.settingUpdates
+ visible = nextVisible
+ }
-
- {#key propsHash}
- {#if constructor && componentProps}
-
+{#key propsHash}
+ {#if constructor && componentSettings && visible}
+
+
{#if children.length}
{#each children as child (child._id)}
@@ -159,9 +192,9 @@
{/if}
- {/if}
- {/key}
-
+
+ {/if}
+{/key}
diff --git a/packages/client/src/index.js b/packages/client/src/index.js
index 66bbce2770..b7a303d9d8 100644
--- a/packages/client/src/index.js
+++ b/packages/client/src/index.js
@@ -1,5 +1,5 @@
import ClientApp from "./components/ClientApp.svelte"
-import { builderStore } from "./store"
+import { builderStore, appStore } from "./store"
let app
@@ -7,14 +7,18 @@ const loadBudibase = () => {
// Update builder store with any builder flags
builderStore.set({
inBuilder: !!window["##BUDIBASE_IN_BUILDER##"],
- appId: window["##BUDIBASE_APP_ID##"],
layout: window["##BUDIBASE_PREVIEW_LAYOUT##"],
screen: window["##BUDIBASE_PREVIEW_SCREEN##"],
selectedComponentId: window["##BUDIBASE_SELECTED_COMPONENT_ID##"],
previewId: window["##BUDIBASE_PREVIEW_ID##"],
previewType: window["##BUDIBASE_PREVIEW_TYPE##"],
+ theme: window["##BUDIBASE_PREVIEW_THEME##"],
})
+ // Set app ID - this window flag is set by both the preview and the real
+ // server rendered app HTML
+ appStore.actions.setAppID(window["##BUDIBASE_APP_ID##"])
+
// Create app if one hasn't been created yet
if (!app) {
app = new ClientApp({
diff --git a/packages/client/src/store/app.js b/packages/client/src/store/app.js
new file mode 100644
index 0000000000..0cabaec4ab
--- /dev/null
+++ b/packages/client/src/store/app.js
@@ -0,0 +1,34 @@
+import * as API from "../api"
+import { get, writable } from "svelte/store"
+
+const createAppStore = () => {
+ const store = writable({})
+
+ // Fetches the app definition including screens, layouts and theme
+ const fetchAppDefinition = async () => {
+ const appId = get(store)?.appId
+ if (!appId) {
+ throw "Cannot fetch app definition without app ID set"
+ }
+ const appDefinition = await API.fetchAppPackage(appId)
+ store.set({
+ ...appDefinition,
+ appId: appDefinition?.application?.appId,
+ })
+ }
+
+ // Sets the initial app ID
+ const setAppID = id => {
+ store.update(state => {
+ state.appId = id
+ return state
+ })
+ }
+
+ return {
+ subscribe: store.subscribe,
+ actions: { setAppID, fetchAppDefinition },
+ }
+}
+
+export const appStore = createAppStore()
diff --git a/packages/client/src/store/auth.js b/packages/client/src/store/auth.js
index 9829d2e350..1fa4ae17b0 100644
--- a/packages/client/src/store/auth.js
+++ b/packages/client/src/store/auth.js
@@ -1,31 +1,23 @@
import * as API from "../api"
-import { writable, get } from "svelte/store"
-import { builderStore } from "./builder"
-import { TableNames } from "../constants"
+import { writable } from "svelte/store"
const createAuthStore = () => {
const store = writable(null)
// Fetches the user object if someone is logged in and has reloaded the page
const fetchUser = async () => {
- // Fetch the first user if inside the builder
- if (get(builderStore).inBuilder) {
- const users = await API.fetchTableData(TableNames.USERS)
- if (!users.error && users[0] != null) {
- store.set(users[0])
- }
- }
+ const user = await API.fetchSelf()
+ store.set(user)
+ }
- // Or fetch the current user from localstorage in a real app
- else {
- const user = await API.fetchSelf()
- store.set(user)
- }
+ const logOut = async () => {
+ window.document.cookie = `budibase:auth=; budibase:currentapp=; Path=/; Expires=Thu, 01 Jan 1970 00:00:01 GMT;`
+ window.location = "/builder/auth/login"
}
return {
subscribe: store.subscribe,
- actions: { fetchUser },
+ actions: { fetchUser, logOut },
}
}
diff --git a/packages/client/src/store/index.js b/packages/client/src/store/index.js
index 9f2dbfdcfb..9a6c74e028 100644
--- a/packages/client/src/store/index.js
+++ b/packages/client/src/store/index.js
@@ -1,4 +1,5 @@
export { authStore } from "./auth"
+export { appStore } from "./app"
export { notificationStore } from "./notification"
export { routeStore } from "./routes"
export { screenStore } from "./screens"
diff --git a/packages/client/src/store/initialise.js b/packages/client/src/store/initialise.js
index 9e24439980..1900e62ce1 100644
--- a/packages/client/src/store/initialise.js
+++ b/packages/client/src/store/initialise.js
@@ -1,7 +1,7 @@
import { routeStore } from "./routes"
-import { screenStore } from "./screens"
+import { appStore } from "./app"
export async function initialise() {
await routeStore.actions.fetchRoutes()
- await screenStore.actions.fetchScreens()
+ await appStore.actions.fetchAppDefinition()
}
diff --git a/packages/client/src/store/screens.js b/packages/client/src/store/screens.js
index 46255d0822..367d9ecfea 100644
--- a/packages/client/src/store/screens.js
+++ b/packages/client/src/store/screens.js
@@ -1,16 +1,12 @@
-import { writable, derived, get } from "svelte/store"
+import { derived } from "svelte/store"
import { routeStore } from "./routes"
import { builderStore } from "./builder"
-import * as API from "../api"
+import { appStore } from "./app"
const createScreenStore = () => {
- const config = writable({
- screens: [],
- layouts: [],
- })
const store = derived(
- [config, routeStore, builderStore],
- ([$config, $routeStore, $builderStore]) => {
+ [appStore, routeStore, builderStore],
+ ([$appStore, $routeStore, $builderStore]) => {
let activeLayout, activeScreen
let layouts, screens
if ($builderStore.inBuilder) {
@@ -23,8 +19,8 @@ const createScreenStore = () => {
activeLayout = { props: { _component: "screenslot" } }
// Find the correct screen by matching the current route
- screens = $config.screens
- layouts = $config.layouts
+ screens = $appStore.screens
+ layouts = $appStore.layouts
if ($routeStore.activeRoute) {
activeScreen = screens.find(
screen => screen._id === $routeStore.activeRoute.screenId
@@ -40,17 +36,8 @@ const createScreenStore = () => {
}
)
- const fetchScreens = async () => {
- const appDefinition = await API.fetchAppDefinition(get(builderStore).appId)
- config.set({
- screens: appDefinition.screens,
- layouts: appDefinition.layouts,
- })
- }
-
return {
subscribe: store.subscribe,
- actions: { fetchScreens },
}
}
diff --git a/packages/client/src/utils/buttonActions.js b/packages/client/src/utils/buttonActions.js
index 9ad0a23616..98ba9dc214 100644
--- a/packages/client/src/utils/buttonActions.js
+++ b/packages/client/src/utils/buttonActions.js
@@ -1,10 +1,15 @@
import { get } from "svelte/store"
-import { routeStore, builderStore, confirmationStore } from "../store"
+import {
+ routeStore,
+ builderStore,
+ confirmationStore,
+ authStore,
+} from "../store"
import { saveRow, deleteRow, executeQuery, triggerAutomation } from "../api"
import { ActionTypes } from "../constants"
const saveRowHandler = async (action, context) => {
- const { fields, providerId } = action.parameters
+ const { fields, providerId, tableId } = action.parameters
if (providerId) {
let draft = context[providerId]
if (fields) {
@@ -12,6 +17,9 @@ const saveRowHandler = async (action, context) => {
draft[field] = value
}
}
+ if (tableId) {
+ draft.tableId = tableId
+ }
await saveRow(draft)
}
}
@@ -74,6 +82,10 @@ const refreshDatasourceHandler = async (action, context) => {
)
}
+const logoutHandler = async () => {
+ await authStore.actions.logOut()
+}
+
const handlerMap = {
["Save Row"]: saveRowHandler,
["Delete Row"]: deleteRowHandler,
@@ -82,6 +94,7 @@ const handlerMap = {
["Trigger Automation"]: triggerAutomationHandler,
["Validate Form"]: validateFormHandler,
["Refresh Datasource"]: refreshDatasourceHandler,
+ ["Log Out"]: logoutHandler,
}
const confirmTextMap = {
diff --git a/packages/client/src/utils/componentProps.js b/packages/client/src/utils/componentProps.js
index 65e86c28d6..5472c57308 100644
--- a/packages/client/src/utils/componentProps.js
+++ b/packages/client/src/utils/componentProps.js
@@ -43,5 +43,17 @@ export const enrichProps = (props, context) => {
)
}
+ // Enrich any click actions in conditions
+ if (enrichedProps._conditions) {
+ enrichedProps._conditions.forEach(condition => {
+ if (condition.setting === "onClick") {
+ condition.settingValue = enrichButtonActions(
+ condition.settingValue,
+ totalContext
+ )
+ }
+ })
+ }
+
return enrichedProps
}
diff --git a/packages/client/src/utils/conditions.js b/packages/client/src/utils/conditions.js
new file mode 100644
index 0000000000..9e4465cd5d
--- /dev/null
+++ b/packages/client/src/utils/conditions.js
@@ -0,0 +1,60 @@
+import {
+ buildLuceneQuery,
+ luceneQuery,
+} from "../../../standard-components/src/lucene"
+
+export const getActiveConditions = conditions => {
+ if (!conditions?.length) {
+ return []
+ }
+
+ return conditions.filter(condition => {
+ // Parse values into correct types
+ if (condition.valueType === "number") {
+ condition.referenceValue = parseFloat(condition.referenceValue)
+ condition.newValue = parseFloat(condition.newValue)
+ } else if (condition.valueType === "datetime") {
+ if (condition.referenceValue) {
+ condition.referenceValue = new Date(
+ condition.referenceValue
+ ).toISOString()
+ }
+ if (condition.newValue) {
+ condition.newValue = new Date(condition.newValue).toISOString()
+ }
+ } else if (condition.valueType === "boolean") {
+ condition.referenceValue =
+ `${condition.referenceValue}`.toLowerCase() === "true"
+ condition.newValue = `${condition.newValue}`.toLowerCase() === "true"
+ }
+
+ // Build lucene compatible condition expression
+ const luceneCondition = {
+ ...condition,
+ type: condition.valueType,
+ field: "newValue",
+ value: condition.referenceValue,
+ }
+
+ const query = buildLuceneQuery([luceneCondition])
+ const result = luceneQuery([luceneCondition], query)
+ return result.length > 0
+ })
+}
+
+export const reduceConditionActions = conditions => {
+ let settingUpdates = {}
+ let visible = null
+
+ conditions?.forEach(condition => {
+ if (condition.action === "show") {
+ visible = true
+ } else if (condition.action === "hide") {
+ visible = false
+ } else if (condition.setting) {
+ settingUpdates[condition.setting] = condition.settingValue
+ }
+ })
+
+ return { settingUpdates, visible }
+}
diff --git a/packages/client/src/utils/styleable.js b/packages/client/src/utils/styleable.js
index 3f02b36600..13eae2ea7f 100644
--- a/packages/client/src/utils/styleable.js
+++ b/packages/client/src/utils/styleable.js
@@ -29,7 +29,7 @@ export const styleable = (node, styles = {}) => {
// overridden by any user specified styles
let baseStyles = {}
if (newStyles.empty) {
- baseStyles.border = "2px dashed var(--grey-5)"
+ baseStyles.border = "2px dashed var(--spectrum-global-color-gray-600)"
baseStyles.padding = "var(--spacing-l)"
baseStyles.overflow = "hidden"
}
diff --git a/packages/server/.gitignore b/packages/server/.gitignore
index c737d00466..e8589f631d 100644
--- a/packages/server/.gitignore
+++ b/packages/server/.gitignore
@@ -2,6 +2,7 @@ node_modules/
myapps/
.env
builder/*
+client/*
public/
db/dev.db/
dist
diff --git a/packages/server/.vscode/launch.json b/packages/server/.vscode/launch.json
index 7417938376..a07cf96b80 100644
--- a/packages/server/.vscode/launch.json
+++ b/packages/server/.vscode/launch.json
@@ -5,10 +5,13 @@
"version": "0.2.0",
"configurations": [
{
+ "name": "Start Server",
"type": "node",
"request": "launch",
- "name": "Start Server",
- "program": "${workspaceFolder}/src/index.js"
+ "runtimeExecutable": "node",
+ "runtimeArgs": ["--nolazy", "-r", "ts-node/register/transpile-only"],
+ "args": ["src/index.ts"],
+ "cwd": "${workspaceRoot}",
},
{
"type": "node",
diff --git a/packages/server/nodemon.json b/packages/server/nodemon.json
new file mode 100644
index 0000000000..a5640776e4
--- /dev/null
+++ b/packages/server/nodemon.json
@@ -0,0 +1,6 @@
+{
+ "watch": ["src"],
+ "ext": "js,ts,json",
+ "ignore": ["src/**/*.spec.ts", "src/**/*.spec.js"],
+ "exec": "ts-node src/index.ts"
+}
\ No newline at end of file
diff --git a/packages/server/package.json b/packages/server/package.json
index 8e093259f5..ea308aa420 100644
--- a/packages/server/package.json
+++ b/packages/server/package.json
@@ -1,7 +1,7 @@
{
"name": "@budibase/server",
"email": "hi@budibase.com",
- "version": "0.9.82",
+ "version": "0.9.83-alpha.0",
"description": "Budibase Web Server",
"main": "src/index.js",
"repository": {
@@ -9,16 +9,17 @@
"url": "https://github.com/Budibase/budibase.git"
},
"scripts": {
- "build": "rm -rf dist/ && tsc && mv dist/src/* dist/ && rmdir dist/src/ && yarn postbuild",
+ "build": "rimraf dist/ && tsc && mv dist/src/* dist/ && rmdir dist/src/ && yarn postbuild",
"postbuild": "copyfiles -u 1 src/**/*.svelte dist/ && copyfiles -u 1 src/**/*.hbs dist/ && copyfiles -u 1 src/**/*.json dist/",
"test": "jest --coverage --maxWorkers=2",
"test:watch": "jest --watch",
- "build:docker": "docker build . -t app-service",
+ "predocker": "copyfiles -f ../client/dist/budibase-client.js ../standard-components/manifest.json client",
+ "build:docker": "yarn run predocker && docker build . -t app-service",
"run:docker": "node dist/index.js",
"dev:stack:up": "node scripts/dev/manage.js up",
"dev:stack:down": "node scripts/dev/manage.js down",
"dev:stack:nuke": "node scripts/dev/manage.js nuke",
- "dev:builder": "yarn run dev:stack:up && ts-node src/index.ts",
+ "dev:builder": "yarn run dev:stack:up && nodemon",
"format": "prettier --config ../../.prettierrc.json 'src/**/*.ts' --write",
"lint": "eslint --fix src/",
"lint:fix": "yarn run format && yarn run lint",
@@ -59,9 +60,9 @@
"author": "Budibase",
"license": "AGPL-3.0-or-later",
"dependencies": {
- "@budibase/auth": "^0.9.82",
- "@budibase/client": "^0.9.82",
- "@budibase/string-templates": "^0.9.82",
+ "@budibase/auth": "^0.9.83-alpha.0",
+ "@budibase/client": "^0.9.83-alpha.0",
+ "@budibase/string-templates": "^0.9.83-alpha.0",
"@elastic/elasticsearch": "7.10.0",
"@koa/router": "8.0.0",
"@sendgrid/mail": "7.1.1",
@@ -114,7 +115,7 @@
"devDependencies": {
"@babel/core": "^7.14.3",
"@babel/preset-env": "^7.14.4",
- "@budibase/standard-components": "^0.9.82",
+ "@budibase/standard-components": "^0.9.83-alpha.0",
"@jest/test-sequencer": "^24.8.0",
"@types/bull": "^3.15.1",
"@types/jest": "^26.0.23",
@@ -131,6 +132,7 @@
"nodemon": "^2.0.4",
"pouchdb-adapter-memory": "^7.2.1",
"prettier": "^2.3.1",
+ "rimraf": "^3.0.2",
"supertest": "^4.0.2",
"ts-jest": "^27.0.3",
"ts-node": "^10.0.0",
diff --git a/packages/server/scripts/integrations/mysql/init.sql b/packages/server/scripts/integrations/mysql/init.sql
index 3ffe84cd7d..4dd75c36d3 100644
--- a/packages/server/scripts/integrations/mysql/init.sql
+++ b/packages/server/scripts/integrations/mysql/init.sql
@@ -1,9 +1,24 @@
CREATE DATABASE IF NOT EXISTS main;
USE main;
CREATE TABLE Persons (
- PersonID int NOT NULL PRIMARY KEY,
+ PersonID int NOT NULL AUTO_INCREMENT,
+ CreatedAt datetime,
+ Age float,
LastName varchar(255),
FirstName varchar(255),
Address varchar(255),
- City varchar(255)
+ City varchar(255),
+ PRIMARY KEY (PersonID)
);
+CREATE TABLE Tasks (
+ TaskID int NOT NULL AUTO_INCREMENT,
+ PersonID INT,
+ TaskName varchar(255),
+ PRIMARY KEY (TaskID),
+ CONSTRAINT fkPersons
+ FOREIGN KEY(PersonID)
+ REFERENCES Persons(PersonID)
+);
+INSERT INTO Persons (FirstName, LastName, Age, Address, City, CreatedAt) VALUES ('Mike', 'Hughes', 28.2, '123 Fake Street', 'Belfast', '2021-01-19 03:14:07');
+INSERT INTO Tasks (PersonID, TaskName) VALUES (1, 'assembling');
+INSERT INTO Tasks (PersonID, TaskName) VALUES (1, 'processing');
diff --git a/packages/server/scripts/integrations/mysql/reset.sh b/packages/server/scripts/integrations/mysql/reset.sh
new file mode 100755
index 0000000000..32778bd11f
--- /dev/null
+++ b/packages/server/scripts/integrations/mysql/reset.sh
@@ -0,0 +1,3 @@
+#!/bin/bash
+docker-compose down
+docker volume prune -f
diff --git a/packages/server/scripts/integrations/postgres/init.sql b/packages/server/scripts/integrations/postgres/init.sql
index 8d76f54a10..5a99520c1e 100644
--- a/packages/server/scripts/integrations/postgres/init.sql
+++ b/packages/server/scripts/integrations/postgres/init.sql
@@ -1,17 +1,42 @@
SELECT 'CREATE DATABASE main'
WHERE NOT EXISTS (SELECT FROM pg_database WHERE datname = 'main')\gexec
CREATE TABLE Persons (
- PersonID INT NOT NULL PRIMARY KEY,
+ PersonID SERIAL PRIMARY KEY,
LastName varchar(255),
FirstName varchar(255),
Address varchar(255),
- City varchar(255)
+ City varchar(255) DEFAULT 'Belfast'
);
CREATE TABLE Tasks (
- TaskID INT NOT NULL PRIMARY KEY,
+ TaskID SERIAL PRIMARY KEY,
PersonID INT,
TaskName varchar(255),
CONSTRAINT fkPersons
FOREIGN KEY(PersonID)
REFERENCES Persons(PersonID)
);
+CREATE TABLE Products (
+ ProductID SERIAL PRIMARY KEY,
+ ProductName varchar(255)
+);
+CREATE TABLE Products_Tasks (
+ ProductID INT NOT NULL,
+ TaskID INT NOT NULL,
+ CONSTRAINT fkProducts
+ FOREIGN KEY(ProductID)
+ REFERENCES Products(ProductID),
+ CONSTRAINT fkTasks
+ FOREIGN KEY(TaskID)
+ REFERENCES Tasks(TaskID),
+ PRIMARY KEY (ProductID, TaskID)
+);
+INSERT INTO Persons (FirstName, LastName, Address, City) VALUES ('Mike', 'Hughes', '123 Fake Street', 'Belfast');
+INSERT INTO Tasks (PersonID, TaskName) VALUES (1, 'assembling');
+INSERT INTO Tasks (PersonID, TaskName) VALUES (1, 'processing');
+INSERT INTO Products (ProductName) VALUES ('Computers');
+INSERT INTO Products (ProductName) VALUES ('Laptops');
+INSERT INTO Products (ProductName) VALUES ('Chairs');
+INSERT INTO Products_Tasks (ProductID, TaskID) VALUES (1, 1);
+INSERT INTO Products_Tasks (ProductID, TaskID) VALUES (2, 1);
+INSERT INTO Products_Tasks (ProductID, TaskID) VALUES (3, 1);
+INSERT INTO Products_Tasks (ProductID, TaskID) VALUES (1, 2);
diff --git a/packages/server/scripts/integrations/postgres/reset.sh b/packages/server/scripts/integrations/postgres/reset.sh
new file mode 100755
index 0000000000..32778bd11f
--- /dev/null
+++ b/packages/server/scripts/integrations/postgres/reset.sh
@@ -0,0 +1,3 @@
+#!/bin/bash
+docker-compose down
+docker volume prune -f
diff --git a/packages/server/src/api/controllers/application.js b/packages/server/src/api/controllers/application.js
index 7db8bacd0b..a2e254461a 100644
--- a/packages/server/src/api/controllers/application.js
+++ b/packages/server/src/api/controllers/application.js
@@ -33,6 +33,11 @@ const {
} = require("../../utilities/workerRequests")
const { clientLibraryPath } = require("../../utilities")
const { getAllLocks } = require("../../utilities/redis")
+const {
+ updateClientLibrary,
+ backupClientLibrary,
+ revertClientLibrary,
+} = require("../../utilities/fileSystem/clientLibrary")
const URL_REGEX_SLASH = /\/|\\/g
@@ -67,15 +72,18 @@ async function getAppUrlIfNotInUse(ctx) {
let url
if (ctx.request.body.url) {
url = encodeURI(ctx.request.body.url)
- } else {
+ } else if (ctx.request.body.name) {
url = encodeURI(`${ctx.request.body.name}`)
}
- url = `/${url.replace(URL_REGEX_SLASH, "")}`.toLowerCase()
+ if (url) {
+ url = `/${url.replace(URL_REGEX_SLASH, "")}`.toLowerCase()
+ }
if (!env.SELF_HOSTED) {
return url
}
const deployedApps = await getDeployedApps(ctx)
if (
+ url &&
deployedApps[url] != null &&
deployedApps[url].appId !== ctx.params.appId
) {
@@ -161,7 +169,15 @@ exports.fetchAppDefinition = async function (ctx) {
exports.fetchAppPackage = async function (ctx) {
const db = new CouchDB(ctx.params.appId)
const application = await db.get(DocumentTypes.APP_METADATA)
- const [layouts, screens] = await Promise.all([getLayouts(db), getScreens(db)])
+ const layouts = await getLayouts(db)
+ let screens = await getScreens(db)
+
+ // Only filter screens if the user is not a builder
+ if (!(ctx.user.builder && ctx.user.builder.global)) {
+ const userRoleId = getUserRoleId(ctx)
+ const accessController = new AccessController(ctx.params.appId)
+ screens = await accessController.checkScreensAccess(screens, userRoleId)
+ }
ctx.body = {
application,
@@ -220,27 +236,54 @@ exports.create = async function (ctx) {
}
exports.update = async function (ctx) {
- const url = await getAppUrlIfNotInUse(ctx)
+ const data = await updateAppPackage(ctx, ctx.request.body, ctx.params.appId)
+ ctx.status = 200
+ ctx.body = data
+}
+
+exports.updateClient = async function (ctx) {
+ // Get current app version
const db = new CouchDB(ctx.params.appId)
const application = await db.get(DocumentTypes.APP_METADATA)
+ const currentVersion = application.version
- const data = ctx.request.body
- const newData = { ...application, ...data, url }
- if (ctx.request.body._rev !== application._rev) {
- newData._rev = application._rev
+ // Update client library and manifest
+ if (!env.isTest()) {
+ await backupClientLibrary(ctx.params.appId)
+ await updateClientLibrary(ctx.params.appId)
}
- // the locked by property is attached by server but generated from
- // Redis, shouldn't ever store it
- if (newData.lockedBy) {
- delete newData.lockedBy
+ // Update versions in app package
+ const appPackageUpdates = {
+ version: packageJson.version,
+ revertableVersion: currentVersion,
}
-
- const response = await db.put(newData)
- data._rev = response.rev
-
+ const data = await updateAppPackage(ctx, appPackageUpdates, ctx.params.appId)
ctx.status = 200
- ctx.body = response
+ ctx.body = data
+}
+
+exports.revertClient = async function (ctx) {
+ // Check app can be reverted
+ const db = new CouchDB(ctx.params.appId)
+ const application = await db.get(DocumentTypes.APP_METADATA)
+ if (!application.revertableVersion) {
+ ctx.throw(400, "There is no version to revert to")
+ }
+
+ // Update client library and manifest
+ if (!env.isTest()) {
+ await revertClientLibrary(ctx.params.appId)
+ }
+
+ // Update versions in app package
+ const appPackageUpdates = {
+ version: application.revertableVersion,
+ revertableVersion: null,
+ }
+ const data = await updateAppPackage(ctx, appPackageUpdates, ctx.params.appId)
+ ctx.status = 200
+ ctx.body = data
}
exports.delete = async function (ctx) {
@@ -258,6 +301,23 @@ exports.delete = async function (ctx) {
ctx.body = result
}
+const updateAppPackage = async (ctx, appPackage, appId) => {
+ const url = await getAppUrlIfNotInUse(ctx)
+ const db = new CouchDB(appId)
+ const application = await db.get(DocumentTypes.APP_METADATA)
+
+ const newAppPackage = { ...application, ...appPackage, url }
+ if (appPackage._rev !== application._rev) {
+ newAppPackage._rev = application._rev
+ }
+
+ // the locked by property is attached by server but generated from
+ // Redis, shouldn't ever store it
+ delete newAppPackage.lockedBy
+
+ return await db.put(newAppPackage)
+}
+
const createEmptyAppPackage = async (ctx, app) => {
const db = new CouchDB(app.appId)
diff --git a/packages/server/src/api/controllers/component.js b/packages/server/src/api/controllers/component.js
index c678d8e587..06cb2cd211 100644
--- a/packages/server/src/api/controllers/component.js
+++ b/packages/server/src/api/controllers/component.js
@@ -20,10 +20,14 @@ exports.fetchAppComponentDefinitions = async function (ctx) {
const definitions = {}
for (let { manifest, library } of componentManifests) {
for (let key of Object.keys(manifest)) {
- const fullComponentName = `${library}/${key}`.toLowerCase()
- definitions[fullComponentName] = {
- component: fullComponentName,
- ...manifest[key],
+ if (key === "features") {
+ definitions[key] = manifest[key]
+ } else {
+ const fullComponentName = `${library}/${key}`.toLowerCase()
+ definitions[fullComponentName] = {
+ component: fullComponentName,
+ ...manifest[key],
+ }
}
}
}
diff --git a/packages/server/src/api/controllers/datasource.js b/packages/server/src/api/controllers/datasource.js
index b6d25b7b83..dabd5a6e96 100644
--- a/packages/server/src/api/controllers/datasource.js
+++ b/packages/server/src/api/controllers/datasource.js
@@ -48,7 +48,7 @@ exports.buildSchemaFromDb = async function (ctx) {
// Connect to the DB and build the schema
const connector = new Connector(datasource.config)
- await connector.buildSchema(datasource._id)
+ await connector.buildSchema(datasource._id, datasource.entities)
datasource.entities = connector.tables
const response = await db.post(datasource)
diff --git a/packages/server/src/api/controllers/row/ExternalRequest.ts b/packages/server/src/api/controllers/row/ExternalRequest.ts
new file mode 100644
index 0000000000..c5fad441bf
--- /dev/null
+++ b/packages/server/src/api/controllers/row/ExternalRequest.ts
@@ -0,0 +1,525 @@
+import {
+ Operation,
+ SearchFilters,
+ SortJson,
+ PaginationJson,
+ RelationshipsJson,
+} from "../../../definitions/datasource"
+import {
+ Row,
+ Table,
+ FieldSchema,
+ Datasource,
+} from "../../../definitions/common"
+import {
+ breakRowIdField,
+ generateRowIdField,
+} from "../../../integrations/utils"
+
+interface ManyRelationship {
+ tableId?: string
+ id?: string
+ isUpdate?: boolean
+ [key: string]: any
+}
+
+interface RunConfig {
+ id: string
+ row: Row
+ filters: SearchFilters
+ sort: SortJson
+ paginate: PaginationJson
+}
+
+module External {
+ const { makeExternalQuery } = require("./utils")
+ const { DataSourceOperation, FieldTypes } = require("../../../constants")
+ const { breakExternalTableId, isSQL } = require("../../../integrations/utils")
+ const { processObjectSync } = require("@budibase/string-templates")
+ const { cloneDeep } = require("lodash/fp")
+ const { isEqual } = require("lodash")
+ const CouchDB = require("../../../db")
+
+ function buildFilters(
+ id: string | undefined,
+ filters: SearchFilters,
+ table: Table
+ ) {
+ const primary = table.primary
+ // if passed in array need to copy for shifting etc
+ let idCopy = cloneDeep(id)
+ if (filters) {
+ // need to map over the filters and make sure the _id field isn't present
+ for (let filter of Object.values(filters)) {
+ if (filter._id && primary) {
+ const parts = breakRowIdField(filter._id)
+ for (let field of primary) {
+ filter[field] = parts.shift()
+ }
+ }
+ // make sure this field doesn't exist on any filter
+ delete filter._id
+ }
+ }
+ // there is no id, just use the user provided filters
+ if (!idCopy || !table) {
+ return filters
+ }
+ // if used as URL parameter it will have been joined
+ if (!Array.isArray(idCopy)) {
+ idCopy = breakRowIdField(idCopy)
+ }
+ const equal: any = {}
+ if (primary && idCopy) {
+ for (let field of primary) {
+ // work through the ID and get the parts
+ equal[field] = idCopy.shift()
+ }
+ }
+ return {
+ equal,
+ }
+ }
+
+ function generateIdForRow(row: Row, table: Table): string {
+ const primary = table.primary
+ if (!row || !primary) {
+ return ""
+ }
+ // build id array
+ let idParts = []
+ for (let field of primary) {
+ if (row[field]) {
+ idParts.push(row[field])
+ }
+ }
+ if (idParts.length === 0) {
+ return ""
+ }
+ return generateRowIdField(idParts)
+ }
+
+ function getEndpoint(tableId: string | undefined, operation: string) {
+ if (!tableId) {
+ return {}
+ }
+ const { datasourceId, tableName } = breakExternalTableId(tableId)
+ return {
+ datasourceId,
+ entityId: tableName,
+ operation,
+ }
+ }
+
+ function basicProcessing(row: Row, table: Table) {
+ const thisRow: { [key: string]: any } = {}
+ // filter the row down to what is actually the row (not joined)
+ for (let fieldName of Object.keys(table.schema)) {
+ thisRow[fieldName] = row[fieldName]
+ }
+ thisRow._id = generateIdForRow(row, table)
+ thisRow.tableId = table._id
+ thisRow._rev = "rev"
+ return thisRow
+ }
+
+ function isMany(field: FieldSchema) {
+ return (
+ field.relationshipType && field.relationshipType.split("-")[0] === "many"
+ )
+ }
+
+ class ExternalRequest {
+ private readonly appId: string
+ private operation: Operation
+ private tableId: string
+ private datasource: Datasource
+ private tables: { [key: string]: Table } = {}
+
+ constructor(
+ appId: string,
+ operation: Operation,
+ tableId: string,
+ datasource: Datasource
+ ) {
+ this.appId = appId
+ this.operation = operation
+ this.tableId = tableId
+ this.datasource = datasource
+ if (datasource && datasource.entities) {
+ this.tables = datasource.entities
+ }
+ }
+
+ inputProcessing(row: Row, table: Table) {
+ if (!row) {
+ return { row, manyRelationships: [] }
+ }
+ // we don't really support composite keys for relationships, this is why [0] is used
+ // @ts-ignore
+ const tablePrimary: string = table.primary[0]
+ let newRow: Row = {},
+ manyRelationships: ManyRelationship[] = []
+ for (let [key, field] of Object.entries(table.schema)) {
+ // if set already, or not set just skip it
+ if (!row[key] || newRow[key] || field.autocolumn) {
+ continue
+ }
+ // if its not a link then just copy it over
+ if (field.type !== FieldTypes.LINK) {
+ newRow[key] = row[key]
+ continue
+ }
+ const { tableName: linkTableName } = breakExternalTableId(field.tableId)
+ // table has to exist for many to many
+ if (!this.tables[linkTableName]) {
+ continue
+ }
+ const linkTable = this.tables[linkTableName]
+ // @ts-ignore
+ const linkTablePrimary = linkTable.primary[0]
+ if (!isMany(field)) {
+ newRow[field.foreignKey || linkTablePrimary] = breakRowIdField(
+ row[key][0]
+ )[0]
+ } else {
+ // we're not inserting a doc, will be a bunch of update calls
+ const isUpdate = !field.through
+ const thisKey: string = isUpdate ? "id" : linkTablePrimary
+ // @ts-ignore
+ const otherKey: string = isUpdate ? field.foreignKey : tablePrimary
+ row[key].map((relationship: any) => {
+ // we don't really support composite keys for relationships, this is why [0] is used
+ manyRelationships.push({
+ tableId: field.through || field.tableId,
+ isUpdate,
+ [thisKey]: breakRowIdField(relationship)[0],
+ // leave the ID for enrichment later
+ [otherKey]: `{{ literal ${tablePrimary} }}`,
+ })
+ })
+ }
+ }
+ // we return the relationships that may need to be created in the through table
+ // we do this so that if the ID is generated by the DB it can be inserted
+ // after the fact
+ return { row: newRow, manyRelationships }
+ }
+
+ /**
+ * This iterates through the returned rows and works out what elements of the rows
+ * actually match up to another row (based on primary keys) - this is pretty specific
+ * to SQL and the way that SQL relationships are returned based on joins.
+ */
+ updateRelationshipColumns(
+ row: Row,
+ rows: { [key: string]: Row },
+ relationships: RelationshipsJson[]
+ ) {
+ const columns: { [key: string]: any } = {}
+ for (let relationship of relationships) {
+ const linkedTable = this.tables[relationship.tableName]
+ if (!linkedTable) {
+ continue
+ }
+ let linked = basicProcessing(row, linkedTable)
+ if (!linked._id) {
+ continue
+ }
+ // if not returning full docs then get the minimal links out
+ const display = linkedTable.primaryDisplay
+ linked = {
+ primaryDisplay: display ? linked[display] : undefined,
+ _id: linked._id,
+ }
+ columns[relationship.column] = linked
+ }
+ for (let [column, related] of Object.entries(columns)) {
+ if (!row._id) {
+ continue
+ }
+ const rowId: string = row._id
+ if (!Array.isArray(rows[rowId][column])) {
+ rows[rowId][column] = []
+ }
+ // make sure relationship hasn't been found already
+ if (
+ !rows[rowId][column].find(
+ (relation: Row) => relation._id === related._id
+ )
+ ) {
+ rows[rowId][column].push(related)
+ }
+ }
+ return rows
+ }
+
+ outputProcessing(
+ rows: Row[],
+ table: Table,
+ relationships: RelationshipsJson[]
+ ) {
+ if (rows[0].read === true) {
+ return []
+ }
+ let finalRows: { [key: string]: Row } = {}
+ for (let row of rows) {
+ const rowId = generateIdForRow(row, table)
+ row._id = rowId
+ // this is a relationship of some sort
+ if (finalRows[rowId]) {
+ finalRows = this.updateRelationshipColumns(
+ row,
+ finalRows,
+ relationships
+ )
+ continue
+ }
+ const thisRow = basicProcessing(row, table)
+ finalRows[thisRow._id] = thisRow
+ // do this at end once its been added to the final rows
+ finalRows = this.updateRelationshipColumns(
+ row,
+ finalRows,
+ relationships
+ )
+ }
+ return Object.values(finalRows)
+ }
+
+ /**
+ * Gets the list of relationship JSON structures based on the columns in the table,
+ * this will be used by the underlying library to build whatever relationship mechanism
+ * it has (e.g. SQL joins).
+ */
+ buildRelationships(table: Table): RelationshipsJson[] {
+ const relationships = []
+ for (let [fieldName, field] of Object.entries(table.schema)) {
+ if (field.type !== FieldTypes.LINK) {
+ continue
+ }
+ const { tableName: linkTableName } = breakExternalTableId(field.tableId)
+ // no table to link to, this is not a valid relationships
+ if (!this.tables[linkTableName]) {
+ continue
+ }
+ const linkTable = this.tables[linkTableName]
+ if (!table.primary || !linkTable.primary) {
+ continue
+ }
+ const definition = {
+ // if no foreign key specified then use the name of the field in other table
+ from: field.foreignKey || table.primary[0],
+ to: field.fieldName,
+ tableName: linkTableName,
+ through: undefined,
+ // need to specify where to put this back into
+ column: fieldName,
+ }
+ if (field.through) {
+ const { tableName: throughTableName } = breakExternalTableId(
+ field.through
+ )
+ definition.through = throughTableName
+ // don't support composite keys for relationships
+ definition.from = table.primary[0]
+ definition.to = linkTable.primary[0]
+ }
+ relationships.push(definition)
+ }
+ return relationships
+ }
+
+ /**
+ * This is a cached lookup, of relationship records, this is mainly for creating/deleting junction
+ * information.
+ */
+ async lookup(
+ row: Row,
+ relationship: ManyRelationship,
+ cache: { [key: string]: Row[] } = {}
+ ) {
+ const { tableId, isUpdate, id, ...rest } = relationship
+ const { tableName } = breakExternalTableId(tableId)
+ const table = this.tables[tableName]
+ if (isUpdate) {
+ return { rows: [], table }
+ }
+ // if not updating need to make sure we have a list of all possible options
+ let fullKey: string = tableId + "/",
+ rowKey: string = ""
+ for (let key of Object.keys(rest)) {
+ if (row[key]) {
+ fullKey += key
+ rowKey = key
+ }
+ }
+ if (cache[fullKey] == null) {
+ cache[fullKey] = await makeExternalQuery(this.appId, {
+ endpoint: getEndpoint(tableId, DataSourceOperation.READ),
+ filters: {
+ equal: {
+ [rowKey]: row[rowKey],
+ },
+ },
+ })
+ }
+ return { rows: cache[fullKey], table }
+ }
+
+ /**
+ * Once a row has been written we may need to update a many field, e.g. updating foreign keys
+ * in a bunch of rows in another table, or inserting/deleting rows from a junction table (many to many).
+ * This is quite a complex process and is handled by this function, there are a few things going on here:
+ * 1. If updating foreign keys its relatively simple, just create a filter for the row that needs updated
+ * and write the various components.
+ * 2. If junction table, then we lookup what exists already, write what doesn't exist, work out what
+ * isn't supposed to exist anymore and delete those. This is better than the usual method of delete them
+ * all and then re-create, as theres no chance of losing data (e.g. delete succeed, but write fail).
+ */
+ async handleManyRelationships(row: Row, relationships: ManyRelationship[]) {
+ const { appId } = this
+ if (relationships.length === 0) {
+ return
+ }
+ // if we're creating (in a through table) need to wipe the existing ones first
+ const promises = []
+ const cache: { [key: string]: Row[] } = {}
+ for (let relationship of relationships) {
+ const { tableId, isUpdate, id, ...rest } = relationship
+ const body = processObjectSync(rest, row)
+ const { table, rows } = await this.lookup(row, relationship, cache)
+ const found = rows.find(row => isEqual(body, row))
+ const operation = isUpdate
+ ? DataSourceOperation.UPDATE
+ : DataSourceOperation.CREATE
+ if (!found) {
+ promises.push(
+ makeExternalQuery(appId, {
+ endpoint: getEndpoint(tableId, operation),
+ // if we're doing many relationships then we're writing, only one response
+ body,
+ filters: buildFilters(id, {}, table),
+ })
+ )
+ } else {
+ // remove the relationship from the rows
+ rows.splice(rows.indexOf(found), 1)
+ }
+ }
+ // finally if creating, cleanup any rows that aren't supposed to be here
+ for (let [key, rows] of Object.entries(cache)) {
+ // @ts-ignore
+ const tableId: string = key.split("/").shift()
+ const { tableName } = breakExternalTableId(tableId)
+ const table = this.tables[tableName]
+ for (let row of rows) {
+ promises.push(
+ makeExternalQuery(this.appId, {
+ endpoint: getEndpoint(tableId, DataSourceOperation.DELETE),
+ filters: buildFilters(generateIdForRow(row, table), {}, table),
+ })
+ )
+ }
+ }
+ await Promise.all(promises)
+ }
+
+ /**
+ * This function is a bit crazy, but the exact purpose of it is to protect against the scenario in which
+ * you have column overlap in relationships, e.g. we join a few different tables and they all have the
+ * concept of an ID, but for some of them it will be null (if they say don't have a relationship).
+ * Creating the specific list of fields that we desire, and excluding the ones that are no use to us
+ * is more performant and has the added benefit of protecting against this scenario.
+ */
+ buildFields(table: Table) {
+ function extractNonLinkFieldNames(table: Table, existing: string[] = []) {
+ return Object.entries(table.schema)
+ .filter(
+ column =>
+ column[1].type !== FieldTypes.LINK &&
+ !existing.find((field: string) => field.includes(column[0]))
+ )
+ .map(column => `${table.name}.${column[0]}`)
+ }
+ let fields = extractNonLinkFieldNames(table)
+ for (let field of Object.values(table.schema)) {
+ if (field.type !== FieldTypes.LINK) {
+ continue
+ }
+ const { tableName: linkTableName } = breakExternalTableId(field.tableId)
+ const linkTable = this.tables[linkTableName]
+ if (linkTable) {
+ const linkedFields = extractNonLinkFieldNames(linkTable, fields)
+ fields = fields.concat(linkedFields)
+ }
+ }
+ return fields
+ }
+
+ async run({ id, row, filters, sort, paginate }: RunConfig) {
+ const { appId, operation, tableId } = this
+ let { datasourceId, tableName } = breakExternalTableId(tableId)
+ if (!this.datasource) {
+ const db = new CouchDB(appId)
+ this.datasource = await db.get(datasourceId)
+ if (!this.datasource || !this.datasource.entities) {
+ throw "No tables found, fetch tables before query."
+ }
+ this.tables = this.datasource.entities
+ }
+ const table = this.tables[tableName]
+ let isSql = isSQL(this.datasource)
+ if (!table) {
+ throw `Unable to process query, table "${tableName}" not defined.`
+ }
+ // clean up row on ingress using schema
+ filters = buildFilters(id, filters, table)
+ const relationships = this.buildRelationships(table)
+ const processed = this.inputProcessing(row, table)
+ row = processed.row
+ if (
+ operation === DataSourceOperation.DELETE &&
+ (filters == null || Object.keys(filters).length === 0)
+ ) {
+ throw "Deletion must be filtered"
+ }
+ let json = {
+ endpoint: {
+ datasourceId,
+ entityId: tableName,
+ operation,
+ },
+ resource: {
+ // have to specify the fields to avoid column overlap (for SQL)
+ fields: isSql ? this.buildFields(table) : [],
+ },
+ filters,
+ sort,
+ paginate,
+ relationships,
+ body: row,
+ // pass an id filter into extra, purely for mysql/returning
+ extra: {
+ idFilter: buildFilters(id || generateIdForRow(row, table), {}, table),
+ },
+ }
+ // can't really use response right now
+ const response = await makeExternalQuery(appId, json)
+ // handle many to many relationships now if we know the ID (could be auto increment)
+ if (processed.manyRelationships) {
+ await this.handleManyRelationships(
+ response[0],
+ processed.manyRelationships
+ )
+ }
+ const output = this.outputProcessing(response, table, relationships)
+ // if reading it'll just be an array of rows, return whole thing
+ return operation === DataSourceOperation.READ && Array.isArray(response)
+ ? output
+ : { row: output[0], table }
+ }
+ }
+
+ module.exports = ExternalRequest
+}
diff --git a/packages/server/src/api/controllers/row/external.js b/packages/server/src/api/controllers/row/external.js
index 896f5a78e2..3a96064a9f 100644
--- a/packages/server/src/api/controllers/row/external.js
+++ b/packages/server/src/api/controllers/row/external.js
@@ -1,136 +1,19 @@
-const { makeExternalQuery } = require("./utils")
-const { DataSourceOperation, SortDirection } = require("../../../constants")
-const { getExternalTable } = require("../table/utils")
+const {
+ DataSourceOperation,
+ SortDirection,
+ FieldTypes,
+} = require("../../../constants")
const {
breakExternalTableId,
- generateRowIdField,
breakRowIdField,
} = require("../../../integrations/utils")
-const { cloneDeep } = require("lodash/fp")
+const ExternalRequest = require("./ExternalRequest")
+const CouchDB = require("../../../db")
-function inputProcessing(row, table) {
- if (!row) {
- return row
- }
- let newRow = {}
- for (let key of Object.keys(table.schema)) {
- // currently excludes empty strings
- if (row[key]) {
- newRow[key] = row[key]
- }
- }
- return newRow
-}
-
-function generateIdForRow(row, table) {
- if (!row) {
- return
- }
- const primary = table.primary
- // build id array
- let idParts = []
- for (let field of primary) {
- idParts.push(row[field])
- }
- return generateRowIdField(idParts)
-}
-
-function outputProcessing(rows, table) {
- // if no rows this is what is returned? Might be PG only
- if (rows[0].read === true) {
- return []
- }
- for (let row of rows) {
- row._id = generateIdForRow(row, table)
- row.tableId = table._id
- row._rev = "rev"
- }
- return rows
-}
-
-function buildFilters(id, filters, table) {
- const primary = table.primary
- // if passed in array need to copy for shifting etc
- let idCopy = cloneDeep(id)
- if (filters) {
- // need to map over the filters and make sure the _id field isn't present
- for (let filter of Object.values(filters)) {
- if (filter._id) {
- const parts = breakRowIdField(filter._id)
- for (let field of primary) {
- filter[field] = parts.shift()
- }
- }
- // make sure this field doesn't exist on any filter
- delete filter._id
- }
- }
- // there is no id, just use the user provided filters
- if (!idCopy || !table) {
- return filters
- }
- // if used as URL parameter it will have been joined
- if (typeof idCopy === "string") {
- idCopy = breakRowIdField(idCopy)
- }
- const equal = {}
- for (let field of primary) {
- // work through the ID and get the parts
- equal[field] = idCopy.shift()
- }
- return {
- equal,
- }
-}
-
-async function handleRequest(
- appId,
- operation,
- tableId,
- { id, row, filters, sort, paginate } = {}
-) {
- let { datasourceId, tableName } = breakExternalTableId(tableId)
- const table = await getExternalTable(appId, datasourceId, tableName)
- if (!table) {
- throw `Unable to process query, table "${tableName}" not defined.`
- }
- // clean up row on ingress using schema
- filters = buildFilters(id, filters, table)
- row = inputProcessing(row, table)
- if (
- operation === DataSourceOperation.DELETE &&
- (filters == null || Object.keys(filters).length === 0)
- ) {
- throw "Deletion must be filtered"
- }
- let json = {
- endpoint: {
- datasourceId,
- entityId: tableName,
- operation,
- },
- resource: {
- // not specifying any fields means "*"
- fields: [],
- },
- filters,
- sort,
- paginate,
- body: row,
- // pass an id filter into extra, purely for mysql/returning
- extra: {
- idFilter: buildFilters(id || generateIdForRow(row, table), {}, table),
- },
- }
- // can't really use response right now
- const response = await makeExternalQuery(appId, json)
- // we searched for rows in someway
- if (operation === DataSourceOperation.READ && Array.isArray(response)) {
- return outputProcessing(response, table)
- } else {
- row = outputProcessing(response, table)[0]
- return { row, table }
- }
+async function handleRequest(appId, operation, tableId, opts = {}) {
+ return new ExternalRequest(appId, operation, tableId, opts.datasource).run(
+ opts
+ )
}
exports.patch = async ctx => {
@@ -172,9 +55,15 @@ exports.find = async ctx => {
const appId = ctx.appId
const id = ctx.params.rowId
const tableId = ctx.params.tableId
- return handleRequest(appId, DataSourceOperation.READ, tableId, {
- id,
- })
+ const response = await handleRequest(
+ appId,
+ DataSourceOperation.READ,
+ tableId,
+ {
+ id,
+ }
+ )
+ return response ? response[0] : response
}
exports.destroy = async ctx => {
@@ -270,7 +159,56 @@ exports.validate = async () => {
return { valid: true }
}
-exports.fetchEnrichedRow = async () => {
- // TODO: How does this work
- throw "Not Implemented"
+exports.fetchEnrichedRow = async ctx => {
+ const appId = ctx.appId
+ const id = ctx.params.rowId
+ const tableId = ctx.params.tableId
+ const { datasourceId, tableName } = breakExternalTableId(tableId)
+ const db = new CouchDB(appId)
+ const datasource = await db.get(datasourceId)
+ if (!datasource || !datasource.entities) {
+ ctx.throw(400, "Datasource has not been configured for plus API.")
+ }
+ const tables = datasource.entities
+ const response = await handleRequest(
+ appId,
+ DataSourceOperation.READ,
+ tableId,
+ {
+ id,
+ datasource,
+ }
+ )
+ const table = tables[tableName]
+ const row = response[0]
+ // this seems like a lot of work, but basically we need to dig deeper for the enrich
+ // for a single row, there is probably a better way to do this with some smart multi-layer joins
+ for (let [fieldName, field] of Object.entries(table.schema)) {
+ if (
+ field.type !== FieldTypes.LINK ||
+ !row[fieldName] ||
+ row[fieldName].length === 0
+ ) {
+ continue
+ }
+ const links = row[fieldName]
+ const linkedTableId = field.tableId
+ const linkedTable = tables[breakExternalTableId(linkedTableId).tableName]
+ // don't support composite keys right now
+ const linkedIds = links.map(link => breakRowIdField(link._id)[0])
+ row[fieldName] = await handleRequest(
+ appId,
+ DataSourceOperation.READ,
+ linkedTableId,
+ {
+ tables,
+ filters: {
+ oneOf: {
+ [linkedTable.primary]: linkedIds,
+ },
+ },
+ }
+ )
+ }
+ return row
}
diff --git a/packages/server/src/api/controllers/table/utils.js b/packages/server/src/api/controllers/table/utils.js
index cdfd390027..78dae60ab1 100644
--- a/packages/server/src/api/controllers/table/utils.js
+++ b/packages/server/src/api/controllers/table/utils.js
@@ -204,15 +204,18 @@ class TableSaveFunctions {
}
}
-exports.getExternalTable = async (appId, datasourceId, tableName) => {
+exports.getAllExternalTables = async (appId, datasourceId) => {
const db = new CouchDB(appId)
const datasource = await db.get(datasourceId)
if (!datasource || !datasource.entities) {
throw "Datasource is not configured fully."
}
- return Object.values(datasource.entities).find(
- entity => entity.name === tableName
- )
+ return datasource.entities
+}
+
+exports.getExternalTable = async (appId, datasourceId, tableName) => {
+ const entities = await exports.getAllExternalTables(appId, datasourceId)
+ return entities[tableName]
}
exports.TableSaveFunctions = TableSaveFunctions
diff --git a/packages/server/src/api/routes/application.js b/packages/server/src/api/routes/application.js
index a7209df3e9..c2eb19e101 100644
--- a/packages/server/src/api/routes/application.js
+++ b/packages/server/src/api/routes/application.js
@@ -11,6 +11,16 @@ router
.get("/api/applications/:appId/appPackage", controller.fetchAppPackage)
.put("/api/applications/:appId", authorized(BUILDER), controller.update)
.post("/api/applications", authorized(BUILDER), controller.create)
+ .post(
+ "/api/applications/:appId/client/update",
+ authorized(BUILDER),
+ controller.updateClient
+ )
+ .post(
+ "/api/applications/:appId/client/revert",
+ authorized(BUILDER),
+ controller.revertClient
+ )
.delete("/api/applications/:appId", authorized(BUILDER), controller.delete)
module.exports = router
diff --git a/packages/server/src/api/routes/tests/application.spec.js b/packages/server/src/api/routes/tests/application.spec.js
index 2333787e6e..05e0bc231b 100644
--- a/packages/server/src/api/routes/tests/application.spec.js
+++ b/packages/server/src/api/routes/tests/application.spec.js
@@ -94,7 +94,7 @@ describe("/applications", () => {
})
describe("update", () => {
- it("should be able to fetch the app package", async () => {
+ it("should be able to update the app package", async () => {
const res = await request
.put(`/api/applications/${config.getAppId()}`)
.send({
@@ -107,6 +107,30 @@ describe("/applications", () => {
})
})
+ describe("manage client library version", () => {
+ it("should be able to update the app client library version", async () => {
+ console.log(config.getAppId())
+ await request
+ .post(`/api/applications/${config.getAppId()}/client/update`)
+ .set(config.defaultHeaders())
+ .expect("Content-Type", /json/)
+ .expect(200)
+ })
+ it("should be able to revert the app client library version", async () => {
+ // We need to first update the version so that we can then revert
+ await request
+ .post(`/api/applications/${config.getAppId()}/client/update`)
+ .set(config.defaultHeaders())
+ .expect("Content-Type", /json/)
+ .expect(200)
+ await request
+ .post(`/api/applications/${config.getAppId()}/client/revert`)
+ .set(config.defaultHeaders())
+ .expect("Content-Type", /json/)
+ .expect(200)
+ })
+ })
+
describe("edited at", () => {
it("middleware should set edited at", async () => {
const headers = config.defaultHeaders()
diff --git a/packages/server/src/api/routes/tests/datasource.spec.js b/packages/server/src/api/routes/tests/datasource.spec.js
index d53001b06e..a041de4310 100644
--- a/packages/server/src/api/routes/tests/datasource.spec.js
+++ b/packages/server/src/api/routes/tests/datasource.spec.js
@@ -94,7 +94,7 @@ describe("/datasources", () => {
.expect(200)
// this is mock data, can't test it
expect(res.body).toBeDefined()
- expect(pg.queryMock).toHaveBeenCalledWith(`select "name", "age" from "users" where "name" like $1 limit $2`, ["John%", 5000])
+ expect(pg.queryMock).toHaveBeenCalledWith(`select "name", "age" from "users" where "users"."name" like $1 limit $2`, ["John%", 5000])
})
})
diff --git a/packages/server/src/api/routes/tests/misc.spec.js b/packages/server/src/api/routes/tests/misc.spec.js
index 04a5c62431..b1dd683060 100644
--- a/packages/server/src/api/routes/tests/misc.spec.js
+++ b/packages/server/src/api/routes/tests/misc.spec.js
@@ -31,7 +31,13 @@ describe("run misc tests", () => {
describe("/version", () => {
it("should confirm version", async () => {
const res = await request.get("/version").expect(200)
- expect(res.text.split(".").length).toEqual(3)
+ const text = res.text
+ if (text.includes("alpha")) {
+ expect(text.split(".").length).toEqual(4)
+ } else {
+ expect(text.split(".").length).toEqual(3)
+ }
+
})
})
diff --git a/packages/server/src/api/routes/tests/routing.spec.js b/packages/server/src/api/routes/tests/routing.spec.js
index 96ec492dbc..81f56a939d 100644
--- a/packages/server/src/api/routes/tests/routing.spec.js
+++ b/packages/server/src/api/routes/tests/routing.spec.js
@@ -2,7 +2,6 @@ const setup = require("./utilities")
const { basicScreen } = setup.structures
const { checkBuilderEndpoint } = require("./utilities/TestFunctions")
const { BUILTIN_ROLE_IDS } = require("@budibase/auth/roles")
-const workerRequests = require("../../../utilities/workerRequests")
const route = "/test"
diff --git a/packages/server/src/constants/definitions.ts b/packages/server/src/constants/definitions.ts
index 685c2a9824..8ab995adc4 100644
--- a/packages/server/src/constants/definitions.ts
+++ b/packages/server/src/constants/definitions.ts
@@ -26,3 +26,17 @@ export interface Table {
primaryDisplay?: string
sourceId?: string
}
+
+export interface BudibaseAppMetadata {
+ _id: string
+ _rev?: string
+ appId: string
+ type: string
+ version: string
+ componentlibraries: string[]
+ name: string
+ url: string
+ instance: { _id: string }
+ updatedAt: Date
+ createdAt: Date
+}
diff --git a/packages/server/src/constants/layouts.js b/packages/server/src/constants/layouts.js
index f435c31d1e..2402a1f7db 100644
--- a/packages/server/src/constants/layouts.js
+++ b/packages/server/src/constants/layouts.js
@@ -15,6 +15,7 @@ const EMPTY_LAYOUT = {
{
_id: "7fcf11e4-6f5b-4085-8e0d-9f3d44c98967",
_component: "@budibase/standard-components/screenslot",
+ _instanceName: "Screen slot",
_styles: {
normal: {
flex: "1 1 auto",
@@ -63,6 +64,7 @@ const BASE_LAYOUTS = [
{
_id: "7fcf11e4-6f5b-4085-8e0d-9f3d44c98967",
_component: "@budibase/standard-components/screenslot",
+ _instanceName: "Screen slot",
_styles: {
normal: {
flex: "1 1 auto",
@@ -84,6 +86,7 @@ const BASE_LAYOUTS = [
normal: {},
selected: {},
},
+ title: "{{ name }}",
navigation: "Top",
width: "Large",
links: [
@@ -109,6 +112,7 @@ const BASE_LAYOUTS = [
{
_id: "7fcf11e4-6f5b-4085-8e0d-9f3d44c98967",
_component: "@budibase/standard-components/screenslot",
+ _instanceName: "Screen slot",
_styles: {
normal: {
flex: "1 1 auto",
diff --git a/packages/server/src/definitions/common.ts b/packages/server/src/definitions/common.ts
new file mode 100644
index 0000000000..ec837a8101
--- /dev/null
+++ b/packages/server/src/definitions/common.ts
@@ -0,0 +1,101 @@
+import { SourceNames } from "./datasource"
+
+interface Base {
+ _id?: string
+ _rev?: string
+}
+
+export interface FieldSchema {
+ // TODO: replace with field types enum when done
+ type: string
+ fieldName?: string
+ name: string
+ tableId?: string
+ relationshipType?: string
+ through?: string
+ foreignKey?: string
+ autocolumn?: boolean
+ constraints?: {
+ type?: string
+ email?: boolean
+ inclusion?: string[]
+ length?: {
+ minimum?: string | number
+ maximum?: string | number
+ }
+ presence?: boolean
+ }
+}
+
+export interface TableSchema {
+ [key: string]: FieldSchema
+}
+
+export interface Table extends Base {
+ type?: string
+ views?: {}
+ name?: string
+ primary?: string[]
+ schema: TableSchema
+ primaryDisplay?: string
+ sourceId?: string
+}
+
+export interface Row extends Base {
+ type?: string
+ tableId?: string
+ [key: string]: any
+}
+
+interface JsonSchemaField {
+ properties: {
+ [key: string]: {
+ type: string
+ title: string
+ customType?: string
+ }
+ }
+ required?: string[]
+}
+
+export interface AutomationStep {
+ description: string
+ event?: string
+ icon: string
+ id: string
+ inputs: {
+ [key: string]: any
+ }
+ name: string
+ schema: {
+ inputs: JsonSchemaField
+ outputs: JsonSchemaField
+ }
+ stepId: string
+ tagline: string
+ type: string
+}
+
+export interface Automation extends Base {
+ name: string
+ type: string
+ appId?: string
+ definition: {
+ steps: AutomationStep[]
+ trigger?: AutomationStep
+ }
+}
+
+export interface Datasource extends Base {
+ type: string
+ name: string
+ source: SourceNames
+ // the config is defined by the schema
+ config: {
+ [key: string]: string | number | boolean
+ }
+ plus: boolean
+ entities?: {
+ [key: string]: Table
+ }
+}
diff --git a/packages/server/src/integrations/base/definitions.ts b/packages/server/src/definitions/datasource.ts
similarity index 69%
rename from packages/server/src/integrations/base/definitions.ts
rename to packages/server/src/definitions/datasource.ts
index c202a828d0..90270dd113 100644
--- a/packages/server/src/integrations/base/definitions.ts
+++ b/packages/server/src/definitions/datasource.ts
@@ -26,6 +26,20 @@ export enum DatasourceFieldTypes {
JSON = "json",
}
+export enum SourceNames {
+ POSTGRES = "POSTGRES",
+ DYNAMODB = "DYNAMODB",
+ MONGODB = "MONGODB",
+ ELASTICSEARCH = "ELASTICSEARCH",
+ COUCHDB = "COUCHDB",
+ SQL_SERVER = "SQL_SERVER",
+ S3 = "S3",
+ AIRTABLE = "AIRTABLE",
+ MYSQL = "MYSQL",
+ ARANGODB = "ARANGODB",
+ REST = "REST",
+}
+
export interface QueryDefinition {
type: QueryTypes
displayName?: string
@@ -47,7 +61,7 @@ export interface Integration {
}
export interface SearchFilters {
- allOr: boolean
+ allOr?: boolean
string?: {
[key: string]: string
}
@@ -72,6 +86,26 @@ export interface SearchFilters {
notEmpty?: {
[key: string]: any
}
+ oneOf?: {
+ [key: string]: any[]
+ }
+}
+
+export interface SortJson {
+ [key: string]: SortDirection
+}
+
+export interface PaginationJson {
+ limit: number
+ page: string | number
+}
+
+export interface RelationshipsJson {
+ through?: string
+ from?: string
+ to?: string
+ tableName: string
+ column: string
}
export interface QueryJson {
@@ -84,17 +118,13 @@ export interface QueryJson {
fields: string[]
}
filters?: SearchFilters
- sort?: {
- [key: string]: SortDirection
- }
- paginate?: {
- limit: number
- page: string | number
- }
+ sort?: SortJson
+ paginate?: PaginationJson
body?: object
- extra: {
+ extra?: {
idFilter?: SearchFilters
}
+ relationships?: RelationshipsJson[]
}
export interface SqlQuery {
diff --git a/packages/server/src/integrations/airtable.ts b/packages/server/src/integrations/airtable.ts
index a99dfc7c72..7a80f51bd0 100644
--- a/packages/server/src/integrations/airtable.ts
+++ b/packages/server/src/integrations/airtable.ts
@@ -2,7 +2,7 @@ import {
Integration,
DatasourceFieldTypes,
QueryTypes,
-} from "./base/definitions"
+} from "../definitions/datasource"
module AirtableModule {
const Airtable = require("airtable")
diff --git a/packages/server/src/integrations/arangodb.ts b/packages/server/src/integrations/arangodb.ts
index 7741b8be94..c5eac32892 100644
--- a/packages/server/src/integrations/arangodb.ts
+++ b/packages/server/src/integrations/arangodb.ts
@@ -2,7 +2,7 @@ import {
Integration,
DatasourceFieldTypes,
QueryTypes,
-} from "./base/definitions"
+} from "../definitions/datasource"
module ArangoModule {
const { Database, aql } = require("arangojs")
diff --git a/packages/server/src/integrations/base/sql.ts b/packages/server/src/integrations/base/sql.ts
index 6573a0c47c..66dd269412 100644
--- a/packages/server/src/integrations/base/sql.ts
+++ b/packages/server/src/integrations/base/sql.ts
@@ -6,18 +6,38 @@ import {
QueryOptions,
SortDirection,
Operation,
-} from "./definitions"
+ RelationshipsJson,
+} from "../../definitions/datasource"
+import { isIsoDateString } from "../utils"
+type KnexQuery = Knex.QueryBuilder | Knex
+
+function parseBody(body: any) {
+ for (let [key, value] of Object.entries(body)) {
+ if (typeof value !== "string") {
+ continue
+ }
+ if (isIsoDateString(value)) {
+ body[key] = new Date(value)
+ } else if (!isNaN(parseFloat(value))) {
+ body[key] = parseFloat(value)
+ }
+ }
+ return body
+}
+
+// right now we only do filters on the specific table being queried
function addFilters(
- query: any,
+ tableName: string,
+ query: KnexQuery,
filters: SearchFilters | undefined
-): Knex.QueryBuilder {
+): KnexQuery {
function iterate(
structure: { [key: string]: any },
fn: (key: string, value: any) => void
) {
for (let [key, value] of Object.entries(structure)) {
- fn(key, value)
+ fn(`${tableName}.${key}`, value)
}
}
if (!filters) {
@@ -25,6 +45,12 @@ function addFilters(
}
// if all or specified in filters, then everything is an or
const allOr = filters.allOr
+ if (filters.oneOf) {
+ iterate(filters.oneOf, (key, array) => {
+ const fnc = allOr ? "orWhereIn" : "whereIn"
+ query = query[fnc](key, array)
+ })
+ }
if (filters.string) {
iterate(filters.string, (key, value) => {
const fnc = allOr ? "orWhere" : "where"
@@ -67,20 +93,60 @@ function addFilters(
return query
}
-function buildCreate(knex: Knex, json: QueryJson, opts: QueryOptions) {
+function addRelationships(
+ query: KnexQuery,
+ fromTable: string,
+ relationships: RelationshipsJson[] | undefined
+): KnexQuery {
+ if (!relationships) {
+ return query
+ }
+ for (let relationship of relationships) {
+ const from = relationship.from,
+ to = relationship.to,
+ toTable = relationship.tableName
+ if (!relationship.through) {
+ // @ts-ignore
+ query = query.leftJoin(
+ toTable,
+ `${fromTable}.${from}`,
+ `${relationship.tableName}.${to}`
+ )
+ } else {
+ const throughTable = relationship.through
+ query = query
+ // @ts-ignore
+ .leftJoin(
+ throughTable,
+ `${fromTable}.${from}`,
+ `${throughTable}.${from}`
+ )
+ .leftJoin(toTable, `${toTable}.${to}`, `${throughTable}.${to}`)
+ }
+ }
+ return query
+}
+
+function buildCreate(
+ knex: Knex,
+ json: QueryJson,
+ opts: QueryOptions
+): KnexQuery {
const { endpoint, body } = json
- let query = knex(endpoint.entityId)
+ let query: KnexQuery = knex(endpoint.entityId)
+ const parsedBody = parseBody(body)
// mysql can't use returning
if (opts.disableReturning) {
- return query.insert(body)
+ return query.insert(parsedBody)
} else {
- return query.insert(body).returning("*")
+ return query.insert(parsedBody).returning("*")
}
}
-function buildRead(knex: Knex, json: QueryJson, limit: number) {
- let { endpoint, resource, filters, sort, paginate } = json
- let query: Knex.QueryBuilder = knex(endpoint.entityId)
+function buildRead(knex: Knex, json: QueryJson, limit: number): KnexQuery {
+ let { endpoint, resource, filters, sort, paginate, relationships } = json
+ const tableName = endpoint.entityId
+ let query: KnexQuery = knex(tableName)
// select all if not specified
if (!resource) {
resource = { fields: [] }
@@ -92,7 +158,9 @@ function buildRead(knex: Knex, json: QueryJson, limit: number) {
query = query.select("*")
}
// handle where
- query = addFilters(query, filters)
+ query = addFilters(tableName, query, filters)
+ // handle join
+ query = addRelationships(query, tableName, relationships)
// handle sorting
if (sort) {
for (let [key, value] of Object.entries(sort)) {
@@ -114,22 +182,31 @@ function buildRead(knex: Knex, json: QueryJson, limit: number) {
return query
}
-function buildUpdate(knex: Knex, json: QueryJson, opts: QueryOptions) {
+function buildUpdate(
+ knex: Knex,
+ json: QueryJson,
+ opts: QueryOptions
+): KnexQuery {
const { endpoint, body, filters } = json
- let query = knex(endpoint.entityId)
- query = addFilters(query, filters)
+ let query: KnexQuery = knex(endpoint.entityId)
+ const parsedBody = parseBody(body)
+ query = addFilters(endpoint.entityId, query, filters)
// mysql can't use returning
if (opts.disableReturning) {
- return query.update(body)
+ return query.update(parsedBody)
} else {
- return query.update(body).returning("*")
+ return query.update(parsedBody).returning("*")
}
}
-function buildDelete(knex: Knex, json: QueryJson, opts: QueryOptions) {
+function buildDelete(
+ knex: Knex,
+ json: QueryJson,
+ opts: QueryOptions
+): KnexQuery {
const { endpoint, filters } = json
- let query = knex(endpoint.entityId)
- query = addFilters(query, filters)
+ let query: KnexQuery = knex(endpoint.entityId)
+ query = addFilters(endpoint.entityId, query, filters)
// mysql can't use returning
if (opts.disableReturning) {
return query.delete()
@@ -180,6 +257,8 @@ class SqlQueryBuilder {
default:
throw `Operation type is not supported by SQL query builder`
}
+
+ // @ts-ignore
return query.toSQL().toNative()
}
}
diff --git a/packages/server/src/integrations/couchdb.ts b/packages/server/src/integrations/couchdb.ts
index a813cf2385..983e6cdac2 100644
--- a/packages/server/src/integrations/couchdb.ts
+++ b/packages/server/src/integrations/couchdb.ts
@@ -2,7 +2,7 @@ import {
Integration,
DatasourceFieldTypes,
QueryTypes,
-} from "./base/definitions"
+} from "../definitions/datasource"
module CouchDBModule {
const PouchDB = require("pouchdb")
diff --git a/packages/server/src/integrations/dynamodb.ts b/packages/server/src/integrations/dynamodb.ts
index 0baf09a866..6b99ba04cc 100644
--- a/packages/server/src/integrations/dynamodb.ts
+++ b/packages/server/src/integrations/dynamodb.ts
@@ -2,7 +2,7 @@ import {
Integration,
DatasourceFieldTypes,
QueryTypes,
-} from "./base/definitions"
+} from "../definitions/datasource"
module DynamoModule {
const AWS = require("aws-sdk")
diff --git a/packages/server/src/integrations/elasticsearch.ts b/packages/server/src/integrations/elasticsearch.ts
index 2562ca0dcd..147858c8dd 100644
--- a/packages/server/src/integrations/elasticsearch.ts
+++ b/packages/server/src/integrations/elasticsearch.ts
@@ -2,7 +2,7 @@ import {
Integration,
DatasourceFieldTypes,
QueryTypes,
-} from "./base/definitions"
+} from "../definitions/datasource"
module ElasticsearchModule {
const { Client } = require("@elastic/elasticsearch")
diff --git a/packages/server/src/integrations/index.ts b/packages/server/src/integrations/index.ts
index 4999f0c867..c0acd6b225 100644
--- a/packages/server/src/integrations/index.ts
+++ b/packages/server/src/integrations/index.ts
@@ -9,33 +9,34 @@ const airtable = require("./airtable")
const mysql = require("./mysql")
const arangodb = require("./arangodb")
const rest = require("./rest")
+const { SourceNames } = require("../definitions/datasource")
const DEFINITIONS = {
- POSTGRES: postgres.schema,
- DYNAMODB: dynamodb.schema,
- MONGODB: mongodb.schema,
- ELASTICSEARCH: elasticsearch.schema,
- COUCHDB: couchdb.schema,
- SQL_SERVER: sqlServer.schema,
- S3: s3.schema,
- AIRTABLE: airtable.schema,
- MYSQL: mysql.schema,
- ARANGODB: arangodb.schema,
- REST: rest.schema,
+ [SourceNames.POSTGRES]: postgres.schema,
+ [SourceNames.DYNAMODB]: dynamodb.schema,
+ [SourceNames.MONGODB]: mongodb.schema,
+ [SourceNames.ELASTICSEARCH]: elasticsearch.schema,
+ [SourceNames.COUCHDB]: couchdb.schema,
+ [SourceNames.SQL_SERVER]: sqlServer.schema,
+ [SourceNames.S3]: s3.schema,
+ [SourceNames.AIRTABLE]: airtable.schema,
+ [SourceNames.MYSQL]: mysql.schema,
+ [SourceNames.ARANGODB]: arangodb.schema,
+ [SourceNames.REST]: rest.schema,
}
const INTEGRATIONS = {
- POSTGRES: postgres.integration,
- DYNAMODB: dynamodb.integration,
- MONGODB: mongodb.integration,
- ELASTICSEARCH: elasticsearch.integration,
- COUCHDB: couchdb.integration,
- S3: s3.integration,
- SQL_SERVER: sqlServer.integration,
- AIRTABLE: airtable.integration,
- MYSQL: mysql.integration,
- ARANGODB: arangodb.integration,
- REST: rest.integration,
+ [SourceNames.POSTGRES]: postgres.integration,
+ [SourceNames.DYNAMODB]: dynamodb.integration,
+ [SourceNames.MONGODB]: mongodb.integration,
+ [SourceNames.ELASTICSEARCH]: elasticsearch.integration,
+ [SourceNames.COUCHDB]: couchdb.integration,
+ [SourceNames.SQL_SERVER]: s3.integration,
+ [SourceNames.S3]: sqlServer.integration,
+ [SourceNames.AIRTABLE]: airtable.integration,
+ [SourceNames.MYSQL]: mysql.integration,
+ [SourceNames.ARANGODB]: arangodb.integration,
+ [SourceNames.REST]: rest.integration,
}
module.exports = {
diff --git a/packages/server/src/integrations/microsoftSqlServer.ts b/packages/server/src/integrations/microsoftSqlServer.ts
index ff428eacff..f5a9d73b09 100644
--- a/packages/server/src/integrations/microsoftSqlServer.ts
+++ b/packages/server/src/integrations/microsoftSqlServer.ts
@@ -4,7 +4,7 @@ import {
QueryTypes,
QueryJson,
SqlQuery,
-} from "./base/definitions"
+} from "../definitions/datasource"
import { getSqlQuery } from "./utils"
module MSSQLModule {
diff --git a/packages/server/src/integrations/mongodb.ts b/packages/server/src/integrations/mongodb.ts
index b248be84c4..af7b49153d 100644
--- a/packages/server/src/integrations/mongodb.ts
+++ b/packages/server/src/integrations/mongodb.ts
@@ -2,7 +2,7 @@ import {
Integration,
DatasourceFieldTypes,
QueryTypes,
-} from "./base/definitions"
+} from "../definitions/datasource"
module MongoDBModule {
const { MongoClient } = require("mongodb")
diff --git a/packages/server/src/integrations/mysql.ts b/packages/server/src/integrations/mysql.ts
index 6940f1e3c6..fab151fc0d 100644
--- a/packages/server/src/integrations/mysql.ts
+++ b/packages/server/src/integrations/mysql.ts
@@ -5,7 +5,8 @@ import {
Operation,
QueryJson,
SqlQuery,
-} from "./base/definitions"
+} from "../definitions/datasource"
+import { Table, TableSchema } from "../definitions/common"
import { getSqlQuery } from "./utils"
module MySQLModule {
@@ -28,6 +29,7 @@ module MySQLModule {
blob: FieldTypes.LONGFORM,
enum: FieldTypes.STRING,
varchar: FieldTypes.STRING,
+ float: FieldTypes.NUMBER,
int: FieldTypes.NUMBER,
numeric: FieldTypes.NUMBER,
bigint: FieldTypes.NUMBER,
@@ -139,7 +141,7 @@ module MySQLModule {
}
async buildSchema(datasourceId: string) {
- const tables: any = {}
+ const tables: { [key: string]: Table } = {}
const database = this.config.database
this.client.connect()
@@ -154,7 +156,7 @@ module MySQLModule {
)
for (let tableName of tableNames) {
const primaryKeys = []
- const schema: any = {}
+ const schema: TableSchema = {}
const descResp = await internalQuery(
this.client,
{ sql: `DESCRIBE ${tableName};` },
@@ -162,14 +164,19 @@ module MySQLModule {
)
for (let column of descResp) {
const columnName = column.Field
- if (column.Key === "PRI") {
+ if (column.Key === "PRI" && primaryKeys.indexOf(column.Key) === -1) {
primaryKeys.push(columnName)
}
const constraints = {
- required: column.Null !== "YES",
+ presence: column.Null !== "YES",
}
+ const isAuto: boolean =
+ typeof column.Extra === "string" &&
+ (column.Extra === "auto_increment" ||
+ column.Extra.toLowerCase().includes("generated"))
schema[columnName] = {
name: columnName,
+ autocolumn: isAuto,
type: convertType(column.Type, TYPE_MAP),
constraints,
}
@@ -212,7 +219,7 @@ module MySQLModule {
}
async getReturningRow(json: QueryJson) {
- if (!json.extra.idFilter) {
+ if (!json.extra || !json.extra.idFilter) {
return {}
}
const input = this._query({
diff --git a/packages/server/src/integrations/postgres.ts b/packages/server/src/integrations/postgres.ts
index 787bce7e4e..85d1b44b26 100644
--- a/packages/server/src/integrations/postgres.ts
+++ b/packages/server/src/integrations/postgres.ts
@@ -4,8 +4,8 @@ import {
QueryTypes,
QueryJson,
SqlQuery,
-} from "./base/definitions"
-import { Table } from "../constants/definitions"
+} from "../definitions/datasource"
+import { Table } from "../definitions/common"
import { getSqlQuery } from "./utils"
module PostgresModule {
@@ -134,8 +134,9 @@ module PostgresModule {
/**
* Fetches the tables from the postgres table and assigns them to the datasource.
* @param {*} datasourceId - datasourceId to fetch
+ * @param entities - the tables that are to be built
*/
- async buildSchema(datasourceId: string) {
+ async buildSchema(datasourceId: string, entities: Record
) {
let tableKeys: { [key: string]: string[] } = {}
try {
const primaryKeysResponse = await this.client.query(
@@ -146,7 +147,11 @@ module PostgresModule {
if (!tableKeys[tableName]) {
tableKeys[tableName] = []
}
- tableKeys[tableName].push(table.column_name || table.primary_key)
+ const key = table.column_name || table.primary_key
+ // only add the unique keys
+ if (key && tableKeys[tableName].indexOf(key) === -1) {
+ tableKeys[tableName].push(key)
+ }
}
} catch (err) {
tableKeys = {}
@@ -167,10 +172,27 @@ module PostgresModule {
name: tableName,
schema: {},
}
+
+ // add the existing relationships from the entities if they exist, to prevent them from being overridden
+ if (entities && entities[tableName]) {
+ const existingTableSchema = entities[tableName].schema
+ for (let key in existingTableSchema) {
+ if (!existingTableSchema.hasOwnProperty(key)) {
+ continue
+ }
+ if (existingTableSchema[key].type === "link") {
+ tables[tableName].schema[key] = existingTableSchema[key]
+ }
+ }
+ }
}
const type: string = convertType(column.data_type, TYPE_MAP)
+ const isAuto: boolean =
+ typeof column.column_default === "string" &&
+ column.column_default.startsWith("nextval")
tables[tableName].schema[columnName] = {
+ autocolumn: isAuto,
name: columnName,
type,
}
diff --git a/packages/server/src/integrations/rest.ts b/packages/server/src/integrations/rest.ts
index 8b6d0e70da..c55e991980 100644
--- a/packages/server/src/integrations/rest.ts
+++ b/packages/server/src/integrations/rest.ts
@@ -2,7 +2,7 @@ import {
Integration,
DatasourceFieldTypes,
QueryTypes,
-} from "./base/definitions"
+} from "../definitions/datasource"
module RestModule {
const fetch = require("node-fetch")
diff --git a/packages/server/src/integrations/s3.ts b/packages/server/src/integrations/s3.ts
index 58d58be443..691f3a05c0 100644
--- a/packages/server/src/integrations/s3.ts
+++ b/packages/server/src/integrations/s3.ts
@@ -1,4 +1,4 @@
-import { Integration, QueryTypes } from "./base/definitions"
+import { Integration, QueryTypes } from "../definitions/datasource"
module S3Module {
const AWS = require("aws-sdk")
diff --git a/packages/server/src/integrations/tests/postgres.spec.js b/packages/server/src/integrations/tests/postgres.spec.js
index 5d0283ec90..4ce5f12e96 100644
--- a/packages/server/src/integrations/tests/postgres.spec.js
+++ b/packages/server/src/integrations/tests/postgres.spec.js
@@ -17,7 +17,7 @@ describe("Postgres Integration", () => {
it("calls the create method with the correct params", async () => {
const sql = "insert into users (name, age) values ('Joe', 123);"
- const response = await config.integration.create({
+ await config.integration.create({
sql
})
expect(pg.queryMock).toHaveBeenCalledWith(sql, [])
@@ -25,7 +25,7 @@ describe("Postgres Integration", () => {
it("calls the read method with the correct params", async () => {
const sql = "select * from users;"
- const response = await config.integration.read({
+ await config.integration.read({
sql
})
expect(pg.queryMock).toHaveBeenCalledWith(sql, [])
diff --git a/packages/server/src/integrations/tests/sql.spec.js b/packages/server/src/integrations/tests/sql.spec.js
index 2b6badd92d..fb57fe79e7 100644
--- a/packages/server/src/integrations/tests/sql.spec.js
+++ b/packages/server/src/integrations/tests/sql.spec.js
@@ -81,7 +81,7 @@ describe("SQL query builder", () => {
}))
expect(query).toEqual({
bindings: ["John%", limit],
- sql: `select * from "${TABLE_NAME}" where "name" like $1 limit $2`
+ sql: `select * from "${TABLE_NAME}" where "${TABLE_NAME}"."name" like $1 limit $2`
})
})
@@ -98,7 +98,7 @@ describe("SQL query builder", () => {
}))
expect(query).toEqual({
bindings: [2, 10, limit],
- sql: `select * from "${TABLE_NAME}" where "age" between $1 and $2 limit $3`
+ sql: `select * from "${TABLE_NAME}" where "${TABLE_NAME}"."age" between $1 and $2 limit $3`
})
})
@@ -114,7 +114,7 @@ describe("SQL query builder", () => {
}))
expect(query).toEqual({
bindings: [10, "John", limit],
- sql: `select * from "${TABLE_NAME}" where ("age" = $1) or ("name" = $2) limit $3`
+ sql: `select * from "${TABLE_NAME}" where ("${TABLE_NAME}"."age" = $1) or ("${TABLE_NAME}"."name" = $2) limit $3`
})
})
@@ -139,7 +139,7 @@ describe("SQL query builder", () => {
}))
expect(query).toEqual({
bindings: ["John", 1001],
- sql: `update "${TABLE_NAME}" set "name" = $1 where "id" = $2 returning *`
+ sql: `update "${TABLE_NAME}" set "name" = $1 where "${TABLE_NAME}"."id" = $2 returning *`
})
})
@@ -151,7 +151,7 @@ describe("SQL query builder", () => {
}))
expect(query).toEqual({
bindings: [1001],
- sql: `delete from "${TABLE_NAME}" where "id" = $1 returning *`
+ sql: `delete from "${TABLE_NAME}" where "${TABLE_NAME}"."id" = $1 returning *`
})
})
diff --git a/packages/server/src/integrations/utils.ts b/packages/server/src/integrations/utils.ts
index 87ed185ba3..03751bb467 100644
--- a/packages/server/src/integrations/utils.ts
+++ b/packages/server/src/integrations/utils.ts
@@ -1,4 +1,6 @@
-import { SqlQuery } from "./base/definitions"
+import { SqlQuery } from "../definitions/datasource"
+import { Datasource } from "../definitions/common"
+import { SourceNames } from "../definitions/datasource"
const { DocumentTypes, SEPARATOR } = require("../db/utils")
const { FieldTypes } = require("../constants")
@@ -31,13 +33,13 @@ export function generateRowIdField(keyProps: any[] = []) {
}
// should always return an array
-export function breakRowIdField(_id: string) {
+export function breakRowIdField(_id: string): any[] {
if (!_id) {
- return null
+ return []
}
// have to replace on the way back as we swapped out the double quotes
// when encoding, but JSON can't handle the single quotes
- const decoded = decodeURIComponent(_id).replace(/'/g, '"')
+ const decoded: string = decodeURIComponent(_id).replace(/'/g, '"')
const parsed = JSON.parse(decoded)
return Array.isArray(parsed) ? parsed : [parsed]
}
@@ -58,3 +60,19 @@ export function getSqlQuery(query: SqlQuery | string): SqlQuery {
return query
}
}
+
+export function isSQL(datasource: Datasource): boolean {
+ if (!datasource || !datasource.source) {
+ return false
+ }
+ const SQL = [SourceNames.POSTGRES, SourceNames.SQL_SERVER, SourceNames.MYSQL]
+ return SQL.indexOf(datasource.source) !== -1
+}
+
+export function isIsoDateString(str: string) {
+ if (!/\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}.\d{3}Z/.test(str)) {
+ return false
+ }
+ let d = new Date(str)
+ return d.toISOString() === str
+}
diff --git a/packages/server/src/middleware/currentapp.js b/packages/server/src/middleware/currentapp.js
index bf043f67b3..7169a36320 100644
--- a/packages/server/src/middleware/currentapp.js
+++ b/packages/server/src/middleware/currentapp.js
@@ -2,10 +2,10 @@ const { getAppId, setCookie, getCookie, clearCookie } =
require("@budibase/auth").utils
const { Cookies } = require("@budibase/auth").constants
const { getRole } = require("@budibase/auth/roles")
-const { getGlobalSelf } = require("../utilities/workerRequests")
const { BUILTIN_ROLE_IDS } = require("@budibase/auth/roles")
const { generateUserMetadataID } = require("../db/utils")
const { dbExists } = require("@budibase/auth/db")
+const { getCachedSelf } = require("../utilities/global")
const CouchDB = require("../db")
module.exports = async (ctx, next) => {
@@ -31,29 +31,17 @@ module.exports = async (ctx, next) => {
}
}
- let updateCookie = false,
- appId,
+ let appId,
roleId = BUILTIN_ROLE_IDS.PUBLIC
if (!ctx.user) {
// not logged in, try to set a cookie for public apps
- updateCookie = true
appId = requestAppId
- } else if (
- requestAppId != null &&
- (appCookie == null ||
- requestAppId !== appCookie.appId ||
- appCookie.roleId === BUILTIN_ROLE_IDS.PUBLIC ||
- !appCookie.roleId)
- ) {
+ } else if (requestAppId != null) {
// Different App ID means cookie needs reset, or if the same public user has logged in
- const globalUser = await getGlobalSelf(ctx, requestAppId)
- updateCookie = true
+ const globalUser = await getCachedSelf(ctx, requestAppId)
appId = requestAppId
// retrieving global user gets the right role
roleId = globalUser.roleId || BUILTIN_ROLE_IDS.BASIC
- } else if (appCookie != null) {
- appId = appCookie.appId
- roleId = appCookie.roleId || BUILTIN_ROLE_IDS.BASIC
}
// nothing more to do
if (!appId) {
@@ -73,8 +61,12 @@ module.exports = async (ctx, next) => {
role: await getRole(appId, roleId),
}
}
- if (updateCookie) {
- setCookie(ctx, { appId, roleId }, Cookies.CurrentApp)
+ if (
+ requestAppId !== appId ||
+ appCookie == null ||
+ appCookie.appId !== requestAppId
+ ) {
+ setCookie(ctx, { appId }, Cookies.CurrentApp)
}
return next()
}
diff --git a/packages/server/src/middleware/tests/currentapp.spec.js b/packages/server/src/middleware/tests/currentapp.spec.js
index 2b4a815542..7bdaa929d1 100644
--- a/packages/server/src/middleware/tests/currentapp.spec.js
+++ b/packages/server/src/middleware/tests/currentapp.spec.js
@@ -23,6 +23,15 @@ function mockReset() {
function mockAuthWithNoCookie() {
jest.resetModules()
mockWorker()
+ jest.mock("@budibase/auth/cache", () => ({
+ user: {
+ getUser: () => {
+ return {
+ _id: "us_uuid1",
+ }
+ },
+ },
+ }))
jest.mock("@budibase/auth", () => ({
utils: {
getAppId: jest.fn(),
diff --git a/packages/server/src/tests/utilities/TestConfiguration.js b/packages/server/src/tests/utilities/TestConfiguration.js
index 204af06b0a..4b9fe73424 100644
--- a/packages/server/src/tests/utilities/TestConfiguration.js
+++ b/packages/server/src/tests/utilities/TestConfiguration.js
@@ -17,6 +17,8 @@ const { cleanup } = require("../../utilities/fileSystem")
const { Cookies, Headers } = require("@budibase/auth").constants
const { jwt } = require("@budibase/auth").auth
const { StaticDatabases } = require("@budibase/auth/db")
+const { createASession } = require("@budibase/auth/sessions")
+const { user: userCache } = require("@budibase/auth/cache")
const CouchDB = require("../../db")
const GLOBAL_USER_ID = "us_uuid1"
@@ -62,7 +64,7 @@ class TestConfiguration {
return request.body
}
- async globalUser(id = GLOBAL_USER_ID, builder = true) {
+ async globalUser(id = GLOBAL_USER_ID, builder = true, roles) {
const db = new CouchDB(StaticDatabases.GLOBAL.name)
let existing
try {
@@ -73,8 +75,9 @@ class TestConfiguration {
const user = {
_id: id,
...existing,
- roles: {},
+ roles: roles || {},
}
+ await createASession(id, "sessionid")
if (builder) {
user.builder = { global: true }
}
@@ -103,6 +106,7 @@ class TestConfiguration {
defaultHeaders() {
const auth = {
userId: GLOBAL_USER_ID,
+ sessionId: "sessionid",
}
const app = {
roleId: BUILTIN_ROLE_IDS.ADMIN,
@@ -138,13 +142,7 @@ class TestConfiguration {
roleId = BUILTIN_ROLE_IDS.ADMIN,
builder = false,
}) {
- let user
- try {
- user = await this.createUser(email, PASSWORD, roleId)
- } catch (err) {
- // allow errors here
- }
- return this.login(email, PASSWORD, { roleId, userId: user._id, builder })
+ return this.login(email, PASSWORD, { roleId, builder })
}
async createApp(appName) {
@@ -313,6 +311,7 @@ class TestConfiguration {
async createUser(id = null) {
const globalId = !id ? `us_${Math.random()}` : `us_${id}`
const resp = await this.globalUser(globalId)
+ await userCache.invalidateUser(globalId)
return {
...resp,
globalId,
@@ -326,14 +325,19 @@ class TestConfiguration {
}
// make sure the user exists in the global DB
if (roleId !== BUILTIN_ROLE_IDS.PUBLIC) {
- await this.globalUser(userId, builder)
+ const appId = `app${this.getAppId().split("app_dev")[1]}`
+ await this.globalUser(userId, builder, {
+ [appId]: roleId,
+ })
}
if (!email || !password) {
await this.createUser()
}
+ await createASession(userId, "sessionid")
// have to fake this
const auth = {
userId,
+ sessionId: "sessionid",
}
const app = {
roleId: roleId,
@@ -343,6 +347,7 @@ class TestConfiguration {
const appToken = jwt.sign(app, env.JWT_SECRET)
// returning necessary request headers
+ await userCache.invalidateUser(userId)
return {
Accept: "application/json",
Cookie: [
diff --git a/packages/server/src/utilities/fileSystem/clientLibrary.js b/packages/server/src/utilities/fileSystem/clientLibrary.js
new file mode 100644
index 0000000000..3f0d31f257
--- /dev/null
+++ b/packages/server/src/utilities/fileSystem/clientLibrary.js
@@ -0,0 +1,154 @@
+const { join } = require("path")
+const { ObjectStoreBuckets } = require("../../constants")
+const fs = require("fs")
+const { upload, retrieveToTmp, streamUpload } = require("./utilities")
+const { resolve } = require("../centralPath")
+const env = require("../../environment")
+const TOP_LEVEL_PATH = join(__dirname, "..", "..", "..")
+
+/**
+ * Client library paths in the object store:
+ * Previously, the entire standard-components package was downloaded from NPM
+ * as a tarball and extracted to the object store, even though only the manifest
+ * was ever needed. Therefore we need to support old apps which may still have
+ * the manifest at this location for the first update.
+ *
+ * The new paths for the in-use version are:
+ * {appId}/manifest.json
+ * {appId}/budibase-client.js
+ *
+ * The paths for the backups are:
+ * {appId}/manifest.json.bak
+ * {appId}/budibase-client.js.bak
+ *
+ * We don't rely on NPM at all any more, as when updating to the latest version
+ * we pull both the manifest and client bundle from the server's dependencies
+ * in the local file system.
+ */
+
+/**
+ * Backs up the current client library version by copying both the manifest
+ * and client bundle to .bak extensions in the object store. Only the one
+ * previous version is stored as a backup, which can be reverted to.
+ * @param appId The app ID to backup
+ * @returns {Promise}
+ */
+exports.backupClientLibrary = async appId => {
+ // Copy existing manifest to tmp
+ let tmpManifestPath
+ try {
+ // Try to load the manifest from the new file location
+ tmpManifestPath = await retrieveToTmp(
+ ObjectStoreBuckets.APPS,
+ join(appId, "manifest.json")
+ )
+ } catch (error) {
+ // Fallback to loading it from the old location for old apps
+ tmpManifestPath = await retrieveToTmp(
+ ObjectStoreBuckets.APPS,
+ join(
+ appId,
+ "node_modules",
+ "budibase",
+ "standard-components",
+ "package",
+ "manifest.json"
+ )
+ )
+ }
+
+ // Copy existing client lib to tmp
+ const tmpClientPath = await retrieveToTmp(
+ ObjectStoreBuckets.APPS,
+ join(appId, "budibase-client.js")
+ )
+
+ // Upload manifest and client library as backups
+ const manifestUpload = upload({
+ bucket: ObjectStoreBuckets.APPS,
+ filename: join(appId, "manifest.json.bak"),
+ path: tmpManifestPath,
+ type: "application/json",
+ })
+ const clientUpload = upload({
+ bucket: ObjectStoreBuckets.APPS,
+ filename: join(appId, "budibase-client.js.bak"),
+ path: tmpClientPath,
+ type: "application/javascript",
+ })
+ await Promise.all([manifestUpload, clientUpload])
+}
+
+/**
+ * Uploads the latest version of the component manifest and the client library
+ * to the object store, overwriting the existing version.
+ * @param appId The app ID to update
+ * @returns {Promise}
+ */
+exports.updateClientLibrary = async appId => {
+ let manifest, client
+
+ if (env.isDev()) {
+ // Load the symlinked version in dev which is always the newest
+ manifest = require.resolve("@budibase/standard-components/manifest.json")
+ client = require.resolve("@budibase/client")
+ } else {
+ // Load the bundled version in prod
+ manifest = resolve(TOP_LEVEL_PATH, "client", "manifest.json")
+ client = resolve(TOP_LEVEL_PATH, "client", "budibase-client.js")
+ }
+
+ // Upload latest manifest and client library
+ const manifestUpload = streamUpload(
+ ObjectStoreBuckets.APPS,
+ join(appId, "manifest.json"),
+ fs.createReadStream(manifest),
+ {
+ ContentType: "application/json",
+ }
+ )
+ const clientUpload = streamUpload(
+ ObjectStoreBuckets.APPS,
+ join(appId, "budibase-client.js"),
+ fs.createReadStream(client),
+ {
+ ContentType: "application/javascript",
+ }
+ )
+ await Promise.all([manifestUpload, clientUpload])
+}
+
+/**
+ * Reverts the version of the client library and manifest to the previously
+ * used version for an app.
+ * @param appId The app ID to revert
+ * @returns {Promise}
+ */
+exports.revertClientLibrary = async appId => {
+ // Copy backups manifest to tmp directory
+ const tmpManifestPath = await retrieveToTmp(
+ ObjectStoreBuckets.APPS,
+ join(appId, "manifest.json.bak")
+ )
+
+ // Copy backup client lib to tmp
+ const tmpClientPath = await retrieveToTmp(
+ ObjectStoreBuckets.APPS,
+ join(appId, "budibase-client.js.bak")
+ )
+
+ // Upload backups as new versions
+ const manifestUpload = upload({
+ bucket: ObjectStoreBuckets.APPS,
+ filename: join(appId, "manifest.json"),
+ path: tmpManifestPath,
+ type: "application/json",
+ })
+ const clientUpload = upload({
+ bucket: ObjectStoreBuckets.APPS,
+ filename: join(appId, "budibase-client.js"),
+ path: tmpClientPath,
+ type: "application/javascript",
+ })
+ await Promise.all([manifestUpload, clientUpload])
+}
diff --git a/packages/server/src/utilities/fileSystem/index.js b/packages/server/src/utilities/fileSystem/index.js
index afacbf8cdf..b83ff03854 100644
--- a/packages/server/src/utilities/fileSystem/index.js
+++ b/packages/server/src/utilities/fileSystem/index.js
@@ -13,7 +13,7 @@ const {
deleteFolder,
downloadTarball,
} = require("./utilities")
-const { downloadLibraries, uploadClientLibrary } = require("./newApp")
+const { updateClientLibrary } = require("./clientLibrary")
const download = require("download")
const env = require("../../environment")
const { homedir } = require("os")
@@ -139,13 +139,12 @@ exports.performBackup = async (appId, backupName) => {
}
/**
- * Downloads required libraries and creates a new path in the object store.
+ * Uploads the latest client library to the object store.
* @param {string} appId The ID of the app which is being created.
* @return {Promise} once promise completes app resources should be ready in object store.
*/
exports.createApp = async appId => {
- await downloadLibraries(appId)
- await uploadClientLibrary(appId)
+ await updateClientLibrary(appId)
}
/**
@@ -193,8 +192,17 @@ exports.getComponentLibraryManifest = async (appId, library) => {
delete require.cache[require.resolve(path)]
return require(path)
}
- const path = join(appId, "node_modules", library, "package", filename)
- let resp = await retrieve(ObjectStoreBuckets.APPS, path)
+
+ let resp
+ try {
+ // Try to load the manifest from the new file location
+ const path = join(appId, filename)
+ resp = await retrieve(ObjectStoreBuckets.APPS, path)
+ } catch (error) {
+ // Fallback to loading it from the old location for old apps
+ const path = join(appId, "node_modules", library, "package", filename)
+ resp = await retrieve(ObjectStoreBuckets.APPS, path)
+ }
if (typeof resp !== "string") {
resp = resp.toString("utf8")
}
diff --git a/packages/server/src/utilities/fileSystem/newApp.js b/packages/server/src/utilities/fileSystem/newApp.js
deleted file mode 100644
index 735f0d523e..0000000000
--- a/packages/server/src/utilities/fileSystem/newApp.js
+++ /dev/null
@@ -1,36 +0,0 @@
-const packageJson = require("../../../package.json")
-const { join } = require("path")
-const { ObjectStoreBuckets } = require("../../constants")
-const { streamUpload, downloadTarball } = require("./utilities")
-const fs = require("fs")
-
-const BUCKET_NAME = ObjectStoreBuckets.APPS
-
-// can't really test this due to the downloading nature of it, wouldn't be a great test case
-/* istanbul ignore next */
-exports.downloadLibraries = async appId => {
- const LIBRARIES = ["standard-components"]
-
- const paths = {}
- // Need to download tarballs directly from NPM as our users may not have node on their machine
- for (let lib of LIBRARIES) {
- // download tarball
- const registryUrl = `https://registry.npmjs.org/@budibase/${lib}/-/${lib}-${packageJson.version}.tgz`
- const path = join(appId, "node_modules", "@budibase", lib)
- paths[`@budibase/${lib}`] = await downloadTarball(
- registryUrl,
- BUCKET_NAME,
- path
- )
- }
- return paths
-}
-
-exports.uploadClientLibrary = async appId => {
- const sourcepath = require.resolve("@budibase/client")
- const destPath = join(appId, "budibase-client.js")
-
- await streamUpload(BUCKET_NAME, destPath, fs.createReadStream(sourcepath), {
- ContentType: "application/javascript",
- })
-}
diff --git a/packages/server/src/utilities/global.js b/packages/server/src/utilities/global.js
index eddbd63cd7..3ce794b406 100644
--- a/packages/server/src/utilities/global.js
+++ b/packages/server/src/utilities/global.js
@@ -7,6 +7,7 @@ const {
const { BUILTIN_ROLE_IDS } = require("@budibase/auth/roles")
const { getDeployedAppID } = require("@budibase/auth/db")
const { getGlobalUserParams } = require("@budibase/auth/db")
+const { user: userCache } = require("@budibase/auth/cache")
exports.updateAppRole = (appId, user) => {
if (!user.roles) {
@@ -25,15 +26,24 @@ exports.updateAppRole = (appId, user) => {
return user
}
-exports.getGlobalUser = async (appId, userId) => {
- const db = CouchDB(StaticDatabases.GLOBAL.name)
- let user = await db.get(getGlobalIDFromUserMetadataID(userId))
+function processUser(appId, user) {
if (user) {
delete user.password
}
return exports.updateAppRole(appId, user)
}
+exports.getCachedSelf = async (ctx, appId) => {
+ const user = await userCache.getUser(ctx.user._id)
+ return processUser(appId, user)
+}
+
+exports.getGlobalUser = async (appId, userId) => {
+ const db = CouchDB(StaticDatabases.GLOBAL.name)
+ let user = await db.get(getGlobalIDFromUserMetadataID(userId))
+ return processUser(appId, user)
+}
+
exports.getGlobalUsers = async (appId = null, users = null) => {
const db = CouchDB(StaticDatabases.GLOBAL.name)
let globalUsers
diff --git a/packages/server/tsconfig.json b/packages/server/tsconfig.json
index bd6dbc1686..934d0bdd2b 100644
--- a/packages/server/tsconfig.json
+++ b/packages/server/tsconfig.json
@@ -8,7 +8,8 @@
"strict": true,
"noImplicitAny": true,
"esModuleInterop": true,
- "resolveJsonModule": true
+ "resolveJsonModule": true,
+ "incremental": true
},
"include": [
"./src/**/*"
diff --git a/packages/server/yarn.lock b/packages/server/yarn.lock
index 0939a1add3..c4be7d4512 100644
--- a/packages/server/yarn.lock
+++ b/packages/server/yarn.lock
@@ -1146,11 +1146,12 @@
resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39"
integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==
-"@budibase/auth@^0.9.66":
- version "0.9.66"
- resolved "https://registry.yarnpkg.com/@budibase/auth/-/auth-0.9.66.tgz#543eb6e0cbc0072d8567fdb5ce0f60a601e84f9f"
- integrity sha512-hLVCzSmXk7X6oYpNQz06wYyXeN/eJP1AWKtfJfvUOCyE1zLDAxxkvk6UTnAZJ6Mj013QNjWfI9ohlncvY1vsmQ==
+"@budibase/auth@^0.9.80-alpha.7":
+ version "0.9.80-alpha.7"
+ resolved "https://registry.yarnpkg.com/@budibase/auth/-/auth-0.9.80-alpha.7.tgz#6fb4c40a5f437bb9f7e49c9acafbc601b0dffa49"
+ integrity sha512-9KZy8hqdpaWRY2n3pRAThP4Jb9TsrfJsJFdfDndJtPO1tTNKtDw2LGEwrT5Kym0a0SBHEzVrXq1Vw/sg72ACIQ==
dependencies:
+ "@techpass/passport-openidconnect" "^0.3.0"
aws-sdk "^2.901.0"
bcryptjs "^2.4.3"
ioredis "^4.27.1"
@@ -1167,10 +1168,10 @@
uuid "^8.3.2"
zlib "^1.0.5"
-"@budibase/bbui@^0.9.66":
- version "0.9.66"
- resolved "https://registry.yarnpkg.com/@budibase/bbui/-/bbui-0.9.66.tgz#aba79def0d90c2fcb322ae787c06b47f6c1c3814"
- integrity sha512-2P7SFbrw5/E8g4eSZ4OBuJOMDQPyjZBTcZkGtMIP2BlGH3Pn6OilYrH9OmHhn0zebzFA4hGoRgrT2TOiMBRCrg==
+"@budibase/bbui@^0.9.80-alpha.7":
+ version "0.9.80-alpha.7"
+ resolved "https://registry.yarnpkg.com/@budibase/bbui/-/bbui-0.9.80-alpha.7.tgz#5fbb7a6617a35a560151377fdc67a845f5620803"
+ integrity sha512-VJPP6A3BhxsLQzEfKPz3alCiT0nMqeM75P/reT1jsRxZsOCJ8vFn7g2c8aH2bEIcCqOWeUaaxVDuj8ghbzByUw==
dependencies:
"@adobe/spectrum-css-workflow-icons" "^1.2.1"
"@spectrum-css/actionbutton" "^1.0.1"
@@ -1215,68 +1216,66 @@
svelte-flatpickr "^3.1.0"
svelte-portal "^1.0.0"
-"@budibase/client@^0.9.66":
- version "0.9.66"
- resolved "https://registry.yarnpkg.com/@budibase/client/-/client-0.9.66.tgz#04a0838352169607fc005f9910e7c2d485fdbe06"
- integrity sha512-2SJWAZjqi5DUdAJBYmyfKuCw1pHmgzdjEHgU0kP5MZpHxcllKcyQCTELRVFRebz74PR9GibjvNNUIexQQElEVQ==
+"@budibase/client@^0.9.80-alpha.7":
+ version "0.9.80-alpha.7"
+ resolved "https://registry.yarnpkg.com/@budibase/client/-/client-0.9.80-alpha.7.tgz#9d2e98b90cd9fdcfc659826d19b5dc206cdcfe7d"
+ integrity sha512-szLz2JpWI9ZMyVz7IPap1fQ7e+uphuthOkOsERplmq4EXbv914/YILdEfUm01s4aeOEOdkeogz31t8t75es6Dg==
dependencies:
- "@budibase/bbui" "^0.9.66"
- "@budibase/standard-components" "^0.9.66"
- "@budibase/string-templates" "^0.9.66"
+ "@budibase/bbui" "^0.9.80-alpha.7"
+ "@budibase/standard-components" "^0.9.80-alpha.7"
+ "@budibase/string-templates" "^0.9.80-alpha.7"
regexparam "^1.3.0"
shortid "^2.2.15"
svelte-spa-router "^3.0.5"
"@budibase/handlebars-helpers@^0.11.4":
- version "0.11.4"
- resolved "https://registry.yarnpkg.com/@budibase/handlebars-helpers/-/handlebars-helpers-0.11.4.tgz#8acfa2ee84134f7be4b2906e710fce6d25c5d000"
- integrity sha512-AJNJYlJnxZmn9QJ8tBl8nrm4YxbwHP4AR0pbiVGK+EoOylkNBlUnZ/QDL1VyqM5fTkAE/Z2IZVLKrrG3kxuWLA==
+ version "0.11.5"
+ resolved "https://registry.yarnpkg.com/@budibase/handlebars-helpers/-/handlebars-helpers-0.11.5.tgz#e9cc90a44e94ad536992cf10906829b633e94bc5"
+ integrity sha512-ZxpyNtTHxS8Y+yTicbgWvYDAydooUSjOf3Y+wmTE2d4NpDgO0g0IjepLfZV+KASv9XBr//ylJdjE4hClX9NTFw==
dependencies:
- arr-flatten "^1.1.0"
- array-sort "^0.1.4"
- define-property "^1.0.0"
+ array-sort "^1.0.0"
+ define-property "^2.0.2"
extend-shallow "^3.0.2"
- "falsey" "^0.3.2"
+ "falsey" "^1.0.0"
for-in "^1.0.2"
- for-own "^1.0.0"
get-object "^0.2.0"
- get-value "^2.0.6"
- handlebars "^4.0.11"
+ get-value "^3.0.1"
+ handlebars "^4.7.7"
handlebars-utils "^1.0.6"
- has-value "^1.0.0"
+ has-value "^2.0.2"
helper-date "^1.0.1"
helper-markdown "^1.0.0"
helper-md "^0.2.2"
html-tag "^2.0.0"
is-even "^1.0.0"
- is-glob "^4.0.0"
- is-number "^4.0.0"
- kind-of "^6.0.0"
- logging-helpers "^1.0.0"
- micromatch "^3.1.4"
+ is-glob "^4.0.1"
+ kind-of "^6.0.3"
+ micromatch "^3.1.5"
relative "^3.0.2"
- striptags "^3.1.0"
+ striptags "^3.1.1"
to-gfm-code-block "^0.1.1"
year "^0.2.1"
-"@budibase/standard-components@^0.9.66":
- version "0.9.66"
- resolved "https://registry.yarnpkg.com/@budibase/standard-components/-/standard-components-0.9.66.tgz#79ee98e0b5b71801360594b59966f203197eb6ae"
- integrity sha512-iq+ninGbe5GqNRk8qxlgXXH7hgCFJ90+Xw1zhYRtIE//BmeGYHxEJjDTjG+7qSHPvp2ZB4KkLiD/y7/H0zwuEA==
+"@budibase/standard-components@^0.9.80-alpha.7":
+ version "0.9.80-alpha.7"
+ resolved "https://registry.yarnpkg.com/@budibase/standard-components/-/standard-components-0.9.80-alpha.7.tgz#17f13a25bfcda873f44d1460493325adcfe6f188"
+ integrity sha512-ohEVqhRxp2FeOlEnJtfBhyqtwmRGI/qPGs0K9FQfLQglMYJtPN5FgMrJ1gtN0W3zn7TOfNFnTcQIxIdLxSLwyA==
dependencies:
- "@budibase/bbui" "^0.9.66"
+ "@budibase/bbui" "^0.9.80-alpha.7"
+ "@spectrum-css/card" "^3.0.3"
"@spectrum-css/link" "^3.1.3"
"@spectrum-css/page" "^3.0.1"
+ "@spectrum-css/typography" "^3.0.2"
"@spectrum-css/vars" "^3.0.1"
apexcharts "^3.22.1"
dayjs "^1.10.5"
svelte-apexcharts "^1.0.2"
svelte-flatpickr "^3.1.0"
-"@budibase/string-templates@^0.9.66":
- version "0.9.66"
- resolved "https://registry.yarnpkg.com/@budibase/string-templates/-/string-templates-0.9.66.tgz#700145549f1636cb46f88b94ef23b3a064058b75"
- integrity sha512-eFFBTTKlRpzNSNwKGOclRkXlrKr5UxV3sCU2QfskPXai4hx9RtD/LyKKSlLshVU1ZjwfTCor9cm7f/hhxRzuRA==
+"@budibase/string-templates@^0.9.80-alpha.7":
+ version "0.9.80-alpha.7"
+ resolved "https://registry.yarnpkg.com/@budibase/string-templates/-/string-templates-0.9.80-alpha.7.tgz#10b06fc8652c00065f8928caebfcd0d143660078"
+ integrity sha512-lD3BSWXW6PrdAbZcpVXSsr/fA8NdwvQ8W7T4chQ661UUMKVOYLnGwAvvAOArGpkdzSOAfSEuzgIB0+pBc92qWQ==
dependencies:
"@budibase/handlebars-helpers" "^0.11.4"
dayjs "^1.10.4"
@@ -2115,6 +2114,11 @@
resolved "https://registry.yarnpkg.com/@spectrum-css/buttongroup/-/buttongroup-3.0.3.tgz#719d868845ac9d2c4f939c1b9f6044507902d5aa"
integrity sha512-eXl8U4QWMWXqyTu654FdQdEGnmczgOYlpIFSHyCMVjhtPqZp2xwnLFiGh6LKw+bLio6eeOZ0L+vpk1GcoYqgkw==
+"@spectrum-css/card@^3.0.3":
+ version "3.0.3"
+ resolved "https://registry.yarnpkg.com/@spectrum-css/card/-/card-3.0.3.tgz#56b2e2da6b80c1583228baa279de7407383bfb6b"
+ integrity sha512-+oKLUI2a0QmQP9EzySeq/G4FpUkkdaDNbuEbqCj2IkPMc/2v/nwzsPhh1fj2UIghGAiiUwXfPpzax1e8fyhQUg==
+
"@spectrum-css/checkbox@^3.0.2":
version "3.0.3"
resolved "https://registry.yarnpkg.com/@spectrum-css/checkbox/-/checkbox-3.0.3.tgz#8577067fc8b97e4609f92bd242364937a533a7bb"
@@ -2274,7 +2278,7 @@
resolved "https://registry.yarnpkg.com/@spectrum-css/treeview/-/treeview-3.0.3.tgz#aeda5175158b9f8d7529cb2b394428eb2a428046"
integrity sha512-D5gGzZC/KtRArdx86Mesc9+99W9nTbUOeyYGqoJoAfJSOttoT6Tk5CrDvlCmAqjKf5rajemAkGri1ChqvUIwkw==
-"@spectrum-css/typography@^3.0.1":
+"@spectrum-css/typography@^3.0.1", "@spectrum-css/typography@^3.0.2":
version "3.0.2"
resolved "https://registry.yarnpkg.com/@spectrum-css/typography/-/typography-3.0.2.tgz#ea3ca0a60e18064527819d48c8c4364cab4fcd38"
integrity sha512-5ZOLmQe0edzsDMyhghUd4hBb5uxGsFrxzf+WasfcUw9klSfTsRZ09n1BsaaWbgrLjlMQ+EEHS46v5VNo0Ms2CA==
@@ -2296,6 +2300,17 @@
dependencies:
defer-to-connect "^1.0.1"
+"@techpass/passport-openidconnect@^0.3.0":
+ version "0.3.0"
+ resolved "https://registry.yarnpkg.com/@techpass/passport-openidconnect/-/passport-openidconnect-0.3.0.tgz#a60b2bbf3f262649a5a02d5d186219944acc3010"
+ integrity sha512-bVsPwl66s7J7GHxTPlW/RJYhZol9SshNznQsx83OOh9G+JWFGoeWxh+xbX+FTdJNoUvGIGbJnpWPY2wC6NOHPw==
+ dependencies:
+ base64url "^3.0.1"
+ oauth "^0.9.15"
+ passport-strategy "^1.0.0"
+ request "^2.88.0"
+ webfinger "^0.4.2"
+
"@tootallnate/once@1":
version "1.1.2"
resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-1.1.2.tgz#ccb91445360179a04e7fe6aff78c00ffc1eeaf82"
@@ -2835,130 +2850,6 @@ ansi-align@^3.0.0:
dependencies:
string-width "^3.0.0"
-ansi-bgblack@^0.1.1:
- version "0.1.1"
- resolved "https://registry.yarnpkg.com/ansi-bgblack/-/ansi-bgblack-0.1.1.tgz#a68ba5007887701b6aafbe3fa0dadfdfa8ee3ca2"
- integrity sha1-poulAHiHcBtqr74/oNrf36juPKI=
- dependencies:
- ansi-wrap "0.1.0"
-
-ansi-bgblue@^0.1.1:
- version "0.1.1"
- resolved "https://registry.yarnpkg.com/ansi-bgblue/-/ansi-bgblue-0.1.1.tgz#67bdc04edc9b9b5278969da196dea3d75c8c3613"
- integrity sha1-Z73ATtybm1J4lp2hlt6j11yMNhM=
- dependencies:
- ansi-wrap "0.1.0"
-
-ansi-bgcyan@^0.1.1:
- version "0.1.1"
- resolved "https://registry.yarnpkg.com/ansi-bgcyan/-/ansi-bgcyan-0.1.1.tgz#58489425600bde9f5507068dd969ebfdb50fe768"
- integrity sha1-WEiUJWAL3p9VBwaN2Wnr/bUP52g=
- dependencies:
- ansi-wrap "0.1.0"
-
-ansi-bggreen@^0.1.1:
- version "0.1.1"
- resolved "https://registry.yarnpkg.com/ansi-bggreen/-/ansi-bggreen-0.1.1.tgz#4e3191248529943f4321e96bf131d1c13816af49"
- integrity sha1-TjGRJIUplD9DIelr8THRwTgWr0k=
- dependencies:
- ansi-wrap "0.1.0"
-
-ansi-bgmagenta@^0.1.1:
- version "0.1.1"
- resolved "https://registry.yarnpkg.com/ansi-bgmagenta/-/ansi-bgmagenta-0.1.1.tgz#9b28432c076eaa999418672a3efbe19391c2c7a1"
- integrity sha1-myhDLAduqpmUGGcqPvvhk5HCx6E=
- dependencies:
- ansi-wrap "0.1.0"
-
-ansi-bgred@^0.1.1:
- version "0.1.1"
- resolved "https://registry.yarnpkg.com/ansi-bgred/-/ansi-bgred-0.1.1.tgz#a76f92838382ba43290a6c1778424f984d6f1041"
- integrity sha1-p2+Sg4OCukMpCmwXeEJPmE1vEEE=
- dependencies:
- ansi-wrap "0.1.0"
-
-ansi-bgwhite@^0.1.1:
- version "0.1.1"
- resolved "https://registry.yarnpkg.com/ansi-bgwhite/-/ansi-bgwhite-0.1.1.tgz#6504651377a58a6ececd0331994e480258e11ba8"
- integrity sha1-ZQRlE3elim7OzQMxmU5IAljhG6g=
- dependencies:
- ansi-wrap "0.1.0"
-
-ansi-bgyellow@^0.1.1:
- version "0.1.1"
- resolved "https://registry.yarnpkg.com/ansi-bgyellow/-/ansi-bgyellow-0.1.1.tgz#c3fe2eb08cd476648029e6874d15a0b38f61d44f"
- integrity sha1-w/4usIzUdmSAKeaHTRWgs49h1E8=
- dependencies:
- ansi-wrap "0.1.0"
-
-ansi-black@^0.1.1:
- version "0.1.1"
- resolved "https://registry.yarnpkg.com/ansi-black/-/ansi-black-0.1.1.tgz#f6185e889360b2545a1ec50c0bf063fc43032453"
- integrity sha1-9hheiJNgslRaHsUMC/Bj/EMDJFM=
- dependencies:
- ansi-wrap "0.1.0"
-
-ansi-blue@^0.1.1:
- version "0.1.1"
- resolved "https://registry.yarnpkg.com/ansi-blue/-/ansi-blue-0.1.1.tgz#15b804990e92fc9ca8c5476ce8f699777c21edbf"
- integrity sha1-FbgEmQ6S/JyoxUds6PaZd3wh7b8=
- dependencies:
- ansi-wrap "0.1.0"
-
-ansi-bold@^0.1.1:
- version "0.1.1"
- resolved "https://registry.yarnpkg.com/ansi-bold/-/ansi-bold-0.1.1.tgz#3e63950af5acc2ae2e670e6f67deb115d1a5f505"
- integrity sha1-PmOVCvWswq4uZw5vZ96xFdGl9QU=
- dependencies:
- ansi-wrap "0.1.0"
-
-ansi-colors@^0.2.0:
- version "0.2.0"
- resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-0.2.0.tgz#72c31de2a0d9a2ccd0cac30cc9823eeb2f6434b5"
- integrity sha1-csMd4qDZoszQysMMyYI+6y9kNLU=
- dependencies:
- ansi-bgblack "^0.1.1"
- ansi-bgblue "^0.1.1"
- ansi-bgcyan "^0.1.1"
- ansi-bggreen "^0.1.1"
- ansi-bgmagenta "^0.1.1"
- ansi-bgred "^0.1.1"
- ansi-bgwhite "^0.1.1"
- ansi-bgyellow "^0.1.1"
- ansi-black "^0.1.1"
- ansi-blue "^0.1.1"
- ansi-bold "^0.1.1"
- ansi-cyan "^0.1.1"
- ansi-dim "^0.1.1"
- ansi-gray "^0.1.1"
- ansi-green "^0.1.1"
- ansi-grey "^0.1.1"
- ansi-hidden "^0.1.1"
- ansi-inverse "^0.1.1"
- ansi-italic "^0.1.1"
- ansi-magenta "^0.1.1"
- ansi-red "^0.1.1"
- ansi-reset "^0.1.1"
- ansi-strikethrough "^0.1.1"
- ansi-underline "^0.1.1"
- ansi-white "^0.1.1"
- ansi-yellow "^0.1.1"
- lazy-cache "^2.0.1"
-
-ansi-cyan@^0.1.1:
- version "0.1.1"
- resolved "https://registry.yarnpkg.com/ansi-cyan/-/ansi-cyan-0.1.1.tgz#538ae528af8982f28ae30d86f2f17456d2609873"
- integrity sha1-U4rlKK+JgvKK4w2G8vF0VtJgmHM=
- dependencies:
- ansi-wrap "0.1.0"
-
-ansi-dim@^0.1.1:
- version "0.1.1"
- resolved "https://registry.yarnpkg.com/ansi-dim/-/ansi-dim-0.1.1.tgz#40de4c603aa8086d8e7a86b8ff998d5c36eefd6c"
- integrity sha1-QN5MYDqoCG2Oeoa4/5mNXDbu/Ww=
- dependencies:
- ansi-wrap "0.1.0"
-
ansi-escapes@^4.2.1:
version "4.3.2"
resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.3.2.tgz#6b2291d1db7d98b6521d5f1efa42d0f3a9feb65e"
@@ -2966,62 +2857,6 @@ ansi-escapes@^4.2.1:
dependencies:
type-fest "^0.21.3"
-ansi-gray@^0.1.1:
- version "0.1.1"
- resolved "https://registry.yarnpkg.com/ansi-gray/-/ansi-gray-0.1.1.tgz#2962cf54ec9792c48510a3deb524436861ef7251"
- integrity sha1-KWLPVOyXksSFEKPetSRDaGHvclE=
- dependencies:
- ansi-wrap "0.1.0"
-
-ansi-green@^0.1.1:
- version "0.1.1"
- resolved "https://registry.yarnpkg.com/ansi-green/-/ansi-green-0.1.1.tgz#8a5d9a979e458d57c40e33580b37390b8e10d0f7"
- integrity sha1-il2al55FjVfEDjNYCzc5C44Q0Pc=
- dependencies:
- ansi-wrap "0.1.0"
-
-ansi-grey@^0.1.1:
- version "0.1.1"
- resolved "https://registry.yarnpkg.com/ansi-grey/-/ansi-grey-0.1.1.tgz#59d98b6ac2ba19f8a51798e9853fba78339a33c1"
- integrity sha1-WdmLasK6GfilF5jphT+6eDOaM8E=
- dependencies:
- ansi-wrap "0.1.0"
-
-ansi-hidden@^0.1.1:
- version "0.1.1"
- resolved "https://registry.yarnpkg.com/ansi-hidden/-/ansi-hidden-0.1.1.tgz#ed6a4c498d2bb7cbb289dbf2a8d1dcc8567fae0f"
- integrity sha1-7WpMSY0rt8uyidvyqNHcyFZ/rg8=
- dependencies:
- ansi-wrap "0.1.0"
-
-ansi-inverse@^0.1.1:
- version "0.1.1"
- resolved "https://registry.yarnpkg.com/ansi-inverse/-/ansi-inverse-0.1.1.tgz#b6af45826fe826bfb528a6c79885794355ccd269"
- integrity sha1-tq9Fgm/oJr+1KKbHmIV5Q1XM0mk=
- dependencies:
- ansi-wrap "0.1.0"
-
-ansi-italic@^0.1.1:
- version "0.1.1"
- resolved "https://registry.yarnpkg.com/ansi-italic/-/ansi-italic-0.1.1.tgz#104743463f625c142a036739cf85eda688986f23"
- integrity sha1-EEdDRj9iXBQqA2c5z4XtpoiYbyM=
- dependencies:
- ansi-wrap "0.1.0"
-
-ansi-magenta@^0.1.1:
- version "0.1.1"
- resolved "https://registry.yarnpkg.com/ansi-magenta/-/ansi-magenta-0.1.1.tgz#063b5ba16fb3f23e1cfda2b07c0a89de11e430ae"
- integrity sha1-BjtboW+z8j4c/aKwfAqJ3hHkMK4=
- dependencies:
- ansi-wrap "0.1.0"
-
-ansi-red@^0.1.1:
- version "0.1.1"
- resolved "https://registry.yarnpkg.com/ansi-red/-/ansi-red-0.1.1.tgz#8c638f9d1080800a353c9c28c8a81ca4705d946c"
- integrity sha1-jGOPnRCAgAo1PJwoyKgcpHBdlGw=
- dependencies:
- ansi-wrap "0.1.0"
-
ansi-regex@^2.0.0:
version "2.1.1"
resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df"
@@ -3037,20 +2872,6 @@ ansi-regex@^5.0.0:
resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.0.tgz#388539f55179bf39339c81af30a654d69f87cb75"
integrity sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==
-ansi-reset@^0.1.1:
- version "0.1.1"
- resolved "https://registry.yarnpkg.com/ansi-reset/-/ansi-reset-0.1.1.tgz#e7e71292c3c7ddcd4d62ef4a6c7c05980911c3b7"
- integrity sha1-5+cSksPH3c1NYu9KbHwFmAkRw7c=
- dependencies:
- ansi-wrap "0.1.0"
-
-ansi-strikethrough@^0.1.1:
- version "0.1.1"
- resolved "https://registry.yarnpkg.com/ansi-strikethrough/-/ansi-strikethrough-0.1.1.tgz#d84877140b2cff07d1c93ebce69904f68885e568"
- integrity sha1-2Eh3FAss/wfRyT685pkE9oiF5Wg=
- dependencies:
- ansi-wrap "0.1.0"
-
ansi-styles@^3.2.0, ansi-styles@^3.2.1:
version "3.2.1"
resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d"
@@ -3070,32 +2891,6 @@ ansi-styles@^5.0.0:
resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-5.2.0.tgz#07449690ad45777d1924ac2abb2fc8895dba836b"
integrity sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==
-ansi-underline@^0.1.1:
- version "0.1.1"
- resolved "https://registry.yarnpkg.com/ansi-underline/-/ansi-underline-0.1.1.tgz#dfc920f4c97b5977ea162df8ffb988308aaa71a4"
- integrity sha1-38kg9Ml7WXfqFi34/7mIMIqqcaQ=
- dependencies:
- ansi-wrap "0.1.0"
-
-ansi-white@^0.1.1:
- version "0.1.1"
- resolved "https://registry.yarnpkg.com/ansi-white/-/ansi-white-0.1.1.tgz#9c77b7c193c5ee992e6011d36ec4c921b4578944"
- integrity sha1-nHe3wZPF7pkuYBHTbsTJIbRXiUQ=
- dependencies:
- ansi-wrap "0.1.0"
-
-ansi-wrap@0.1.0:
- version "0.1.0"
- resolved "https://registry.yarnpkg.com/ansi-wrap/-/ansi-wrap-0.1.0.tgz#a82250ddb0015e9a27ca82e82ea603bbfa45efaf"
- integrity sha1-qCJQ3bABXponyoLoLqYDu/pF768=
-
-ansi-yellow@^0.1.1:
- version "0.1.1"
- resolved "https://registry.yarnpkg.com/ansi-yellow/-/ansi-yellow-0.1.1.tgz#cb9356f2f46c732f0e3199e6102955a77da83c1d"
- integrity sha1-y5NW8vRscy8OMZnmEClVp32oPB0=
- dependencies:
- ansi-wrap "0.1.0"
-
any-base@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/any-base/-/any-base-1.1.0.tgz#ae101a62bc08a597b4c9ab5b7089d456630549fe"
@@ -3123,9 +2918,9 @@ anymatch@^3.0.3, anymatch@~3.1.1:
picomatch "^2.0.4"
apexcharts@^3.19.2, apexcharts@^3.22.1:
- version "3.27.1"
- resolved "https://registry.yarnpkg.com/apexcharts/-/apexcharts-3.27.1.tgz#b0e6dd3b3ace028f29b32fcd88e19a2420a18089"
- integrity sha512-2pfw3pxeWhI0ap5lfxyfGNGoGScfEwfc8XnTpbnzgRdr1AOH5JJN9hh3MvfwrC9TQQfJYC2TZc8P/q9qXUj1bQ==
+ version "3.27.3"
+ resolved "https://registry.yarnpkg.com/apexcharts/-/apexcharts-3.27.3.tgz#1b921ac64dea2f28a2b1aad4b396b38464223849"
+ integrity sha512-1ZrqiQT0VahkqW0kVjf5QVURYGaHMlGN08BoIZG2c2U/gY2AtnEoFN4r9q4d/pYYYKvI9AyLBHq0otzcVGrHAw==
dependencies:
svg.draggable.js "^2.2.2"
svg.easing.js "^2.0.0"
@@ -3204,10 +2999,10 @@ array-flatten@1.1.1:
resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2"
integrity sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=
-array-sort@^0.1.4:
- version "0.1.4"
- resolved "https://registry.yarnpkg.com/array-sort/-/array-sort-0.1.4.tgz#662855eaeb671b4188df4451b2f24a0753992b23"
- integrity sha512-BNcM+RXxndPxiZ2rd76k6nyQLRZr2/B/sdi8pQ+Joafr5AH279L40dfokSUTp8O+AaqYjXWhblBWa2st2nc4fQ==
+array-sort@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/array-sort/-/array-sort-1.0.0.tgz#e4c05356453f56f53512a7d1d6123f2c54c0a88a"
+ integrity sha512-ihLeJkonmdiAsD7vpgN3CRcx2J2S0TiYW+IS/5zHBI7mKUq3ySvBdzzBfD236ubDBQFiiyG3SWCPc+msQ9KoYg==
dependencies:
default-compare "^1.0.0"
get-value "^2.0.6"
@@ -3315,9 +3110,9 @@ aws-sdk@^2.767.0:
xml2js "0.4.19"
aws-sdk@^2.901.0:
- version "2.934.0"
- resolved "https://registry.yarnpkg.com/aws-sdk/-/aws-sdk-2.934.0.tgz#1c26bd8ded15d2f6b2aa3301d35fc5daf1a61d68"
- integrity sha512-k7p08ewrKcbs0ikCLFi9OI98Iv9dMND5244xPxUIjK5BLtuT/9Gr6eSCHfN70eCQyM5Y2xG1VJP6zhpkihu9Ew==
+ version "2.953.0"
+ resolved "https://registry.yarnpkg.com/aws-sdk/-/aws-sdk-2.953.0.tgz#2ba87da084164bcb8e325e67356b8372e54cb5d9"
+ integrity sha512-CCsJm+ggE1HQ2fkCto+JRqJyET81Vw8eZr/KnNw19jqRiAsXNj5GqAh1JNyTCHEif8PcjREtP7o3y093ylSUyg==
dependencies:
buffer "4.9.2"
events "1.1.1"
@@ -3510,7 +3305,7 @@ base64-js@^1.0.2, base64-js@^1.3.1:
resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a"
integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==
-base64url@3.x.x:
+base64url@3.x.x, base64url@^3.0.1:
version "3.0.1"
resolved "https://registry.yarnpkg.com/base64url/-/base64url-3.0.1.tgz#6399d572e2bc3f90a9a8b22d5dbb0a32d33f788d"
integrity sha512-ir1UPr3dkwexU7FdV8qBBbNDRUhMmIekYMFZfi+C/sLNnRESKPl23nB9b2pltqfOQNnGzsDdId90AEtG5tCx4A==
@@ -4374,9 +4169,9 @@ dateformat@^3.0.3:
integrity sha512-jyCETtSl3VMZMWeRo7iY1FL19ges1t55hMo5yaam4Jrsm5EPL89UQkoQRyiI+Yf4k8r2ZpdngkV8hr1lIdjb3Q==
dayjs@^1.10.4, dayjs@^1.10.5:
- version "1.10.5"
- resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.10.5.tgz#5600df4548fc2453b3f163ebb2abbe965ccfb986"
- integrity sha512-BUFis41ikLz+65iH6LHQCDm4YPMj5r1YFLdupPIyM4SGcXMmtiLQ7U37i+hGS8urIuqe7I/ou3IS1jVc4nbN4g==
+ version "1.10.6"
+ resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.10.6.tgz#288b2aa82f2d8418a6c9d4df5898c0737ad02a63"
+ integrity sha512-AztC/IOW4L1Q41A86phW5Thhcrco3xuAA+YX/BLpLWWjRcTj5TOt/QImBLmCKlrF7u7k47arTnOyL6GnbG8Hvw==
debug@2.6.9, debug@^2.2.0, debug@^2.3.3:
version "2.6.9"
@@ -4825,11 +4620,6 @@ error-inject@^1.0.0:
resolved "https://registry.yarnpkg.com/error-inject/-/error-inject-1.0.0.tgz#e2b3d91b54aed672f309d950d154850fa11d4f37"
integrity sha1-4rPZG1Su1nLzCdlQ0VSFD6EdTzc=
-error-symbol@^0.1.0:
- version "0.1.0"
- resolved "https://registry.yarnpkg.com/error-symbol/-/error-symbol-0.1.0.tgz#0a4dae37d600d15a29ba453d8ef920f1844333f6"
- integrity sha1-Ck2uN9YA0VopukU9jvkg8YRDM/Y=
-
es-abstract@^1.17.0-next.0, es-abstract@^1.18.0-next.2:
version "1.18.3"
resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.18.3.tgz#25c4c3380a27aa203c44b2b685bba94da31b63e0"
@@ -5306,12 +5096,10 @@ falafel@^1.0.1:
isarray "0.0.1"
object-keys "^1.0.6"
-"falsey@^0.3.2":
- version "0.3.2"
- resolved "https://registry.yarnpkg.com/falsey/-/falsey-0.3.2.tgz#b21c90c5c34660fc192bf909575db95b6880d597"
- integrity sha512-lxEuefF5MBIVDmE6XeqCdM4BWk1+vYmGZtkbKZ/VFcg6uBBw6fXNEbWmxCjDdQlFc9hy450nkiWwM3VAW6G1qg==
- dependencies:
- kind-of "^5.0.2"
+"falsey@^1.0.0":
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/falsey/-/falsey-1.0.0.tgz#71bdd775c24edad9f2f5c015ce8be24400bb5d7d"
+ integrity sha512-zMDNZ/Ipd8MY0+346CPvhzP1AsiVyNfTOayJza4reAIWf72xbkuFUDcJNxSAsQE1b9Bu0wijKb8Ngnh/a7fI5w==
fast-deep-equal@^3.1.1:
version "3.1.3"
@@ -5556,18 +5344,11 @@ for-each@^0.3.3:
dependencies:
is-callable "^1.1.3"
-for-in@^1.0.1, for-in@^1.0.2:
+for-in@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80"
integrity sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=
-for-own@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/for-own/-/for-own-1.0.0.tgz#c63332f415cedc4b04dbfe70cf836494c53cb44b"
- integrity sha1-xjMy9BXO3EsE2/5wz4NklMU8tEs=
- dependencies:
- for-in "^1.0.1"
-
foreach@^2.0.5:
version "2.0.5"
resolved "https://registry.yarnpkg.com/foreach/-/foreach-2.0.5.tgz#0bee005018aeb260d0a3af3ae658dd0136ec1b99"
@@ -5756,6 +5537,13 @@ get-value@^2.0.3, get-value@^2.0.6:
resolved "https://registry.yarnpkg.com/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28"
integrity sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=
+get-value@^3.0.0, get-value@^3.0.1:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/get-value/-/get-value-3.0.1.tgz#5efd2a157f1d6a516d7524e124ac52d0a39ef5a8"
+ integrity sha512-mKZj9JLQrwMBtj5wxi6MH8Z5eSKaERpAwjg43dPtlGI1ZVEgH/qC7T8/6R2OBSUA+zzHBZgICsVJaEIV2tKTDA==
+ dependencies:
+ isobject "^3.0.1"
+
getopts@2.2.5:
version "2.2.5"
resolved "https://registry.yarnpkg.com/getopts/-/getopts-2.2.5.tgz#67a0fe471cacb9c687d817cab6450b96dde8313b"
@@ -5943,7 +5731,7 @@ handlebars-utils@^1.0.2, handlebars-utils@^1.0.4, handlebars-utils@^1.0.6:
kind-of "^6.0.0"
typeof-article "^0.1.1"
-handlebars@^4.0.11, handlebars@^4.7.6:
+handlebars@^4.7.6, handlebars@^4.7.7:
version "4.7.7"
resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.7.7.tgz#9ce33416aad02dbd6c8fafa8240d5d98004945a1"
integrity sha512-aAcXm5OAfE/8IXkcZvCepKU3VzW1/39Fb5ZuqMtgI/hT8X2YgoMvBY5dLhq/cpOvw7Lk1nK/UF71aLG/ZnVYRA==
@@ -6018,6 +5806,14 @@ has-value@^1.0.0:
has-values "^1.0.0"
isobject "^3.0.0"
+has-value@^2.0.2:
+ version "2.0.2"
+ resolved "https://registry.yarnpkg.com/has-value/-/has-value-2.0.2.tgz#d0f12e8780ba8e90e66ad1a21c707fdb67c25658"
+ integrity sha512-ybKOlcRsK2MqrM3Hmz/lQxXHZ6ejzSPzpNabKB45jb5qDgJvKPa3SdapTsTLwEb9WltgWpOmNax7i+DzNOk4TA==
+ dependencies:
+ get-value "^3.0.0"
+ has-values "^2.0.1"
+
has-values@^0.1.4:
version "0.1.4"
resolved "https://registry.yarnpkg.com/has-values/-/has-values-0.1.4.tgz#6d61de95d91dfca9b9a02089ad384bff8f62b771"
@@ -6031,6 +5827,13 @@ has-values@^1.0.0:
is-number "^3.0.0"
kind-of "^4.0.0"
+has-values@^2.0.1:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/has-values/-/has-values-2.0.1.tgz#3876200ff86d8a8546a9264a952c17d5fc17579d"
+ integrity sha512-+QdH3jOmq9P8GfdjFg0eJudqx1FqU62NQJ4P16rOEHeRdl7ckgwn6uqQjzYE0ZoHVV/e5E2esuJ5Gl5+HUW19w==
+ dependencies:
+ kind-of "^6.0.2"
+
has-yarn@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/has-yarn/-/has-yarn-2.1.0.tgz#137e11354a7b5bf11aa5cb649cf0c6f3ff2b2e77"
@@ -6298,11 +6101,6 @@ inflight@^1.0.4:
once "^1.3.0"
wrappy "1"
-info-symbol@^0.1.0:
- version "0.1.0"
- resolved "https://registry.yarnpkg.com/info-symbol/-/info-symbol-0.1.0.tgz#27841d72867ddb4242cd612d79c10633881c6a78"
- integrity sha1-J4QdcoZ920JCzWEtecEGM4gcang=
-
inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.1, inherits@~2.0.3:
version "2.0.4"
resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c"
@@ -6634,11 +6432,6 @@ is-number@^3.0.0:
dependencies:
kind-of "^3.0.2"
-is-number@^4.0.0:
- version "4.0.0"
- resolved "https://registry.yarnpkg.com/is-number/-/is-number-4.0.0.tgz#0026e37f5454d73e356dfe6564699867c6a7f0ff"
- integrity sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==
-
is-number@^7.0.0:
version "7.0.0"
resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b"
@@ -7895,7 +7688,7 @@ kind-of@^5.0.0, kind-of@^5.0.2:
resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-5.1.0.tgz#729c91e2d857b7a419a1f9aa65685c4c33f5845d"
integrity sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==
-kind-of@^6.0.0, kind-of@^6.0.2:
+kind-of@^6.0.0, kind-of@^6.0.2, kind-of@^6.0.3:
version "6.0.3"
resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd"
integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==
@@ -8062,13 +7855,6 @@ latest-version@^5.0.0:
dependencies:
package-json "^6.3.0"
-lazy-cache@^2.0.1:
- version "2.0.2"
- resolved "https://registry.yarnpkg.com/lazy-cache/-/lazy-cache-2.0.2.tgz#b9190a4f913354694840859f8a8f7084d8822264"
- integrity sha1-uRkKT5EzVGlIQIWfio9whNiCImQ=
- dependencies:
- set-getter "^0.1.0"
-
lcid@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/lcid/-/lcid-2.0.0.tgz#6ef5d2df60e52f82eb228a4c373e8d1f397253cf"
@@ -8389,35 +8175,6 @@ lodash@4.17.21, lodash@4.x, lodash@^4.14.0, lodash@^4.17.11, lodash@^4.17.14, lo
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c"
integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==
-log-ok@^0.1.1:
- version "0.1.1"
- resolved "https://registry.yarnpkg.com/log-ok/-/log-ok-0.1.1.tgz#bea3dd36acd0b8a7240d78736b5b97c65444a334"
- integrity sha1-vqPdNqzQuKckDXhza1uXxlREozQ=
- dependencies:
- ansi-green "^0.1.1"
- success-symbol "^0.1.0"
-
-log-utils@^0.2.1:
- version "0.2.1"
- resolved "https://registry.yarnpkg.com/log-utils/-/log-utils-0.2.1.tgz#a4c217a0dd9a50515d9b920206091ab3d4e031cf"
- integrity sha1-pMIXoN2aUFFdm5ICBgkas9TgMc8=
- dependencies:
- ansi-colors "^0.2.0"
- error-symbol "^0.1.0"
- info-symbol "^0.1.0"
- log-ok "^0.1.1"
- success-symbol "^0.1.0"
- time-stamp "^1.0.1"
- warning-symbol "^0.1.0"
-
-logging-helpers@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/logging-helpers/-/logging-helpers-1.0.0.tgz#b5a37b32ad53eb0137c58c7898a47b175ddb7c36"
- integrity sha512-qyIh2goLt1sOgQQrrIWuwkRjUx4NUcEqEGAcYqD8VOnOC6ItwkrVE8/tA4smGpjzyp4Svhc6RodDp9IO5ghpyA==
- dependencies:
- isobject "^3.0.0"
- log-utils "^0.2.1"
-
loose-envify@^1.0.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf"
@@ -8569,7 +8326,7 @@ methods@^1.0.1, methods@^1.1.1, methods@^1.1.2, methods@~1.1.2:
resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee"
integrity sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=
-micromatch@^3.1.10, micromatch@^3.1.4:
+micromatch@^3.1.10, micromatch@^3.1.4, micromatch@^3.1.5:
version "3.1.10"
resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23"
integrity sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==
@@ -8969,7 +8726,7 @@ oauth-sign@~0.9.0:
resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455"
integrity sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==
-oauth@0.9.x:
+oauth@0.9.x, oauth@^0.9.15:
version "0.9.15"
resolved "https://registry.yarnpkg.com/oauth/-/oauth-0.9.15.tgz#bd1fefaf686c96b75475aed5196412ff60cfb9c1"
integrity sha1-vR/vr2hslrdUda7VGWQS/2DPucE=
@@ -9317,18 +9074,18 @@ passport-local@^1.0.0:
passport-strategy "1.x.x"
passport-oauth1@1.x.x:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/passport-oauth1/-/passport-oauth1-1.1.0.tgz#a7de988a211f9cf4687377130ea74df32730c918"
- integrity sha1-p96YiiEfnPRoc3cTDqdN8ycwyRg=
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/passport-oauth1/-/passport-oauth1-1.2.0.tgz#5229d431781bf5b265bec86ce9a9cce58a756cf9"
+ integrity sha512-Sv2YWodC6jN12M/OXwmR4BIXeeIHjjbwYTQw4kS6tHK4zYzSEpxBgSJJnknBjICA5cj0ju3FSnG1XmHgIhYnLg==
dependencies:
oauth "0.9.x"
passport-strategy "1.x.x"
utils-merge "1.x.x"
passport-oauth2@1.x.x:
- version "1.5.0"
- resolved "https://registry.yarnpkg.com/passport-oauth2/-/passport-oauth2-1.5.0.tgz#64babbb54ac46a4dcab35e7f266ed5294e3c4108"
- integrity sha512-kqBt6vR/5VlCK8iCx1/KpY42kQ+NEHZwsSyt4Y6STiNjU+wWICG1i8ucc1FapXDGO15C5O5VZz7+7vRzrDPXXQ==
+ version "1.6.0"
+ resolved "https://registry.yarnpkg.com/passport-oauth2/-/passport-oauth2-1.6.0.tgz#5f599735e0ea40ea3027643785f81a3a9b4feb50"
+ integrity sha512-emXPLqLcVEcLFR/QvQXZcwLmfK8e9CqvMgmOFJxcNT3okSFMtUbRRKpY20x5euD+01uHsjjCa07DYboEeLXYiw==
dependencies:
base64url "3.x.x"
oauth "0.9.x"
@@ -10343,7 +10100,7 @@ request-promise-native@^1.0.5:
stealthy-require "^1.1.1"
tough-cookie "^2.3.3"
-"request@>= 2.52.0", request@^2.72.0, request@^2.74.0, request@^2.87.0:
+"request@>= 2.52.0", request@^2.72.0, request@^2.74.0, request@^2.87.0, request@^2.88.0:
version "2.88.2"
resolved "https://registry.yarnpkg.com/request/-/request-2.88.2.tgz#d73c918731cb5a87da047e207234146f664d12b3"
integrity sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==
@@ -10467,7 +10224,7 @@ rimraf@2.6.3:
dependencies:
glob "^7.1.3"
-rimraf@^3.0.0:
+rimraf@^3.0.0, rimraf@^3.0.2:
version "3.0.2"
resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a"
integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==
@@ -10552,7 +10309,7 @@ sax@1.2.1:
resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.1.tgz#7b8e656190b228e81a66aea748480d828cd2d37a"
integrity sha1-e45lYZCyKOgaZq6nSEgNgozS03o=
-sax@>=0.6.0, sax@^1.2.4:
+sax@>=0.1.1, sax@>=0.6.0, sax@^1.2.4:
version "1.2.4"
resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9"
integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==
@@ -10649,13 +10406,6 @@ set-blocking@^2.0.0:
resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7"
integrity sha1-BF+XgtARrppoA93TgrJDkrPYkPc=
-set-getter@^0.1.0:
- version "0.1.1"
- resolved "https://registry.yarnpkg.com/set-getter/-/set-getter-0.1.1.tgz#a3110e1b461d31a9cfc8c5c9ee2e9737ad447102"
- integrity sha512-9sVWOy+gthr+0G9DzqqLaYNA7+5OKkSmcqjL9cBpDEaZrr3ShQlyX2cZ/O/ozE41oxn/Tt0LGEM/w4Rub3A3gw==
- dependencies:
- to-object-path "^0.3.0"
-
set-value@^2.0.0, set-value@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/set-value/-/set-value-2.0.1.tgz#a18d40530e6f07de4228c7defe4227af8cad005b"
@@ -11014,6 +10764,11 @@ stealthy-require@^1.1.1:
resolved "https://registry.yarnpkg.com/stealthy-require/-/stealthy-require-1.1.1.tgz#35b09875b4ff49f26a777e509b3090a3226bf24b"
integrity sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks=
+step@0.0.x:
+ version "0.0.6"
+ resolved "https://registry.yarnpkg.com/step/-/step-0.0.6.tgz#143e7849a5d7d3f4a088fe29af94915216eeede2"
+ integrity sha1-FD54SaXX0/SgiP4pr5SRUhbu7eI=
+
strict-uri-encode@^1.0.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz#279b225df1d582b1f54e65addd4352e18faa0713"
@@ -11157,7 +10912,7 @@ strip-outer@^1.0.0:
dependencies:
escape-string-regexp "^1.0.2"
-striptags@^3.1.0:
+striptags@^3.1.1:
version "3.2.0"
resolved "https://registry.yarnpkg.com/striptags/-/striptags-3.2.0.tgz#cc74a137db2de8b0b9a370006334161f7dd67052"
integrity sha512-g45ZOGzHDMe2bdYMdIvdAfCQkCTDMGBazSw1ypMowwGIee7ZQ5dU0rBJ8Jqgl+jAKIv4dbeE1jscZq9wid1Tkw==
@@ -11172,11 +10927,6 @@ sublevel-pouchdb@7.2.2:
ltgt "2.2.1"
readable-stream "1.1.14"
-success-symbol@^0.1.0:
- version "0.1.0"
- resolved "https://registry.yarnpkg.com/success-symbol/-/success-symbol-0.1.0.tgz#24022e486f3bf1cdca094283b769c472d3b72897"
- integrity sha1-JAIuSG878c3KCUKDt2nEctO3KJc=
-
superagent@^3.8.3:
version "3.8.3"
resolved "https://registry.yarnpkg.com/superagent/-/superagent-3.8.3.tgz#460ea0dbdb7d5b11bc4f78deba565f86a178e128"
@@ -11245,9 +10995,9 @@ svelte-apexcharts@^1.0.2:
apexcharts "^3.19.2"
svelte-flatpickr@^3.1.0:
- version "3.1.1"
- resolved "https://registry.yarnpkg.com/svelte-flatpickr/-/svelte-flatpickr-3.1.1.tgz#c79da72a4acab252ed39bac8168f30f79db3ff80"
- integrity sha512-z/sV/AMTqyybeWPCjoWYUOyuMmu9qX2c2f2cRqYos9K9sM5L3CqagtvfVy7GZQrnEYe+K7l/gGDCAyxJNp2+gA==
+ version "3.2.0"
+ resolved "https://registry.yarnpkg.com/svelte-flatpickr/-/svelte-flatpickr-3.2.0.tgz#7af5455670aa1836db1c286f5c827d9bae7df74c"
+ integrity sha512-4JsPP7xFBPpvGNiFxfbYjv+SrGoGSRMvEdY7c+wHz37PM33NLE+IUmz7FQRNaHyVelmrTyAHPY1CNrI7cmTPhA==
dependencies:
flatpickr "^4.5.2"
@@ -11501,11 +11251,6 @@ tildify@2.0.0:
resolved "https://registry.yarnpkg.com/tildify/-/tildify-2.0.0.tgz#f205f3674d677ce698b7067a99e949ce03b4754a"
integrity sha512-Cc+OraorugtXNfs50hU9KS369rFXCfgGLpfCfvlc+Ud5u6VWmUQsOAa9HbTvheQdYnrdJqqv1e5oIqXppMYnSw==
-time-stamp@^1.0.1:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/time-stamp/-/time-stamp-1.1.0.tgz#764a5a11af50561921b133f3b44e618687e0f5c3"
- integrity sha1-dkpaEa9QVhkhsTPztE5hhofg9cM=
-
timed-out@^4.0.1:
version "4.0.1"
resolved "https://registry.yarnpkg.com/timed-out/-/timed-out-4.0.1.tgz#f32eacac5a175bea25d7fab565ab3ed8741ef56f"
@@ -11768,9 +11513,9 @@ typescript@^4.3.4:
integrity sha512-uauPG7XZn9F/mo+7MrsRjyvbxFpzemRjKEZXS4AK83oP2KKOJPvb+9cO/gmnv8arWZvhnjVOXz7B49m1l0e9Ew==
uglify-js@^3.1.4:
- version "3.13.9"
- resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.13.9.tgz#4d8d21dcd497f29cfd8e9378b9df123ad025999b"
- integrity sha512-wZbyTQ1w6Y7fHdt8sJnHfSIuWeDgk6B5rCb4E/AM6QNNPbOMIZph21PW5dRB3h7Df0GszN+t7RuUH6sWK5bF0g==
+ version "3.14.0"
+ resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.14.0.tgz#2d723a0afee81e0d08db9354a9c277006e942386"
+ integrity sha512-R/tiGB1ZXp2BC+TkRGLwj8xUZgdfT2f4UZEgX6aVjJ5uttPrr4fYmwTWDGqVnBCLbOXRMY6nr/BTbwCtVfps0g==
uid2@0.0.x:
version "0.0.3"
@@ -12060,10 +11805,13 @@ walker@^1.0.7, walker@~1.0.5:
dependencies:
makeerror "1.0.x"
-warning-symbol@^0.1.0:
- version "0.1.0"
- resolved "https://registry.yarnpkg.com/warning-symbol/-/warning-symbol-0.1.0.tgz#bb31dd11b7a0f9d67ab2ed95f457b65825bbad21"
- integrity sha1-uzHdEbeg+dZ6su2V9Fe2WCW7rSE=
+webfinger@^0.4.2:
+ version "0.4.2"
+ resolved "https://registry.yarnpkg.com/webfinger/-/webfinger-0.4.2.tgz#3477a6d97799461896039fcffc650b73468ee76d"
+ integrity sha1-NHem2XeZRhiWA5/P/GULc0aO520=
+ dependencies:
+ step "0.0.x"
+ xml2js "0.1.x"
webidl-conversions@^4.0.2:
version "4.0.2"
@@ -12271,6 +12019,13 @@ xml-parse-from-string@^1.0.0:
resolved "https://registry.yarnpkg.com/xml-parse-from-string/-/xml-parse-from-string-1.0.1.tgz#a9029e929d3dbcded169f3c6e28238d95a5d5a28"
integrity sha1-qQKekp09vN7RafPG4oI42VpdWig=
+xml2js@0.1.x:
+ version "0.1.14"
+ resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.1.14.tgz#5274e67f5a64c5f92974cd85139e0332adc6b90c"
+ integrity sha1-UnTmf1pkxfkpdM2FE54DMq3GuQw=
+ dependencies:
+ sax ">=0.1.1"
+
xml2js@0.4.19:
version "0.4.19"
resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.4.19.tgz#686c20f213209e94abf0d1bcf1efaa291c7827a7"
diff --git a/packages/standard-components/manifest.json b/packages/standard-components/manifest.json
index 78879e2803..2410ba56b5 100644
--- a/packages/standard-components/manifest.json
+++ b/packages/standard-components/manifest.json
@@ -1,4 +1,8 @@
{
+ "features": {
+ "spectrumThemes": true,
+ "intelligentLoading": true
+ },
"layout": {
"name": "Layout",
"description": "This component is specific only to layouts",
@@ -230,7 +234,8 @@
"screenslot": {
"name": "Screenslot",
"icon": "WebPage",
- "description": "Contains your app screens"
+ "description": "Contains your app screens",
+ "editable": false
},
"button": {
"name": "Button",
@@ -290,6 +295,11 @@
],
"defaultValue": "M"
},
+ {
+ "type": "boolean",
+ "label": "Quiet",
+ "key": "quiet"
+ },
{
"type": "boolean",
"label": "Disabled",
@@ -448,6 +458,7 @@
}
},
"stackedlist": {
+ "deprecated": true,
"name": "Stacked List",
"icon": "TaskList",
"description": "A basic card component that can contain content and actions.",
@@ -811,30 +822,29 @@
"type": "select",
"label": "Size",
"key": "size",
- "defaultValue": "md",
+ "defaultValue": "ri-1x",
"options": [
- { "value": "ri-xxs", "label": "xxs" },
- { "value": "ri-xs", "label": "xs" },
- { "value": "ri-sm", "label": "sm" },
- { "value": "ri-1x", "label": "md" },
- { "value": "ri-lg", "label": "lg" },
- { "value": "ri-xl", "label": "xl" },
- { "value": "ri-2x", "label": "2x" },
- { "value": "ri-3x", "label": "3x" },
- { "value": "ri-4x", "label": "4x" },
- { "value": "ri-5x", "label": "5x" },
- { "value": "ri-6x", "label": "6x" },
- { "value": "ri-7x", "label": "7x" },
- { "value": "ri-8x", "label": "8x" },
- { "value": "ri-9x", "label": "9x" },
- { "value": "ri-10x", "label": "10x" }
+ { "value": "ri-xxs", "label": "XXS" },
+ { "value": "ri-xs", "label": "XS" },
+ { "value": "ri-sm", "label": "Small" },
+ { "value": "ri-1x", "label": "Medium" },
+ { "value": "ri-lg", "label": "Large" },
+ { "value": "ri-xl", "label": "XL" },
+ { "value": "ri-2x", "label": "2XL" },
+ { "value": "ri-3x", "label": "3XL" },
+ { "value": "ri-4x", "label": "4XL" },
+ { "value": "ri-5x", "label": "5XL" },
+ { "value": "ri-6x", "label": "6XL" },
+ { "value": "ri-7x", "label": "7XL" },
+ { "value": "ri-8x", "label": "8XL" },
+ { "value": "ri-9x", "label": "9XL" },
+ { "value": "ri-10x", "label": "10XL" }
]
},
{
"type": "color",
"label": "Color",
- "key": "color",
- "defaultValue": "#000"
+ "key": "color"
},
{
"type": "event",
@@ -844,6 +854,7 @@
]
},
"navigation": {
+ "deprecated": true,
"name": "Nav Bar",
"description": "A component for handling the navigation within your app.",
"icon": "BreadcrumbNavigation",
@@ -876,7 +887,7 @@
"key": "text"
},
{
- "type": "text",
+ "type": "url",
"label": "URL",
"key": "url",
"placeholder": "/screen"
@@ -1638,6 +1649,7 @@
"actions": [
"ValidateForm"
],
+ "styles": ["size"],
"settings": [
{
"type": "select",
@@ -1651,46 +1663,6 @@
"label": "Schema",
"key": "dataSource"
},
- {
- "type": "select",
- "label": "Theme",
- "key": "theme",
- "defaultValue": "spectrum--light",
- "options": [
- {
- "label": "Lightest",
- "value": "spectrum--lightest"
- },
- {
- "label": "Light",
- "value": "spectrum--light"
- },
- {
- "label": "Dark",
- "value": "spectrum--dark"
- },
- {
- "label": "Darkest",
- "value": "spectrum--darkest"
- }
- ]
- },
- {
- "type": "select",
- "label": "Size",
- "key": "size",
- "defaultValue": "spectrum--medium",
- "options": [
- {
- "label": "Medium",
- "value": "spectrum--medium"
- },
- {
- "label": "Large",
- "value": "spectrum--large"
- }
- ]
- },
{
"type": "boolean",
"label": "Disabled",
@@ -2067,46 +2039,6 @@
"key": "rowCount",
"defaultValue": 8
},
- {
- "type": "select",
- "label": "Theme",
- "key": "theme",
- "defaultValue": "spectrum--light",
- "options": [
- {
- "label": "Lightest",
- "value": "spectrum--lightest"
- },
- {
- "label": "Light",
- "value": "spectrum--light"
- },
- {
- "label": "Dark",
- "value": "spectrum--dark"
- },
- {
- "label": "Darkest",
- "value": "spectrum--darkest"
- }
- ]
- },
- {
- "type": "select",
- "label": "Size",
- "key": "size",
- "defaultValue": "spectrum--medium",
- "options": [
- {
- "label": "Medium",
- "value": "spectrum--medium"
- },
- {
- "label": "Large",
- "value": "spectrum--large"
- }
- ]
- },
{
"type": "multifield",
"label": "Columns",
@@ -2161,5 +2093,42 @@
"defaultValue": "Last 30 days"
}
]
+ },
+ "spectrumcard": {
+ "name": "Card",
+ "icon": "Card",
+ "styles": ["size"],
+ "settings": [
+ {
+ "type": "text",
+ "key": "title",
+ "label": "Title"
+ },
+ {
+ "type": "text",
+ "key": "subtitle",
+ "label": "Subtitle"
+ },
+ {
+ "type": "text",
+ "key": "description",
+ "label": "Description"
+ },
+ {
+ "type": "text",
+ "key": "imageURL",
+ "label": "Image URL"
+ },
+ {
+ "type": "url",
+ "key": "linkURL",
+ "label": "Link URL"
+ },
+ {
+ "type": "boolean",
+ "key": "horizontal",
+ "label": "Horizontal"
+ }
+ ]
}
}
diff --git a/packages/standard-components/package.json b/packages/standard-components/package.json
index c1fa6b7b5b..9302ce41cf 100644
--- a/packages/standard-components/package.json
+++ b/packages/standard-components/package.json
@@ -29,13 +29,15 @@
"keywords": [
"svelte"
],
- "version": "0.9.82",
+ "version": "0.9.83-alpha.0",
"license": "MIT",
"gitHead": "d1836a898cab3f8ab80ee6d8f42be1a9eed7dcdc",
"dependencies": {
- "@budibase/bbui": "^0.9.82",
+ "@budibase/bbui": "^0.9.83-alpha.0",
+ "@spectrum-css/card": "^3.0.3",
"@spectrum-css/link": "^3.1.3",
"@spectrum-css/page": "^3.0.1",
+ "@spectrum-css/typography": "^3.0.2",
"@spectrum-css/vars": "^3.0.1",
"apexcharts": "^3.22.1",
"dayjs": "^1.10.5",
diff --git a/packages/standard-components/src/Button.svelte b/packages/standard-components/src/Button.svelte
index 3086fe95cd..22cc286bf4 100644
--- a/packages/standard-components/src/Button.svelte
+++ b/packages/standard-components/src/Button.svelte
@@ -9,10 +9,12 @@
export let onClick
export let size = "M"
export let type = "primary"
+ export let quiet = false
import { getContext } from "svelte"
+ import "@spectrum-css/typography/dist/index-vars.css"
const { styleable, builderStore } = getContext("sdk")
const component = getContext("component")
@@ -14,8 +15,10 @@
$: placeholder = $builderStore.inBuilder && !text
$: componentText = $builderStore.inBuilder
- ? text || "Placeholder text"
+ ? text || $component.name || "Placeholder text"
: text || ""
+ $: sizeClass = `spectrum-Heading--size${size || "M"}`
+ $: alignClass = `align--${align || "left"}`
// Add color styles to main styles object, otherwise the styleable helper
// overrides the color when it's passed as inline style.
@@ -41,25 +44,19 @@
class:bold
class:italic
class:underline
- class="align--{align || 'left'} size--{size || 'M'}"
+ class="spectrum-Heading {sizeClass} {alignClass}"
>
- {#if bold}
- {componentText}
- {:else}
- {componentText}
- {/if}
+ {componentText}
diff --git a/packages/standard-components/src/Layout.svelte b/packages/standard-components/src/Layout.svelte
index 41110d6706..24c9709895 100644
--- a/packages/standard-components/src/Layout.svelte
+++ b/packages/standard-components/src/Layout.svelte
@@ -126,6 +126,7 @@
overflow: auto;
overflow-x: hidden;
position: relative;
+ background: var(--spectrum-alias-background-color-secondary);
}
.nav-wrapper {
@@ -133,9 +134,10 @@
flex-direction: row;
justify-content: center;
align-items: stretch;
- background: white;
+ background: var(--spectrum-alias-background-color-primary);
z-index: 2;
- box-shadow: 0 0 8px -1px rgba(0, 0, 0, 0.075);
+ border-bottom: 1px solid var(--spectrum-global-color-gray-300);
+ box-shadow: 0 0 10px 0 rgba(0, 0, 0, 0.05);
}
.layout--top .nav-wrapper.sticky {
position: sticky;
@@ -319,7 +321,7 @@
transition: transform 0.26s ease-in-out, opacity 0.26s ease-in-out;
height: 100vh;
opacity: 0;
- background: white;
+ background: var(--spectrum-alias-background-color-secondary);
z-index: 999;
flex-direction: column;
justify-content: flex-start;
@@ -333,7 +335,8 @@
.links.visible {
opacity: 1;
transform: translateX(250px);
- box-shadow: 0 0 40px 20px rgba(0, 0, 0, 0.1);
+ box-shadow: 0 0 80px 20px rgba(0, 0, 0, 0.2);
+ border-right: 1px solid var(--spectrum-global-color-gray-300);
}
.mobile-click-handler.visible {
position: fixed;
diff --git a/packages/standard-components/src/Link.svelte b/packages/standard-components/src/Link.svelte
index d58d75f5c5..7498311e46 100644
--- a/packages/standard-components/src/Link.svelte
+++ b/packages/standard-components/src/Link.svelte
@@ -74,12 +74,15 @@
diff --git a/packages/standard-components/src/Repeater.svelte b/packages/standard-components/src/Repeater.svelte
index b7db019c06..79f044f402 100644
--- a/packages/standard-components/src/Repeater.svelte
+++ b/packages/standard-components/src/Repeater.svelte
@@ -33,7 +33,7 @@
diff --git a/packages/standard-components/src/ScreenSlot.svelte b/packages/standard-components/src/ScreenSlot.svelte
index 724f228c71..f6c2387cf0 100644
--- a/packages/standard-components/src/ScreenSlot.svelte
+++ b/packages/standard-components/src/ScreenSlot.svelte
@@ -30,6 +30,6 @@
}
span {
font-size: var(--font-size-s);
- color: var(--grey-6);
+ color: var(--spectrum-global-color-gray-600);
}
diff --git a/packages/standard-components/src/Section.svelte b/packages/standard-components/src/Section.svelte
index 9557f43e8a..5bd3364b94 100644
--- a/packages/standard-components/src/Section.svelte
+++ b/packages/standard-components/src/Section.svelte
@@ -67,7 +67,7 @@
grid-template-columns: 1fr 1fr;
}
.placeholder {
- border: 2px dashed var(--grey-5);
+ border: 2px dashed var(--spectrum-global-color-gray-600);
padding: var(--spacing-l);
}
diff --git a/packages/standard-components/src/SpectrumCard.svelte b/packages/standard-components/src/SpectrumCard.svelte
new file mode 100644
index 0000000000..5a2596bd2e
--- /dev/null
+++ b/packages/standard-components/src/SpectrumCard.svelte
@@ -0,0 +1,119 @@
+
+
+
+ {#if imageURL}
+
+ {/if}
+
+
+
+ {#if subtitle}
+
+ {/if}
+
+ {#if description}
+
+ {/if}
+
+
+
+
diff --git a/packages/standard-components/src/Text.svelte b/packages/standard-components/src/Text.svelte
index cc962b572b..ff35eeb38e 100644
--- a/packages/standard-components/src/Text.svelte
+++ b/packages/standard-components/src/Text.svelte
@@ -14,7 +14,7 @@
$: placeholder = $builderStore.inBuilder && !text
$: componentText = $builderStore.inBuilder
- ? text || "Placeholder text"
+ ? text || $component.name || "Placeholder text"
: text || ""
// Add color styles to main styles object, otherwise the styleable helper
@@ -54,7 +54,7 @@
}
.placeholder {
font-style: italic;
- color: var(--grey-6);
+ color: var(--spectrum-global-color-gray-600);
}
.bold {
font-weight: 600;
diff --git a/packages/standard-components/src/charts/ApexChart.svelte b/packages/standard-components/src/charts/ApexChart.svelte
index 4782ecb861..173bfd8c62 100644
--- a/packages/standard-components/src/charts/ApexChart.svelte
+++ b/packages/standard-components/src/charts/ApexChart.svelte
@@ -23,6 +23,16 @@
text-transform: capitalize;
}
div :global(.apexcharts-yaxis-label, .apexcharts-xaxis-label) {
- fill: #aaa;
+ fill: var(--spectrum-global-color-gray-600);
+ }
+
+ div :global(.apexcharts-gridline) {
+ stroke: var(--spectrum-global-color-gray-600);
+ }
+ div :global(.apexcharts-legend-text) {
+ color: var(--spectrum-global-color-gray-700) !important;
+ }
+ div :global(.apexcharts-datalabel) {
+ fill: var(--spectrum-global-color-gray-800);
}
diff --git a/packages/standard-components/src/Card.svelte b/packages/standard-components/src/deprecated/Card.svelte
similarity index 100%
rename from packages/standard-components/src/Card.svelte
rename to packages/standard-components/src/deprecated/Card.svelte
diff --git a/packages/standard-components/src/CardHorizontal.svelte b/packages/standard-components/src/deprecated/CardHorizontal.svelte
similarity index 100%
rename from packages/standard-components/src/CardHorizontal.svelte
rename to packages/standard-components/src/deprecated/CardHorizontal.svelte
diff --git a/packages/standard-components/src/Navigation.svelte b/packages/standard-components/src/deprecated/Navigation.svelte
similarity index 100%
rename from packages/standard-components/src/Navigation.svelte
rename to packages/standard-components/src/deprecated/Navigation.svelte
diff --git a/packages/standard-components/src/StackedList.svelte b/packages/standard-components/src/deprecated/StackedList.svelte
similarity index 100%
rename from packages/standard-components/src/StackedList.svelte
rename to packages/standard-components/src/deprecated/StackedList.svelte
diff --git a/packages/standard-components/src/forms/InnerForm.svelte b/packages/standard-components/src/forms/InnerForm.svelte
index b2a174629b..3a63b63bdc 100644
--- a/packages/standard-components/src/forms/InnerForm.svelte
+++ b/packages/standard-components/src/forms/InnerForm.svelte
@@ -5,8 +5,6 @@
import { generateID } from "../helpers"
export let dataSource
- export let theme
- export let size
export let disabled = false
export let initialValues
@@ -160,24 +158,9 @@
{actions}
data={{ ...$formState.values, tableId: dataSource?.tableId }}
>
-
+
{#if loaded}
{/if}
-
-
diff --git a/packages/standard-components/src/index.js b/packages/standard-components/src/index.js
index 2a2c763d21..a137c8c3dc 100644
--- a/packages/standard-components/src/index.js
+++ b/packages/standard-components/src/index.js
@@ -20,20 +20,23 @@ export { default as dataprovider } from "./DataProvider.svelte"
export { default as screenslot } from "./ScreenSlot.svelte"
export { default as button } from "./Button.svelte"
export { default as repeater } from "./Repeater.svelte"
-export { default as stackedlist } from "./StackedList.svelte"
-export { default as card } from "./Card.svelte"
export { default as text } from "./Text.svelte"
-export { default as navigation } from "./Navigation.svelte"
export { default as layout } from "./Layout.svelte"
export { default as link } from "./Link.svelte"
export { default as heading } from "./Heading.svelte"
export { default as image } from "./Image.svelte"
export { default as embed } from "./Embed.svelte"
-export { default as cardhorizontal } from "./CardHorizontal.svelte"
-export { default as cardstat } from "./CardStat.svelte"
export { default as icon } from "./Icon.svelte"
export { default as backgroundimage } from "./BackgroundImage.svelte"
export { default as daterangepicker } from "./DateRangePicker.svelte"
+export { default as cardstat } from "./CardStat.svelte"
+export { default as spectrumcard } from "./SpectrumCard.svelte"
export * from "./charts"
export * from "./forms"
export * from "./table"
+
+// Deprecated component left for compatibility in old apps
+export { default as navigation } from "./deprecated/Navigation.svelte"
+export { default as cardhorizontal } from "./deprecated/CardHorizontal.svelte"
+export { default as stackedlist } from "./deprecated/StackedList.svelte"
+export { default as card } from "./deprecated/Card.svelte"
diff --git a/packages/standard-components/src/lucene.js b/packages/standard-components/src/lucene.js
index 317d8c3e74..50aae1f32c 100644
--- a/packages/standard-components/src/lucene.js
+++ b/packages/standard-components/src/lucene.js
@@ -23,7 +23,7 @@ export const buildLuceneQuery = filter => {
value = parseFloat(value)
}
if (type === "boolean") {
- value = value?.toLowerCase() === "true"
+ value = `${value}`?.toLowerCase() === "true"
}
if (operator.startsWith("range")) {
if (!query.range[field]) {
@@ -91,6 +91,11 @@ export const luceneQuery = (docs, query) => {
return !doc[key] || !doc[key].startsWith(value)
})
+ // Process a fuzzy match (treat the same as starts with when running locally)
+ const fuzzyMatch = match("fuzzy", (key, value, doc) => {
+ return !doc[key] || !doc[key].startsWith(value)
+ })
+
// Process a range match
const rangeMatch = match("range", (key, value, doc) => {
return !doc[key] || doc[key] < value.low || doc[key] > value.high
@@ -120,6 +125,7 @@ export const luceneQuery = (docs, query) => {
const docMatch = doc => {
return (
stringMatch(doc) &&
+ fuzzyMatch(doc) &&
rangeMatch(doc) &&
equalMatch(doc) &&
notEqualMatch(doc) &&
diff --git a/packages/standard-components/src/table/Table.svelte b/packages/standard-components/src/table/Table.svelte
index ad3fb46d5d..3620146ced 100644
--- a/packages/standard-components/src/table/Table.svelte
+++ b/packages/standard-components/src/table/Table.svelte
@@ -3,8 +3,6 @@
import { Table } from "@budibase/bbui"
import SlotRenderer from "./SlotRenderer.svelte"
- export let theme
- export let size
export let dataProvider
export let columns
export let showAutoColumns
@@ -73,12 +71,7 @@
}
-
+
{
- return passport.authenticate("local", async (err, user) => {
- authInternal(ctx, user, err)
+ return passport.authenticate("local", async (err, user, info) => {
+ await authInternal(ctx, user, err, info)
delete user.token
@@ -122,8 +126,56 @@ exports.googleAuth = async (ctx, next) => {
return passport.authenticate(
strategy,
{ successRedirect: "/", failureRedirect: "/error" },
- async (err, user) => {
- authInternal(ctx, user, err)
+ async (err, user, info) => {
+ await authInternal(ctx, user, err, info)
+
+ ctx.redirect("/")
+ }
+ )(ctx, next)
+}
+
+async function oidcStrategyFactory(ctx, configId) {
+ const db = new CouchDB(GLOBAL_DB)
+
+ const config = await authPkg.db.getScopedConfig(db, {
+ type: Configs.OIDC,
+ group: ctx.query.group,
+ })
+
+ const chosenConfig = config.configs.filter(c => c.uuid === configId)[0]
+
+ // require https callback in production
+ const protocol = process.env.NODE_ENV === "production" ? "https" : "http"
+ const callbackUrl = `${protocol}://${ctx.host}/api/admin/auth/oidc/callback`
+
+ return oidc.strategyFactory(chosenConfig, callbackUrl)
+}
+
+/**
+ * The initial call that OIDC authentication makes to take you to the configured OIDC login screen.
+ * On a successful login, you will be redirected to the oidcAuth callback route.
+ */
+exports.oidcPreAuth = async (ctx, next) => {
+ const { configId } = ctx.params
+ const strategy = await oidcStrategyFactory(ctx, configId)
+
+ setCookie(ctx, configId, Cookies.OIDC_CONFIG)
+
+ return passport.authenticate(strategy, {
+ // required 'openid' scope is added by oidc strategy factory
+ scope: ["profile", "email"],
+ })(ctx, next)
+}
+
+exports.oidcAuth = async (ctx, next) => {
+ const configId = getCookie(ctx, Cookies.OIDC_CONFIG)
+ const strategy = await oidcStrategyFactory(ctx, configId)
+
+ return passport.authenticate(
+ strategy,
+ { successRedirect: "/", failureRedirect: "/error" },
+ async (err, user, info) => {
+ await authInternal(ctx, user, err, info)
ctx.redirect("/")
}
diff --git a/packages/worker/src/api/controllers/admin/configs.js b/packages/worker/src/api/controllers/admin/configs.js
index b93bd22c80..78caa817b2 100644
--- a/packages/worker/src/api/controllers/admin/configs.js
+++ b/packages/worker/src/api/controllers/admin/configs.js
@@ -98,23 +98,81 @@ exports.find = async function (ctx) {
}
}
-exports.publicSettings = async function (ctx) {
+exports.publicOidc = async function (ctx) {
const db = new CouchDB(GLOBAL_DB)
try {
// Find the config with the most granular scope based on context
- const config = await getScopedFullConfig(db, {
- type: Configs.SETTINGS,
+ const oidcConfig = await getScopedFullConfig(db, {
+ type: Configs.OIDC,
})
- if (!config) {
+
+ if (!oidcConfig) {
ctx.body = {}
} else {
- ctx.body = config
+ const partialOidcCofig = oidcConfig.config.configs.map(config => {
+ return {
+ logo: config.logo,
+ name: config.name,
+ uuid: config.uuid,
+ }
+ })
+ ctx.body = partialOidcCofig
}
} catch (err) {
ctx.throw(err.status, err)
}
}
+exports.publicSettings = async function (ctx) {
+ const db = new CouchDB(GLOBAL_DB)
+
+ try {
+ // Find the config with the most granular scope based on context
+ const publicConfig = await getScopedFullConfig(db, {
+ type: Configs.SETTINGS,
+ })
+
+ const googleConfig = await getScopedFullConfig(db, {
+ type: Configs.GOOGLE,
+ })
+
+ const oidcConfig = await getScopedFullConfig(db, {
+ type: Configs.OIDC,
+ })
+
+ let config = {}
+ if (!publicConfig) {
+ config = {
+ config: {},
+ }
+ } else {
+ config = publicConfig
+ }
+
+ // google button flag
+ if (googleConfig && googleConfig.config) {
+ const googleActivated =
+ googleConfig.config.activated == undefined || // activated by default for configs pre-activated flag
+ googleConfig.config.activated
+ config.config.google = googleActivated
+ } else {
+ config.config.google = false
+ }
+
+ // oidc button flag
+ if (oidcConfig && oidcConfig.config) {
+ const oidcActivated = oidcConfig.config.configs[0].activated
+ config.config.oidc = oidcActivated
+ } else {
+ config.config.oidc = false
+ }
+
+ ctx.body = config
+ } catch (err) {
+ ctx.throw(err.status, err)
+ }
+}
+
exports.upload = async function (ctx) {
if (ctx.request.files == null || ctx.request.files.file.length > 1) {
ctx.throw(400, "One file must be uploaded.")
@@ -122,12 +180,8 @@ exports.upload = async function (ctx) {
const file = ctx.request.files.file
const { type, name } = ctx.params
- const fileExtension = [...file.name.split(".")].pop()
- // filenames converted to UUIDs so they are unique
- const processedFileName = `${name}.${fileExtension}`
-
const bucket = ObjectStoreBuckets.GLOBAL
- const key = `${type}/${processedFileName}`
+ const key = `${type}/${name}`
await upload({
bucket,
filename: key,
@@ -146,7 +200,7 @@ exports.upload = async function (ctx) {
}
}
const url = `/${bucket}/${key}`
- cfgStructure.config[`${name}Url`] = url
+ cfgStructure.config[`${name}`] = url
// write back to db with url updated
await db.put(cfgStructure)
@@ -184,10 +238,14 @@ exports.configChecklist = async function (ctx) {
})
// They have set up Google Auth
- const oauthConfig = await getScopedFullConfig(db, {
+ const googleConfig = await getScopedFullConfig(db, {
type: Configs.GOOGLE,
})
+ // They have set up OIDC
+ const oidcConfig = await getScopedFullConfig(db, {
+ type: Configs.OIDC,
+ })
// They have set up an admin user
const users = await db.allDocs(
getGlobalUserParams(null, {
@@ -200,7 +258,7 @@ exports.configChecklist = async function (ctx) {
apps: appDbNames.length,
smtp: !!smtpConfig,
adminUser,
- oauth: !!oauthConfig,
+ sso: !!googleConfig || !!oidcConfig,
}
} catch (err) {
ctx.throw(err.status, err)
diff --git a/packages/worker/src/api/controllers/admin/sessions.js b/packages/worker/src/api/controllers/admin/sessions.js
new file mode 100644
index 0000000000..170e97d690
--- /dev/null
+++ b/packages/worker/src/api/controllers/admin/sessions.js
@@ -0,0 +1,37 @@
+const {
+ getAllSessions,
+ getUserSessions,
+ invalidateSessions,
+} = require("@budibase/auth/sessions")
+
+exports.fetch = async ctx => {
+ ctx.body = await getAllSessions()
+}
+
+exports.find = async ctx => {
+ const { userId } = ctx.params
+ const sessions = await getUserSessions(userId)
+ ctx.body = sessions.map(session => session.value)
+}
+
+exports.invalidateUser = async ctx => {
+ const { userId } = ctx.params
+ await invalidateSessions(userId)
+ ctx.body = {
+ message: "User sessions invalidated",
+ }
+}
+
+exports.selfSessions = async ctx => {
+ const userId = ctx.user._id
+ ctx.body = await getUserSessions(userId)
+}
+
+exports.invalidateSession = async ctx => {
+ const userId = ctx.user._id
+ const { sessionId } = ctx.params
+ await invalidateSessions(userId, sessionId)
+ ctx.body = {
+ message: "Session invalidated successfully.",
+ }
+}
diff --git a/packages/worker/src/api/controllers/admin/users.js b/packages/worker/src/api/controllers/admin/users.js
index dbe34d7ded..f524379266 100644
--- a/packages/worker/src/api/controllers/admin/users.js
+++ b/packages/worker/src/api/controllers/admin/users.js
@@ -5,6 +5,8 @@ const { hash, getGlobalUserByEmail } = require("@budibase/auth").utils
const { UserStatus, EmailTemplatePurpose } = require("../../../constants")
const { checkInviteCode } = require("../../../utilities/redis")
const { sendEmail } = require("../../../utilities/email")
+const { user: userCache } = require("@budibase/auth/cache")
+const { invalidateSessions } = require("@budibase/auth/sessions")
const GLOBAL_DB = StaticDatabases.GLOBAL.name
@@ -62,6 +64,7 @@ exports.save = async ctx => {
password: hashedPassword,
...user,
})
+ await userCache.invalidateUser(response.id)
ctx.body = {
_id: response.id,
_rev: response.rev,
@@ -107,6 +110,8 @@ exports.destroy = async ctx => {
const db = new CouchDB(GLOBAL_DB)
const dbUser = await db.get(ctx.params.id)
await db.remove(dbUser._id, dbUser._rev)
+ await userCache.invalidateUser(dbUser._id)
+ await invalidateSessions(dbUser._id)
ctx.body = {
message: `User ${ctx.params.id} deleted.`,
}
@@ -117,13 +122,16 @@ exports.removeAppRole = async ctx => {
const db = new CouchDB(GLOBAL_DB)
const users = await allUsers()
const bulk = []
+ const cacheInvalidations = []
for (let user of users) {
if (user.roles[appId]) {
+ cacheInvalidations.push(userCache.invalidateUser(user._id))
delete user.roles[appId]
bulk.push(user)
}
}
await db.bulkDocs(bulk)
+ await Promise.all(cacheInvalidations)
ctx.body = {
message: "App role removed from all users",
}
@@ -153,6 +161,7 @@ exports.updateSelf = async ctx => {
...user,
...ctx.request.body,
})
+ await userCache.invalidateUser(user._id)
ctx.body = {
_id: response.id,
_rev: response.rev,
diff --git a/packages/worker/src/api/index.js b/packages/worker/src/api/index.js
index bda57863f6..39ae320cc6 100644
--- a/packages/worker/src/api/index.js
+++ b/packages/worker/src/api/index.js
@@ -25,6 +25,14 @@ const PUBLIC_ENDPOINTS = [
route: "/api/admin/auth/google/callback",
method: "GET",
},
+ {
+ route: "/api/admin/auth/oidc",
+ method: "GET",
+ },
+ {
+ route: "/api/admin/auth/oidc/callback",
+ method: "GET",
+ },
{
route: "/api/admin/auth/reset",
method: "POST",
@@ -41,6 +49,10 @@ const PUBLIC_ENDPOINTS = [
route: "/api/admin/configs/public",
method: "GET",
},
+ {
+ route: "/api/admin/configs/publicOidc",
+ method: "GET",
+ },
]
const router = new Router()
diff --git a/packages/worker/src/api/routes/admin/auth.js b/packages/worker/src/api/routes/admin/auth.js
index 04e30fc006..9a7ef5ebac 100644
--- a/packages/worker/src/api/routes/admin/auth.js
+++ b/packages/worker/src/api/routes/admin/auth.js
@@ -39,5 +39,7 @@ router
.post("/api/admin/auth/logout", authController.logout)
.get("/api/admin/auth/google", authController.googlePreAuth)
.get("/api/admin/auth/google/callback", authController.googleAuth)
+ .get("/api/admin/auth/oidc/configs/:configId", authController.oidcPreAuth)
+ .get("/api/admin/auth/oidc/callback", authController.oidcAuth)
module.exports = router
diff --git a/packages/worker/src/api/routes/admin/configs.js b/packages/worker/src/api/routes/admin/configs.js
index 8056ad8cbd..6873d82757 100644
--- a/packages/worker/src/api/routes/admin/configs.js
+++ b/packages/worker/src/api/routes/admin/configs.js
@@ -3,7 +3,7 @@ const controller = require("../../controllers/admin/configs")
const joiValidator = require("../../../middleware/joi-validator")
const adminOnly = require("../../../middleware/adminOnly")
const Joi = require("joi")
-const { Configs, ConfigUploads } = require("../../../constants")
+const { Configs } = require("../../../constants")
const router = Router()
@@ -38,6 +38,24 @@ function googleValidation() {
clientID: Joi.string().required(),
clientSecret: Joi.string().required(),
callbackURL: Joi.string().required(),
+ activated: Joi.boolean().required(),
+ }).unknown(true)
+}
+
+function oidcValidation() {
+ // prettier-ignore
+ return Joi.object({
+ configs: Joi.array().items(
+ Joi.object({
+ clientID: Joi.string().required(),
+ clientSecret: Joi.string().required(),
+ configUrl: Joi.string().required(),
+ logo: Joi.string().allow("", null),
+ name: Joi.string().allow("", null),
+ uuid: Joi.string().required(),
+ activated: Joi.boolean().required(),
+ })
+ ).required(true)
}).unknown(true)
}
@@ -54,7 +72,8 @@ function buildConfigSaveValidation() {
{ is: Configs.SMTP, then: smtpValidation() },
{ is: Configs.SETTINGS, then: settingValidation() },
{ is: Configs.ACCOUNT, then: Joi.object().unknown(true) },
- { is: Configs.GOOGLE, then: googleValidation() }
+ { is: Configs.GOOGLE, then: googleValidation() },
+ { is: Configs.OIDC, then: oidcValidation() }
],
}),
}).required(),
@@ -65,7 +84,7 @@ function buildUploadValidation() {
// prettier-ignore
return joiValidator.params(Joi.object({
type: Joi.string().valid(...Object.values(Configs)).required(),
- name: Joi.string().valid(...Object.values(ConfigUploads)).required(),
+ name: Joi.string().required(),
}).required())
}
@@ -83,7 +102,7 @@ router
buildConfigSaveValidation(),
controller.save
)
- .delete("/api/admin/configs/:id", adminOnly, controller.destroy)
+ .delete("/api/admin/configs/:id/:rev", adminOnly, controller.destroy)
.get("/api/admin/configs", controller.fetch)
.get("/api/admin/configs/checklist", controller.configChecklist)
.get(
@@ -92,6 +111,7 @@ router
controller.fetch
)
.get("/api/admin/configs/public", controller.publicSettings)
+ .get("/api/admin/configs/publicOidc", controller.publicOidc)
.get("/api/admin/configs/:type", buildConfigGetValidation(), controller.find)
.post(
"/api/admin/configs/upload/:type/:name",
diff --git a/packages/worker/src/api/routes/admin/sessions.js b/packages/worker/src/api/routes/admin/sessions.js
new file mode 100644
index 0000000000..9cf5f58f8b
--- /dev/null
+++ b/packages/worker/src/api/routes/admin/sessions.js
@@ -0,0 +1,14 @@
+const Router = require("@koa/router")
+const controller = require("../../controllers/admin/sessions")
+const adminOnly = require("../../../middleware/adminOnly")
+
+const router = Router()
+
+router
+ .get("/api/admin/sessions", adminOnly, controller.fetch)
+ .get("/api/admin/sessions/self", controller.selfSessions)
+ .get("/api/admin/sessions/:userId", adminOnly, controller.find)
+ .delete("/api/admin/sessions/:userId", adminOnly, controller.invalidateUser)
+ .delete("/api/admin/sessions/self/:sessionId", controller.invalidateSession)
+
+module.exports = router
diff --git a/packages/worker/src/api/routes/index.js b/packages/worker/src/api/routes/index.js
index 8b232f7b7c..21ec324880 100644
--- a/packages/worker/src/api/routes/index.js
+++ b/packages/worker/src/api/routes/index.js
@@ -5,6 +5,7 @@ const templateRoutes = require("./admin/templates")
const emailRoutes = require("./admin/email")
const authRoutes = require("./admin/auth")
const roleRoutes = require("./admin/roles")
+const sessionRoutes = require("./admin/sessions")
const appRoutes = require("./app")
exports.routes = [
@@ -15,5 +16,6 @@ exports.routes = [
appRoutes,
templateRoutes,
emailRoutes,
+ sessionRoutes,
roleRoutes,
]
diff --git a/packages/worker/src/api/routes/tests/auth.spec.js b/packages/worker/src/api/routes/tests/auth.spec.js
index 8b9b699839..ceccf7edaf 100644
--- a/packages/worker/src/api/routes/tests/auth.spec.js
+++ b/packages/worker/src/api/routes/tests/auth.spec.js
@@ -1,4 +1,5 @@
const setup = require("./utilities")
+const { Cookies } = require("@budibase/auth").constants
jest.mock("nodemailer")
const sendMailMock = setup.emailMock()
@@ -14,6 +15,10 @@ describe("/api/admin/auth", () => {
afterAll(setup.afterAll)
+ afterEach(() => {
+ jest.clearAllMocks()
+ })
+
it("should be able to generate password reset email", async () => {
// initially configure settings
await config.saveSmtpConfig()
@@ -46,4 +51,56 @@ describe("/api/admin/auth", () => {
.expect(200)
expect(res.body).toEqual({ message: "password reset successfully." })
})
+
+ describe("oidc", () => {
+ const auth = require("@budibase/auth").auth
+
+ // mock the oidc strategy implementation and return value
+ strategyFactory = jest.fn()
+ mockStrategyReturn = jest.fn()
+ strategyFactory.mockReturnValue(mockStrategyReturn)
+ auth.oidc.strategyFactory = strategyFactory
+
+ const passportSpy = jest.spyOn(auth.passport, "authenticate")
+ let oidcConf
+ let chosenConfig
+ let configId
+
+ beforeEach(async () => {
+ oidcConf = await config.saveOIDCConfig()
+ chosenConfig = oidcConf.config.configs[0]
+ configId = chosenConfig.uuid
+ })
+
+ afterEach(() => {
+ expect(strategyFactory).toBeCalledWith(
+ chosenConfig,
+ `http://127.0.0.1:4003/api/admin/auth/oidc/callback` // calculated url
+ )
+ })
+
+ describe("/api/admin/auth/oidc/configs", () => {
+ it("should load strategy and delegate to passport", async () => {
+ await request.get(`/api/admin/auth/oidc/configs/${configId}`)
+
+ expect(passportSpy).toBeCalledWith(mockStrategyReturn, {
+ scope: ["profile", "email"],
+ })
+ expect(passportSpy.mock.calls.length).toBe(1);
+ })
+ })
+
+ describe("/api/admin/auth/oidc/callback", () => {
+ it("should load strategy and delegate to passport", async () => {
+ await request.get(`/api/admin/auth/oidc/callback`)
+ .set(config.getOIDConfigCookie(configId))
+
+ expect(passportSpy).toBeCalledWith(mockStrategyReturn, {
+ successRedirect: "/", failureRedirect: "/error"
+ }, expect.anything())
+ expect(passportSpy.mock.calls.length).toBe(1);
+ })
+ })
+
+ })
})
\ No newline at end of file
diff --git a/packages/worker/src/api/routes/tests/utilities/TestConfiguration.js b/packages/worker/src/api/routes/tests/utilities/TestConfiguration.js
index 746a26c800..812dbe51e2 100644
--- a/packages/worker/src/api/routes/tests/utilities/TestConfiguration.js
+++ b/packages/worker/src/api/routes/tests/utilities/TestConfiguration.js
@@ -5,6 +5,8 @@ const { jwt } = require("@budibase/auth").auth
const { Cookies } = require("@budibase/auth").constants
const { Configs, LOGO_URL } = require("../../../../constants")
const { getGlobalUserByEmail } = require("@budibase/auth").utils
+const { createASession } = require("@budibase/auth/sessions")
+const { newid } = require("../../../../../../auth/src/hashing")
class TestConfiguration {
constructor(openServer = true) {
@@ -56,6 +58,7 @@ class TestConfiguration {
null,
controllers.users.save
)
+ await createASession("us_uuid1", "sessionid")
}
}
@@ -65,15 +68,22 @@ class TestConfiguration {
}
}
+ cookieHeader(cookies) {
+ return {
+ Cookie: [cookies],
+ }
+ }
+
defaultHeaders() {
const user = {
_id: "us_uuid1",
userId: "us_uuid1",
+ sessionId: "sessionid",
}
const authToken = jwt.sign(user, env.JWT_SECRET)
return {
Accept: "application/json",
- Cookie: [`${Cookies.Auth}=${authToken}`],
+ ...this.cookieHeader([`${Cookies.Auth}=${authToken}`]),
}
}
@@ -152,6 +162,33 @@ class TestConfiguration {
)
}
+ getOIDConfigCookie(configId) {
+ const token = jwt.sign(configId, env.JWT_SECRET)
+ return this.cookieHeader([[`${Cookies.OIDC_CONFIG}=${token}`]])
+ }
+
+ async saveOIDCConfig() {
+ await this.deleteConfig(Configs.OIDC)
+ const config = {
+ type: Configs.OIDC,
+ config: {
+ configs: [
+ {
+ configUrl: "http://someconfigurl",
+ clientID: "clientId",
+ clientSecret: "clientSecret",
+ logo: "Microsoft",
+ name: "Active Directory",
+ uuid: newid(),
+ },
+ ],
+ },
+ }
+
+ await this._req(config, null, controllers.config.save)
+ return config
+ }
+
async saveSmtpConfig() {
await this.deleteConfig(Configs.SMTP)
await this._req(
diff --git a/packages/worker/src/constants/index.js b/packages/worker/src/constants/index.js
index aec864be97..231ff37ee2 100644
--- a/packages/worker/src/constants/index.js
+++ b/packages/worker/src/constants/index.js
@@ -16,6 +16,7 @@ exports.Configs = Configs
exports.ConfigUploads = {
LOGO: "logo",
+ OIDC_LOGO: "oidc_logo",
}
const TemplateTypes = {
diff --git a/packages/worker/src/index.js b/packages/worker/src/index.js
index f59f8bab15..8af1380552 100644
--- a/packages/worker/src/index.js
+++ b/packages/worker/src/index.js
@@ -5,6 +5,7 @@ require("@budibase/auth").init(CouchDB)
const Koa = require("koa")
const destroyable = require("server-destroy")
const koaBody = require("koa-body")
+const koaSession = require("koa-session")
const { passport } = require("@budibase/auth").auth
const logger = require("koa-pino-logger")
const http = require("http")
@@ -13,8 +14,11 @@ const redis = require("./utilities/redis")
const app = new Koa()
+app.keys = ["secret", "key"]
+
// set up top level koa middleware
app.use(koaBody({ multipart: true }))
+app.use(koaSession(app))
app.use(
logger({
diff --git a/packages/worker/src/utilities/redis.js b/packages/worker/src/utilities/redis.js
index 0701e500dd..6e55795de1 100644
--- a/packages/worker/src/utilities/redis.js
+++ b/packages/worker/src/utilities/redis.js
@@ -44,7 +44,7 @@ async function getACode(db, code, deleteCode = true) {
exports.init = async () => {
pwResetClient = await new Client(utils.Databases.PW_RESETS).init()
- invitationClient = await new Client(utils.Databases.PW_RESETS).init()
+ invitationClient = await new Client(utils.Databases.INVITATIONS).init()
}
/**
diff --git a/packages/worker/yarn.lock b/packages/worker/yarn.lock
index 53f10856e8..1d4227363f 100644
--- a/packages/worker/yarn.lock
+++ b/packages/worker/yarn.lock
@@ -566,6 +566,17 @@
dependencies:
defer-to-connect "^2.0.0"
+"@techpass/passport-openidconnect@^0.3.0":
+ version "0.3.0"
+ resolved "https://registry.yarnpkg.com/@techpass/passport-openidconnect/-/passport-openidconnect-0.3.0.tgz#a60b2bbf3f262649a5a02d5d186219944acc3010"
+ integrity sha512-bVsPwl66s7J7GHxTPlW/RJYhZol9SshNznQsx83OOh9G+JWFGoeWxh+xbX+FTdJNoUvGIGbJnpWPY2wC6NOHPw==
+ dependencies:
+ base64url "^3.0.1"
+ oauth "^0.9.15"
+ passport-strategy "^1.0.0"
+ request "^2.88.0"
+ webfinger "^0.4.2"
+
"@types/babel__core@^7.0.0", "@types/babel__core@^7.1.7":
version "7.1.14"
resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.1.14.tgz#faaeefc4185ec71c389f4501ee5ec84b170cc402"
@@ -1058,7 +1069,7 @@ base64-js@^1.0.2, base64-js@^1.3.1:
resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a"
integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==
-base64url@3.x.x:
+base64url@3.x.x, base64url@^3.0.1:
version "3.0.1"
resolved "https://registry.yarnpkg.com/base64url/-/base64url-3.0.1.tgz#6399d572e2bc3f90a9a8b22d5dbb0a32d33f788d"
integrity sha512-ir1UPr3dkwexU7FdV8qBBbNDRUhMmIekYMFZfi+C/sLNnRESKPl23nB9b2pltqfOQNnGzsDdId90AEtG5tCx4A==
@@ -4183,7 +4194,7 @@ oauth-sign@~0.9.0:
resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455"
integrity sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==
-oauth@0.9.x:
+oauth@0.9.x, oauth@^0.9.15:
version "0.9.15"
resolved "https://registry.yarnpkg.com/oauth/-/oauth-0.9.15.tgz#bd1fefaf686c96b75475aed5196412ff60cfb9c1"
integrity sha1-vR/vr2hslrdUda7VGWQS/2DPucE=
@@ -4933,7 +4944,7 @@ request-promise-native@^1.0.9:
stealthy-require "^1.1.1"
tough-cookie "^2.3.3"
-request@^2.88.2:
+request@^2.88.0, request@^2.88.2:
version "2.88.2"
resolved "https://registry.yarnpkg.com/request/-/request-2.88.2.tgz#d73c918731cb5a87da047e207234146f664d12b3"
integrity sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==
@@ -5080,7 +5091,7 @@ sax@1.2.1:
resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.1.tgz#7b8e656190b228e81a66aea748480d828cd2d37a"
integrity sha1-e45lYZCyKOgaZq6nSEgNgozS03o=
-sax@>=0.6.0:
+sax@>=0.1.1, sax@>=0.6.0:
version "1.2.4"
resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9"
integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==
@@ -5390,6 +5401,11 @@ stealthy-require@^1.1.1:
resolved "https://registry.yarnpkg.com/stealthy-require/-/stealthy-require-1.1.1.tgz#35b09875b4ff49f26a777e509b3090a3226bf24b"
integrity sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks=
+step@0.0.x:
+ version "0.0.6"
+ resolved "https://registry.yarnpkg.com/step/-/step-0.0.6.tgz#143e7849a5d7d3f4a088fe29af94915216eeede2"
+ integrity sha1-FD54SaXX0/SgiP4pr5SRUhbu7eI=
+
string-length@^4.0.1:
version "4.0.2"
resolved "https://registry.yarnpkg.com/string-length/-/string-length-4.0.2.tgz#a8a8dc7bd5c1a82b9b3c8b87e125f66871b6e57a"
@@ -5923,6 +5939,14 @@ walker@^1.0.7, walker@~1.0.5:
dependencies:
makeerror "1.0.x"
+webfinger@^0.4.2:
+ version "0.4.2"
+ resolved "https://registry.yarnpkg.com/webfinger/-/webfinger-0.4.2.tgz#3477a6d97799461896039fcffc650b73468ee76d"
+ integrity sha1-NHem2XeZRhiWA5/P/GULc0aO520=
+ dependencies:
+ step "0.0.x"
+ xml2js "0.1.x"
+
webidl-conversions@^5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-5.0.0.tgz#ae59c8a00b121543a2acc65c0434f57b0fc11aff"
@@ -6031,6 +6055,13 @@ xml-name-validator@^3.0.0:
resolved "https://registry.yarnpkg.com/xml-name-validator/-/xml-name-validator-3.0.0.tgz#6ae73e06de4d8c6e47f9fb181f78d648ad457c6a"
integrity sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw==
+xml2js@0.1.x:
+ version "0.1.14"
+ resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.1.14.tgz#5274e67f5a64c5f92974cd85139e0332adc6b90c"
+ integrity sha1-UnTmf1pkxfkpdM2FE54DMq3GuQw=
+ dependencies:
+ sax ">=0.1.1"
+
xml2js@0.4.19:
version "0.4.19"
resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.4.19.tgz#686c20f213209e94abf0d1bcf1efaa291c7827a7"