Merge branch 'develop' of github.com:Budibase/budibase into spreadsheet-integration

This commit is contained in:
Andrew Kingston 2023-04-17 17:00:56 +01:00
commit 208e481bbc
126 changed files with 20237 additions and 53623 deletions

View File

@ -62,7 +62,6 @@ jobs:
- name: Build/release Docker images - name: Build/release Docker images
run: | run: |
docker login -u $DOCKER_USER -p $DOCKER_PASSWORD docker login -u $DOCKER_USER -p $DOCKER_PASSWORD
yarn build
yarn build:docker:develop yarn build:docker:develop
env: env:
DOCKER_USER: ${{ secrets.DOCKER_USERNAME }} DOCKER_USER: ${{ secrets.DOCKER_USERNAME }}

View File

@ -107,7 +107,7 @@ jobs:
git pull git pull
mkdir sync mkdir sync
echo "Packaging chart to sync dir" echo "Packaging chart to sync dir"
helm package charts/budibase --version 0.0.0-master --app-version "$RELEASE_VERSION" --destination sync helm package charts/budibase --version 0.0.0-master --app-version v"$RELEASE_VERSION" --destination sync
echo "Packaging successful" echo "Packaging successful"
git checkout gh-pages git checkout gh-pages
echo "Indexing helm repo" echo "Indexing helm repo"

View File

@ -199,7 +199,7 @@ spec:
value: {{ .Values.services.tlsRejectUnauthorized }} value: {{ .Values.services.tlsRejectUnauthorized }}
{{ end }} {{ end }}
image: budibase/apps:{{ .Values.globals.appVersion }} image: budibase/apps:{{ .Values.globals.appVersion | default .Chart.AppVersion }}
imagePullPolicy: Always imagePullPolicy: Always
livenessProbe: livenessProbe:
httpGet: httpGet:

View File

@ -37,7 +37,7 @@ spec:
{{ end }} {{ end }}
spec: spec:
containers: containers:
- image: budibase/proxy:{{ .Values.globals.appVersion }} - image: budibase/proxy:{{ .Values.globals.appVersion | default .Chart.AppVersion }}
imagePullPolicy: Always imagePullPolicy: Always
name: proxy-service name: proxy-service
ports: ports:

View File

@ -188,8 +188,7 @@ spec:
- name: NODE_TLS_REJECT_UNAUTHORIZED - name: NODE_TLS_REJECT_UNAUTHORIZED
value: {{ .Values.services.tlsRejectUnauthorized }} value: {{ .Values.services.tlsRejectUnauthorized }}
{{ end }} {{ end }}
image: budibase/worker:{{ .Values.globals.appVersion | default .Chart.AppVersion }}
image: budibase/worker:{{ .Values.globals.appVersion }}
imagePullPolicy: Always imagePullPolicy: Always
livenessProbe: livenessProbe:
httpGet: httpGet:

View File

@ -74,7 +74,7 @@ tolerations: []
affinity: {} affinity: {}
globals: globals:
appVersion: "latest" appVersion: "" # Use as an override to .Chart.AppVersion
budibaseEnv: PRODUCTION budibaseEnv: PRODUCTION
tenantFeatureFlags: "*:LICENSING,*:USER_GROUPS,*:ONBOARDING_TOUR" tenantFeatureFlags: "*:LICENSING,*:USER_GROUPS,*:ONBOARDING_TOUR"
enableAnalytics: "1" enableAnalytics: "1"

View File

@ -1,6 +1,7 @@
{ {
"version": "2.4.44-alpha.12", "version": "2.5.6-alpha.1",
"npmClient": "yarn", "npmClient": "yarn",
"useWorkspaces": true,
"packages": ["packages/*"], "packages": ["packages/*"],
"command": { "command": {
"publish": { "publish": {

View File

@ -3,7 +3,6 @@
"private": true, "private": true,
"devDependencies": { "devDependencies": {
"@rollup/plugin-json": "^4.0.2", "@rollup/plugin-json": "^4.0.2",
"@types/supertest": "^2.0.12",
"@typescript-eslint/parser": "5.45.0", "@typescript-eslint/parser": "5.45.0",
"babel-eslint": "^10.0.3", "babel-eslint": "^10.0.3",
"eslint": "^7.28.0", "eslint": "^7.28.0",
@ -23,11 +22,10 @@
}, },
"scripts": { "scripts": {
"setup": "node ./hosting/scripts/setup.js && yarn && yarn bootstrap && yarn build && yarn dev", "setup": "node ./hosting/scripts/setup.js && yarn && yarn bootstrap && yarn build && yarn dev",
"bootstrap": "lerna bootstrap", "bootstrap": "lerna link && ./scripts/link-dependencies.sh",
"postbootstrap": "lerna link && ./scripts/link-dependencies.sh",
"build": "lerna run --stream build", "build": "lerna run --stream build",
"build:dev": "lerna run --stream prebuild && tsc --build --watch --preserveWatchOutput", "build:dev": "lerna run --stream prebuild && tsc --build --watch --preserveWatchOutput",
"backend:bootstrap": "./scripts/scopeBackend.sh 'lerna bootstrap' && yarn run postbootstrap", "backend:bootstrap": "./scripts/scopeBackend.sh && yarn run bootstrap",
"backend:build": "./scripts/scopeBackend.sh 'lerna run --stream build'", "backend:build": "./scripts/scopeBackend.sh 'lerna run --stream build'",
"build:sdk": "lerna run --stream build:sdk", "build:sdk": "lerna run --stream build:sdk",
"deps:circular": "madge packages/server/dist/index.js packages/worker/src/index.ts packages/backend-core/dist/src/index.js packages/cli/src/index.js --circular", "deps:circular": "madge packages/server/dist/index.js packages/worker/src/index.ts packages/backend-core/dist/src/index.js packages/cli/src/index.js --circular",
@ -86,5 +84,10 @@
"postinstall": "husky install", "postinstall": "husky install",
"install:pro": "bash scripts/pro/install.sh", "install:pro": "bash scripts/pro/install.sh",
"dep:clean": "yarn clean && yarn bootstrap" "dep:clean": "yarn clean && yarn bootstrap"
},
"workspaces": {
"packages": [
"packages/*"
]
} }
} }

View File

@ -1,6 +1,6 @@
{ {
"name": "@budibase/backend-core", "name": "@budibase/backend-core",
"version": "2.4.44-alpha.12", "version": "2.5.6-alpha.1",
"description": "Budibase backend core libraries used in server and worker", "description": "Budibase backend core libraries used in server and worker",
"main": "dist/src/index.js", "main": "dist/src/index.js",
"types": "dist/src/index.d.ts", "types": "dist/src/index.d.ts",
@ -24,7 +24,7 @@
"dependencies": { "dependencies": {
"@budibase/nano": "10.1.2", "@budibase/nano": "10.1.2",
"@budibase/pouchdb-replication-stream": "1.2.10", "@budibase/pouchdb-replication-stream": "1.2.10",
"@budibase/types": "2.4.44-alpha.12", "@budibase/types": "2.5.6-alpha.1",
"@shopify/jest-koa-mocks": "5.0.1", "@shopify/jest-koa-mocks": "5.0.1",
"@techpass/passport-openidconnect": "0.3.2", "@techpass/passport-openidconnect": "0.3.2",
"aws-cloudfront-sign": "2.2.0", "aws-cloudfront-sign": "2.2.0",
@ -54,16 +54,16 @@
"sanitize-s3-objectkey": "0.0.1", "sanitize-s3-objectkey": "0.0.1",
"semver": "7.3.7", "semver": "7.3.7",
"tar-fs": "2.1.1", "tar-fs": "2.1.1",
"uuid": "8.3.2", "uuid": "8.3.2"
"zlib": "1.0.5"
}, },
"devDependencies": { "devDependencies": {
"@jest/test-sequencer": "29.5.0",
"@swc/core": "^1.3.25", "@swc/core": "^1.3.25",
"@swc/jest": "^0.2.24", "@swc/jest": "^0.2.24",
"@trendyol/jest-testcontainers": "^2.1.1", "@trendyol/jest-testcontainers": "^2.1.1",
"@types/chance": "1.1.3", "@types/chance": "1.1.3",
"@types/ioredis": "4.28.0", "@types/ioredis": "4.28.0",
"@types/jest": "28.1.1", "@types/jest": "29.5.0",
"@types/koa": "2.13.4", "@types/koa": "2.13.4",
"@types/lodash": "4.14.180", "@types/lodash": "4.14.180",
"@types/node": "14.18.20", "@types/node": "14.18.20",
@ -75,14 +75,16 @@
"@types/uuid": "8.3.4", "@types/uuid": "8.3.4",
"chance": "1.1.8", "chance": "1.1.8",
"ioredis-mock": "5.8.0", "ioredis-mock": "5.8.0",
"jest": "28.1.1", "jest": "29.5.0",
"jest-environment-node": "29.5.0",
"jest-serial-runner": "^1.2.1", "jest-serial-runner": "^1.2.1",
"koa": "2.13.4", "koa": "2.13.4",
"nodemon": "2.0.16", "nodemon": "2.0.16",
"pino": "7.11.0",
"pino-pretty": "10.0.0", "pino-pretty": "10.0.0",
"pouchdb-adapter-memory": "7.2.2", "pouchdb-adapter-memory": "7.2.2",
"timekeeper": "2.2.0", "timekeeper": "2.2.0",
"ts-jest": "28.0.4", "ts-jest": "29.0.5",
"ts-node": "10.8.1", "ts-node": "10.8.1",
"tsconfig-paths": "4.0.0", "tsconfig-paths": "4.0.0",
"typescript": "4.7.3" "typescript": "4.7.3"

View File

@ -1,4 +1,5 @@
import { structures, testEnv } from "../../../tests" import { structures } from "../../../tests"
import { testEnv } from "../../../tests/extra"
import * as auth from "../auth" import * as auth from "../auth"
import * as events from "../../events" import * as events from "../../events"

View File

@ -1,6 +1,6 @@
import { DBTestConfiguration } from "../../../tests/extra"
import { import {
structures, structures,
DBTestConfiguration,
expectFunctionWasCalledTimesWith, expectFunctionWasCalledTimesWith,
mocks, mocks,
} from "../../../tests" } from "../../../tests"

View File

@ -1,9 +1,5 @@
import { import { generator, structures } from "../../../tests"
DBTestConfiguration, import { DBTestConfiguration, testEnv } from "../../../tests/extra"
generator,
testEnv,
structures,
} from "../../../tests"
import { ConfigType } from "@budibase/types" import { ConfigType } from "@budibase/types"
import env from "../../environment" import env from "../../environment"
import * as configs from "../configs" import * as configs from "../configs"

View File

@ -2,7 +2,7 @@
// store an app ID to pretend there is a context // store an app ID to pretend there is a context
import env from "../environment" import env from "../environment"
import Context from "./Context" import Context from "./Context"
import * as conversions from "../db/conversions" import * as conversions from "../docIds/conversions"
import { getDB } from "../db/db" import { getDB } from "../db/db"
import { import {
DocumentType, DocumentType,
@ -43,8 +43,12 @@ export function baseGlobalDBName(tenantId: string | undefined | null) {
} }
} }
export function getPlatformURL() {
return env.PLATFORM_URL
}
export function isMultiTenant() { export function isMultiTenant() {
return env.MULTI_TENANCY return !!env.MULTI_TENANCY
} }
export function isTenantIdSet() { export function isTenantIdSet() {

View File

@ -1,4 +1,4 @@
import { testEnv } from "../../../tests" import { testEnv } from "../../../tests/extra"
import * as context from "../" import * as context from "../"
import { DEFAULT_TENANT_ID } from "../../constants" import { DEFAULT_TENANT_ID } from "../../constants"

View File

@ -15,7 +15,7 @@ import { getCouchInfo } from "./connections"
import { directCouchCall } from "./utils" import { directCouchCall } from "./utils"
import { getPouchDB } from "./pouchDB" import { getPouchDB } from "./pouchDB"
import { WriteStream, ReadStream } from "fs" import { WriteStream, ReadStream } from "fs"
import { newid } from "../../newid" import { newid } from "../../docIds/newid"
function buildNano(couchInfo: { url: string; cookie: string }) { function buildNano(couchInfo: { url: string; cookie: string }) {
return Nano({ return Nano({

View File

@ -2,7 +2,7 @@ export * from "./couch"
export * from "./db" export * from "./db"
export * from "./utils" export * from "./utils"
export * from "./views" export * from "./views"
export * from "./conversions" export * from "../docIds/conversions"
export { default as Replication } from "./Replication" export { default as Replication } from "./Replication"
// exports to support old export structure // exports to support old export structure
export * from "../constants/db" export * from "../constants/db"

View File

@ -1,4 +1,4 @@
import { newid } from "../../newid" import { newid } from "../../docIds/newid"
import { getDB } from "../db" import { getDB } from "../db"
import { Database } from "@budibase/types" import { Database } from "@budibase/types"
import { QueryBuilder, paginatedSearch, fullSearch } from "../lucene" import { QueryBuilder, paginatedSearch, fullSearch } from "../lucene"

View File

@ -3,7 +3,7 @@ import {
getProdAppID, getProdAppID,
isDevAppID, isDevAppID,
isProdAppID, isProdAppID,
} from "../conversions" } from "../../docIds/conversions"
import { generateAppID } from "../utils" import { generateAppID } from "../utils"
describe("utils", () => { describe("utils", () => {

View File

@ -1,257 +1,12 @@
import { newid } from "../newid"
import env from "../environment" import env from "../environment"
import { import { DEFAULT_TENANT_ID, SEPARATOR, DocumentType } from "../constants"
DEFAULT_TENANT_ID,
SEPARATOR,
DocumentType,
UNICODE_MAX,
ViewName,
InternalTable,
APP_PREFIX,
} from "../constants"
import { getTenantId, getGlobalDBName } from "../context" import { getTenantId, getGlobalDBName } from "../context"
import { doWithDB, directCouchAllDbs } from "./db" import { doWithDB, directCouchAllDbs } from "./db"
import { getAppMetadata } from "../cache/appMetadata" import { getAppMetadata } from "../cache/appMetadata"
import { isDevApp, isDevAppID, getProdAppID } from "./conversions" import { isDevApp, isDevAppID, getProdAppID } from "../docIds/conversions"
import { App, Database } from "@budibase/types" import { App, Database } from "@budibase/types"
import { getStartEndKeyURL } from "../docIds"
/** export * from "../docIds"
* Generates a new app ID.
* @returns {string} The new app ID which the app doc can be stored under.
*/
export const generateAppID = (tenantId?: string | null) => {
let id = APP_PREFIX
if (tenantId) {
id += `${tenantId}${SEPARATOR}`
}
return `${id}${newid()}`
}
/**
* If creating DB allDocs/query params with only a single top level ID this can be used, this
* is usually the case as most of our docs are top level e.g. tables, automations, users and so on.
* More complex cases such as link docs and rows which have multiple levels of IDs that their
* ID consists of need their own functions to build the allDocs parameters.
* @param {string} docType The type of document which input params are being built for, e.g. user,
* link, app, table and so on.
* @param {string|null} docId The ID of the document minus its type - this is only needed if looking
* for a singular document.
* @param {object} otherProps Add any other properties onto the request, e.g. include_docs.
* @returns {object} Parameters which can then be used with an allDocs request.
*/
export function getDocParams(
docType: string,
docId?: string | null,
otherProps: any = {}
) {
if (docId == null) {
docId = ""
}
return {
...otherProps,
startkey: `${docType}${SEPARATOR}${docId}`,
endkey: `${docType}${SEPARATOR}${docId}${UNICODE_MAX}`,
}
}
/**
* Gets the DB allDocs/query params for retrieving a row.
* @param {string|null} tableId The table in which the rows have been stored.
* @param {string|null} rowId The ID of the row which is being specifically queried for. This can be
* left null to get all the rows in the table.
* @param {object} otherProps Any other properties to add to the request.
* @returns {object} Parameters which can then be used with an allDocs request.
*/
export function getRowParams(
tableId?: string | null,
rowId?: string | null,
otherProps = {}
) {
if (tableId == null) {
return getDocParams(DocumentType.ROW, null, otherProps)
}
const endOfKey = rowId == null ? `${tableId}${SEPARATOR}` : rowId
return getDocParams(DocumentType.ROW, endOfKey, otherProps)
}
/**
* Retrieve the correct index for a view based on default design DB.
*/
export function getQueryIndex(viewName: ViewName) {
return `database/${viewName}`
}
/**
* Gets a new row ID for the specified table.
* @param {string} tableId The table which the row is being created for.
* @param {string|null} id If an ID is to be used then the UUID can be substituted for this.
* @returns {string} The new ID which a row doc can be stored under.
*/
export function generateRowID(tableId: string, id?: string) {
id = id || newid()
return `${DocumentType.ROW}${SEPARATOR}${tableId}${SEPARATOR}${id}`
}
/**
* Check if a given ID is that of a table.
* @returns {boolean}
*/
export const isTableId = (id: string) => {
// this includes datasource plus tables
return (
id &&
(id.startsWith(`${DocumentType.TABLE}${SEPARATOR}`) ||
id.startsWith(`${DocumentType.DATASOURCE_PLUS}${SEPARATOR}`))
)
}
/**
* Check if a given ID is that of a datasource or datasource plus.
* @returns {boolean}
*/
export const isDatasourceId = (id: string) => {
// this covers both datasources and datasource plus
return id && id.startsWith(`${DocumentType.DATASOURCE}${SEPARATOR}`)
}
/**
* Generates a new workspace ID.
* @returns {string} The new workspace ID which the workspace doc can be stored under.
*/
export function generateWorkspaceID() {
return `${DocumentType.WORKSPACE}${SEPARATOR}${newid()}`
}
/**
* Gets parameters for retrieving workspaces.
*/
export function getWorkspaceParams(id = "", otherProps = {}) {
return {
...otherProps,
startkey: `${DocumentType.WORKSPACE}${SEPARATOR}${id}`,
endkey: `${DocumentType.WORKSPACE}${SEPARATOR}${id}${UNICODE_MAX}`,
}
}
/**
* Generates a new global user ID.
* @returns {string} The new user ID which the user doc can be stored under.
*/
export function generateGlobalUserID(id?: any) {
return `${DocumentType.USER}${SEPARATOR}${id || newid()}`
}
/**
* Gets parameters for retrieving users.
*/
export function getGlobalUserParams(globalId: any, otherProps: any = {}) {
if (!globalId) {
globalId = ""
}
const startkey = otherProps?.startkey
return {
...otherProps,
// need to include this incase pagination
startkey: startkey
? startkey
: `${DocumentType.USER}${SEPARATOR}${globalId}`,
endkey: `${DocumentType.USER}${SEPARATOR}${globalId}${UNICODE_MAX}`,
}
}
/**
* Gets parameters for retrieving users, this is a utility function for the getDocParams function.
*/
export function getUserMetadataParams(userId?: string | null, otherProps = {}) {
return getRowParams(InternalTable.USER_METADATA, userId, otherProps)
}
/**
* Generates a new user ID based on the passed in global ID.
* @param {string} globalId The ID of the global user.
* @returns {string} The new user ID which the user doc can be stored under.
*/
export function generateUserMetadataID(globalId: string) {
return generateRowID(InternalTable.USER_METADATA, globalId)
}
/**
* Breaks up the ID to get the global ID.
*/
export function getGlobalIDFromUserMetadataID(id: string) {
const prefix = `${DocumentType.ROW}${SEPARATOR}${InternalTable.USER_METADATA}${SEPARATOR}`
if (!id || !id.includes(prefix)) {
return id
}
return id.split(prefix)[1]
}
export function getUsersByAppParams(appId: any, otherProps: any = {}) {
const prodAppId = getProdAppID(appId)
return {
...otherProps,
startkey: prodAppId,
endkey: `${prodAppId}${UNICODE_MAX}`,
}
}
/**
* Generates a template ID.
* @param ownerId The owner/user of the template, this could be global or a workspace level.
*/
export function generateTemplateID(ownerId: any) {
return `${DocumentType.TEMPLATE}${SEPARATOR}${ownerId}${SEPARATOR}${newid()}`
}
export function generateAppUserID(prodAppId: string, userId: string) {
return `${prodAppId}${SEPARATOR}${userId}`
}
/**
* Gets parameters for retrieving templates. Owner ID must be specified, either global or a workspace level.
*/
export function getTemplateParams(
ownerId: any,
templateId: any,
otherProps = {}
) {
if (!templateId) {
templateId = ""
}
let final
if (templateId) {
final = templateId
} else {
final = `${DocumentType.TEMPLATE}${SEPARATOR}${ownerId}${SEPARATOR}`
}
return {
...otherProps,
startkey: final,
endkey: `${final}${UNICODE_MAX}`,
}
}
/**
* Generates a new role ID.
* @returns {string} The new role ID which the role doc can be stored under.
*/
export function generateRoleID(id?: any) {
return `${DocumentType.ROLE}${SEPARATOR}${id || newid()}`
}
/**
* Gets parameters for retrieving a role, this is a utility function for the getDocParams function.
*/
export function getRoleParams(roleId?: string | null, otherProps = {}) {
return getDocParams(DocumentType.ROLE, roleId, otherProps)
}
export function getStartEndKeyURL(baseKey: any, tenantId?: string) {
const tenancy = tenantId ? `${SEPARATOR}${tenantId}` : ""
return `startkey="${baseKey}${tenancy}"&endkey="${baseKey}${tenancy}${UNICODE_MAX}"`
}
/** /**
* if in production this will use the CouchDB _all_dbs call to retrieve a list of databases. If testing * if in production this will use the CouchDB _all_dbs call to retrieve a list of databases. If testing
@ -411,29 +166,6 @@ export async function dbExists(dbName: any) {
) )
} }
/**
* Generates a new dev info document ID - this is scoped to a user.
* @returns {string} The new dev info ID which info for dev (like api key) can be stored under.
*/
export const generateDevInfoID = (userId: any) => {
return `${DocumentType.DEV_INFO}${SEPARATOR}${userId}`
}
/**
* Generates a new plugin ID - to be used in the global DB.
* @returns {string} The new plugin ID which a plugin metadata document can be stored under.
*/
export const generatePluginID = (name: string) => {
return `${DocumentType.PLUGIN}${SEPARATOR}${name}`
}
/**
* Gets parameters for retrieving automations, this is a utility function for the getDocParams function.
*/
export const getPluginParams = (pluginId?: string | null, otherProps = {}) => {
return getDocParams(DocumentType.PLUGIN, pluginId, otherProps)
}
export function pagination<T>( export function pagination<T>(
data: T[], data: T[],
pageSize: number, pageSize: number,

View File

@ -0,0 +1,102 @@
import {
APP_PREFIX,
DocumentType,
InternalTable,
SEPARATOR,
} from "../constants"
import { newid } from "./newid"
/**
* Generates a new app ID.
* @returns {string} The new app ID which the app doc can be stored under.
*/
export const generateAppID = (tenantId?: string | null) => {
let id = APP_PREFIX
if (tenantId) {
id += `${tenantId}${SEPARATOR}`
}
return `${id}${newid()}`
}
/**
* Gets a new row ID for the specified table.
* @param {string} tableId The table which the row is being created for.
* @param {string|null} id If an ID is to be used then the UUID can be substituted for this.
* @returns {string} The new ID which a row doc can be stored under.
*/
export function generateRowID(tableId: string, id?: string) {
id = id || newid()
return `${DocumentType.ROW}${SEPARATOR}${tableId}${SEPARATOR}${id}`
}
/**
* Generates a new workspace ID.
* @returns {string} The new workspace ID which the workspace doc can be stored under.
*/
export function generateWorkspaceID() {
return `${DocumentType.WORKSPACE}${SEPARATOR}${newid()}`
}
/**
* Generates a new global user ID.
* @returns {string} The new user ID which the user doc can be stored under.
*/
export function generateGlobalUserID(id?: any) {
return `${DocumentType.USER}${SEPARATOR}${id || newid()}`
}
/**
* Generates a new user ID based on the passed in global ID.
* @param {string} globalId The ID of the global user.
* @returns {string} The new user ID which the user doc can be stored under.
*/
export function generateUserMetadataID(globalId: string) {
return generateRowID(InternalTable.USER_METADATA, globalId)
}
/**
* Breaks up the ID to get the global ID.
*/
export function getGlobalIDFromUserMetadataID(id: string) {
const prefix = `${DocumentType.ROW}${SEPARATOR}${InternalTable.USER_METADATA}${SEPARATOR}`
if (!id || !id.includes(prefix)) {
return id
}
return id.split(prefix)[1]
}
/**
* Generates a template ID.
* @param ownerId The owner/user of the template, this could be global or a workspace level.
*/
export function generateTemplateID(ownerId: any) {
return `${DocumentType.TEMPLATE}${SEPARATOR}${ownerId}${SEPARATOR}${newid()}`
}
export function generateAppUserID(prodAppId: string, userId: string) {
return `${prodAppId}${SEPARATOR}${userId}`
}
/**
* Generates a new role ID.
* @returns {string} The new role ID which the role doc can be stored under.
*/
export function generateRoleID(id?: any) {
return `${DocumentType.ROLE}${SEPARATOR}${id || newid()}`
}
/**
* Generates a new dev info document ID - this is scoped to a user.
* @returns {string} The new dev info ID which info for dev (like api key) can be stored under.
*/
export const generateDevInfoID = (userId: any) => {
return `${DocumentType.DEV_INFO}${SEPARATOR}${userId}`
}
/**
* Generates a new plugin ID - to be used in the global DB.
* @returns {string} The new plugin ID which a plugin metadata document can be stored under.
*/
export const generatePluginID = (name: string) => {
return `${DocumentType.PLUGIN}${SEPARATOR}${name}`
}

View File

@ -0,0 +1,2 @@
export * from "./ids"
export * from "./params"

View File

@ -0,0 +1,174 @@
import {
DocumentType,
InternalTable,
SEPARATOR,
UNICODE_MAX,
ViewName,
} from "../constants"
import { getProdAppID } from "./conversions"
/**
* If creating DB allDocs/query params with only a single top level ID this can be used, this
* is usually the case as most of our docs are top level e.g. tables, automations, users and so on.
* More complex cases such as link docs and rows which have multiple levels of IDs that their
* ID consists of need their own functions to build the allDocs parameters.
* @param {string} docType The type of document which input params are being built for, e.g. user,
* link, app, table and so on.
* @param {string|null} docId The ID of the document minus its type - this is only needed if looking
* for a singular document.
* @param {object} otherProps Add any other properties onto the request, e.g. include_docs.
* @returns {object} Parameters which can then be used with an allDocs request.
*/
export function getDocParams(
docType: string,
docId?: string | null,
otherProps: any = {}
) {
if (docId == null) {
docId = ""
}
return {
...otherProps,
startkey: `${docType}${SEPARATOR}${docId}`,
endkey: `${docType}${SEPARATOR}${docId}${UNICODE_MAX}`,
}
}
/**
* Gets the DB allDocs/query params for retrieving a row.
* @param {string|null} tableId The table in which the rows have been stored.
* @param {string|null} rowId The ID of the row which is being specifically queried for. This can be
* left null to get all the rows in the table.
* @param {object} otherProps Any other properties to add to the request.
* @returns {object} Parameters which can then be used with an allDocs request.
*/
export function getRowParams(
tableId?: string | null,
rowId?: string | null,
otherProps = {}
) {
if (tableId == null) {
return getDocParams(DocumentType.ROW, null, otherProps)
}
const endOfKey = rowId == null ? `${tableId}${SEPARATOR}` : rowId
return getDocParams(DocumentType.ROW, endOfKey, otherProps)
}
/**
* Retrieve the correct index for a view based on default design DB.
*/
export function getQueryIndex(viewName: ViewName) {
return `database/${viewName}`
}
/**
* Check if a given ID is that of a table.
* @returns {boolean}
*/
export const isTableId = (id: string) => {
// this includes datasource plus tables
return (
id &&
(id.startsWith(`${DocumentType.TABLE}${SEPARATOR}`) ||
id.startsWith(`${DocumentType.DATASOURCE_PLUS}${SEPARATOR}`))
)
}
/**
* Check if a given ID is that of a datasource or datasource plus.
* @returns {boolean}
*/
export const isDatasourceId = (id: string) => {
// this covers both datasources and datasource plus
return id && id.startsWith(`${DocumentType.DATASOURCE}${SEPARATOR}`)
}
/**
* Gets parameters for retrieving workspaces.
*/
export function getWorkspaceParams(id = "", otherProps = {}) {
return {
...otherProps,
startkey: `${DocumentType.WORKSPACE}${SEPARATOR}${id}`,
endkey: `${DocumentType.WORKSPACE}${SEPARATOR}${id}${UNICODE_MAX}`,
}
}
/**
* Gets parameters for retrieving users.
*/
export function getGlobalUserParams(globalId: any, otherProps: any = {}) {
if (!globalId) {
globalId = ""
}
const startkey = otherProps?.startkey
return {
...otherProps,
// need to include this incase pagination
startkey: startkey
? startkey
: `${DocumentType.USER}${SEPARATOR}${globalId}`,
endkey: `${DocumentType.USER}${SEPARATOR}${globalId}${UNICODE_MAX}`,
}
}
/**
* Gets parameters for retrieving users, this is a utility function for the getDocParams function.
*/
export function getUserMetadataParams(userId?: string | null, otherProps = {}) {
return getRowParams(InternalTable.USER_METADATA, userId, otherProps)
}
export function getUsersByAppParams(appId: any, otherProps: any = {}) {
const prodAppId = getProdAppID(appId)
return {
...otherProps,
startkey: prodAppId,
endkey: `${prodAppId}${UNICODE_MAX}`,
}
}
/**
* Gets parameters for retrieving templates. Owner ID must be specified, either global or a workspace level.
*/
export function getTemplateParams(
ownerId: any,
templateId: any,
otherProps = {}
) {
if (!templateId) {
templateId = ""
}
let final
if (templateId) {
final = templateId
} else {
final = `${DocumentType.TEMPLATE}${SEPARATOR}${ownerId}${SEPARATOR}`
}
return {
...otherProps,
startkey: final,
endkey: `${final}${UNICODE_MAX}`,
}
}
/**
* Gets parameters for retrieving a role, this is a utility function for the getDocParams function.
*/
export function getRoleParams(roleId?: string | null, otherProps = {}) {
return getDocParams(DocumentType.ROLE, roleId, otherProps)
}
export function getStartEndKeyURL(baseKey: any, tenantId?: string) {
const tenancy = tenantId ? `${SEPARATOR}${tenantId}` : ""
return `startkey="${baseKey}${tenancy}"&endkey="${baseKey}${tenancy}${UNICODE_MAX}"`
}
/**
* Gets parameters for retrieving automations, this is a utility function for the getDocParams function.
*/
export const getPluginParams = (pluginId?: string | null, otherProps = {}) => {
return getDocParams(DocumentType.PLUGIN, pluginId, otherProps)
}

View File

@ -1,4 +1,4 @@
import { testEnv } from "../../../../../tests" import { testEnv } from "../../../../../tests/extra"
import PosthogProcessor from "../PosthogProcessor" import PosthogProcessor from "../PosthogProcessor"
import { Event, IdentityType, Hosting } from "@budibase/types" import { Event, IdentityType, Hosting } from "@budibase/types"
const tk = require("timekeeper") const tk = require("timekeeper")

View File

@ -1,4 +1,5 @@
import { structures, testEnv, mocks } from "../../../../../tests" import { structures, mocks } from "../../../../../tests"
import { testEnv } from "../../../../../tests/extra"
import { SSOAuthDetails, User } from "@budibase/types" import { SSOAuthDetails, User } from "@budibase/types"
import { HTTPError } from "../../../../errors" import { HTTPError } from "../../../../errors"

View File

@ -1,7 +1,7 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP // Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`migrations should match snapshot 1`] = ` exports[`migrations should match snapshot 1`] = `
Object { {
"_id": "migrations", "_id": "migrations",
"_rev": "1-2f64479842a0513aa8b97f356b0b9127", "_rev": "1-2f64479842a0513aa8b97f356b0b9127",
"createdAt": "2020-01-01T00:00:00.000Z", "createdAt": "2020-01-01T00:00:00.000Z",

View File

@ -1,4 +1,4 @@
import { testEnv, DBTestConfiguration } from "../../../tests" import { testEnv, DBTestConfiguration } from "../../../tests/extra"
import * as migrations from "../index" import * as migrations from "../index"
import * as context from "../../context" import * as context from "../../context"
import { MigrationType } from "@budibase/types" import { MigrationType } from "@budibase/types"

View File

@ -1,6 +1,6 @@
import * as app from "../app" import * as app from "../app"
import { getAppFileUrl } from "../app" import { getAppFileUrl } from "../app"
import { testEnv } from "../../../../tests" import { testEnv } from "../../../../tests/extra"
describe("app", () => { describe("app", () => {
beforeEach(() => { beforeEach(() => {

View File

@ -1,5 +1,5 @@
import * as global from "../global" import * as global from "../global"
import { testEnv } from "../../../../tests" import { testEnv } from "../../../../tests/extra"
describe("global", () => { describe("global", () => {
describe("getGlobalFileUrl", () => { describe("getGlobalFileUrl", () => {

View File

@ -1,5 +1,6 @@
import * as plugins from "../plugins" import * as plugins from "../plugins"
import { structures, testEnv } from "../../../../tests" import { structures } from "../../../../tests"
import { testEnv } from "../../../../tests/extra"
describe("plugins", () => { describe("plugins", () => {
describe("enrichPluginURLs", () => { describe("enrichPluginURLs", () => {

View File

@ -3,7 +3,7 @@ import AWS from "aws-sdk"
import stream from "stream" import stream from "stream"
import fetch from "node-fetch" import fetch from "node-fetch"
import tar from "tar-fs" import tar from "tar-fs"
const zlib = require("zlib") import zlib from "zlib"
import { promisify } from "util" import { promisify } from "util"
import { join } from "path" import { join } from "path"
import fs from "fs" import fs from "fs"
@ -415,7 +415,7 @@ export const downloadTarballDirect = async (
throw new Error(`unexpected response ${response.statusText}`) throw new Error(`unexpected response ${response.statusText}`)
} }
await streamPipeline(response.body, zlib.Unzip(), tar.extract(path)) await streamPipeline(response.body, zlib.createUnzip(), tar.extract(path))
} }
export const downloadTarball = async ( export const downloadTarball = async (
@ -431,7 +431,7 @@ export const downloadTarball = async (
} }
const tmpPath = join(budibaseTempDir(), path) const tmpPath = join(budibaseTempDir(), path)
await streamPipeline(response.body, zlib.Unzip(), tar.extract(tmpPath)) await streamPipeline(response.body, zlib.createUnzip(), tar.extract(tmpPath))
if (!env.isTest() && env.SELF_HOSTED) { if (!env.isTest() && env.SELF_HOSTED) {
await uploadDirectory(bucketName, tmpPath, path) await uploadDirectory(bucketName, tmpPath, path)
} }

View File

@ -1,4 +1,5 @@
import { DBTestConfiguration, structures } from "../../../tests" import { structures } from "../../../tests"
import { DBTestConfiguration } from "../../../tests/extra"
import * as tenants from "../tenants" import * as tenants from "../tenants"
describe("tenants", () => { describe("tenants", () => {

View File

@ -12,7 +12,7 @@ export enum SecretOption {
ENCRYPTION = "encryption", ENCRYPTION = "encryption",
} }
function getSecret(secretOption: SecretOption): string { export function getSecret(secretOption: SecretOption): string {
let secret, secretName let secret, secretName
switch (secretOption) { switch (secretOption) {
case SecretOption.ENCRYPTION: case SecretOption.ENCRYPTION:

View File

@ -24,7 +24,7 @@ export enum PermissionType {
QUERY = "query", QUERY = "query",
} }
class Permission { export class Permission {
type: PermissionType type: PermissionType
level: PermissionLevel level: PermissionLevel
@ -34,7 +34,7 @@ class Permission {
} }
} }
function levelToNumber(perm: PermissionLevel) { export function levelToNumber(perm: PermissionLevel) {
switch (perm) { switch (perm) {
// not everything has execute privileges // not everything has execute privileges
case PermissionLevel.EXECUTE: case PermissionLevel.EXECUTE:
@ -55,7 +55,7 @@ function levelToNumber(perm: PermissionLevel) {
* @param {string} userPermLevel The permission level of the user. * @param {string} userPermLevel The permission level of the user.
* @return {string[]} All the permission levels this user is allowed to carry out. * @return {string[]} All the permission levels this user is allowed to carry out.
*/ */
function getAllowedLevels(userPermLevel: PermissionLevel) { export function getAllowedLevels(userPermLevel: PermissionLevel): string[] {
switch (userPermLevel) { switch (userPermLevel) {
case PermissionLevel.EXECUTE: case PermissionLevel.EXECUTE:
return [PermissionLevel.EXECUTE] return [PermissionLevel.EXECUTE]
@ -64,9 +64,9 @@ function getAllowedLevels(userPermLevel: PermissionLevel) {
case PermissionLevel.WRITE: case PermissionLevel.WRITE:
case PermissionLevel.ADMIN: case PermissionLevel.ADMIN:
return [ return [
PermissionLevel.EXECUTE,
PermissionLevel.READ, PermissionLevel.READ,
PermissionLevel.WRITE, PermissionLevel.WRITE,
PermissionLevel.EXECUTE,
] ]
default: default:
return [] return []
@ -81,7 +81,7 @@ export enum BuiltinPermissionID {
POWER = "power", POWER = "power",
} }
const BUILTIN_PERMISSIONS = { export const BUILTIN_PERMISSIONS = {
PUBLIC: { PUBLIC: {
_id: BuiltinPermissionID.PUBLIC, _id: BuiltinPermissionID.PUBLIC,
name: "Public", name: "Public",

View File

@ -0,0 +1,31 @@
import { encrypt, decrypt, SecretOption, getSecret } from "../encryption"
import env from "../../environment"
describe("encryption", () => {
it("should throw an error if API encryption key is not set", () => {
const jwt = getSecret(SecretOption.API)
expect(jwt).toBe(env.JWT_SECRET)
})
it("should throw an error if encryption key is not set", () => {
expect(() => getSecret(SecretOption.ENCRYPTION)).toThrow(
'Secret "ENCRYPTION_KEY" has not been set in environment.'
)
})
it("should encrypt and decrypt a string using API encryption key", () => {
env._set("API_ENCRYPTION_KEY", "api_secret")
const plaintext = "budibase"
const apiEncrypted = encrypt(plaintext, SecretOption.API)
const decrypted = decrypt(apiEncrypted, SecretOption.API)
expect(decrypted).toEqual(plaintext)
})
it("should encrypt and decrypt a string using encryption key", () => {
env._set("ENCRYPTION_KEY", "normal_secret")
const plaintext = "budibase"
const encryptionEncrypted = encrypt(plaintext, SecretOption.ENCRYPTION)
const decrypted = decrypt(encryptionEncrypted, SecretOption.ENCRYPTION)
expect(decrypted).toEqual(plaintext)
})
})

View File

@ -0,0 +1,145 @@
import { cloneDeep } from "lodash"
import * as permissions from "../permissions"
import { BUILTIN_ROLE_IDS } from "../roles"
describe("levelToNumber", () => {
it("should return 0 for EXECUTE", () => {
expect(permissions.levelToNumber(permissions.PermissionLevel.EXECUTE)).toBe(
0
)
})
it("should return 1 for READ", () => {
expect(permissions.levelToNumber(permissions.PermissionLevel.READ)).toBe(1)
})
it("should return 2 for WRITE", () => {
expect(permissions.levelToNumber(permissions.PermissionLevel.WRITE)).toBe(2)
})
it("should return 3 for ADMIN", () => {
expect(permissions.levelToNumber(permissions.PermissionLevel.ADMIN)).toBe(3)
})
it("should return -1 for an unknown permission level", () => {
expect(
permissions.levelToNumber("unknown" as permissions.PermissionLevel)
).toBe(-1)
})
})
describe("getAllowedLevels", () => {
it('should return ["execute"] for EXECUTE', () => {
expect(
permissions.getAllowedLevels(permissions.PermissionLevel.EXECUTE)
).toEqual([permissions.PermissionLevel.EXECUTE])
})
it('should return ["execute", "read"] for READ', () => {
expect(
permissions.getAllowedLevels(permissions.PermissionLevel.READ)
).toEqual([
permissions.PermissionLevel.EXECUTE,
permissions.PermissionLevel.READ,
])
})
it('should return ["execute", "read", "write"] for WRITE', () => {
expect(
permissions.getAllowedLevels(permissions.PermissionLevel.WRITE)
).toEqual([
permissions.PermissionLevel.EXECUTE,
permissions.PermissionLevel.READ,
permissions.PermissionLevel.WRITE,
])
})
it('should return ["execute", "read", "write"] for ADMIN', () => {
expect(
permissions.getAllowedLevels(permissions.PermissionLevel.ADMIN)
).toEqual([
permissions.PermissionLevel.EXECUTE,
permissions.PermissionLevel.READ,
permissions.PermissionLevel.WRITE,
])
})
it("should return [] for an unknown permission level", () => {
expect(
permissions.getAllowedLevels("unknown" as permissions.PermissionLevel)
).toEqual([])
})
})
describe("doesHaveBasePermission", () => {
it("should return true if base permission has the required level", () => {
const permType = permissions.PermissionType.USER
const permLevel = permissions.PermissionLevel.READ
const rolesHierarchy = [
{
roleId: BUILTIN_ROLE_IDS.ADMIN,
permissionId: permissions.BuiltinPermissionID.ADMIN,
},
]
expect(
permissions.doesHaveBasePermission(permType, permLevel, rolesHierarchy)
).toBe(true)
})
it("should return false if base permission does not have the required level", () => {
const permType = permissions.PermissionType.APP
const permLevel = permissions.PermissionLevel.READ
const rolesHierarchy = [
{
roleId: BUILTIN_ROLE_IDS.PUBLIC,
permissionId: permissions.BuiltinPermissionID.PUBLIC,
},
]
expect(
permissions.doesHaveBasePermission(permType, permLevel, rolesHierarchy)
).toBe(false)
})
})
describe("isPermissionLevelHigherThanRead", () => {
it("should return true if level is higher than read", () => {
expect(
permissions.isPermissionLevelHigherThanRead(
permissions.PermissionLevel.WRITE
)
).toBe(true)
})
it("should return false if level is read or lower", () => {
expect(
permissions.isPermissionLevelHigherThanRead(
permissions.PermissionLevel.READ
)
).toBe(false)
})
})
describe("getBuiltinPermissions", () => {
it("returns a clone of the builtin permissions", () => {
const builtins = permissions.getBuiltinPermissions()
expect(builtins).toEqual(cloneDeep(permissions.BUILTIN_PERMISSIONS))
expect(builtins).not.toBe(permissions.BUILTIN_PERMISSIONS)
})
})
describe("getBuiltinPermissionByID", () => {
it("returns correct permission object for valid ID", () => {
const expectedPermission = {
_id: permissions.BuiltinPermissionID.PUBLIC,
name: "Public",
permissions: [
new permissions.Permission(
permissions.PermissionType.WEBHOOK,
permissions.PermissionLevel.EXECUTE
),
],
}
expect(permissions.getBuiltinPermissionByID("public")).toEqual(
expectedPermission
)
})
})

View File

@ -3,8 +3,8 @@ import {
getTenantId, getTenantId,
getTenantIDFromAppID, getTenantIDFromAppID,
isMultiTenant, isMultiTenant,
getPlatformURL,
} from "../context" } from "../context"
import env from "../environment"
import { import {
BBContext, BBContext,
TenantResolutionStrategy, TenantResolutionStrategy,
@ -93,7 +93,7 @@ export const getTenantIDFromCtx = (
// subdomain // subdomain
if (isAllowed(TenantResolutionStrategy.SUBDOMAIN)) { if (isAllowed(TenantResolutionStrategy.SUBDOMAIN)) {
// e.g. budibase.app or local.com:10000 // e.g. budibase.app or local.com:10000
const platformHost = new URL(env.PLATFORM_URL).host.split(":")[0] const platformHost = new URL(getPlatformURL()).host.split(":")[0]
// e.g. tenant.budibase.app or tenant.local.com // e.g. tenant.budibase.app or tenant.local.com
const requestHost = ctx.host const requestHost = ctx.host
// parse the tenant id from the difference // parse the tenant id from the difference

View File

@ -0,0 +1,184 @@
import { TenantResolutionStrategy } from "@budibase/types"
import { addTenantToUrl, isUserInAppTenant, getTenantIDFromCtx } from "../"
import { isMultiTenant, getTenantIDFromAppID } from "../../context"
jest.mock("../../context", () => ({
getTenantId: jest.fn(() => "budibase"),
isMultiTenant: jest.fn(() => true),
getTenantIDFromAppID: jest.fn(),
getPlatformURL: jest.fn(() => "https://app.com"),
DEFAULT_TENANT_ID: "default",
}))
const mockedIsMultiTenant = isMultiTenant as jest.MockedFunction<
typeof isMultiTenant
>
const mockedGetTenantIDFromAppID = getTenantIDFromAppID as jest.MockedFunction<
typeof getTenantIDFromAppID
>
describe("addTenantToUrl", () => {
it("should append tenantId parameter to the URL", () => {
const url = "https://budibase.com"
const expectedUrl = "https://budibase.com?tenantId=budibase"
expect(addTenantToUrl(url)).toEqual(expectedUrl)
})
it("should append tenantId parameter to the URL query string", () => {
const url = "https://budibase.com?var=test"
const expectedUrl = "https://budibase.com?var=test&tenantId=budibase"
expect(addTenantToUrl(url)).toEqual(expectedUrl)
})
it("should not append tenantId parameter to the URL if isMultiTenant is false", () => {
mockedIsMultiTenant.mockImplementation(() => false)
const url = "https://budibase.com"
const expectedUrl = "https://budibase.com"
expect(addTenantToUrl(url)).toEqual(expectedUrl)
})
})
describe("isUserInAppTenant", () => {
mockedGetTenantIDFromAppID.mockImplementation(() => "budibase")
const mockUser = { tenantId: "budibase" }
it("returns true if user tenant ID matches app tenant ID", () => {
const appId = "app-budibase"
const result = isUserInAppTenant(appId, mockUser)
expect(result).toBe(true)
})
it("uses default tenant ID if user is not provided", () => {
const appId = "app-budibase"
const result = isUserInAppTenant(appId)
expect(result).toBe(true)
})
it("uses default tenant ID if app tenant ID is not found", () => {
const appId = "not-budibase-app"
const result = isUserInAppTenant(appId, mockUser)
expect(result).toBe(true)
})
it("returns false if user tenant ID does not match app tenant ID", () => {
const appId = "app-budibase"
mockedGetTenantIDFromAppID.mockImplementation(() => "not-budibase")
const result = isUserInAppTenant(appId, mockUser)
expect(result).toBe(false)
})
})
let mockOpts: any = {}
function createCtx(opts: {
originalUrl?: string
headers?: Record<string, string>
qsTenantId?: string
userTenantId?: string
host?: string
path?: string
}) {
const createdCtx: any = {
originalUrl: opts.originalUrl || "budibase.com",
matched: [{ name: "name" }],
throw: jest.fn(),
request: { headers: {} },
}
if (opts.headers) {
createdCtx.request.headers = opts.headers
}
if (opts.qsTenantId) {
createdCtx.request.query = { tenantId: opts.qsTenantId }
}
if (opts.userTenantId) {
createdCtx.user = { tenantId: opts.userTenantId }
}
if (opts.host) {
createdCtx.host = opts.host
}
if (opts.path) {
createdCtx.matched = [
{
paramNames: [{ name: "tenantId" }],
params: () => ({ tenantId: opts.path }),
captures: jest.fn(),
},
]
}
return createdCtx as any
}
describe("getTenantIDFromCtx", () => {
describe("when tenant can be found", () => {
it("returns the tenant ID from the user object", () => {
mockedIsMultiTenant.mockImplementation(() => true)
const ctx = createCtx({ userTenantId: "budibase" })
expect(getTenantIDFromCtx(ctx, mockOpts)).toEqual("budibase")
})
it("returns the tenant ID from the header", () => {
mockedIsMultiTenant.mockImplementation(() => true)
const ctx = createCtx({ headers: { "x-budibase-tenant-id": "budibase" } })
mockOpts = { includeStrategies: [TenantResolutionStrategy.HEADER] }
expect(getTenantIDFromCtx(ctx, mockOpts)).toEqual("budibase")
})
it("returns the tenant ID from the query param", () => {
mockedIsMultiTenant.mockImplementation(() => true)
mockOpts = { includeStrategies: [TenantResolutionStrategy.QUERY] }
const ctx = createCtx({ qsTenantId: "budibase" })
expect(getTenantIDFromCtx(ctx, mockOpts)).toEqual("budibase")
})
it("returns the tenant ID from the subdomain", () => {
mockedIsMultiTenant.mockImplementation(() => true)
const ctx = createCtx({ host: "bb.app.com" })
mockOpts = { includeStrategies: [TenantResolutionStrategy.SUBDOMAIN] }
expect(getTenantIDFromCtx(ctx, mockOpts)).toEqual("bb")
})
it("returns the tenant ID from the path", () => {
mockedIsMultiTenant.mockImplementation(() => true)
const ctx = createCtx({ path: "bb" })
mockOpts = { includeStrategies: [TenantResolutionStrategy.PATH] }
expect(getTenantIDFromCtx(ctx, mockOpts)).toEqual("bb")
})
})
describe("when tenant cannot be found", () => {
it("throws a 403 error if allowNoTenant is false", () => {
const ctx = createCtx({})
mockOpts = {
allowNoTenant: false,
excludeStrategies: [
TenantResolutionStrategy.QUERY,
TenantResolutionStrategy.SUBDOMAIN,
TenantResolutionStrategy.PATH,
],
}
expect(getTenantIDFromCtx(ctx, mockOpts)).toBeNull()
expect(ctx.throw).toBeCalledTimes(1)
expect(ctx.throw).toBeCalledWith(403, "Tenant id not set")
})
it("returns null if allowNoTenant is true", () => {
const ctx = createCtx({})
mockOpts = {
allowNoTenant: true,
excludeStrategies: [
TenantResolutionStrategy.QUERY,
TenantResolutionStrategy.SUBDOMAIN,
TenantResolutionStrategy.PATH,
],
}
expect(getTenantIDFromCtx(ctx, mockOpts)).toBeNull()
})
})
it("returns the default tenant ID when isMultiTenant() returns false", () => {
mockedIsMultiTenant.mockImplementation(() => false)
const ctx = createCtx({})
expect(getTenantIDFromCtx(ctx, mockOpts)).toEqual("default")
})
})

View File

@ -1,5 +1,5 @@
import env from "../environment" import env from "../environment"
export * from "../newid" export * from "../docIds/newid"
const bcrypt = env.JS_BCRYPT ? require("bcryptjs") : require("bcrypt") const bcrypt = env.JS_BCRYPT ? require("bcryptjs") : require("bcrypt")
const SALT_ROUNDS = env.SALT_ROUNDS || 10 const SALT_ROUNDS = env.SALT_ROUNDS || 10

View File

@ -1,4 +1,5 @@
import { structures, DBTestConfiguration } from "../../../tests" import { structures } from "../../../tests"
import { DBTestConfiguration } from "../../../tests/extra"
import * as utils from "../../utils" import * as utils from "../../utils"
import * as db from "../../db" import * as db from "../../db"
import { Header } from "../../constants" import { Header } from "../../constants"

View File

@ -0,0 +1,34 @@
export enum LogLevel {
TRACE = "trace",
DEBUG = "debug",
INFO = "info",
WARN = "warn",
ERROR = "error",
}
const LOG_INDEX: { [key in LogLevel]: number } = {
[LogLevel.TRACE]: 1,
[LogLevel.DEBUG]: 2,
[LogLevel.INFO]: 3,
[LogLevel.WARN]: 4,
[LogLevel.ERROR]: 5,
}
const setIndex = LOG_INDEX[process.env.LOG_LEVEL as LogLevel]
if (setIndex > LOG_INDEX.trace) {
global.console.trace = jest.fn()
}
if (setIndex > LOG_INDEX.debug) {
global.console.debug = jest.fn()
}
if (setIndex > LOG_INDEX.info) {
global.console.info = jest.fn()
global.console.log = jest.fn()
}
if (setIndex > LOG_INDEX.warn) {
global.console.warn = jest.fn()
}

View File

@ -1,9 +1,6 @@
export * as mocks from "./mocks" export * as mocks from "./mocks"
export * as structures from "./structures" export * as structures from "./structures"
export { generator } from "./structures" export { generator } from "./structures"
export * as testEnv from "./testEnv"
export * as testContainerUtils from "./testContainerUtils" export * as testContainerUtils from "./testContainerUtils"
export * from "./jestUtils" export * from "./jestUtils"
export { default as DBTestConfiguration } from "./DBTestConfiguration"

View File

@ -0,0 +1,3 @@
jest.mock("../../../../src/logging/alerts")
import * as _alerts from "../../../../src/logging/alerts"
export const alerts = jest.mocked(_alerts)

View File

@ -0,0 +1,123 @@
beforeAll(async () => {
const processors = await import("../../../../src/events/processors")
const events = await import("../../../../src/events")
jest.spyOn(processors.analyticsProcessor, "processEvent")
jest.spyOn(events.identification, "identifyTenantGroup")
jest.spyOn(events.identification, "identifyUser")
jest.spyOn(events.backfill, "appSucceeded")
jest.spyOn(events.backfill, "tenantSucceeded")
jest.spyOn(events.account, "created")
jest.spyOn(events.account, "deleted")
jest.spyOn(events.account, "verified")
jest.spyOn(events.app, "created")
jest.spyOn(events.app, "updated")
jest.spyOn(events.app, "deleted")
jest.spyOn(events.app, "published")
jest.spyOn(events.app, "unpublished")
jest.spyOn(events.app, "templateImported")
jest.spyOn(events.app, "fileImported")
jest.spyOn(events.app, "versionUpdated")
jest.spyOn(events.app, "versionReverted")
jest.spyOn(events.app, "reverted")
jest.spyOn(events.app, "exported")
jest.spyOn(events.auth, "login")
jest.spyOn(events.auth, "logout")
jest.spyOn(events.auth, "SSOCreated")
jest.spyOn(events.auth, "SSOUpdated")
jest.spyOn(events.auth, "SSOActivated")
jest.spyOn(events.auth, "SSODeactivated")
jest.spyOn(events.automation, "created")
jest.spyOn(events.automation, "deleted")
jest.spyOn(events.automation, "tested")
jest.spyOn(events.automation, "stepCreated")
jest.spyOn(events.automation, "stepDeleted")
jest.spyOn(events.automation, "triggerUpdated")
jest.spyOn(events.datasource, "created")
jest.spyOn(events.datasource, "updated")
jest.spyOn(events.datasource, "deleted")
jest.spyOn(events.email, "SMTPCreated")
jest.spyOn(events.email, "SMTPUpdated")
jest.spyOn(events.layout, "created")
jest.spyOn(events.layout, "deleted")
jest.spyOn(events.org, "nameUpdated")
jest.spyOn(events.org, "logoUpdated")
jest.spyOn(events.org, "platformURLUpdated")
jest.spyOn(events.org, "analyticsOptOut")
jest.spyOn(events.installation, "versionChecked")
jest.spyOn(events.query, "created")
jest.spyOn(events.query, "updated")
jest.spyOn(events.query, "deleted")
jest.spyOn(events.query, "imported")
jest.spyOn(events.query, "previewed")
jest.spyOn(events.role, "created")
jest.spyOn(events.role, "updated")
jest.spyOn(events.role, "deleted")
jest.spyOn(events.role, "assigned")
jest.spyOn(events.role, "unassigned")
jest.spyOn(events.rows, "imported")
jest.spyOn(events.rows, "created")
jest.spyOn(events.screen, "created")
jest.spyOn(events.screen, "deleted")
jest.spyOn(events.user, "created")
jest.spyOn(events.user, "updated")
jest.spyOn(events.user, "deleted")
jest.spyOn(events.user, "permissionAdminAssigned")
jest.spyOn(events.user, "permissionAdminRemoved")
jest.spyOn(events.user, "permissionBuilderAssigned")
jest.spyOn(events.user, "permissionBuilderRemoved")
jest.spyOn(events.user, "invited")
jest.spyOn(events.user, "inviteAccepted")
jest.spyOn(events.user, "passwordForceReset")
jest.spyOn(events.user, "passwordUpdated")
jest.spyOn(events.user, "passwordResetRequested")
jest.spyOn(events.user, "passwordReset")
jest.spyOn(events.group, "created")
jest.spyOn(events.group, "updated")
jest.spyOn(events.group, "deleted")
jest.spyOn(events.group, "usersAdded")
jest.spyOn(events.group, "usersDeleted")
jest.spyOn(events.group, "createdOnboarding")
jest.spyOn(events.group, "permissionsEdited")
jest.spyOn(events.serve, "servedBuilder")
jest.spyOn(events.serve, "servedApp")
jest.spyOn(events.serve, "servedAppPreview")
jest.spyOn(events.table, "created")
jest.spyOn(events.table, "updated")
jest.spyOn(events.table, "deleted")
jest.spyOn(events.table, "exported")
jest.spyOn(events.table, "imported")
jest.spyOn(events.view, "created")
jest.spyOn(events.view, "updated")
jest.spyOn(events.view, "deleted")
jest.spyOn(events.view, "exported")
jest.spyOn(events.view, "filterCreated")
jest.spyOn(events.view, "filterUpdated")
jest.spyOn(events.view, "filterDeleted")
jest.spyOn(events.view, "calculationCreated")
jest.spyOn(events.view, "calculationUpdated")
jest.spyOn(events.view, "calculationDeleted")
jest.spyOn(events.plugin, "init")
jest.spyOn(events.plugin, "imported")
jest.spyOn(events.plugin, "deleted")
})

View File

@ -0,0 +1,17 @@
const mockFetch = jest.fn((url: any, opts: any) => {
const fetch = jest.requireActual("node-fetch")
const env = jest.requireActual("../../../../src/environment").default
if (url.includes(env.COUCH_DB_URL)) {
return fetch(url, opts)
}
return undefined
})
const enable = () => {
jest.mock("node-fetch", () => mockFetch)
}
export default {
...mockFetch,
enable,
}

View File

@ -1,10 +1,10 @@
jest.mock("../../../src/accounts") jest.mock("../../../../src/accounts")
import * as _accounts from "../../../src/accounts" import * as _accounts from "../../../../src/accounts"
export const accounts = jest.mocked(_accounts) export const accounts = jest.mocked(_accounts)
export * as date from "./date" export * as date from "./date"
export * as licenses from "./licenses" export * as licenses from "./licenses"
export { default as fetch } from "./fetch" export { default as fetch } from "./fetch"
export * from "./alerts" export * from "./alerts"
import "./posthog"
import "./events" import "./events"
import "./posthog"

View File

@ -1,5 +1,5 @@
import { generator, uuid } from "." import { generator, uuid } from "."
import * as db from "../../../src/db/utils" import { generateGlobalUserID } from "../../../../src/docIds"
import { import {
Account, Account,
AccountSSOProvider, AccountSSOProvider,
@ -39,7 +39,7 @@ export const cloudAccount = (): CloudAccount => {
return { return {
...account(), ...account(),
hosting: Hosting.CLOUD, hosting: Hosting.CLOUD,
budibaseUserId: db.generateGlobalUserID(), budibaseUserId: generateGlobalUserID(),
} }
} }

View File

@ -1,6 +1,6 @@
import { generator } from "." import { generator } from "."
import { App } from "@budibase/types" import { App } from "@budibase/types"
import { DEFAULT_TENANT_ID, DocumentType } from "../../../src/constants" import { DEFAULT_TENANT_ID, DocumentType } from "../../../../src/constants"
export function app(id: string): App { export function app(id: string): App {
return { return {

View File

@ -1,5 +1,5 @@
import { structures } from ".." import { structures } from ".."
import { newid } from "../../../src/newid" import { newid } from "../../../../src/docIds/newid"
export function id() { export function id() {
return `db_${newid()}` return `db_${newid()}`

View File

@ -1,23 +1,31 @@
import { ScimCreateGroupRequest, ScimCreateUserRequest } from "@budibase/types" import { ScimCreateGroupRequest, ScimCreateUserRequest } from "@budibase/types"
import { uuid } from "./common" import { uuid } from "./common"
import { generator } from "./generator" import { generator } from "./generator"
import _ from "lodash"
export function createUserRequest(userData?: { interface CreateUserRequestFields {
externalId?: string externalId: string
email?: string email: string
firstName?: string firstName: string
lastName?: string lastName: string
username?: string username: string
}) { }
const {
externalId = uuid(),
email = generator.email(),
firstName = generator.first(),
lastName = generator.last(),
username = generator.name(),
} = userData || {}
const user: ScimCreateUserRequest = { export function createUserRequest(userData?: Partial<CreateUserRequestFields>) {
const defaultValues = {
externalId: uuid(),
email: generator.email(),
firstName: generator.first(),
lastName: generator.last(),
username: generator.name(),
}
const { externalId, email, firstName, lastName, username } = _.assign(
defaultValues,
userData
)
let user: ScimCreateUserRequest = {
schemas: [ schemas: [
"urn:ietf:params:scim:schemas:core:2.0:User", "urn:ietf:params:scim:schemas:core:2.0:User",
"urn:ietf:params:scim:schemas:extension:enterprise:2.0:User", "urn:ietf:params:scim:schemas:extension:enterprise:2.0:User",
@ -35,13 +43,17 @@ export function createUserRequest(userData?: {
meta: { meta: {
resourceType: "User", resourceType: "User",
}, },
name: {
formatted: generator.name(),
familyName: lastName,
givenName: firstName,
},
roles: [], roles: [],
} }
if (firstName || lastName) {
user.name = {
formatted: [firstName, lastName].filter(s => s).join(" "),
familyName: lastName,
givenName: firstName,
}
}
return user return user
} }

View File

@ -1,4 +1,4 @@
import { newid } from "../../../src/newid" import { newid } from "../../../../src/docIds/newid"
export function id() { export function id() {
return `tenant-${newid()}` return `tenant-${newid()}`

View File

@ -1,5 +1,5 @@
import "./mocks" import "../core/utilities/mocks"
import * as structures from "./structures" import * as structures from "../core/utilities/structures"
import * as testEnv from "./testEnv" import * as testEnv from "./testEnv"
import * as context from "../../src/context" import * as context from "../../src/context"

View File

@ -0,0 +1,2 @@
export * as testEnv from "./testEnv"
export { default as DBTestConfiguration } from "./DBTestConfiguration"

View File

@ -1,6 +1,6 @@
import env from "../../src/environment" import env from "../../src/environment"
import * as context from "../../src/context" import * as context from "../../src/context"
import * as structures from "./structures" import * as structures from "../core/utilities/structures"
// TENANCY // TENANCY

View File

@ -1 +1 @@
export * from "./utilities" export * from "./core/utilities"

View File

@ -1,6 +1,7 @@
import "./core/logging"
import env from "../src/environment" import env from "../src/environment"
import { cleanup } from "../src/timers" import { cleanup } from "../src/timers"
import { mocks, testContainerUtils } from "./utilities" import { mocks, testContainerUtils } from "./core/utilities"
// must explicitly enable fetch mock // must explicitly enable fetch mock
mocks.fetch.enable() mocks.fetch.enable()

View File

@ -1,3 +0,0 @@
jest.mock("../../../src/logging/alerts")
import * as _alerts from "../../../src/logging/alerts"
export const alerts = jest.mocked(_alerts)

View File

@ -1,122 +0,0 @@
import * as processors from "../../../src/events/processors"
import * as events from "../../../src/events"
jest.spyOn(processors.analyticsProcessor, "processEvent")
jest.spyOn(events.identification, "identifyTenantGroup")
jest.spyOn(events.identification, "identifyUser")
jest.spyOn(events.backfill, "appSucceeded")
jest.spyOn(events.backfill, "tenantSucceeded")
jest.spyOn(events.account, "created")
jest.spyOn(events.account, "deleted")
jest.spyOn(events.account, "verified")
jest.spyOn(events.app, "created")
jest.spyOn(events.app, "updated")
jest.spyOn(events.app, "deleted")
jest.spyOn(events.app, "published")
jest.spyOn(events.app, "unpublished")
jest.spyOn(events.app, "templateImported")
jest.spyOn(events.app, "fileImported")
jest.spyOn(events.app, "versionUpdated")
jest.spyOn(events.app, "versionReverted")
jest.spyOn(events.app, "reverted")
jest.spyOn(events.app, "exported")
jest.spyOn(events.auth, "login")
jest.spyOn(events.auth, "logout")
jest.spyOn(events.auth, "SSOCreated")
jest.spyOn(events.auth, "SSOUpdated")
jest.spyOn(events.auth, "SSOActivated")
jest.spyOn(events.auth, "SSODeactivated")
jest.spyOn(events.automation, "created")
jest.spyOn(events.automation, "deleted")
jest.spyOn(events.automation, "tested")
jest.spyOn(events.automation, "stepCreated")
jest.spyOn(events.automation, "stepDeleted")
jest.spyOn(events.automation, "triggerUpdated")
jest.spyOn(events.datasource, "created")
jest.spyOn(events.datasource, "updated")
jest.spyOn(events.datasource, "deleted")
jest.spyOn(events.email, "SMTPCreated")
jest.spyOn(events.email, "SMTPUpdated")
jest.spyOn(events.layout, "created")
jest.spyOn(events.layout, "deleted")
jest.spyOn(events.org, "nameUpdated")
jest.spyOn(events.org, "logoUpdated")
jest.spyOn(events.org, "platformURLUpdated")
jest.spyOn(events.org, "analyticsOptOut")
jest.spyOn(events.installation, "versionChecked")
jest.spyOn(events.query, "created")
jest.spyOn(events.query, "updated")
jest.spyOn(events.query, "deleted")
jest.spyOn(events.query, "imported")
jest.spyOn(events.query, "previewed")
jest.spyOn(events.role, "created")
jest.spyOn(events.role, "updated")
jest.spyOn(events.role, "deleted")
jest.spyOn(events.role, "assigned")
jest.spyOn(events.role, "unassigned")
jest.spyOn(events.rows, "imported")
jest.spyOn(events.rows, "created")
jest.spyOn(events.screen, "created")
jest.spyOn(events.screen, "deleted")
jest.spyOn(events.user, "created")
jest.spyOn(events.user, "updated")
jest.spyOn(events.user, "deleted")
jest.spyOn(events.user, "permissionAdminAssigned")
jest.spyOn(events.user, "permissionAdminRemoved")
jest.spyOn(events.user, "permissionBuilderAssigned")
jest.spyOn(events.user, "permissionBuilderRemoved")
jest.spyOn(events.user, "invited")
jest.spyOn(events.user, "inviteAccepted")
jest.spyOn(events.user, "passwordForceReset")
jest.spyOn(events.user, "passwordUpdated")
jest.spyOn(events.user, "passwordResetRequested")
jest.spyOn(events.user, "passwordReset")
jest.spyOn(events.group, "created")
jest.spyOn(events.group, "updated")
jest.spyOn(events.group, "deleted")
jest.spyOn(events.group, "usersAdded")
jest.spyOn(events.group, "usersDeleted")
jest.spyOn(events.group, "createdOnboarding")
jest.spyOn(events.group, "permissionsEdited")
jest.spyOn(events.serve, "servedBuilder")
jest.spyOn(events.serve, "servedApp")
jest.spyOn(events.serve, "servedAppPreview")
jest.spyOn(events.table, "created")
jest.spyOn(events.table, "updated")
jest.spyOn(events.table, "deleted")
jest.spyOn(events.table, "exported")
jest.spyOn(events.table, "imported")
jest.spyOn(events.view, "created")
jest.spyOn(events.view, "updated")
jest.spyOn(events.view, "deleted")
jest.spyOn(events.view, "exported")
jest.spyOn(events.view, "filterCreated")
jest.spyOn(events.view, "filterUpdated")
jest.spyOn(events.view, "filterDeleted")
jest.spyOn(events.view, "calculationCreated")
jest.spyOn(events.view, "calculationUpdated")
jest.spyOn(events.view, "calculationDeleted")
jest.spyOn(events.plugin, "init")
jest.spyOn(events.plugin, "imported")
jest.spyOn(events.plugin, "deleted")

View File

@ -1,10 +0,0 @@
const mockFetch = jest.fn()
const enable = () => {
jest.mock("node-fetch", () => mockFetch)
}
export default {
...mockFetch,
enable,
}

File diff suppressed because it is too large Load Diff

View File

@ -1,7 +1,7 @@
{ {
"name": "@budibase/bbui", "name": "@budibase/bbui",
"description": "A UI solution used in the different Budibase projects.", "description": "A UI solution used in the different Budibase projects.",
"version": "2.4.44-alpha.12", "version": "2.5.6-alpha.1",
"license": "MPL-2.0", "license": "MPL-2.0",
"svelte": "src/index.js", "svelte": "src/index.js",
"module": "dist/bbui.es.js", "module": "dist/bbui.es.js",
@ -38,8 +38,8 @@
], ],
"dependencies": { "dependencies": {
"@adobe/spectrum-css-workflow-icons": "1.2.1", "@adobe/spectrum-css-workflow-icons": "1.2.1",
"@budibase/shared-core": "2.4.44-alpha.12", "@budibase/shared-core": "2.5.6-alpha.1",
"@budibase/string-templates": "2.4.44-alpha.12", "@budibase/string-templates": "2.5.6-alpha.1",
"@spectrum-css/accordion": "3.0.24", "@spectrum-css/accordion": "3.0.24",
"@spectrum-css/actionbutton": "1.0.1", "@spectrum-css/actionbutton": "1.0.1",
"@spectrum-css/actiongroup": "1.0.1", "@spectrum-css/actiongroup": "1.0.1",

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,6 @@
{ {
"name": "@budibase/builder", "name": "@budibase/builder",
"version": "2.4.44-alpha.12", "version": "2.5.6-alpha.1",
"license": "GPL-3.0", "license": "GPL-3.0",
"private": true, "private": true,
"scripts": { "scripts": {
@ -58,11 +58,11 @@
} }
}, },
"dependencies": { "dependencies": {
"@budibase/bbui": "2.4.44-alpha.12", "@budibase/bbui": "2.5.6-alpha.1",
"@budibase/client": "2.4.44-alpha.12", "@budibase/client": "2.5.6-alpha.1",
"@budibase/frontend-core": "2.4.44-alpha.12", "@budibase/frontend-core": "2.5.6-alpha.1",
"@budibase/shared-core": "2.4.44-alpha.12", "@budibase/shared-core": "2.5.6-alpha.1",
"@budibase/string-templates": "2.4.44-alpha.12", "@budibase/string-templates": "2.5.6-alpha.1",
"@fortawesome/fontawesome-svg-core": "^6.2.1", "@fortawesome/fontawesome-svg-core": "^6.2.1",
"@fortawesome/free-brands-svg-icons": "^6.2.1", "@fortawesome/free-brands-svg-icons": "^6.2.1",
"@fortawesome/free-solid-svg-icons": "^6.2.1", "@fortawesome/free-solid-svg-icons": "^6.2.1",

View File

@ -120,7 +120,7 @@ export const toBindingsArray = (valueMap, prefix, category) => {
return [] return []
} }
return Object.keys(valueMap).reduce((acc, binding) => { return Object.keys(valueMap).reduce((acc, binding) => {
if (!binding || !valueMap[binding]) { if (!binding) {
return acc return acc
} }

View File

@ -42,7 +42,13 @@
</script> </script>
{#if type === "options" && meta.constraints.inclusion.length !== 0} {#if type === "options" && meta.constraints.inclusion.length !== 0}
<Select {label} bind:value options={meta.constraints.inclusion} sort /> <Select
{label}
bind:value
options={meta.constraints.inclusion}
sort
{error}
/>
{:else if type === "datetime"} {:else if type === "datetime"}
<DatePicker <DatePicker
{error} {error}

View File

@ -27,11 +27,10 @@
notifications.success("Row saved successfully") notifications.success("Row saved successfully")
dispatch("updaterows", res._id) dispatch("updaterows", res._id)
} catch (error) { } catch (error) {
if (error.handled) {
const response = error.json const response = error.json
if (response?.errors) { if (error.handled && response?.errors) {
errors = response.errors errors = response.errors
} else if (response?.validationErrors) { } else if (error.handled && response?.validationErrors) {
const mappedErrors = {} const mappedErrors = {}
for (let field in response.validationErrors) { for (let field in response.validationErrors) {
mappedErrors[ mappedErrors[
@ -39,9 +38,8 @@
] = `${field} ${response.validationErrors[field][0]}` ] = `${field} ${response.validationErrors[field][0]}`
} }
errors = mappedErrors errors = mappedErrors
}
} else { } else {
notifications.error("Failed to save row") notifications.error(`Failed to save row - ${error.message}`)
} }
// Prevent modal closing if there were errors // Prevent modal closing if there were errors
return false return false

View File

@ -65,6 +65,14 @@
label: "Must not contain", label: "Must not contain",
value: "notContains", value: "notContains",
}, },
MaxFileSize: {
label: "Max file size (MB)",
value: "maxFileSize",
},
MaxUploadSize: {
label: "Max total upload size (MB)",
value: "maxUploadSize",
},
} }
const ConstraintMap = { const ConstraintMap = {
["string"]: [ ["string"]: [
@ -94,7 +102,11 @@
Constraints.Equal, Constraints.Equal,
Constraints.NotEqual, Constraints.NotEqual,
], ],
["attachment"]: [Constraints.Required], ["attachment"]: [
Constraints.Required,
Constraints.MaxFileSize,
Constraints.MaxUploadSize,
],
["link"]: [ ["link"]: [
Constraints.Required, Constraints.Required,
Constraints.Contains, Constraints.Contains,
@ -283,7 +295,7 @@
disabled={rule.constraint === "required"} disabled={rule.constraint === "required"}
on:change={e => (rule.value = e.detail)} on:change={e => (rule.value = e.detail)}
/> />
{:else if rule.type !== "array" && ["maxLength", "minLength", "regex", "notRegex", "contains", "notContains"].includes(rule.constraint)} {:else if rule.type !== "array" && ["maxUploadSize", "maxFileSize", "maxLength", "minLength", "regex", "notRegex", "contains", "notContains"].includes(rule.constraint)}
<!-- Certain constraints always need string values--> <!-- Certain constraints always need string values-->
<Input <Input
bind:value={rule.value} bind:value={rule.value}
@ -376,7 +388,7 @@
gap: var(--spacing-l); gap: var(--spacing-l);
display: grid; display: grid;
align-items: center; align-items: center;
grid-template-columns: 190px 120px 1fr 1fr auto auto; grid-template-columns: 200px 120px 1fr 1fr auto auto;
border-radius: var(--border-radius-s); border-radius: var(--border-radius-s);
transition: background-color ease-in-out 130ms; transition: background-color ease-in-out 130ms;
} }

View File

@ -75,8 +75,7 @@
let loaded = false let loaded = false
let editModal, deleteModal let editModal, deleteModal
const scimEnabled = $features.isScimEnabled $: scimEnabled = $features.isScimEnabled
$: readonly = !$auth.isAdmin || scimEnabled $: readonly = !$auth.isAdmin || scimEnabled
$: page = $pageInfo.page $: page = $pageInfo.page
$: fetchUsers(page, searchTerm) $: fetchUsers(page, searchTerm)

View File

@ -86,8 +86,7 @@
let user let user
let loaded = false let loaded = false
const scimEnabled = $features.isScimEnabled $: scimEnabled = $features.isScimEnabled
$: isSSO = !!user?.provider $: isSSO = !!user?.provider
$: readonly = !$auth.isAdmin || scimEnabled $: readonly = !$auth.isAdmin || scimEnabled
$: privileged = user?.admin?.global || user?.builder?.global $: privileged = user?.admin?.global || user?.builder?.global

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,6 @@
{ {
"name": "@budibase/cli", "name": "@budibase/cli",
"version": "2.4.44-alpha.12", "version": "2.5.6-alpha.1",
"description": "Budibase CLI, for developers, self hosting and migrations.", "description": "Budibase CLI, for developers, self hosting and migrations.",
"main": "dist/index.js", "main": "dist/index.js",
"bin": { "bin": {
@ -9,7 +9,7 @@
"author": "Budibase", "author": "Budibase",
"license": "GPL-3.0", "license": "GPL-3.0",
"scripts": { "scripts": {
"prebuild": "rm -rf prebuilds 2> /dev/null && cp -r node_modules/leveldown/prebuilds prebuilds", "prebuild": "rm -rf prebuilds 2> /dev/null && cp -r ../../node_modules/leveldown/prebuilds prebuilds",
"rename": "renamer --find .node --replace .fake 'prebuilds/**'", "rename": "renamer --find .node --replace .fake 'prebuilds/**'",
"tsc": "tsc -p tsconfig.build.json", "tsc": "tsc -p tsconfig.build.json",
"pkg": "pkg . --out-path build --no-bytecode --public --public-packages \"*\" -C GZip", "pkg": "pkg . --out-path build --no-bytecode --public --public-packages \"*\" -C GZip",
@ -29,9 +29,9 @@
"outputPath": "build" "outputPath": "build"
}, },
"dependencies": { "dependencies": {
"@budibase/backend-core": "2.4.44-alpha.12", "@budibase/backend-core": "2.5.6-alpha.1",
"@budibase/string-templates": "2.4.44-alpha.12", "@budibase/string-templates": "2.5.6-alpha.1",
"@budibase/types": "2.4.44-alpha.12", "@budibase/types": "2.5.6-alpha.1",
"axios": "0.21.2", "axios": "0.21.2",
"chalk": "4.1.0", "chalk": "4.1.0",
"cli-progress": "3.11.2", "cli-progress": "3.11.2",

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,6 @@
{ {
"name": "@budibase/client", "name": "@budibase/client",
"version": "2.4.44-alpha.12", "version": "2.5.6-alpha.1",
"license": "MPL-2.0", "license": "MPL-2.0",
"module": "dist/budibase-client.js", "module": "dist/budibase-client.js",
"main": "dist/budibase-client.js", "main": "dist/budibase-client.js",
@ -19,11 +19,11 @@
"dev:builder": "rollup -cw" "dev:builder": "rollup -cw"
}, },
"dependencies": { "dependencies": {
"@budibase/bbui": "2.4.44-alpha.12", "@budibase/bbui": "2.5.6-alpha.1",
"@budibase/frontend-core": "2.4.44-alpha.12", "@budibase/frontend-core": "2.5.6-alpha.1",
"@budibase/shared-core": "2.4.44-alpha.12", "@budibase/shared-core": "2.5.6-alpha.1",
"@budibase/string-templates": "2.4.44-alpha.12", "@budibase/string-templates": "2.5.6-alpha.1",
"@budibase/types": "2.4.44-alpha.12", "@budibase/types": "2.5.6-alpha.1",
"@spectrum-css/button": "^3.0.3", "@spectrum-css/button": "^3.0.3",
"@spectrum-css/card": "^3.0.3", "@spectrum-css/card": "^3.0.3",
"@spectrum-css/divider": "^1.0.3", "@spectrum-css/divider": "^1.0.3",

View File

@ -241,6 +241,25 @@ const maxLengthHandler = (value, rule) => {
return value == null || value.length <= limit return value == null || value.length <= limit
} }
// Evaluates a max file size (MB) constraint
const maxFileSizeHandler = (value, rule) => {
const limit = parseType(rule.value, "number")
return (
value == null ||
!value.some(attachment => attachment.size / 1000000 > limit)
)
}
// Evaluates a max total upload size (MB) constraint
const maxUploadSizeHandler = (value, rule) => {
const limit = parseType(rule.value, "number")
return (
value == null ||
value.reduce((acc, currentItem) => acc + currentItem.size, 0) / 1000000 <=
limit
)
}
// Evaluates a min value constraint // Evaluates a min value constraint
const minValueHandler = (value, rule) => { const minValueHandler = (value, rule) => {
// Use same type as the value so that things can be compared // Use same type as the value so that things can be compared
@ -330,6 +349,8 @@ const handlerMap = {
contains: containsHandler, contains: containsHandler,
notContains: notContainsHandler, notContains: notContainsHandler,
json: jsonHandler, json: jsonHandler,
maxFileSize: maxFileSizeHandler,
maxUploadSize: maxUploadSizeHandler,
} }
/** /**

File diff suppressed because it is too large Load Diff

View File

@ -1,13 +1,13 @@
{ {
"name": "@budibase/frontend-core", "name": "@budibase/frontend-core",
"version": "2.4.44-alpha.12", "version": "2.5.6-alpha.1",
"description": "Budibase frontend core libraries used in builder and client", "description": "Budibase frontend core libraries used in builder and client",
"author": "Budibase", "author": "Budibase",
"license": "MPL-2.0", "license": "MPL-2.0",
"svelte": "src/index.js", "svelte": "src/index.js",
"dependencies": { "dependencies": {
"@budibase/bbui": "2.4.44-alpha.12", "@budibase/bbui": "2.5.6-alpha.1",
"@budibase/shared-core": "2.4.44-alpha.12", "@budibase/shared-core": "2.5.6-alpha.1",
"dayjs": "^1.11.7", "dayjs": "^1.11.7",
"lodash": "^4.17.21", "lodash": "^4.17.21",
"socket.io-client": "^4.6.1", "socket.io-client": "^4.6.1",

View File

@ -1,79 +0,0 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1
"@socket.io/component-emitter@~3.1.0":
version "3.1.0"
resolved "https://registry.yarnpkg.com/@socket.io/component-emitter/-/component-emitter-3.1.0.tgz#96116f2a912e0c02817345b3c10751069920d553"
integrity sha512-+9jVqKhRSpsc591z5vX+X5Yyw+he/HCB4iQ/RYxw35CEPaY1gnsNE43nf9n9AaYjAQrTiI/mOwKUKdUs9vf7Xg==
dayjs@^1.11.7:
version "1.11.7"
resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.11.7.tgz#4b296922642f70999544d1144a2c25730fce63e2"
integrity sha512-+Yw9U6YO5TQohxLcIkrXBeY73WP3ejHWVvx8XCk3gxvQDCTEmS48ZrSZCKciI7Bhl/uCMyxYtE9UqRILmFphkQ==
debug@~4.3.1, debug@~4.3.2:
version "4.3.4"
resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865"
integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==
dependencies:
ms "2.1.2"
engine.io-client@~6.4.0:
version "6.4.0"
resolved "https://registry.yarnpkg.com/engine.io-client/-/engine.io-client-6.4.0.tgz#88cd3082609ca86d7d3c12f0e746d12db4f47c91"
integrity sha512-GyKPDyoEha+XZ7iEqam49vz6auPnNJ9ZBfy89f+rMMas8AuiMWOZ9PVzu8xb9ZC6rafUqiGHSCfu22ih66E+1g==
dependencies:
"@socket.io/component-emitter" "~3.1.0"
debug "~4.3.1"
engine.io-parser "~5.0.3"
ws "~8.11.0"
xmlhttprequest-ssl "~2.0.0"
engine.io-parser@~5.0.3:
version "5.0.6"
resolved "https://registry.yarnpkg.com/engine.io-parser/-/engine.io-parser-5.0.6.tgz#7811244af173e157295dec9b2718dfe42a64ef45"
integrity sha512-tjuoZDMAdEhVnSFleYPCtdL2GXwVTGtNjoeJd9IhIG3C1xs9uwxqRNEu5WpnDZCaozwVlK/nuQhpodhXSIMaxw==
lodash@^4.17.21:
version "4.17.21"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c"
integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==
ms@2.1.2:
version "2.1.2"
resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009"
integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==
socket.io-client@^4.6.1:
version "4.6.1"
resolved "https://registry.yarnpkg.com/socket.io-client/-/socket.io-client-4.6.1.tgz#80d97d5eb0feca448a0fb6d69a7b222d3d547eab"
integrity sha512-5UswCV6hpaRsNg5kkEHVcbBIXEYoVbMQaHJBXJCyEQ+CiFPV1NIOY0XOFWG4XR4GZcB8Kn6AsRs/9cy9TbqVMQ==
dependencies:
"@socket.io/component-emitter" "~3.1.0"
debug "~4.3.2"
engine.io-client "~6.4.0"
socket.io-parser "~4.2.1"
socket.io-parser@~4.2.1:
version "4.2.2"
resolved "https://registry.yarnpkg.com/socket.io-parser/-/socket.io-parser-4.2.2.tgz#1dd384019e25b7a3d374877f492ab34f2ad0d206"
integrity sha512-DJtziuKypFkMMHCm2uIshOYC7QaylbtzQwiMYDuCKy3OPkjLzu4B2vAhTlqipRHHzrI0NJeBAizTK7X+6m1jVw==
dependencies:
"@socket.io/component-emitter" "~3.1.0"
debug "~4.3.1"
svelte@^3.46.2:
version "3.49.0"
resolved "https://registry.yarnpkg.com/svelte/-/svelte-3.49.0.tgz#5baee3c672306de1070c3b7888fc2204e36a4029"
integrity sha512-+lmjic1pApJWDfPCpUUTc1m8azDqYCG1JN9YEngrx/hUyIcFJo6VZhj0A1Ai0wqoHcEIuQy+e9tk+4uDgdtsFA==
ws@~8.11.0:
version "8.11.0"
resolved "https://registry.yarnpkg.com/ws/-/ws-8.11.0.tgz#6a0d36b8edfd9f96d8b25683db2f8d7de6e8e143"
integrity sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg==
xmlhttprequest-ssl@~2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/xmlhttprequest-ssl/-/xmlhttprequest-ssl-2.0.0.tgz#91360c86b914e67f44dce769180027c0da618c67"
integrity sha512-QKxVRxiRACQcVuQEYFsI1hhkrMlrXHPegbbd1yn9UHOmRxY+si12nQYzri3vbzt8VdTTRviqcKxcyllFas5z2A==

View File

@ -1,6 +1,6 @@
{ {
"name": "@budibase/sdk", "name": "@budibase/sdk",
"version": "2.4.44-alpha.12", "version": "2.5.6-alpha.1",
"description": "Budibase Public API SDK", "description": "Budibase Public API SDK",
"author": "Budibase", "author": "Budibase",
"license": "MPL-2.0", "license": "MPL-2.0",

View File

@ -1,635 +0,0 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1
"@babel/code-frame@^7.10.4":
version "7.18.6"
resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.18.6.tgz#3b25d38c89600baa2dcc219edfa88a74eb2c427a"
integrity sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==
dependencies:
"@babel/highlight" "^7.18.6"
"@babel/helper-validator-identifier@^7.18.6":
version "7.18.6"
resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.18.6.tgz#9c97e30d31b2b8c72a1d08984f2ca9b574d7a076"
integrity sha512-MmetCkz9ej86nJQV+sFCxoGGrUbU3q02kgLciwkrt9QqEB7cP39oKEY0PakknEO0Gu20SskMRi+AYZ3b1TpN9g==
"@babel/highlight@^7.18.6":
version "7.18.6"
resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.18.6.tgz#81158601e93e2563795adcbfbdf5d64be3f2ecdf"
integrity sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==
dependencies:
"@babel/helper-validator-identifier" "^7.18.6"
chalk "^2.0.0"
js-tokens "^4.0.0"
"@jridgewell/gen-mapping@^0.3.0":
version "0.3.2"
resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz#c1aedc61e853f2bb9f5dfe6d4442d3b565b253b9"
integrity sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==
dependencies:
"@jridgewell/set-array" "^1.0.1"
"@jridgewell/sourcemap-codec" "^1.4.10"
"@jridgewell/trace-mapping" "^0.3.9"
"@jridgewell/resolve-uri@^3.0.3":
version "3.1.0"
resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz#2203b118c157721addfe69d47b70465463066d78"
integrity sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==
"@jridgewell/set-array@^1.0.1":
version "1.1.2"
resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.1.2.tgz#7c6cf998d6d20b914c0a55a91ae928ff25965e72"
integrity sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==
"@jridgewell/source-map@^0.3.2":
version "0.3.2"
resolved "https://registry.yarnpkg.com/@jridgewell/source-map/-/source-map-0.3.2.tgz#f45351aaed4527a298512ec72f81040c998580fb"
integrity sha512-m7O9o2uR8k2ObDysZYzdfhb08VuEml5oWGiosa1VdaPZ/A6QyPkAJuwN0Q1lhULOf6B7MtQmHENS743hWtCrgw==
dependencies:
"@jridgewell/gen-mapping" "^0.3.0"
"@jridgewell/trace-mapping" "^0.3.9"
"@jridgewell/sourcemap-codec@^1.4.10":
version "1.4.14"
resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz#add4c98d341472a289190b424efbdb096991bb24"
integrity sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==
"@jridgewell/trace-mapping@^0.3.9":
version "0.3.15"
resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.15.tgz#aba35c48a38d3fd84b37e66c9c0423f9744f9774"
integrity sha512-oWZNOULl+UbhsgB51uuZzglikfIKSUBO/M9W2OfEjn7cmqoAiCgmv9lyACTUacZwBz0ITnJ2NqjU8Tx0DHL88g==
dependencies:
"@jridgewell/resolve-uri" "^3.0.3"
"@jridgewell/sourcemap-codec" "^1.4.10"
"@rollup/plugin-commonjs@^18.0.0":
version "18.1.0"
resolved "https://registry.yarnpkg.com/@rollup/plugin-commonjs/-/plugin-commonjs-18.1.0.tgz#5a760d757af168a50727c0ae080251fbfcc5eb02"
integrity sha512-h3e6T9rUxVMAQswpDIobfUHn/doMzM9sgkMrsMWCFLmB84PSoC8mV8tOloAJjSRwdqhXBqstlX2BwBpHJvbhxg==
dependencies:
"@rollup/pluginutils" "^3.1.0"
commondir "^1.0.1"
estree-walker "^2.0.1"
glob "^7.1.6"
is-reference "^1.2.1"
magic-string "^0.25.7"
resolve "^1.17.0"
"@rollup/plugin-inject@^4.0.0":
version "4.0.4"
resolved "https://registry.yarnpkg.com/@rollup/plugin-inject/-/plugin-inject-4.0.4.tgz#fbeee66e9a700782c4f65c8b0edbafe58678fbc2"
integrity sha512-4pbcU4J/nS+zuHk+c+OL3WtmEQhqxlZ9uqfjQMQDOHOPld7PsCd8k5LWs8h5wjwJN7MgnAn768F2sDxEP4eNFQ==
dependencies:
"@rollup/pluginutils" "^3.1.0"
estree-walker "^2.0.1"
magic-string "^0.25.7"
"@rollup/plugin-node-resolve@^11.2.1":
version "11.2.1"
resolved "https://registry.yarnpkg.com/@rollup/plugin-node-resolve/-/plugin-node-resolve-11.2.1.tgz#82aa59397a29cd4e13248b106e6a4a1880362a60"
integrity sha512-yc2n43jcqVyGE2sqV5/YCmocy9ArjVAP/BeXyTtADTBBX6V0e5UMqwO8CdQ0kzjb6zu5P1qMzsScCMRvE9OlVg==
dependencies:
"@rollup/pluginutils" "^3.1.0"
"@types/resolve" "1.17.1"
builtin-modules "^3.1.0"
deepmerge "^4.2.2"
is-module "^1.0.0"
resolve "^1.19.0"
"@rollup/pluginutils@^3.1.0":
version "3.1.0"
resolved "https://registry.yarnpkg.com/@rollup/pluginutils/-/pluginutils-3.1.0.tgz#706b4524ee6dc8b103b3c995533e5ad680c02b9b"
integrity sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg==
dependencies:
"@types/estree" "0.0.39"
estree-walker "^1.0.1"
picomatch "^2.2.2"
"@types/estree@*":
version "1.0.0"
resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.0.tgz#5fb2e536c1ae9bf35366eed879e827fa59ca41c2"
integrity sha512-WulqXMDUTYAXCjZnk6JtIHPigp55cVtDgDrO2gHRwhyJto21+1zbVCtOYB2L1F9w4qCQ0rOGWBnBe0FNTiEJIQ==
"@types/estree@0.0.39":
version "0.0.39"
resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.39.tgz#e177e699ee1b8c22d23174caaa7422644389509f"
integrity sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==
"@types/node@*":
version "18.7.18"
resolved "https://registry.yarnpkg.com/@types/node/-/node-18.7.18.tgz#633184f55c322e4fb08612307c274ee6d5ed3154"
integrity sha512-m+6nTEOadJZuTPkKR/SYK3A2d7FZrgElol9UP1Kae90VVU4a6mxnPuLiIW1m4Cq4gZ/nWb9GrdVXJCoCazDAbg==
"@types/resolve@1.17.1":
version "1.17.1"
resolved "https://registry.yarnpkg.com/@types/resolve/-/resolve-1.17.1.tgz#3afd6ad8967c77e4376c598a82ddd58f46ec45d6"
integrity sha512-yy7HuzQhj0dhGpD8RLXSZWEkLsV9ibvxvi6EiJ3bkqLAO1RGo0WbkWQiwpRlSFymTJRz0d3k5LM3kkx8ArDbLw==
dependencies:
"@types/node" "*"
acorn@^8.5.0:
version "8.8.0"
resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.8.0.tgz#88c0187620435c7f6015803f5539dae05a9dbea8"
integrity sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w==
ansi-styles@^3.2.1:
version "3.2.1"
resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d"
integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==
dependencies:
color-convert "^1.9.0"
asynckit@^0.4.0:
version "0.4.0"
resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79"
integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==
balanced-match@^1.0.0:
version "1.0.2"
resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee"
integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==
brace-expansion@^1.1.7:
version "1.1.11"
resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd"
integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==
dependencies:
balanced-match "^1.0.0"
concat-map "0.0.1"
buffer-from@^1.0.0:
version "1.1.2"
resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5"
integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==
builtin-modules@^3.1.0:
version "3.3.0"
resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-3.3.0.tgz#cae62812b89801e9656336e46223e030386be7b6"
integrity sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==
call-bind@^1.0.0:
version "1.0.2"
resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.2.tgz#b1d4e89e688119c3c9a903ad30abb2f6a919be3c"
integrity sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==
dependencies:
function-bind "^1.1.1"
get-intrinsic "^1.0.2"
chalk@^2.0.0:
version "2.4.2"
resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424"
integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==
dependencies:
ansi-styles "^3.2.1"
escape-string-regexp "^1.0.5"
supports-color "^5.3.0"
color-convert@^1.9.0:
version "1.9.3"
resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8"
integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==
dependencies:
color-name "1.1.3"
color-name@1.1.3:
version "1.1.3"
resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25"
integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==
combined-stream@^1.0.8:
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@^2.20.0:
version "2.20.3"
resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33"
integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==
commondir@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b"
integrity sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==
component-emitter@^1.3.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.3.0.tgz#16e4070fba8ae29b679f2215853ee181ab2eabc0"
integrity sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==
concat-map@0.0.1:
version "0.0.1"
resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==
cookiejar@^2.1.2:
version "2.1.4"
resolved "https://registry.yarnpkg.com/cookiejar/-/cookiejar-2.1.4.tgz#ee669c1fea2cf42dc31585469d193fef0d65771b"
integrity sha512-LDx6oHrK+PhzLKJU9j5S7/Y3jM/mUHvD/DeI1WQmJn652iPC5Y4TBzC9l+5OMOXlyTTA+SmVUPm0HQUwpD5Jqw==
debug@^4.1.1:
version "4.3.4"
resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865"
integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==
dependencies:
ms "2.1.2"
deepmerge@^4.2.2:
version "4.2.2"
resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.2.2.tgz#44d2ea3679b8f4d4ffba33f03d865fc1e7bf4955"
integrity sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==
delayed-stream@~1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619"
integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==
escape-string-regexp@^1.0.5:
version "1.0.5"
resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==
estree-walker@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-1.0.1.tgz#31bc5d612c96b704106b477e6dd5d8aa138cb700"
integrity sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==
estree-walker@^2.0.1:
version "2.0.2"
resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-2.0.2.tgz#52f010178c2a4c117a7757cfe942adb7d2da4cac"
integrity sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==
fast-safe-stringify@^2.0.7:
version "2.1.1"
resolved "https://registry.yarnpkg.com/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz#c406a83b6e70d9e35ce3b30a81141df30aeba884"
integrity sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==
form-data@^3.0.0:
version "3.0.1"
resolved "https://registry.yarnpkg.com/form-data/-/form-data-3.0.1.tgz#ebd53791b78356a99af9a300d4282c4d5eb9755f"
integrity sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==
dependencies:
asynckit "^0.4.0"
combined-stream "^1.0.8"
mime-types "^2.1.12"
formidable@^1.2.2:
version "1.2.6"
resolved "https://registry.yarnpkg.com/formidable/-/formidable-1.2.6.tgz#d2a51d60162bbc9b4a055d8457a7c75315d1a168"
integrity sha512-KcpbcpuLNOwrEjnbpMC0gS+X8ciDoZE1kkqzat4a8vrprf+s9pKNQ/QIwWfbfs4ltgmFl3MD177SNTkve3BwGQ==
fs.realpath@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"
integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==
fsevents@~2.3.2:
version "2.3.2"
resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a"
integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==
function-bind@^1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d"
integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==
get-intrinsic@^1.0.2:
version "1.1.3"
resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.1.3.tgz#063c84329ad93e83893c7f4f243ef63ffa351385"
integrity sha512-QJVz1Tj7MS099PevUG5jvnt9tSkXN8K14dxQlikJuPt4uD9hHAHjLyLBiLR5zELelBdD9QNRAXZzsJx0WaDL9A==
dependencies:
function-bind "^1.1.1"
has "^1.0.3"
has-symbols "^1.0.3"
glob@^7.1.6:
version "7.2.3"
resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b"
integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==
dependencies:
fs.realpath "^1.0.0"
inflight "^1.0.4"
inherits "2"
minimatch "^3.1.1"
once "^1.3.0"
path-is-absolute "^1.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"
integrity sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==
has-flag@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b"
integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==
has-symbols@^1.0.3:
version "1.0.3"
resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8"
integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==
has@^1.0.3:
version "1.0.3"
resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796"
integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==
dependencies:
function-bind "^1.1.1"
inflight@^1.0.4:
version "1.0.6"
resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9"
integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==
dependencies:
once "^1.3.0"
wrappy "1"
inherits@2, 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==
is-core-module@^2.9.0:
version "2.10.0"
resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.10.0.tgz#9012ede0a91c69587e647514e1d5277019e728ed"
integrity sha512-Erxj2n/LDAZ7H8WNJXd9tw38GYM3dv8rk8Zcs+jJuxYTW7sozH+SS8NtrSjVL1/vpLvWi1hxy96IzjJ3EHTJJg==
dependencies:
has "^1.0.3"
is-module@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/is-module/-/is-module-1.0.0.tgz#3258fb69f78c14d5b815d664336b4cffb6441591"
integrity sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==
is-reference@^1.2.1:
version "1.2.1"
resolved "https://registry.yarnpkg.com/is-reference/-/is-reference-1.2.1.tgz#8b2dac0b371f4bc994fdeaba9eb542d03002d0b7"
integrity sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ==
dependencies:
"@types/estree" "*"
jest-worker@^26.2.1:
version "26.6.2"
resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-26.6.2.tgz#7f72cbc4d643c365e27b9fd775f9d0eaa9c7a8ed"
integrity sha512-KWYVV1c4i+jbMpaBC+U++4Va0cp8OisU185o73T1vo99hqi7w8tSJfUXYswwqqrjzwxa6KpRK54WhPvwf5w6PQ==
dependencies:
"@types/node" "*"
merge-stream "^2.0.0"
supports-color "^7.0.0"
js-tokens@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499"
integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==
lru-cache@^6.0.0:
version "6.0.0"
resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94"
integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==
dependencies:
yallist "^4.0.0"
magic-string@^0.25.7:
version "0.25.9"
resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.25.9.tgz#de7f9faf91ef8a1c91d02c2e5314c8277dbcdd1c"
integrity sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==
dependencies:
sourcemap-codec "^1.4.8"
merge-stream@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60"
integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==
methods@^1.1.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee"
integrity sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==
mime-db@1.52.0:
version "1.52.0"
resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70"
integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==
mime-types@^2.1.12:
version "2.1.35"
resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a"
integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==
dependencies:
mime-db "1.52.0"
mime@^2.4.6:
version "2.6.0"
resolved "https://registry.yarnpkg.com/mime/-/mime-2.6.0.tgz#a2a682a95cd4d0cb1d6257e28f83da7e35800367"
integrity sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==
minimatch@^3.1.1:
version "3.1.2"
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b"
integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==
dependencies:
brace-expansion "^1.1.7"
ms@2.1.2:
version "2.1.2"
resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009"
integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==
object-inspect@^1.9.0:
version "1.12.2"
resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.12.2.tgz#c0641f26394532f28ab8d796ab954e43c009a8ea"
integrity sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==
once@^1.3.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==
dependencies:
wrappy "1"
path-is-absolute@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f"
integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==
path-parse@^1.0.7:
version "1.0.7"
resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735"
integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==
picomatch@^2.2.2:
version "2.3.1"
resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42"
integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==
qs@^6.9.4:
version "6.11.0"
resolved "https://registry.yarnpkg.com/qs/-/qs-6.11.0.tgz#fd0d963446f7a65e1367e01abd85429453f0c37a"
integrity sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==
dependencies:
side-channel "^1.0.4"
randombytes@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a"
integrity sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==
dependencies:
safe-buffer "^5.1.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"
resolve@^1.17.0, resolve@^1.19.0:
version "1.22.1"
resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.1.tgz#27cb2ebb53f91abb49470a928bba7558066ac177"
integrity sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==
dependencies:
is-core-module "^2.9.0"
path-parse "^1.0.7"
supports-preserve-symlinks-flag "^1.0.0"
rollup-plugin-polyfill-node@^0.8.0:
version "0.8.0"
resolved "https://registry.yarnpkg.com/rollup-plugin-polyfill-node/-/rollup-plugin-polyfill-node-0.8.0.tgz#859c070822f5e38d221e5b4238cb34aa894c2b19"
integrity sha512-C4UeKedOmOBkB3FgR+z/v9kzRwV1Q/H8xWs1u1+CNe4XOV6hINfOrcO+TredKxYvopCmr+WKUSNsFUnD1RLHgQ==
dependencies:
"@rollup/plugin-inject" "^4.0.0"
rollup-plugin-terser@^7.0.2:
version "7.0.2"
resolved "https://registry.yarnpkg.com/rollup-plugin-terser/-/rollup-plugin-terser-7.0.2.tgz#e8fbba4869981b2dc35ae7e8a502d5c6c04d324d"
integrity sha512-w3iIaU4OxcF52UUXiZNsNeuXIMDvFrr+ZXK6bFZ0Q60qyVfq4uLptoS4bbq3paG3x216eQllFZX7zt6TIImguQ==
dependencies:
"@babel/code-frame" "^7.10.4"
jest-worker "^26.2.1"
serialize-javascript "^4.0.0"
terser "^5.0.0"
rollup@^2.44.0:
version "2.79.0"
resolved "https://registry.yarnpkg.com/rollup/-/rollup-2.79.0.tgz#9177992c9f09eb58c5e56cbfa641607a12b57ce2"
integrity sha512-x4KsrCgwQ7ZJPcFA/SUu6QVcYlO7uRLfLAy0DSA4NS2eG8japdbpM50ToH7z4iObodRYOJ0soneF0iaQRJ6zhA==
optionalDependencies:
fsevents "~2.3.2"
safe-buffer@^5.1.0, 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==
semver@^7.3.2:
version "7.3.7"
resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.7.tgz#12c5b649afdbf9049707796e22a4028814ce523f"
integrity sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==
dependencies:
lru-cache "^6.0.0"
serialize-javascript@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-4.0.0.tgz#b525e1238489a5ecfc42afacc3fe99e666f4b1aa"
integrity sha512-GaNA54380uFefWghODBWEGisLZFj00nS5ACs6yHa9nLqlLpVLO8ChDGeKRjZnV4Nh4n0Qi7nhYZD/9fCPzEqkw==
dependencies:
randombytes "^2.1.0"
side-channel@^1.0.4:
version "1.0.4"
resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.4.tgz#efce5c8fdc104ee751b25c58d4290011fa5ea2cf"
integrity sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==
dependencies:
call-bind "^1.0.0"
get-intrinsic "^1.0.2"
object-inspect "^1.9.0"
source-map-support@~0.5.20:
version "0.5.21"
resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.21.tgz#04fe7c7f9e1ed2d662233c28cb2b35b9f63f6e4f"
integrity sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==
dependencies:
buffer-from "^1.0.0"
source-map "^0.6.0"
source-map@^0.6.0:
version "0.6.1"
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263"
integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==
sourcemap-codec@^1.4.8:
version "1.4.8"
resolved "https://registry.yarnpkg.com/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz#ea804bd94857402e6992d05a38ef1ae35a9ab4c4"
integrity sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==
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"
superagent@^5.3.0:
version "5.3.1"
resolved "https://registry.yarnpkg.com/superagent/-/superagent-5.3.1.tgz#d62f3234d76b8138c1320e90fa83dc1850ccabf1"
integrity sha512-wjJ/MoTid2/RuGCOFtlacyGNxN9QLMgcpYLDQlWFIhhdJ93kNscFonGvrpAHSCVjRVj++DGCglocF7Aej1KHvQ==
dependencies:
component-emitter "^1.3.0"
cookiejar "^2.1.2"
debug "^4.1.1"
fast-safe-stringify "^2.0.7"
form-data "^3.0.0"
formidable "^1.2.2"
methods "^1.1.2"
mime "^2.4.6"
qs "^6.9.4"
readable-stream "^3.6.0"
semver "^7.3.2"
supports-color@^5.3.0:
version "5.5.0"
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f"
integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==
dependencies:
has-flag "^3.0.0"
supports-color@^7.0.0:
version "7.2.0"
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da"
integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==
dependencies:
has-flag "^4.0.0"
supports-preserve-symlinks-flag@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09"
integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==
terser@^5.0.0:
version "5.15.0"
resolved "https://registry.yarnpkg.com/terser/-/terser-5.15.0.tgz#e16967894eeba6e1091509ec83f0c60e179f2425"
integrity sha512-L1BJiXVmheAQQy+as0oF3Pwtlo4s3Wi1X2zNZ2NxOB4wx9bdS9Vk67XQENLFdLYGCK/Z2di53mTj/hBafR+dTA==
dependencies:
"@jridgewell/source-map" "^0.3.2"
acorn "^8.5.0"
commander "^2.20.0"
source-map-support "~0.5.20"
util-deprecate@^1.0.1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==
wrappy@1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==
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==

View File

@ -1,7 +1,7 @@
{ {
"name": "@budibase/server", "name": "@budibase/server",
"email": "hi@budibase.com", "email": "hi@budibase.com",
"version": "2.4.44-alpha.12", "version": "2.5.6-alpha.1",
"description": "Budibase Web Server", "description": "Budibase Web Server",
"main": "src/index.ts", "main": "src/index.ts",
"repository": { "repository": {
@ -45,12 +45,12 @@
"license": "GPL-3.0", "license": "GPL-3.0",
"dependencies": { "dependencies": {
"@apidevtools/swagger-parser": "10.0.3", "@apidevtools/swagger-parser": "10.0.3",
"@budibase/backend-core": "2.4.44-alpha.12", "@budibase/backend-core": "2.5.6-alpha.1",
"@budibase/client": "2.4.44-alpha.12", "@budibase/client": "2.5.6-alpha.1",
"@budibase/pro": "2.4.44-alpha.12", "@budibase/pro": "2.5.6-alpha.1",
"@budibase/shared-core": "2.4.44-alpha.12", "@budibase/shared-core": "2.5.6-alpha.1",
"@budibase/string-templates": "2.4.44-alpha.12", "@budibase/string-templates": "2.5.6-alpha.1",
"@budibase/types": "2.4.44-alpha.12", "@budibase/types": "2.5.6-alpha.1",
"@bull-board/api": "3.7.0", "@bull-board/api": "3.7.0",
"@bull-board/koa": "3.9.4", "@bull-board/koa": "3.9.4",
"@elastic/elasticsearch": "7.10.0", "@elastic/elasticsearch": "7.10.0",
@ -116,11 +116,10 @@
"to-json-schema": "0.2.5", "to-json-schema": "0.2.5",
"uuid": "3.3.2", "uuid": "3.3.2",
"validate.js": "0.13.1", "validate.js": "0.13.1",
"vm2": "3.9.11", "vm2": "3.9.16",
"worker-farm": "1.7.0", "worker-farm": "1.7.0",
"xml2js": "0.4.23", "xml2js": "0.5.0",
"yargs": "13.2.4", "yargs": "13.2.4"
"zlib": "1.0.5"
}, },
"devDependencies": { "devDependencies": {
"@babel/core": "7.17.4", "@babel/core": "7.17.4",
@ -149,7 +148,7 @@
"@types/tar": "6.1.3", "@types/tar": "6.1.3",
"@typescript-eslint/parser": "5.45.0", "@typescript-eslint/parser": "5.45.0",
"apidoc": "0.50.4", "apidoc": "0.50.4",
"babel-jest": "27.5.1", "babel-jest": "29.5.0",
"copyfiles": "2.4.1", "copyfiles": "2.4.1",
"docker-compose": "0.23.17", "docker-compose": "0.23.17",
"eslint": "6.8.0", "eslint": "6.8.0",
@ -157,6 +156,7 @@
"is-wsl": "2.2.0", "is-wsl": "2.2.0",
"jest": "29.5.0", "jest": "29.5.0",
"jest-openapi": "0.14.2", "jest-openapi": "0.14.2",
"jest-runner": "29.5.0",
"jest-serial-runner": "^1.2.1", "jest-serial-runner": "^1.2.1",
"nodemon": "2.0.15", "nodemon": "2.0.15",
"openapi-types": "9.3.1", "openapi-types": "9.3.1",

View File

@ -11,6 +11,7 @@ if [ "$1" = '/opt/mssql/bin/sqlservr' ]; then
echo "RUNNING BUDIBASE SETUP" echo "RUNNING BUDIBASE SETUP"
cat setup.sql
#run the setup script to create the DB and the schema in the DB #run the setup script to create the DB and the schema in the DB
/opt/mssql-tools/bin/sqlcmd -S localhost -U sa -P Passw0rd -i setup.sql /opt/mssql-tools/bin/sqlcmd -S localhost -U sa -P Passw0rd -i setup.sql

View File

@ -34,7 +34,7 @@ GO
CREATE TABLE people CREATE TABLE people
( (
name varchar(30) NOT NULL, name varchar(30) NOT NULL,
age varchar(20), age int default 20 NOT NULL,
CONSTRAINT pk_people PRIMARY KEY NONCLUSTERED (name, age) CONSTRAINT pk_people PRIMARY KEY NONCLUSTERED (name, age)
); );
@ -50,22 +50,22 @@ VALUES
('Processing', 1); ('Processing', 1);
INSERT INTO people (name, age) INSERT INTO people (name, age)
VALUES ('Bob', '30'), VALUES ('Bob', 30),
('Bert', '10'), ('Bert', 10),
('Jack', '12'), ('Jack', 12),
('Mike', '31'), ('Mike', 31),
('Dave', '44'), ('Dave', 44),
('Jim', '43'), ('Jim', 43),
('Kerry', '32'), ('Kerry', 32),
('Julie', '12'), ('Julie', 12),
('Kim', '55'), ('Kim', 55),
('Andy', '33'), ('Andy', 33),
('John', '22'), ('John', 22),
('Ruth', '66'), ('Ruth', 66),
('Robert', '88'), ('Robert', 88),
('Bobert', '99'), ('Bobert', 99),
('Jan', '22'), ('Jan', 22),
('Megan', '11'); ('Megan', 11);
IF OBJECT_ID ('Chains.sizes', 'U') IS NOT NULL IF OBJECT_ID ('Chains.sizes', 'U') IS NOT NULL

View File

@ -3,7 +3,7 @@ USE main;
CREATE TABLE Persons ( CREATE TABLE Persons (
PersonID int NOT NULL AUTO_INCREMENT, PersonID int NOT NULL AUTO_INCREMENT,
CreatedAt datetime, CreatedAt datetime,
Age float, Age float DEFAULT 20 NOT NULL,
LastName varchar(255), LastName varchar(255),
FirstName varchar(255), FirstName varchar(255),
Address varchar(255), Address varchar(255),

View File

@ -8,6 +8,7 @@ CREATE TABLE Persons (
FirstName varchar(255), FirstName varchar(255),
Address varchar(255), Address varchar(255),
City varchar(255) DEFAULT 'Belfast', City varchar(255) DEFAULT 'Belfast',
Age INTEGER DEFAULT 20 NOT NULL,
Type person_job Type person_job
); );
CREATE TABLE Tasks ( CREATE TABLE Tasks (

Some files were not shown because too many files have changed in this diff Show More