Merge remote-tracking branch 'origin/develop' into bug/budi-5901-usage-quota-document-conflicts-can-cause

This commit is contained in:
adrinr 2023-03-07 12:41:58 +01:00
commit 4d854ea5a7
132 changed files with 2455 additions and 1106 deletions

View File

@ -37,7 +37,7 @@ jobs:
wc -l values.preprod.yaml wc -l values.preprod.yaml
- name: Deploy to Preprod Environment - name: Deploy to Preprod Environment
uses: glopezep/helm@v1.7.1 uses: budibase/helm@v1.8.0
with: with:
release: budibase-preprod release: budibase-preprod
namespace: budibase namespace: budibase

View File

@ -38,7 +38,7 @@ jobs:
wc -l values.release.yaml wc -l values.release.yaml
- name: Deploy to Release Environment - name: Deploy to Release Environment
uses: glopezep/helm@v1.7.1 uses: budibase/helm@v1.8.0
with: with:
release: budibase-release release: budibase-release
namespace: budibase namespace: budibase

View File

@ -16,9 +16,13 @@ jobs:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
with: with:
node-version: 14.x
fetch_depth: 0 fetch_depth: 0
- name: Use Node.js 14.x
uses: actions/setup-node@v1
with:
node-version: 14.x
- name: Get the latest budibase release version - name: Get the latest budibase release version
id: version id: version
run: | run: |

View File

@ -107,7 +107,7 @@ jobs:
wc -l values.preprod.yaml wc -l values.preprod.yaml
- name: Deploy to Preprod Environment - name: Deploy to Preprod Environment
uses: glopezep/helm@v1.7.1 uses: budibase/helm@v1.8.0
with: with:
release: budibase-preprod release: budibase-preprod
namespace: budibase namespace: budibase

View File

@ -51,6 +51,14 @@ spec:
value: {{ tpl .Values.services.proxy.upstreams.minio . | quote }} value: {{ tpl .Values.services.proxy.upstreams.minio . | quote }}
- name: COUCHDB_UPSTREAM_URL - name: COUCHDB_UPSTREAM_URL
value: {{ .Values.services.couchdb.url | default (tpl .Values.services.proxy.upstreams.couchdb .) | quote }} value: {{ .Values.services.couchdb.url | default (tpl .Values.services.proxy.upstreams.couchdb .) | quote }}
{{ if .Values.services.proxy.proxyRateLimitWebhooksPerSecond }}
- name: PROXY_RATE_LIMIT_WEBHOOKS_PER_SECOND
value: {{ .Values.services.proxy.proxyRateLimitWebhooksPerSecond | quote }}
{{ end }}
{{ if .Values.services.proxy.proxyRateLimitApiPerSecond }}
- name: PROXY_RATE_LIMIT_API_PER_SECOND
value: {{ .Values.services.proxy.proxyRateLimitApiPerSecond | quote }}
{{ end }}
- name: RESOLVER - name: RESOLVER
{{ if .Values.services.proxy.resolver }} {{ if .Values.services.proxy.resolver }}
value: {{ .Values.services.proxy.resolver }} value: {{ .Values.services.proxy.resolver }}

View File

@ -245,7 +245,7 @@ couchdb:
## The CouchDB image ## The CouchDB image
image: image:
repository: couchdb repository: couchdb
tag: 3.2.1 tag: 3.1.1
pullPolicy: IfNotPresent pullPolicy: IfNotPresent
## Experimental integration with Lucene-powered fulltext search ## Experimental integration with Lucene-powered fulltext search

View File

@ -1,5 +1,5 @@
{ {
"version": "2.3.18-alpha.17", "version": "2.3.21-alpha.1",
"npmClient": "yarn", "npmClient": "yarn",
"packages": [ "packages": [
"packages/*" "packages/*"

View File

@ -1,6 +1,6 @@
{ {
"name": "@budibase/backend-core", "name": "@budibase/backend-core",
"version": "2.3.18-alpha.17", "version": "2.3.21-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",
@ -22,9 +22,9 @@
"test:watch": "jest --watchAll" "test:watch": "jest --watchAll"
}, },
"dependencies": { "dependencies": {
"@budibase/nano": "10.1.1", "@budibase/nano": "10.1.2",
"@budibase/pouchdb-replication-stream": "1.2.10", "@budibase/pouchdb-replication-stream": "1.2.10",
"@budibase/types": "2.3.18-alpha.17", "@budibase/types": "2.3.21-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",

View File

@ -28,6 +28,7 @@ import * as events from "../events"
import * as configs from "../configs" import * as configs from "../configs"
import { clearCookie, getCookie } from "../utils" import { clearCookie, getCookie } from "../utils"
import { ssoSaveUserNoOp } from "../middleware/passport/sso/sso" import { ssoSaveUserNoOp } from "../middleware/passport/sso/sso"
import env from "../environment"
const refresh = require("passport-oauth2-refresh") const refresh = require("passport-oauth2-refresh")
export { export {
@ -52,7 +53,7 @@ export const jwt = require("jsonwebtoken")
_passport.use(new LocalStrategy(local.options, local.authenticate)) _passport.use(new LocalStrategy(local.options, local.authenticate))
if (jwtPassport.options.secretOrKey) { if (jwtPassport.options.secretOrKey) {
_passport.use(new JwtStrategy(jwtPassport.options, jwtPassport.authenticate)) _passport.use(new JwtStrategy(jwtPassport.options, jwtPassport.authenticate))
} else { } else if (!env.DISABLE_JWT_WARNING) {
logAlert("No JWT Secret supplied, cannot configure JWT strategy") logAlert("No JWT Secret supplied, cannot configure JWT strategy")
} }

View File

@ -1,6 +1,6 @@
import { getAppClient } from "../redis/init" import { getAppClient } from "../redis/init"
import { doWithDB, DocumentType } from "../db" import { doWithDB, DocumentType } from "../db"
import { Database } from "@budibase/types" import { Database, App } from "@budibase/types"
const AppState = { const AppState = {
INVALID: "invalid", INVALID: "invalid",
@ -65,7 +65,7 @@ export async function getAppMetadata(appId: string) {
if (isInvalid(metadata)) { if (isInvalid(metadata)) {
throw { status: 404, message: "No app metadata found" } throw { status: 404, message: "No app metadata found" }
} }
return metadata return metadata as App
} }
/** /**

View File

@ -42,7 +42,9 @@ export async function getConfig<T extends Config>(
} }
} }
export async function save(config: Config) { export async function save(
config: Config
): Promise<{ id: string; rev: string }> {
const db = context.getGlobalDB() const db = context.getGlobalDB()
return db.put(config) return db.put(config)
} }
@ -54,7 +56,7 @@ export async function getSettingsConfigDoc(): Promise<SettingsConfig> {
if (!config) { if (!config) {
config = { config = {
_id: generateConfigID(ConfigType.GOOGLE), _id: generateConfigID(ConfigType.SETTINGS),
type: ConfigType.SETTINGS, type: ConfigType.SETTINGS,
config: {}, config: {},
} }

View File

@ -94,6 +94,7 @@ const environment = {
SMTP_HOST: process.env.SMTP_HOST, SMTP_HOST: process.env.SMTP_HOST,
SMTP_PORT: parseInt(process.env.SMTP_PORT || ""), SMTP_PORT: parseInt(process.env.SMTP_PORT || ""),
SMTP_FROM_ADDRESS: process.env.SMTP_FROM_ADDRESS, SMTP_FROM_ADDRESS: process.env.SMTP_FROM_ADDRESS,
DISABLE_JWT_WARNING: process.env.DISABLE_JWT_WARNING,
/** /**
* Enable to allow an admin user to login using a password. * Enable to allow an admin user to login using a password.
* This can be useful to prevent lockout when configuring SSO. * This can be useful to prevent lockout when configuring SSO.

View File

@ -8,7 +8,7 @@ import {
HostInfo, HostInfo,
} from "@budibase/types" } from "@budibase/types"
import { EventProcessor } from "./types" import { EventProcessor } from "./types"
import { getAppId } from "../../context" import { getAppId, doInTenant, getTenantId } from "../../context"
import BullQueue from "bull" import BullQueue from "bull"
import { createQueue, JobQueue } from "../../queue" import { createQueue, JobQueue } from "../../queue"
import { isAudited } from "../../utils" import { isAudited } from "../../utils"
@ -26,28 +26,30 @@ export default class AuditLogsProcessor implements EventProcessor {
JobQueue.AUDIT_LOG JobQueue.AUDIT_LOG
) )
return AuditLogsProcessor.auditLogQueue.process(async job => { return AuditLogsProcessor.auditLogQueue.process(async job => {
let properties = job.data.properties return doInTenant(job.data.tenantId, async () => {
if (properties.audited) { let properties = job.data.properties
properties = { if (properties.audited) {
...properties, properties = {
...properties.audited, ...properties,
...properties.audited,
}
delete properties.audited
} }
delete properties.audited
}
// this feature is disabled by default due to privacy requirements // this feature is disabled by default due to privacy requirements
// in some countries - available as env var in-case it is desired // in some countries - available as env var in-case it is desired
// in self host deployments // in self host deployments
let hostInfo: HostInfo | undefined = {} let hostInfo: HostInfo | undefined = {}
if (env.ENABLE_AUDIT_LOG_IP_ADDR) { if (env.ENABLE_AUDIT_LOG_IP_ADDR) {
hostInfo = job.data.opts.hostInfo hostInfo = job.data.opts.hostInfo
} }
await writeAuditLogs(job.data.event, properties, { await writeAuditLogs(job.data.event, properties, {
userId: job.data.opts.userId, userId: job.data.opts.userId,
timestamp: job.data.opts.timestamp, timestamp: job.data.opts.timestamp,
appId: job.data.opts.appId, appId: job.data.opts.appId,
hostInfo, hostInfo,
})
}) })
}) })
} }
@ -72,6 +74,7 @@ export default class AuditLogsProcessor implements EventProcessor {
appId: getAppId(), appId: getAppId(),
hostInfo: identity.hostInfo, hostInfo: identity.hostInfo,
}, },
tenantId: getTenantId(),
}) })
} }
} }

View File

@ -154,7 +154,8 @@ export default function (
return next() return next()
} }
} catch (err: any) { } catch (err: any) {
console.error("Auth Error", err?.message || err) console.error(`Auth Error: ${err.message}`)
console.error(err)
// invalid token, clear the cookie // invalid token, clear the cookie
if (err && err.name === "JsonWebTokenError") { if (err && err.name === "JsonWebTokenError") {
clearCookie(ctx, Cookie.Auth) clearCookie(ctx, Cookie.Auth)

View File

@ -87,6 +87,7 @@ export const runMigration = async (
const lengthStatement = length > 1 ? `[${count}/${length}]` : "" const lengthStatement = length > 1 ? `[${count}/${length}]` : ""
const db = getDB(dbName) const db = getDB(dbName)
try { try {
const doc = await getMigrationsDoc(db) const doc = await getMigrationsDoc(db)

View File

@ -8,6 +8,8 @@ import {
CloudAccount, CloudAccount,
Hosting, Hosting,
SSOAccount, SSOAccount,
CreateAccount,
CreatePassswordAccount,
} from "@budibase/types" } from "@budibase/types"
import _ from "lodash" import _ from "lodash"
@ -29,6 +31,10 @@ export const account = (): Account => {
} }
} }
export function selfHostAccount() {
return account()
}
export const cloudAccount = (): CloudAccount => { export const cloudAccount = (): CloudAccount => {
return { return {
...account(), ...account(),
@ -47,9 +53,9 @@ function provider(): AccountSSOProvider {
return _.sample(Object.values(AccountSSOProvider)) as AccountSSOProvider return _.sample(Object.values(AccountSSOProvider)) as AccountSSOProvider
} }
export function ssoAccount(): SSOAccount { export function ssoAccount(account: Account = cloudAccount()): SSOAccount {
return { return {
...cloudAccount(), ...account,
authType: AuthType.SSO, authType: AuthType.SSO,
oauth2: { oauth2: {
accessToken: generator.string(), accessToken: generator.string(),
@ -61,3 +67,49 @@ export function ssoAccount(): SSOAccount {
thirdPartyProfile: {}, thirdPartyProfile: {},
} }
} }
export const cloudCreateAccount: CreatePassswordAccount = {
email: "cloud@budibase.com",
tenantId: "cloud",
hosting: Hosting.CLOUD,
authType: AuthType.PASSWORD,
password: "Password123!",
tenantName: "cloud",
name: "Budi Armstrong",
size: "10+",
profession: "Software Engineer",
}
export const cloudSSOCreateAccount: CreateAccount = {
email: "cloud-sso@budibase.com",
tenantId: "cloud-sso",
hosting: Hosting.CLOUD,
authType: AuthType.SSO,
tenantName: "cloudsso",
name: "Budi Armstrong",
size: "10+",
profession: "Software Engineer",
}
export const selfCreateAccount: CreatePassswordAccount = {
email: "self@budibase.com",
tenantId: "self",
hosting: Hosting.SELF,
authType: AuthType.PASSWORD,
password: "Password123!",
tenantName: "self",
name: "Budi Armstrong",
size: "10+",
profession: "Software Engineer",
}
export const selfSSOCreateAccount: CreateAccount = {
email: "self-sso@budibase.com",
tenantId: "self-sso",
hosting: Hosting.SELF,
authType: AuthType.SSO,
tenantName: "selfsso",
name: "Budi Armstrong",
size: "10+",
profession: "Software Engineer",
}

View File

@ -1,6 +1,7 @@
import { import {
GoogleInnerConfig, GoogleInnerConfig,
JwtClaims, JwtClaims,
OAuth2,
OIDCInnerConfig, OIDCInnerConfig,
OIDCWellKnownConfig, OIDCWellKnownConfig,
SSOAuthDetails, SSOAuthDetails,
@ -14,6 +15,13 @@ import * as shared from "./shared"
import _ from "lodash" import _ from "lodash"
import { user } from "./shared" import { user } from "./shared"
export function OAuth(): OAuth2 {
return {
refreshToken: generator.string(),
accessToken: generator.string(),
}
}
export function authDetails(userDoc?: User): SSOAuthDetails { export function authDetails(userDoc?: User): SSOAuthDetails {
if (!userDoc) { if (!userDoc) {
userDoc = user() userDoc = user()
@ -28,10 +36,7 @@ export function authDetails(userDoc?: User): SSOAuthDetails {
return { return {
email: userDoc.email, email: userDoc.email,
oauth2: { oauth2: OAuth(),
refreshToken: generator.string(),
accessToken: generator.string(),
},
profile, profile,
provider, provider,
providerType: providerType(), providerType: providerType(),

View File

@ -475,10 +475,10 @@
resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39"
integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==
"@budibase/nano@10.1.1": "@budibase/nano@10.1.2":
version "10.1.1" version "10.1.2"
resolved "https://registry.yarnpkg.com/@budibase/nano/-/nano-10.1.1.tgz#36ccda4d9bb64b5ee14dd2b27a295b40739b1038" resolved "https://registry.yarnpkg.com/@budibase/nano/-/nano-10.1.2.tgz#10fae5a1ab39be6a81261f40e7b7ec6d21cbdd4a"
integrity sha512-kbMIzMkjVtl+xI0UPwVU0/pn8/ccxTyfzwBz6Z+ZiN2oUSb0fJCe0qwA6o8dxwSa8nZu4MbGAeMJl3CJndmWtA== integrity sha512-1w+YN2n/M5aZ9hBKCP4NEjdQbT8BfCLRizkdvm0Je665eEHw3aE1hvo8mon9Ro9QuDdxj1DfDMMFnym6/QUwpQ==
dependencies: dependencies:
"@types/tough-cookie" "^4.0.2" "@types/tough-cookie" "^4.0.2"
axios "^1.1.3" axios "^1.1.3"

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.3.18-alpha.17", "version": "2.3.21-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,7 +38,7 @@
], ],
"dependencies": { "dependencies": {
"@adobe/spectrum-css-workflow-icons": "1.2.1", "@adobe/spectrum-css-workflow-icons": "1.2.1",
"@budibase/string-templates": "2.3.18-alpha.17", "@budibase/string-templates": "2.3.21-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",

View File

@ -15,6 +15,7 @@
export let sort = false export let sort = false
export let autoWidth = false export let autoWidth = false
export let fetchTerm = null export let fetchTerm = null
export let useFetch = false
export let customPopoverHeight export let customPopoverHeight
const dispatch = createEventDispatcher() const dispatch = createEventDispatcher()
@ -86,6 +87,7 @@
isPlaceholder={!value?.length} isPlaceholder={!value?.length}
{autocomplete} {autocomplete}
bind:fetchTerm bind:fetchTerm
{useFetch}
{isOptionSelected} {isOptionSelected}
{getOptionLabel} {getOptionLabel}
{getOptionValue} {getOptionValue}

View File

@ -33,6 +33,7 @@
export let autocomplete = false export let autocomplete = false
export let sort = false export let sort = false
export let fetchTerm = null export let fetchTerm = null
export let useFetch = false
export let customPopoverHeight export let customPopoverHeight
export let align = "left" export let align = "left"
export let footer = null export let footer = null
@ -150,9 +151,9 @@
> >
{#if autocomplete} {#if autocomplete}
<Search <Search
value={fetchTerm ? fetchTerm : searchTerm} value={useFetch ? fetchTerm : searchTerm}
on:change={event => on:change={event =>
fetchTerm ? (fetchTerm = event.detail) : (searchTerm = event.detail)} useFetch ? (fetchTerm = event.detail) : (searchTerm = event.detail)}
{disabled} {disabled}
placeholder="Search" placeholder="Search"
/> />

View File

@ -17,6 +17,7 @@
export let autoWidth = false export let autoWidth = false
export let autocomplete = false export let autocomplete = false
export let fetchTerm = null export let fetchTerm = null
export let useFetch = false
export let customPopoverHeight export let customPopoverHeight
const dispatch = createEventDispatcher() const dispatch = createEventDispatcher()
@ -41,6 +42,7 @@
{autocomplete} {autocomplete}
{customPopoverHeight} {customPopoverHeight}
bind:fetchTerm bind:fetchTerm
{useFetch}
on:change={onChange} on:change={onChange}
on:click on:click
/> />

View File

@ -1,6 +1,6 @@
{ {
"name": "@budibase/builder", "name": "@budibase/builder",
"version": "2.3.18-alpha.17", "version": "2.3.21-alpha.1",
"license": "GPL-3.0", "license": "GPL-3.0",
"private": true, "private": true,
"scripts": { "scripts": {
@ -58,10 +58,10 @@
} }
}, },
"dependencies": { "dependencies": {
"@budibase/bbui": "2.3.18-alpha.17", "@budibase/bbui": "2.3.21-alpha.1",
"@budibase/client": "2.3.18-alpha.17", "@budibase/client": "2.3.21-alpha.1",
"@budibase/frontend-core": "2.3.18-alpha.17", "@budibase/frontend-core": "2.3.21-alpha.1",
"@budibase/string-templates": "2.3.18-alpha.17", "@budibase/string-templates": "2.3.21-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

@ -24,7 +24,10 @@
let updateModal let updateModal
$: appId = $store.appId $: appId = $store.appId
$: updateAvailable = clientPackage.version !== $store.version $: updateAvailable =
clientPackage.version &&
$store.version &&
clientPackage.version !== $store.version
$: revertAvailable = $store.revertableVersion != null $: revertAvailable = $store.revertableVersion != null
const refreshAppPackage = async () => { const refreshAppPackage = async () => {

View File

@ -20,6 +20,12 @@
x => x =>
x._id !== BUDIBASE_INTERNAL_DB_ID && x.type !== BUDIBASE_DATASOURCE_TYPE x._id !== BUDIBASE_INTERNAL_DB_ID && x.type !== BUDIBASE_DATASOURCE_TYPE
) )
// Ensure query params exist so they can be bound
$: {
if (!parameters.queryParams) {
parameters.queryParams = {}
}
}
function fetchQueryDefinition(query) { function fetchQueryDefinition(query) {
const source = $datasources.list.find( const source = $datasources.list.find(

View File

@ -1,22 +1,66 @@
<script> <script>
import { Label, Checkbox } from "@budibase/bbui" import { store } from "builderStore"
import { onMount } from "svelte"
import { Label, Checkbox, Select } from "@budibase/bbui"
import DrawerBindableInput from "components/common/bindings/DrawerBindableInput.svelte" import DrawerBindableInput from "components/common/bindings/DrawerBindableInput.svelte"
import DrawerBindableCombobox from "components/common/bindings/DrawerBindableCombobox.svelte"
export let parameters export let parameters
export let bindings = [] export let bindings = []
$: urlOptions = $store.screens
.map(screen => screen.routing?.route)
.filter(x => x != null)
const typeOptions = [
{
label: "Screen",
value: "screen",
},
{
label: "URL",
value: "url",
},
]
onMount(() => {
if (!parameters.type) {
parameters.type = "screen"
}
})
</script> </script>
<div class="root"> <div class="root">
<Label small>Screen</Label> <Label small>Destination</Label>
<DrawerBindableInput <Select
title="Destination URL" placeholder={null}
placeholder="/screen" bind:value={parameters.type}
value={parameters.url} options={typeOptions}
on:change={value => (parameters.url = value.detail)} on:change={() => (parameters.url = "")}
{bindings}
/> />
<div /> {#if parameters.type === "screen"}
<Checkbox text="Open screen in modal" bind:value={parameters.peek} /> <DrawerBindableCombobox
title="Destination"
placeholder="/screen"
value={parameters.url}
on:change={value => (parameters.url = value.detail)}
{bindings}
options={urlOptions}
appendBindingsAsOptions={false}
/>
<div />
<Checkbox text="Open screen in modal" bind:value={parameters.peek} />
{:else}
<DrawerBindableInput
title="Destination"
placeholder="/url"
value={parameters.url}
on:change={value => (parameters.url = value.detail)}
{bindings}
/>
<div />
<Checkbox text="New Tab" bind:value={parameters.externalNewTab} />
{/if}
</div> </div>
<style> <style>
@ -24,7 +68,7 @@
display: grid; display: grid;
align-items: center; align-items: center;
gap: var(--spacing-m); gap: var(--spacing-m);
grid-template-columns: auto 1fr; grid-template-columns: auto;
max-width: 400px; max-width: 400px;
margin: 0 auto; margin: 0 auto;
} }

View File

@ -35,6 +35,7 @@
let parameters let parameters
let data = [] let data = []
let saveId let saveId
let currentTab = "JSON"
$: datasource = $datasources.list.find(ds => ds._id === query.datasourceId) $: datasource = $datasources.list.find(ds => ds._id === query.datasourceId)
$: query.schema = fieldsToSchema(fields) $: query.schema = fieldsToSchema(fields)
@ -84,7 +85,16 @@
return return
} }
data = response.rows data = response.rows
// need to merge fields that already exist/might have changed
if (fields) {
for (let key of Object.keys(response.schema)) {
if (fields[key]) {
response.schema[key] = fields[key]
}
}
}
fields = response.schema fields = response.schema
currentTab = "JSON"
notifications.success("Query executed successfully") notifications.success("Query executed successfully")
} catch (error) { } catch (error) {
notifications.error(`Query Error: ${error.message}`) notifications.error(`Query Error: ${error.message}`)
@ -205,7 +215,7 @@
</Body> </Body>
<section class="viewer"> <section class="viewer">
{#if data} {#if data}
<Tabs selected="JSON"> <Tabs bind:selected={currentTab}>
<Tab title="JSON"> <Tab title="JSON">
<JSONPreview data={data[0]} minHeight="120" /> <JSONPreview data={data[0]} minHeight="120" />
</Tab> </Tab>

View File

@ -18,7 +18,7 @@
return list.map(item => { return list.map(item => {
return { return {
...item, ...item,
selected: selected.find(x => x === item._id) != null, selected: selected?.find(x => x === item._id) != null,
} }
}) })
} }

View File

@ -62,3 +62,8 @@ export const PluginSource = {
GITHUB: "Github", GITHUB: "Github",
FILE: "File Upload", FILE: "File Upload",
} }
export const OnboardingType = {
EMAIL: "email",
PASSWORD: "password",
}

View File

@ -346,8 +346,15 @@
onMount(() => { onMount(() => {
rendered = true rendered = true
searchFocus = true
}) })
function handleKeyDown(evt) {
if (evt.key === "Enter" && queryIsEmail && !inviting) {
onInviteUser()
}
}
const userTitle = user => { const userTitle = user => {
if (user.admin?.global) { if (user.admin?.global) {
return "Admin" return "Admin"
@ -370,6 +377,8 @@
} }
</script> </script>
<svelte:window on:keydown={handleKeyDown} />
<div <div
id="builder-side-panel-container" id="builder-side-panel-container"
class:open={$store.builderSidePanel} class:open={$store.builderSidePanel}
@ -403,6 +412,7 @@
autocomplete="off" autocomplete="off"
disabled={inviting} disabled={inviting}
value={query} value={query}
autofocus
on:input={e => { on:input={e => {
query = e.target.value.trim() query = e.target.value.trim()
}} }}

View File

@ -120,89 +120,86 @@
}) })
</script> </script>
{#await promise} <TourPopover />
<!-- This should probably be some kind of loading state? -->
<div class="loading" />
{:then _}
<TourPopover />
{#if $store.builderSidePanel} {#if $store.builderSidePanel}
<BuilderSidePanel /> <BuilderSidePanel />
{/if} {/if}
<div class="root"> <div class="root">
<div class="top-nav"> <div class="top-nav">
<div class="topleftnav"> <div class="topleftnav">
<ActionMenu> <ActionMenu>
<div slot="control"> <div slot="control">
<Icon size="M" hoverable name="ShowMenu" /> <Icon size="M" hoverable name="ShowMenu" />
</div> </div>
<MenuItem on:click={() => $goto("../../portal/apps")}> <MenuItem on:click={() => $goto("../../portal/apps")}>
Exit to portal Exit to portal
</MenuItem> </MenuItem>
<MenuItem <MenuItem
on:click={() => $goto(`../../portal/overview/${application}`)} on:click={() => $goto(`../../portal/overview/${application}`)}
> >
Overview Overview
</MenuItem> </MenuItem>
<MenuItem <MenuItem
on:click={() => on:click={() => $goto(`../../portal/overview/${application}/access`)}
$goto(`../../portal/overview/${application}/access`)} >
> Access
Access </MenuItem>
</MenuItem> <MenuItem
<MenuItem on:click={() =>
on:click={() => $goto(`../../portal/overview/${application}/automation-history`)}
$goto(`../../portal/overview/${application}/automation-history`)} >
> Automation history
Automation history </MenuItem>
</MenuItem> <MenuItem
<MenuItem on:click={() => $goto(`../../portal/overview/${application}/backups`)}
on:click={() => >
$goto(`../../portal/overview/${application}/backups`)} Backups
> </MenuItem>
Backups
</MenuItem>
<MenuItem <MenuItem
on:click={() => on:click={() =>
$goto(`../../portal/overview/${application}/name-and-url`)} $goto(`../../portal/overview/${application}/name-and-url`)}
> >
Name and URL Name and URL
</MenuItem> </MenuItem>
<MenuItem <MenuItem
on:click={() => on:click={() => $goto(`../../portal/overview/${application}/version`)}
$goto(`../../portal/overview/${application}/version`)} >
> Version
Version </MenuItem>
</MenuItem> </ActionMenu>
</ActionMenu> <Heading size="XS">{$store.name}</Heading>
<Heading size="XS">{$store.name || "App"}</Heading> </div>
</div> <div class="topcenternav">
<div class="topcenternav"> <Tabs {selected} size="M">
<Tabs {selected} size="M"> {#each $layout.children as { path, title }}
{#each $layout.children as { path, title }} <TourWrap tourStepKey={`builder-${title}-section`}>
<TourWrap tourStepKey={`builder-${title}-section`}> <Tab
<Tab quiet
quiet selected={$isActive(path)}
selected={$isActive(path)} on:click={topItemNavigate(path)}
on:click={topItemNavigate(path)} title={capitalise(title)}
title={capitalise(title)} id={`builder-${title}-tab`}
id={`builder-${title}-tab`} />
/> </TourWrap>
</TourWrap> {/each}
{/each} </Tabs>
</Tabs> </div>
</div> <div class="toprightnav">
<div class="toprightnav"> <AppActions {application} />
<AppActions {application} />
</div>
</div> </div>
<slot />
</div> </div>
{:catch error} {#await promise}
<p>Something went wrong: {error.message}</p> <!-- This should probably be some kind of loading state? -->
{/await} <div class="loading" />
{:then _}
<slot />
{:catch error}
<p>Something went wrong: {error.message}</p>
{/await}
</div>
<style> <style>
.loading { .loading {

View File

@ -13,6 +13,7 @@
let formData = {} let formData = {}
let onboarding = false let onboarding = false
let errors = {} let errors = {}
let loaded = false
$: company = $organisation.company || "Budibase" $: company = $organisation.company || "Budibase"
@ -39,6 +40,11 @@
if (invite?.email) { if (invite?.email) {
formData.email = invite?.email formData.email = invite?.email
} }
if ($organisation.isSSOEnforced) {
// auto accept invite and redirect to login
await users.acceptInvite(inviteCode)
$goto("../auth")
}
} catch (error) { } catch (error) {
notifications.error(error.message) notifications.error(error.message)
} }
@ -61,130 +67,135 @@
try { try {
await organisation.init() await organisation.init()
await getInvite() await getInvite()
loaded = true
} catch (error) { } catch (error) {
notifications.error("Error getting invite config") notifications.error("Error getting invite config")
} }
}) })
</script> </script>
<TestimonialPage> {#if loaded}
<Layout gap="M" noPadding> <TestimonialPage>
<img alt="logo" src={$organisation.logoUrl || Logo} /> <Layout gap="M" noPadding>
<Layout gap="XS" noPadding> <img alt="logo" src={$organisation.logoUrl || Logo} />
<Heading size="M">Join {company}</Heading> <Layout gap="XS" noPadding>
<Body size="M">Create your account to access your budibase apps!</Body> <Heading size="M">Join {company}</Heading>
</Layout> <Body size="M">Create your account to access your budibase apps!</Body>
</Layout>
<Layout gap="S" noPadding> <Layout gap="S" noPadding>
<FancyForm bind:this={form}> <FancyForm bind:this={form}>
<FancyInput <FancyInput
label="Email" label="Email"
value={formData.email} value={formData.email}
disabled={true} disabled={true}
error={errors.email} error={errors.email}
/> />
<FancyInput <FancyInput
label="First name" label="First name"
value={formData.firstName} value={formData.firstName}
on:change={e => { on:change={e => {
formData = { formData = {
...formData, ...formData,
firstName: e.detail, firstName: e.detail,
} }
}} }}
validate={() => { validate={() => {
let fieldError = { let fieldError = {
firstName: !formData.firstName firstName: !formData.firstName
? "Please enter your first name" ? "Please enter your first name"
: undefined,
}
errors = handleError({ ...errors, ...fieldError })
}}
error={errors.firstName}
disabled={onboarding}
/>
<FancyInput
label="Last name (optional)"
value={formData.lastName}
on:change={e => {
formData = {
...formData,
lastName: e.detail,
}
}}
disabled={onboarding}
/>
<FancyInput
label="Password"
value={formData.password}
type="password"
on:change={e => {
formData = {
...formData,
password: e.detail,
}
}}
validate={() => {
let fieldError = {}
fieldError["password"] = !formData.password
? "Please enter a password"
: undefined
fieldError["confirmationPassword"] =
!passwordsMatch(
formData.password,
formData.confirmationPassword
) && formData.confirmationPassword
? "Passwords must match"
: undefined
errors = handleError({ ...errors, ...fieldError })
}}
error={errors.password}
disabled={onboarding}
/>
<FancyInput
label="Repeat password"
value={formData.confirmationPassword}
type="password"
on:change={e => {
formData = {
...formData,
confirmationPassword: e.detail,
}
}}
validate={() => {
let fieldError = {
confirmationPassword:
!passwordsMatch(
formData.password,
formData.confirmationPassword
) && formData.password
? "Passwords must match"
: undefined, : undefined,
} }
errors = handleError({ ...errors, ...fieldError }) errors = handleError({ ...errors, ...fieldError })
}} }}
error={errors.confirmationPassword} error={errors.firstName}
disabled={onboarding} disabled={onboarding}
/> />
</FancyForm> <FancyInput
label="Last name (optional)"
value={formData.lastName}
on:change={e => {
formData = {
...formData,
lastName: e.detail,
}
}}
disabled={onboarding}
/>
{#if !$organisation.isSSOEnforced}
<FancyInput
label="Password"
value={formData.password}
type="password"
on:change={e => {
formData = {
...formData,
password: e.detail,
}
}}
validate={() => {
let fieldError = {}
fieldError["password"] = !formData.password
? "Please enter a password"
: undefined
fieldError["confirmationPassword"] =
!passwordsMatch(
formData.password,
formData.confirmationPassword
) && formData.confirmationPassword
? "Passwords must match"
: undefined
errors = handleError({ ...errors, ...fieldError })
}}
error={errors.password}
disabled={onboarding}
/>
<FancyInput
label="Repeat password"
value={formData.confirmationPassword}
type="password"
on:change={e => {
formData = {
...formData,
confirmationPassword: e.detail,
}
}}
validate={() => {
let fieldError = {
confirmationPassword:
!passwordsMatch(
formData.password,
formData.confirmationPassword
) && formData.password
? "Passwords must match"
: undefined,
}
errors = handleError({ ...errors, ...fieldError })
}}
error={errors.confirmationPassword}
disabled={onboarding}
/>
{/if}
</FancyForm>
</Layout>
<div>
<Button
size="L"
disabled={Object.keys(errors).length > 0 || onboarding}
cta
on:click={acceptInvite}
>
Create account
</Button>
</div>
</Layout> </Layout>
<div> </TestimonialPage>
<Button {/if}
size="L"
disabled={Object.keys(errors).length > 0 || onboarding}
cta
on:click={acceptInvite}
>
Create account
</Button>
</div>
</Layout>
</TestimonialPage>
<style> <style>
img { img {

View File

@ -1,11 +1,11 @@
<script> <script>
import { Button } from "@budibase/bbui" import { Button } from "@budibase/bbui"
import { goto } from "@roxi/routify" import { goto } from "@roxi/routify"
import { auth, admin } from "stores/portal" import { auth, admin, licensing } from "stores/portal"
import { isEnabled, TENANT_FEATURE_FLAGS } from "helpers/featureFlags" import { isEnabled, TENANT_FEATURE_FLAGS } from "helpers/featureFlags"
</script> </script>
{#if isEnabled(TENANT_FEATURE_FLAGS.LICENSING)} {#if isEnabled(TENANT_FEATURE_FLAGS.LICENSING) && !$licensing.isEnterprisePlan}
{#if $admin.cloud && $auth?.user?.accountPortalAccess} {#if $admin.cloud && $auth?.user?.accountPortalAccess}
<Button <Button
cta cta

View File

@ -12,18 +12,20 @@
} }
</script> </script>
<div {#if row?.user?.email}
class="container" <div
on:mouseover={() => (showTooltip = true)} class="container"
on:focus={() => (showTooltip = true)} on:mouseover={() => (showTooltip = true)}
on:mouseleave={() => (showTooltip = false)} on:focus={() => (showTooltip = true)}
> on:mouseleave={() => (showTooltip = false)}
<Avatar size="M" initials={getInitials(row?.user)} /> >
</div> <Avatar size="M" initials={getInitials(row.user)} />
{#if showTooltip}
<div class="tooltip">
<Tooltip textWrapping text={row?.user.email} direction="bottom" />
</div> </div>
{#if showTooltip}
<div class="tooltip">
<Tooltip textWrapping text={row.user.email} direction="bottom" />
</div>
{/if}
{/if} {/if}
<style> <style>

View File

@ -257,6 +257,7 @@
<div class="select"> <div class="select">
<Multiselect <Multiselect
bind:fetchTerm={userSearchTerm} bind:fetchTerm={userSearchTerm}
useFetch
placeholder="All users" placeholder="All users"
label="Users" label="Users"
autocomplete autocomplete

View File

@ -368,7 +368,7 @@
</div> </div>
{#if !$licensing.enforceableSSO} {#if !$licensing.enforceableSSO}
<Tags> <Tags>
<Tag icon="LockClosed">Business plan</Tag> <Tag icon="LockClosed">Enterprise plan</Tag>
</Tags> </Tags>
{/if} {/if}
</div> </div>

View File

@ -1,9 +1,8 @@
<script> <script>
import { ModalContent, Body, Layout, Icon } from "@budibase/bbui" import { ModalContent, Body, Layout, Icon } from "@budibase/bbui"
import { OnboardingType } from "../../../../../../constants"
export let chooseCreationType export let chooseCreationType
let emailOnboardingKey = "emailOnboarding"
let basicOnboaridngKey = "basicOnboarding"
let selectedOnboardingType let selectedOnboardingType
</script> </script>
@ -20,9 +19,9 @@
<Layout noPadding gap="S"> <Layout noPadding gap="S">
<div <div
class="onboarding-type item" class="onboarding-type item"
class:selected={selectedOnboardingType == emailOnboardingKey} class:selected={selectedOnboardingType == OnboardingType.EMAIL}
on:click={() => { on:click={() => {
selectedOnboardingType = emailOnboardingKey selectedOnboardingType = OnboardingType.EMAIL
}} }}
> >
<div class="content onboarding-type-wrap"> <div class="content onboarding-type-wrap">
@ -32,7 +31,7 @@
</div> </div>
</div> </div>
<div style="color: var(--spectrum-global-color-green-600); float: right"> <div style="color: var(--spectrum-global-color-green-600); float: right">
{#if selectedOnboardingType == emailOnboardingKey} {#if selectedOnboardingType == OnboardingType.EMAIL}
<div class="checkmark-spacing"> <div class="checkmark-spacing">
<Icon size="S" name="CheckmarkCircle" /> <Icon size="S" name="CheckmarkCircle" />
</div> </div>
@ -42,9 +41,9 @@
<div <div
class="onboarding-type item" class="onboarding-type item"
class:selected={selectedOnboardingType == basicOnboaridngKey} class:selected={selectedOnboardingType == OnboardingType.PASSWORD}
on:click={() => { on:click={() => {
selectedOnboardingType = basicOnboaridngKey selectedOnboardingType = OnboardingType.PASSWORD
}} }}
> >
<div class="content onboarding-type-wrap"> <div class="content onboarding-type-wrap">
@ -54,7 +53,7 @@
</div> </div>
</div> </div>
<div style="color: var(--spectrum-global-color-green-600); float: right"> <div style="color: var(--spectrum-global-color-green-600); float: right">
{#if selectedOnboardingType == basicOnboaridngKey} {#if selectedOnboardingType == OnboardingType.PASSWORD}
<div class="checkmark-spacing"> <div class="checkmark-spacing">
<Icon size="S" name="CheckmarkCircle" /> <Icon size="S" name="CheckmarkCircle" />
</div> </div>

View File

@ -13,7 +13,7 @@
Divider, Divider,
} from "@budibase/bbui" } from "@budibase/bbui"
import AddUserModal from "./_components/AddUserModal.svelte" import AddUserModal from "./_components/AddUserModal.svelte"
import { users, groups, auth, licensing } from "stores/portal" import { users, groups, auth, licensing, organisation } from "stores/portal"
import { onMount } from "svelte" import { onMount } from "svelte"
import DeleteRowsButton from "components/backend/DataTable/buttons/DeleteRowsButton.svelte" import DeleteRowsButton from "components/backend/DataTable/buttons/DeleteRowsButton.svelte"
import GroupsTableRenderer from "./_components/GroupsTableRenderer.svelte" import GroupsTableRenderer from "./_components/GroupsTableRenderer.svelte"
@ -27,6 +27,7 @@
import { get } from "svelte/store" import { get } from "svelte/store"
import { Constants, Utils, fetchData } from "@budibase/frontend-core" import { Constants, Utils, fetchData } from "@budibase/frontend-core"
import { API } from "api" import { API } from "api"
import { OnboardingType } from "../../../../../constants"
const fetch = fetchData({ const fetch = fetchData({
API, API,
@ -105,10 +106,18 @@
const debouncedUpdateFetch = Utils.debounce(updateFetch, 250) const debouncedUpdateFetch = Utils.debounce(updateFetch, 250)
const showOnboardingTypeModal = async addUsersData => { const showOnboardingTypeModal = async addUsersData => {
// no-op if users already exist
userData = await removingDuplicities(addUsersData) userData = await removingDuplicities(addUsersData)
if (!userData?.users?.length) return if (!userData?.users?.length) {
return
}
onboardingTypeModal.show() if ($organisation.isSSOEnforced) {
// bypass the onboarding type selection of sso is enforced
await chooseCreationType(OnboardingType.EMAIL)
} else {
onboardingTypeModal.show()
}
} }
async function createUserFlow() { async function createUserFlow() {
@ -181,7 +190,7 @@
} }
async function chooseCreationType(onboardingType) { async function chooseCreationType(onboardingType) {
if (onboardingType === "emailOnboarding") { if (onboardingType === OnboardingType.EMAIL) {
await createUserFlow() await createUserFlow()
} else { } else {
await createUsers() await createUsers()

View File

@ -12,6 +12,7 @@ export const createLicensingStore = () => {
// the top level license // the top level license
license: undefined, license: undefined,
isFreePlan: true, isFreePlan: true,
isEnterprisePlan: true,
// features // features
groupsEnabled: false, groupsEnabled: false,
backupsEnabled: false, backupsEnabled: false,
@ -53,7 +54,9 @@ export const createLicensingStore = () => {
}, },
setLicense: () => { setLicense: () => {
const license = get(auth).user.license const license = get(auth).user.license
const isFreePlan = license?.plan.type === Constants.PlanType.FREE const planType = license?.plan.type
const isEnterprisePlan = planType === Constants.PlanType.ENTERPRISE
const isFreePlan = planType === Constants.PlanType.FREE
const groupsEnabled = license.features.includes( const groupsEnabled = license.features.includes(
Constants.Features.USER_GROUPS Constants.Features.USER_GROUPS
) )
@ -74,6 +77,7 @@ export const createLicensingStore = () => {
return { return {
...state, ...state,
license, license,
isEnterprisePlan,
isFreePlan, isFreePlan,
groupsEnabled, groupsEnabled,
backupsEnabled, backupsEnabled,

View File

@ -75,11 +75,13 @@ export const menu = derived([admin, auth], ([$admin, $auth]) => {
title: "Usage", title: "Usage",
href: "/builder/portal/account/usage", href: "/builder/portal/account/usage",
}, },
{ ]
if ($auth.isAdmin) {
accountSubPages.push({
title: "Audit Logs", title: "Audit Logs",
href: "/builder/portal/account/auditLogs", href: "/builder/portal/account/auditLogs",
}, })
] }
if ($admin.cloud && $auth?.user?.accountPortalAccess) { if ($admin.cloud && $auth?.user?.accountPortalAccess) {
accountSubPages.push({ accountSubPages.push({
title: "Upgrade", title: "Upgrade",

View File

@ -6,3 +6,4 @@ docker-error.log
envoy.yaml envoy.yaml
*.tar.gz *.tar.gz
prebuilds/ prebuilds/
dist/

View File

@ -1,16 +1,19 @@
{ {
"name": "@budibase/cli", "name": "@budibase/cli",
"version": "2.3.18-alpha.17", "version": "2.3.21-alpha.1",
"description": "Budibase CLI, for developers, self hosting and migrations.", "description": "Budibase CLI, for developers, self hosting and migrations.",
"main": "src/index.js", "main": "dist/index.js",
"bin": { "bin": {
"budi": "src/index.js" "budi": "dist/index.js"
}, },
"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",
"build": "yarn prebuild && renamer --find .node --replace .fake 'prebuilds/**' && pkg . --out-path build && yarn postbuild", "rename": "renamer --find .node --replace .fake 'prebuilds/**'",
"tsc": "tsc -p tsconfig.build.json",
"pkg": "pkg . --out-path build --no-bytecode --public --public-packages \"*\" -C GZip",
"build": "yarn prebuild && yarn rename && yarn tsc && yarn pkg && yarn postbuild",
"postbuild": "rm -rf prebuilds 2> /dev/null" "postbuild": "rm -rf prebuilds 2> /dev/null"
}, },
"pkg": { "pkg": {
@ -26,9 +29,9 @@
"outputPath": "build" "outputPath": "build"
}, },
"dependencies": { "dependencies": {
"@budibase/backend-core": "2.3.18-alpha.17", "@budibase/backend-core": "2.3.21-alpha.1",
"@budibase/string-templates": "2.3.18-alpha.17", "@budibase/string-templates": "2.3.21-alpha.1",
"@budibase/types": "2.3.18-alpha.17", "@budibase/types": "2.3.21-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",
@ -40,7 +43,7 @@
"inquirer": "8.0.0", "inquirer": "8.0.0",
"joi": "17.6.0", "joi": "17.6.0",
"lookpath": "1.1.0", "lookpath": "1.1.0",
"node-fetch": "2", "node-fetch": "2.6.7",
"pkg": "5.8.0", "pkg": "5.8.0",
"posthog-node": "1.0.7", "posthog-node": "1.0.7",
"pouchdb": "7.3.0", "pouchdb": "7.3.0",
@ -50,8 +53,15 @@
"yaml": "^2.1.1" "yaml": "^2.1.1"
}, },
"devDependencies": { "devDependencies": {
"@swc/core": "^1.3.25",
"@swc/jest": "^0.2.24",
"@types/jest": "^29.4.0",
"@types/node-fetch": "2.6.1",
"@types/pouchdb": "^6.4.0",
"copyfiles": "^2.4.1", "copyfiles": "^2.4.1",
"eslint": "^7.20.0", "eslint": "^7.20.0",
"renamer": "^4.0.0" "renamer": "^4.0.0",
"ts-node": "^10.9.1",
"typescript": "4.7.3"
} }
} }

View File

@ -1,32 +0,0 @@
const PostHog = require("posthog-node")
const { POSTHOG_TOKEN, AnalyticsEvents } = require("../constants")
const ConfigManager = require("../structures/ConfigManager")
class AnalyticsClient {
constructor() {
this.client = new PostHog(POSTHOG_TOKEN)
this.configManager = new ConfigManager()
}
capture(event) {
if (this.configManager.config.analyticsDisabled) return
this.client.capture(event)
}
enable() {
this.configManager.removeKey("analyticsDisabled")
this.client.capture({ event: AnalyticsEvents.OptIn, distinctId: "cli" })
}
disable() {
this.client.capture({ event: AnalyticsEvents.OptOut, distinctId: "cli" })
this.configManager.setValue("analyticsDisabled", true)
}
status() {
return this.configManager.config.analyticsDisabled ? "disabled" : "enabled"
}
}
module.exports = AnalyticsClient

View File

@ -0,0 +1,33 @@
import PostHog from "posthog-node"
import { POSTHOG_TOKEN, AnalyticsEvent } from "../constants"
import { ConfigManager } from "../structures/ConfigManager"
export class AnalyticsClient {
client: PostHog
configManager: ConfigManager
constructor() {
this.client = new PostHog(POSTHOG_TOKEN, {})
this.configManager = new ConfigManager()
}
capture(event: { distinctId: string; event: string; properties?: any }) {
if (this.configManager.config.analyticsDisabled) return
this.client.capture(event)
}
enable() {
this.configManager.removeKey("analyticsDisabled")
this.client.capture({ event: AnalyticsEvent.OptIn, distinctId: "cli" })
}
disable() {
this.client.capture({ event: AnalyticsEvent.OptOut, distinctId: "cli" })
this.configManager.setValue("analyticsDisabled", true)
}
status() {
return this.configManager.config.analyticsDisabled ? "disabled" : "enabled"
}
}

View File

@ -1,7 +1,7 @@
const Command = require("../structures/Command") import { Command } from "../structures/Command"
const { CommandWords } = require("../constants") import { CommandWord } from "../constants"
const { success, error } = require("../utils") import { success, error } from "../utils"
const AnalyticsClient = require("./Client") import { AnalyticsClient } from "./Client"
const client = new AnalyticsClient() const client = new AnalyticsClient()
@ -14,11 +14,10 @@ async function optOut() {
"Successfully opted out of Budibase analytics. You can opt in at any time by running 'budi analytics opt-in'" "Successfully opted out of Budibase analytics. You can opt in at any time by running 'budi analytics opt-in'"
) )
) )
} catch (err) { } catch (err: any) {
console.log( console.log(
error( error(
"Error opting out of Budibase analytics. Please try again later.", `Error opting out of Budibase analytics. Please try again later - ${err}`
err
) )
) )
} }
@ -50,7 +49,7 @@ async function status() {
} }
} }
const command = new Command(`${CommandWords.ANALYTICS}`) export default new Command(`${CommandWord.ANALYTICS}`)
.addHelp("Control the analytics you send to Budibase.") .addHelp("Control the analytics you send to Budibase.")
.addSubOption("--optin", "Opt in to sending analytics to Budibase", optIn) .addSubOption("--optin", "Opt in to sending analytics to Budibase", optIn)
.addSubOption("--optout", "Opt out of sending analytics to Budibase.", optOut) .addSubOption("--optout", "Opt out of sending analytics to Budibase.", optOut)
@ -59,5 +58,3 @@ const command = new Command(`${CommandWords.ANALYTICS}`)
"Check whether you are currently opted in to Budibase analytics.", "Check whether you are currently opted in to Budibase analytics.",
status status
) )
exports.command = command

View File

@ -1,28 +1,30 @@
const Command = require("../structures/Command") import { Command } from "../structures/Command"
const { CommandWords } = require("../constants") import { CommandWord } from "../constants"
const fs = require("fs") import fs from "fs"
const { join } = require("path") import { join } from "path"
const { getAllDbs } = require("../core/db") import { getAllDbs } from "../core/db"
const tar = require("tar") import { progressBar, httpCall } from "../utils"
const { progressBar, httpCall } = require("../utils") import {
const {
TEMP_DIR, TEMP_DIR,
COUCH_DIR, COUCH_DIR,
MINIO_DIR, MINIO_DIR,
getConfig, getConfig,
replication, replication,
getPouches, getPouches,
} = require("./utils") } from "./utils"
const { exportObjects, importObjects } = require("./objectStore") import { exportObjects, importObjects } from "./objectStore"
const tar = require("tar")
async function exportBackup(opts) { type BackupOpts = { env?: string; import?: string; export?: string }
async function exportBackup(opts: BackupOpts) {
const envFile = opts.env || undefined const envFile = opts.env || undefined
let filename = opts["export"] || opts let filename = opts["export"] || (opts as string)
if (typeof filename !== "string") { if (typeof filename !== "string") {
filename = `backup-${new Date().toISOString()}.tar.gz` filename = `backup-${new Date().toISOString()}.tar.gz`
} }
const config = await getConfig(envFile) const config = await getConfig(envFile)
const dbList = await getAllDbs(config["COUCH_DB_URL"]) const dbList = (await getAllDbs(config["COUCH_DB_URL"])) as string[]
const { Remote, Local } = getPouches(config) const { Remote, Local } = getPouches(config)
if (fs.existsSync(TEMP_DIR)) { if (fs.existsSync(TEMP_DIR)) {
fs.rmSync(TEMP_DIR, { recursive: true }) fs.rmSync(TEMP_DIR, { recursive: true })
@ -55,9 +57,9 @@ async function exportBackup(opts) {
console.log(`Generated export file - ${filename}`) console.log(`Generated export file - ${filename}`)
} }
async function importBackup(opts) { async function importBackup(opts: BackupOpts) {
const envFile = opts.env || undefined const envFile = opts.env || undefined
const filename = opts["import"] || opts const filename = opts["import"] || (opts as string)
const config = await getConfig(envFile) const config = await getConfig(envFile)
if (!filename || !fs.existsSync(filename)) { if (!filename || !fs.existsSync(filename)) {
console.error("Cannot import without specifying a valid file to import") console.error("Cannot import without specifying a valid file to import")
@ -99,7 +101,7 @@ async function importBackup(opts) {
fs.rmSync(TEMP_DIR, { recursive: true }) fs.rmSync(TEMP_DIR, { recursive: true })
} }
async function pickOne(opts) { async function pickOne(opts: BackupOpts) {
if (opts["import"]) { if (opts["import"]) {
return importBackup(opts) return importBackup(opts)
} else if (opts["export"]) { } else if (opts["export"]) {
@ -107,7 +109,7 @@ async function pickOne(opts) {
} }
} }
const command = new Command(`${CommandWords.BACKUPS}`) export default new Command(`${CommandWord.BACKUPS}`)
.addHelp( .addHelp(
"Allows building backups of Budibase, as well as importing a backup to a new instance." "Allows building backups of Budibase, as well as importing a backup to a new instance."
) )
@ -126,5 +128,3 @@ const command = new Command(`${CommandWords.BACKUPS}`)
"Provide an environment variable file to configure the CLI.", "Provide an environment variable file to configure the CLI.",
pickOne pickOne
) )
exports.command = command

View File

@ -1,8 +1,8 @@
const { objectStore } = require("@budibase/backend-core") import { objectStore } from "@budibase/backend-core"
const fs = require("fs") import fs from "fs"
const { join } = require("path") import { join } from "path"
const { TEMP_DIR, MINIO_DIR } = require("./utils") import { TEMP_DIR, MINIO_DIR } from "./utils"
const { progressBar } = require("../utils") import { progressBar } from "../utils"
const { const {
ObjectStoreBuckets, ObjectStoreBuckets,
ObjectStore, ObjectStore,
@ -13,10 +13,10 @@ const {
const bucketList = Object.values(ObjectStoreBuckets) const bucketList = Object.values(ObjectStoreBuckets)
exports.exportObjects = async () => { export async function exportObjects() {
const path = join(TEMP_DIR, MINIO_DIR) const path = join(TEMP_DIR, MINIO_DIR)
fs.mkdirSync(path) fs.mkdirSync(path)
let fullList = [] let fullList: any[] = []
let errorCount = 0 let errorCount = 0
for (let bucket of bucketList) { for (let bucket of bucketList) {
const client = ObjectStore(bucket) const client = ObjectStore(bucket)
@ -26,7 +26,7 @@ exports.exportObjects = async () => {
errorCount++ errorCount++
continue continue
} }
const list = await client.listObjectsV2().promise() const list = (await client.listObjectsV2().promise()) as { Contents: any[] }
fullList = fullList.concat(list.Contents.map(el => ({ ...el, bucket }))) fullList = fullList.concat(list.Contents.map(el => ({ ...el, bucket })))
} }
if (errorCount === bucketList.length) { if (errorCount === bucketList.length) {
@ -48,7 +48,7 @@ exports.exportObjects = async () => {
bar.stop() bar.stop()
} }
exports.importObjects = async () => { export async function importObjects() {
const path = join(TEMP_DIR, MINIO_DIR) const path = join(TEMP_DIR, MINIO_DIR)
const buckets = fs.readdirSync(path) const buckets = fs.readdirSync(path)
let total = 0 let total = 0

View File

@ -1,12 +1,13 @@
const dotenv = require("dotenv") import dotenv from "dotenv"
const fs = require("fs") import fs from "fs"
const { string } = require("../questions") import { string } from "../questions"
const { getPouch } = require("../core/db") import { getPouch } from "../core/db"
const { env: environment } = require("@budibase/backend-core") import { env as environment } from "@budibase/backend-core"
import PouchDB from "pouchdb"
exports.TEMP_DIR = ".temp" export const TEMP_DIR = ".temp"
exports.COUCH_DIR = "couchdb" export const COUCH_DIR = "couchdb"
exports.MINIO_DIR = "minio" export const MINIO_DIR = "minio"
const REQUIRED = [ const REQUIRED = [
{ value: "MAIN_PORT", default: "10000" }, { value: "MAIN_PORT", default: "10000" },
@ -19,7 +20,7 @@ const REQUIRED = [
{ value: "MINIO_SECRET_KEY" }, { value: "MINIO_SECRET_KEY" },
] ]
exports.checkURLs = config => { export function checkURLs(config: Record<string, string>) {
const mainPort = config["MAIN_PORT"], const mainPort = config["MAIN_PORT"],
username = config["COUCH_DB_USER"], username = config["COUCH_DB_USER"],
password = config["COUCH_DB_PASSWORD"] password = config["COUCH_DB_PASSWORD"]
@ -34,23 +35,23 @@ exports.checkURLs = config => {
return config return config
} }
exports.askQuestions = async () => { export async function askQuestions() {
console.log( console.log(
"*** NOTE: use a .env file to load these parameters repeatedly ***" "*** NOTE: use a .env file to load these parameters repeatedly ***"
) )
let config = {} let config: Record<string, string> = {}
for (let property of REQUIRED) { for (let property of REQUIRED) {
config[property.value] = await string(property.value, property.default) config[property.value] = await string(property.value, property.default)
} }
return config return config
} }
exports.loadEnvironment = path => { export function loadEnvironment(path: string) {
if (!fs.existsSync(path)) { if (!fs.existsSync(path)) {
throw "Unable to file specified .env file" throw "Unable to file specified .env file"
} }
const env = fs.readFileSync(path, "utf8") const env = fs.readFileSync(path, "utf8")
const config = exports.checkURLs(dotenv.parse(env)) const config = checkURLs(dotenv.parse(env))
for (let required of REQUIRED) { for (let required of REQUIRED) {
if (!config[required.value]) { if (!config[required.value]) {
throw `Cannot find "${required.value}" property in .env file` throw `Cannot find "${required.value}" property in .env file`
@ -60,12 +61,12 @@ exports.loadEnvironment = path => {
} }
// true is the default value passed by commander // true is the default value passed by commander
exports.getConfig = async (envFile = true) => { export async function getConfig(envFile: boolean | string = true) {
let config let config
if (envFile !== true) { if (envFile !== true) {
config = exports.loadEnvironment(envFile) config = loadEnvironment(envFile as string)
} else { } else {
config = await exports.askQuestions() config = await askQuestions()
} }
// fill out environment // fill out environment
for (let key of Object.keys(config)) { for (let key of Object.keys(config)) {
@ -74,12 +75,16 @@ exports.getConfig = async (envFile = true) => {
return config return config
} }
exports.replication = async (from, to) => { export async function replication(
from: PouchDB.Database,
to: PouchDB.Database
) {
const pouch = getPouch() const pouch = getPouch()
try { try {
await pouch.replicate(from, to, { await pouch.replicate(from, to, {
batch_size: 1000, batch_size: 1000,
batch_limit: 5, batches_limit: 5,
// @ts-ignore
style: "main_only", style: "main_only",
}) })
} catch (err) { } catch (err) {
@ -87,7 +92,7 @@ exports.replication = async (from, to) => {
} }
} }
exports.getPouches = config => { export function getPouches(config: Record<string, string>) {
const Remote = getPouch(config["COUCH_DB_URL"]) const Remote = getPouch(config["COUCH_DB_URL"])
const Local = getPouch() const Local = getPouch()
return { Remote, Local } return { Remote, Local }

View File

@ -1,25 +0,0 @@
const { Event } = require("@budibase/types")
exports.CommandWords = {
BACKUPS: "backups",
HOSTING: "hosting",
ANALYTICS: "analytics",
HELP: "help",
PLUGIN: "plugins",
}
exports.InitTypes = {
QUICK: "quick",
DIGITAL_OCEAN: "do",
}
exports.AnalyticsEvents = {
OptOut: "analytics:opt:out",
OptIn: "analytics:opt:in",
SelfHostInit: "hosting:init",
PluginInit: Event.PLUGIN_INIT,
}
exports.POSTHOG_TOKEN = "phc_yGOn4i7jWKaCTapdGR6lfA4AvmuEQ2ijn5zAVSFYPlS"
exports.GENERATED_USER_EMAIL = "admin@admin.com"

View File

@ -0,0 +1,4 @@
export { CommandWord, InitType, AnalyticsEvent } from "@budibase/types"
export const POSTHOG_TOKEN = "phc_yGOn4i7jWKaCTapdGR6lfA4AvmuEQ2ijn5zAVSFYPlS"
export const GENERATED_USER_EMAIL = "admin@admin.com"

View File

@ -1,12 +1,12 @@
const PouchDB = require("pouchdb") import PouchDB from "pouchdb"
const { checkSlashesInUrl } = require("../utils") import { checkSlashesInUrl } from "../utils"
const fetch = require("node-fetch") import fetch from "node-fetch"
/** /**
* Fully qualified URL including username and password, or nothing for local * Fully qualified URL including username and password, or nothing for local
*/ */
exports.getPouch = (url = undefined) => { export function getPouch(url?: string) {
let POUCH_DB_DEFAULTS = {} let POUCH_DB_DEFAULTS
if (!url) { if (!url) {
POUCH_DB_DEFAULTS = { POUCH_DB_DEFAULTS = {
prefix: undefined, prefix: undefined,
@ -19,11 +19,12 @@ exports.getPouch = (url = undefined) => {
} }
const replicationStream = require("pouchdb-replication-stream") const replicationStream = require("pouchdb-replication-stream")
PouchDB.plugin(replicationStream.plugin) PouchDB.plugin(replicationStream.plugin)
// @ts-ignore
PouchDB.adapter("writableStream", replicationStream.adapters.writableStream) PouchDB.adapter("writableStream", replicationStream.adapters.writableStream)
return PouchDB.defaults(POUCH_DB_DEFAULTS) return PouchDB.defaults(POUCH_DB_DEFAULTS) as PouchDB.Static
} }
exports.getAllDbs = async url => { export async function getAllDbs(url: string) {
const response = await fetch( const response = await fetch(
checkSlashesInUrl(encodeURI(`${url}/_all_dbs`)), checkSlashesInUrl(encodeURI(`${url}/_all_dbs`)),
{ {

View File

@ -1,2 +1,3 @@
process.env.NO_JS = "1" process.env.NO_JS = "1"
process.env.JS_BCRYPT = "1" process.env.JS_BCRYPT = "1"
process.env.DISABLE_JWT_WARNING = "1"

View File

@ -1,11 +0,0 @@
const AnalyticsClient = require("./analytics/Client")
const client = new AnalyticsClient()
exports.captureEvent = (event, properties) => {
client.capture({
distinctId: "cli",
event,
properties,
})
}

View File

@ -0,0 +1,11 @@
import { AnalyticsClient } from "./analytics/Client"
const client = new AnalyticsClient()
export function captureEvent(event: string, properties: any) {
client.capture({
distinctId: "cli",
event,
properties,
})
}

View File

@ -1,21 +1,21 @@
const util = require("util") import util from "util"
const exec = util.promisify(require("child_process").exec) const runCommand = util.promisify(require("child_process").exec)
exports.exec = async (command, dir = "./") => { export async function exec(command: string, dir = "./") {
const { stdout } = await exec(command, { cwd: dir }) const { stdout } = await runCommand(command, { cwd: dir })
return stdout return stdout
} }
exports.utilityInstalled = async utilName => { export async function utilityInstalled(utilName: string) {
try { try {
await exports.exec(`${utilName} --version`) await exec(`${utilName} --version`)
return true return true
} catch (err) { } catch (err) {
return false return false
} }
} }
exports.runPkgCommand = async (command, dir = "./") => { export async function runPkgCommand(command: string, dir = "./") {
const yarn = await exports.utilityInstalled("yarn") const yarn = await exports.utilityInstalled("yarn")
const npm = await exports.utilityInstalled("npm") const npm = await exports.utilityInstalled("npm")
if (!yarn && !npm) { if (!yarn && !npm) {

View File

@ -2,15 +2,16 @@ const { success } = require("../utils")
const { updateDockerComposeService } = require("./utils") const { updateDockerComposeService } = require("./utils")
const randomString = require("randomstring") const randomString = require("randomstring")
const { GENERATED_USER_EMAIL } = require("../constants") const { GENERATED_USER_EMAIL } = require("../constants")
import { DockerCompose } from "./types"
exports.generateUser = async (password, silent) => { export async function generateUser(password: string | null, silent: boolean) {
const email = GENERATED_USER_EMAIL const email = GENERATED_USER_EMAIL
if (!password) { if (!password) {
password = randomString.generate({ length: 6 }) password = randomString.generate({ length: 6 })
} }
updateDockerComposeService(service => { updateDockerComposeService((service: DockerCompose) => {
service.environment["BB_ADMIN_USER_EMAIL"] = email service.environment["BB_ADMIN_USER_EMAIL"] = email
service.environment["BB_ADMIN_USER_PASSWORD"] = password service.environment["BB_ADMIN_USER_PASSWORD"] = password as string
}) })
if (!silent) { if (!silent) {
console.log( console.log(

View File

@ -1,14 +1,14 @@
const Command = require("../structures/Command") import { Command } from "../structures/Command"
const { CommandWords } = require("../constants") import { CommandWord } from "../constants"
const { init } = require("./init") import { init } from "./init"
const { start } = require("./start") import { start } from "./start"
const { stop } = require("./stop") import { stop } from "./stop"
const { status } = require("./status") import { status } from "./status"
const { update } = require("./update") import { update } from "./update"
const { generateUser } = require("./genUser") import { generateUser } from "./genUser"
const { watchPlugins } = require("./watch") import { watchPlugins } from "./watch"
const command = new Command(`${CommandWords.HOSTING}`) export default new Command(`${CommandWord.HOSTING}`)
.addHelp("Controls self hosting on the Budibase platform.") .addHelp("Controls self hosting on the Budibase platform.")
.addSubOption( .addSubOption(
"--init [type]", "--init [type]",
@ -46,5 +46,3 @@ const command = new Command(`${CommandWords.HOSTING}`)
generateUser generateUser
) )
.addSubOption("--single", "Specify this with init to use the single image.") .addSubOption("--single", "Specify this with init to use the single image.")
exports.command = command

View File

@ -1,24 +1,25 @@
const { InitTypes, AnalyticsEvents } = require("../constants") import { InitType, AnalyticsEvent } from "../constants"
const { confirmation } = require("../questions") import { confirmation } from "../questions"
const { captureEvent } = require("../events") import { captureEvent } from "../events"
const makeFiles = require("./makeFiles") import * as makeFiles from "./makeFiles"
const axios = require("axios") import { parseEnv } from "../utils"
const { parseEnv } = require("../utils") import { checkDockerConfigured, downloadDockerCompose } from "./utils"
const { checkDockerConfigured, downloadFiles } = require("./utils") import { watchPlugins } from "./watch"
const { watchPlugins } = require("./watch") import { generateUser } from "./genUser"
const { generateUser } = require("./genUser") import fetch from "node-fetch"
const DO_USER_DATA_URL = "http://169.254.169.254/metadata/v1/user-data" const DO_USER_DATA_URL = "http://169.254.169.254/metadata/v1/user-data"
async function getInitConfig(type, isQuick, port) { async function getInitConfig(type: string, isQuick: boolean, port: number) {
const config = isQuick ? makeFiles.QUICK_CONFIG : {} const config: any = isQuick ? makeFiles.QUICK_CONFIG : {}
if (type === InitTypes.DIGITAL_OCEAN) { if (type === InitType.DIGITAL_OCEAN) {
try { try {
const output = await axios.get(DO_USER_DATA_URL) const output = await fetch(DO_USER_DATA_URL)
const response = parseEnv(output.data) const data = await output.text()
const response = parseEnv(data)
for (let [key, value] of Object.entries(makeFiles.ConfigMap)) { for (let [key, value] of Object.entries(makeFiles.ConfigMap)) {
if (response[key]) { if (response[key]) {
config[value] = response[key] config[value as string] = response[key]
} }
} }
} catch (err) { } catch (err) {
@ -32,7 +33,7 @@ async function getInitConfig(type, isQuick, port) {
return config return config
} }
exports.init = async opts => { export async function init(opts: any) {
let type, isSingle, watchDir, genUser, port, silent let type, isSingle, watchDir, genUser, port, silent
if (typeof opts === "string") { if (typeof opts === "string") {
type = opts type = opts
@ -44,7 +45,7 @@ exports.init = async opts => {
port = opts["port"] port = opts["port"]
silent = opts["silent"] silent = opts["silent"]
} }
const isQuick = type === InitTypes.QUICK || type === InitTypes.DIGITAL_OCEAN const isQuick = type === InitType.QUICK || type === InitType.DIGITAL_OCEAN
await checkDockerConfigured() await checkDockerConfigured()
if (!isQuick) { if (!isQuick) {
const shouldContinue = await confirmation( const shouldContinue = await confirmation(
@ -55,12 +56,12 @@ exports.init = async opts => {
return return
} }
} }
captureEvent(AnalyticsEvents.SelfHostInit, { captureEvent(AnalyticsEvent.SelfHostInit, {
type, type,
}) })
const config = await getInitConfig(type, isQuick, port) const config = await getInitConfig(type, isQuick, port)
if (!isSingle) { if (!isSingle) {
await downloadFiles() await downloadDockerCompose()
await makeFiles.makeEnv(config, silent) await makeFiles.makeEnv(config, silent)
} else { } else {
await makeFiles.makeSingleCompose(config, silent) await makeFiles.makeSingleCompose(config, silent)

View File

@ -1,15 +1,15 @@
const { number } = require("../questions") import { number } from "../questions"
const { success, stringifyToDotEnv } = require("../utils") import { success, stringifyToDotEnv } from "../utils"
const fs = require("fs") import fs from "fs"
const path = require("path") import path from "path"
import yaml from "yaml"
import { getAppService } from "./utils"
const randomString = require("randomstring") const randomString = require("randomstring")
const yaml = require("yaml")
const { getAppService } = require("./utils")
const SINGLE_IMAGE = "budibase/budibase:latest" const SINGLE_IMAGE = "budibase/budibase:latest"
const VOL_NAME = "budibase_data" const VOL_NAME = "budibase_data"
const COMPOSE_PATH = path.resolve("./docker-compose.yaml") export const COMPOSE_PATH = path.resolve("./docker-compose.yaml")
const ENV_PATH = path.resolve("./.env") export const ENV_PATH = path.resolve("./.env")
function getSecrets(opts = { single: false }) { function getSecrets(opts = { single: false }) {
const secrets = [ const secrets = [
@ -19,7 +19,7 @@ function getSecrets(opts = { single: false }) {
"REDIS_PASSWORD", "REDIS_PASSWORD",
"INTERNAL_API_KEY", "INTERNAL_API_KEY",
] ]
const obj = {} const obj: Record<string, string> = {}
secrets.forEach(secret => (obj[secret] = randomString.generate())) secrets.forEach(secret => (obj[secret] = randomString.generate()))
// setup couch creds separately // setup couch creds separately
if (opts && opts.single) { if (opts && opts.single) {
@ -32,7 +32,7 @@ function getSecrets(opts = { single: false }) {
return obj return obj
} }
function getSingleCompose(port) { function getSingleCompose(port: number) {
const singleComposeObj = { const singleComposeObj = {
version: "3", version: "3",
services: { services: {
@ -53,7 +53,7 @@ function getSingleCompose(port) {
return yaml.stringify(singleComposeObj) return yaml.stringify(singleComposeObj)
} }
function getEnv(port) { function getEnv(port: number) {
const partOne = stringifyToDotEnv({ const partOne = stringifyToDotEnv({
MAIN_PORT: port, MAIN_PORT: port,
}) })
@ -77,19 +77,21 @@ function getEnv(port) {
].join("\n") ].join("\n")
} }
exports.ENV_PATH = ENV_PATH export const ConfigMap = {
exports.COMPOSE_PATH = COMPOSE_PATH
module.exports.ConfigMap = {
MAIN_PORT: "port", MAIN_PORT: "port",
} }
module.exports.QUICK_CONFIG = { export const QUICK_CONFIG = {
key: "budibase", key: "budibase",
port: 10000, port: 10000,
} }
async function make(path, contentsFn, inputs = {}, silent) { async function make(
path: string,
contentsFn: Function,
inputs: any = {},
silent: boolean
) {
const port = const port =
inputs.port || inputs.port ||
(await number( (await number(
@ -107,15 +109,15 @@ async function make(path, contentsFn, inputs = {}, silent) {
} }
} }
module.exports.makeEnv = async (inputs = {}, silent) => { export async function makeEnv(inputs: any = {}, silent: boolean) {
return make(ENV_PATH, getEnv, inputs, silent) return make(ENV_PATH, getEnv, inputs, silent)
} }
module.exports.makeSingleCompose = async (inputs = {}, silent) => { export async function makeSingleCompose(inputs: any = {}, silent: boolean) {
return make(COMPOSE_PATH, getSingleCompose, inputs, silent) return make(COMPOSE_PATH, getSingleCompose, inputs, silent)
} }
module.exports.getEnvProperty = property => { export function getEnvProperty(property: string) {
const props = fs.readFileSync(ENV_PATH, "utf8").split(property) const props = fs.readFileSync(ENV_PATH, "utf8").split(property)
if (props[0].charAt(0) === "=") { if (props[0].charAt(0) === "=") {
property = props[0] property = props[0]
@ -125,7 +127,7 @@ module.exports.getEnvProperty = property => {
return property.split("=")[1].split("\n")[0] return property.split("=")[1].split("\n")[0]
} }
module.exports.getComposeProperty = property => { export function getComposeProperty(property: string) {
const { service } = getAppService(COMPOSE_PATH) const { service } = getAppService(COMPOSE_PATH)
if (property === "port" && Array.isArray(service.ports)) { if (property === "port" && Array.isArray(service.ports)) {
const port = service.ports[0] const port = service.ports[0]

View File

@ -1,14 +1,10 @@
const { import { checkDockerConfigured, checkInitComplete, handleError } from "./utils"
checkDockerConfigured, import { info, success } from "../utils"
checkInitComplete, import * as makeFiles from "./makeFiles"
handleError, import compose from "docker-compose"
} = require("./utils") import fs from "fs"
const { info, success } = require("../utils")
const makeFiles = require("./makeFiles")
const compose = require("docker-compose")
const fs = require("fs")
exports.start = async () => { export async function start() {
await checkDockerConfigured() await checkDockerConfigured()
checkInitComplete() checkInitComplete()
console.log( console.log(

View File

@ -1,12 +1,8 @@
const { import { checkDockerConfigured, checkInitComplete, handleError } from "./utils"
checkDockerConfigured, import { info } from "../utils"
checkInitComplete, import compose from "docker-compose"
handleError,
} = require("./utils")
const { info } = require("../utils")
const compose = require("docker-compose")
exports.status = async () => { export async function status() {
await checkDockerConfigured() await checkDockerConfigured()
checkInitComplete() checkInitComplete()
console.log(info("Budibase status")) console.log(info("Budibase status"))

View File

@ -1,12 +1,8 @@
const { import { checkDockerConfigured, checkInitComplete, handleError } from "./utils"
checkDockerConfigured, import { info, success } from "../utils"
checkInitComplete, import compose from "docker-compose"
handleError,
} = require("./utils")
const { info, success } = require("../utils")
const compose = require("docker-compose")
exports.stop = async () => { export async function stop() {
await checkDockerConfigured() await checkDockerConfigured()
checkInitComplete() checkInitComplete()
console.log(info("Stopping services, this may take a moment.")) console.log(info("Stopping services, this may take a moment."))

View File

@ -0,0 +1,4 @@
export interface DockerCompose {
environment: Record<string, string>
volumes: string[]
}

View File

@ -1,20 +1,20 @@
const { import {
checkDockerConfigured, checkDockerConfigured,
checkInitComplete, checkInitComplete,
downloadFiles, downloadDockerCompose,
handleError, handleError,
getServices, getServices,
} = require("./utils") } from "./utils"
const { confirmation } = require("../questions") import { confirmation } from "../questions"
const compose = require("docker-compose") import compose from "docker-compose"
const { COMPOSE_PATH } = require("./makeFiles") import { COMPOSE_PATH } from "./makeFiles"
const { info, success } = require("../utils") import { info, success } from "../utils"
const { start } = require("./start") import { start } from "./start"
const BB_COMPOSE_SERVICES = ["app-service", "worker-service", "proxy-service"] const BB_COMPOSE_SERVICES = ["app-service", "worker-service", "proxy-service"]
const BB_SINGLE_SERVICE = ["budibase"] const BB_SINGLE_SERVICE = ["budibase"]
exports.update = async () => { export async function update() {
const { services } = getServices(COMPOSE_PATH) const { services } = getServices(COMPOSE_PATH)
const isSingle = Object.keys(services).length === 1 const isSingle = Object.keys(services).length === 1
await checkDockerConfigured() await checkDockerConfigured()
@ -23,7 +23,7 @@ exports.update = async () => {
!isSingle && !isSingle &&
(await confirmation("Do you wish to update you docker-compose.yaml?")) (await confirmation("Do you wish to update you docker-compose.yaml?"))
) { ) {
await downloadFiles() await downloadDockerCompose()
} }
await handleError(async () => { await handleError(async () => {
const status = await compose.ps() const status = await compose.ps()

View File

@ -1,24 +1,24 @@
const { lookpath } = require("lookpath") import { lookpath } from "lookpath"
const fs = require("fs") import fs from "fs"
const makeFiles = require("./makeFiles") import * as makeFiles from "./makeFiles"
const { logErrorToFile, downloadFile, error } = require("../utils") import { logErrorToFile, downloadFile, error } from "../utils"
const yaml = require("yaml") import yaml from "yaml"
import { DockerCompose } from "./types"
const ERROR_FILE = "docker-error.log" const ERROR_FILE = "docker-error.log"
const FILE_URLS = [ const COMPOSE_URL =
"https://raw.githubusercontent.com/Budibase/budibase/master/hosting/docker-compose.yaml", "https://raw.githubusercontent.com/Budibase/budibase/master/hosting/docker-compose.yaml"
]
exports.downloadFiles = async () => { export async function downloadDockerCompose() {
const promises = [] const fileName = COMPOSE_URL.split("/").slice(-1)[0]
for (let url of FILE_URLS) { try {
const fileName = url.split("/").slice(-1)[0] await downloadFile(COMPOSE_URL, `./${fileName}`)
promises.push(downloadFile(url, `./${fileName}`)) } catch (err) {
console.error(error(`Failed to retrieve compose file - ${err}`))
} }
await Promise.all(promises)
} }
exports.checkDockerConfigured = async () => { export async function checkDockerConfigured() {
const error = const error =
"docker/docker-compose has not been installed, please follow instructions at: https://docs.budibase.com/docs/docker-compose" "docker/docker-compose has not been installed, please follow instructions at: https://docs.budibase.com/docs/docker-compose"
const docker = await lookpath("docker") const docker = await lookpath("docker")
@ -28,7 +28,7 @@ exports.checkDockerConfigured = async () => {
} }
} }
exports.checkInitComplete = () => { export function checkInitComplete() {
if ( if (
!fs.existsSync(makeFiles.ENV_PATH) && !fs.existsSync(makeFiles.ENV_PATH) &&
!fs.existsSync(makeFiles.COMPOSE_PATH) !fs.existsSync(makeFiles.COMPOSE_PATH)
@ -37,10 +37,10 @@ exports.checkInitComplete = () => {
} }
} }
exports.handleError = async func => { export async function handleError(func: Function) {
try { try {
await func() await func()
} catch (err) { } catch (err: any) {
if (err && err.err) { if (err && err.err) {
logErrorToFile(ERROR_FILE, err.err) logErrorToFile(ERROR_FILE, err.err)
} }
@ -48,14 +48,14 @@ exports.handleError = async func => {
} }
} }
exports.getServices = path => { export function getServices(path: string) {
const dockerYaml = fs.readFileSync(path, "utf8") const dockerYaml = fs.readFileSync(path, "utf8")
const parsedYaml = yaml.parse(dockerYaml) const parsedYaml = yaml.parse(dockerYaml)
return { yaml: parsedYaml, services: parsedYaml.services } return { yaml: parsedYaml, services: parsedYaml.services }
} }
exports.getAppService = path => { export function getAppService(path: string) {
const { yaml, services } = exports.getServices(path), const { yaml, services } = getServices(path),
serviceList = Object.keys(services) serviceList = Object.keys(services)
let service let service
if (services["app-service"]) { if (services["app-service"]) {
@ -66,14 +66,17 @@ exports.getAppService = path => {
return { yaml, service } return { yaml, service }
} }
exports.updateDockerComposeService = updateFn => { export function updateDockerComposeService(
// eslint-disable-next-line no-unused-vars
updateFn: (service: DockerCompose) => void
) {
const opts = ["docker-compose.yaml", "docker-compose.yml"] const opts = ["docker-compose.yaml", "docker-compose.yml"]
const dockerFilePath = opts.find(name => fs.existsSync(name)) const dockerFilePath = opts.find(name => fs.existsSync(name))
if (!dockerFilePath) { if (!dockerFilePath) {
console.log(error("Unable to locate docker-compose YAML.")) console.log(error("Unable to locate docker-compose YAML."))
return return
} }
const { yaml: parsedYaml, service } = exports.getAppService(dockerFilePath) const { yaml: parsedYaml, service } = getAppService(dockerFilePath)
if (!service) { if (!service) {
console.log( console.log(
error( error(

View File

@ -1,9 +1,10 @@
const { resolve } = require("path") import { resolve } from "path"
const fs = require("fs") import fs from "fs"
const { error, success } = require("../utils") import { error, success } from "../utils"
const { updateDockerComposeService } = require("./utils") import { updateDockerComposeService } from "./utils"
import { DockerCompose } from "./types"
exports.watchPlugins = async (pluginPath, silent) => { export async function watchPlugins(pluginPath: string, silent: boolean) {
const PLUGIN_PATH = "/plugins" const PLUGIN_PATH = "/plugins"
// get absolute path // get absolute path
pluginPath = resolve(pluginPath) pluginPath = resolve(pluginPath)
@ -15,7 +16,7 @@ exports.watchPlugins = async (pluginPath, silent) => {
) )
return return
} }
updateDockerComposeService(service => { updateDockerComposeService((service: DockerCompose) => {
// set environment variable // set environment variable
service.environment["PLUGINS_DIR"] = PLUGIN_PATH service.environment["PLUGINS_DIR"] = PLUGIN_PATH
// add volumes to parsed yaml // add volumes to parsed yaml

View File

@ -1,10 +1,10 @@
#!/usr/bin/env node #!/usr/bin/env node
require("./prebuilds") import "./prebuilds"
require("./environment") import "./environment"
import { getCommands } from "./options"
import { Command } from "commander"
import { getHelpDescription } from "./utils"
const json = require("../package.json") const json = require("../package.json")
const { getCommands } = require("./options")
const { Command } = require("commander")
const { getHelpDescription } = require("./utils")
// add hosting config // add hosting config
async function init() { async function init() {

View File

@ -1,8 +0,0 @@
const analytics = require("./analytics")
const hosting = require("./hosting")
const backups = require("./backups")
const plugins = require("./plugins")
exports.getCommands = () => {
return [hosting.command, analytics.command, backups.command, plugins.command]
}

View File

@ -0,0 +1,8 @@
import analytics from "./analytics"
import hosting from "./hosting"
import backups from "./backups"
import plugins from "./plugins"
export function getCommands() {
return [hosting, analytics, backups, plugins]
}

View File

@ -1,18 +1,22 @@
const Command = require("../structures/Command") import { Command } from "../structures/Command"
const { CommandWords, AnalyticsEvents, InitTypes } = require("../constants") import { CommandWord, AnalyticsEvent, InitType } from "../constants"
const { getSkeleton, fleshOutSkeleton } = require("./skeleton") import { getSkeleton, fleshOutSkeleton } from "./skeleton"
const questions = require("../questions") import * as questions from "../questions"
const fs = require("fs") import fs from "fs"
const { PLUGIN_TYPE_ARR } = require("@budibase/types") import { PluginType, PLUGIN_TYPE_ARR } from "@budibase/types"
const { plugins } = require("@budibase/backend-core") import { plugins } from "@budibase/backend-core"
const { runPkgCommand } = require("../exec") import { runPkgCommand } from "../exec"
const { join } = require("path") import { join } from "path"
const { success, error, info, moveDirectory } = require("../utils") import { success, error, info, moveDirectory } from "../utils"
const { captureEvent } = require("../events") import { captureEvent } from "../events"
import { GENERATED_USER_EMAIL } from "../constants"
import { init as hostingInit } from "../hosting/init"
import { start as hostingStart } from "../hosting/start"
const fp = require("find-free-port") const fp = require("find-free-port")
const { GENERATED_USER_EMAIL } = require("../constants")
const { init: hostingInit } = require("../hosting/init") type PluginOpts = {
const { start: hostingStart } = require("../hosting/start") init?: PluginType
}
function checkInPlugin() { function checkInPlugin() {
if (!fs.existsSync("package.json")) { if (!fs.existsSync("package.json")) {
@ -27,7 +31,7 @@ function checkInPlugin() {
} }
} }
async function askAboutTopLevel(name) { async function askAboutTopLevel(name: string) {
const files = fs.readdirSync(process.cwd()) const files = fs.readdirSync(process.cwd())
// we are in an empty git repo, don't ask // we are in an empty git repo, don't ask
if (files.find(file => file === ".git")) { if (files.find(file => file === ".git")) {
@ -45,8 +49,8 @@ async function askAboutTopLevel(name) {
} }
} }
async function init(opts) { async function init(opts: PluginOpts) {
const type = opts["init"] || opts const type = opts["init"] || (opts as PluginType)
if (!type || !PLUGIN_TYPE_ARR.includes(type)) { if (!type || !PLUGIN_TYPE_ARR.includes(type)) {
console.log( console.log(
error( error(
@ -82,7 +86,7 @@ async function init(opts) {
} else { } else {
console.log(info(`Plugin created in directory "${name}"`)) console.log(info(`Plugin created in directory "${name}"`))
} }
captureEvent(AnalyticsEvents.PluginInit, { captureEvent(AnalyticsEvent.PluginInit, {
type, type,
name, name,
description, description,
@ -109,7 +113,7 @@ async function verify() {
version = pkgJson.version version = pkgJson.version
plugins.validate(schemaJson) plugins.validate(schemaJson)
return { name, version } return { name, version }
} catch (err) { } catch (err: any) {
if (err && err.message && err.message.includes("not valid JSON")) { if (err && err.message && err.message.includes("not valid JSON")) {
console.log(error(`schema.json is not valid JSON: ${err.message}`)) console.log(error(`schema.json is not valid JSON: ${err.message}`))
} else { } else {
@ -120,7 +124,7 @@ async function verify() {
async function build() { async function build() {
const verified = await verify() const verified = await verify()
if (!verified.name) { if (!verified?.name) {
return return
} }
console.log(success("Verified!")) console.log(success("Verified!"))
@ -132,7 +136,7 @@ async function build() {
async function watch() { async function watch() {
const verified = await verify() const verified = await verify()
if (!verified.name) { if (!verified?.name) {
return return
} }
const output = join("dist", `${verified.name}-${verified.version}.tar.gz`) const output = join("dist", `${verified.name}-${verified.version}.tar.gz`)
@ -150,7 +154,7 @@ async function dev() {
const [port] = await fp(10000) const [port] = await fp(10000)
const password = "admin" const password = "admin"
await hostingInit({ await hostingInit({
init: InitTypes.QUICK, init: InitType.QUICK,
single: true, single: true,
watchPluginDir: pluginDir, watchPluginDir: pluginDir,
genUser: password, genUser: password,
@ -168,7 +172,7 @@ async function dev() {
console.log(success("Password: ") + info(password)) console.log(success("Password: ") + info(password))
} }
const command = new Command(`${CommandWords.PLUGIN}`) export default new Command(`${CommandWord.PLUGIN}`)
.addHelp( .addHelp(
"Custom plugins for Budibase, init, build and verify your components and datasources with this tool." "Custom plugins for Budibase, init, build and verify your components and datasources with this tool."
) )
@ -192,5 +196,3 @@ const command = new Command(`${CommandWords.PLUGIN}`)
"Run a development environment which automatically watches the current directory.", "Run a development environment which automatically watches the current directory.",
dev dev
) )
exports.command = command

View File

@ -1,21 +1,21 @@
const fetch = require("node-fetch") import fetch from "node-fetch"
import fs from "fs"
import os from "os"
import { join } from "path"
import { processStringSync } from "@budibase/string-templates"
const download = require("download") const download = require("download")
const fs = require("fs")
const os = require("os")
const { join } = require("path")
const tar = require("tar") const tar = require("tar")
const { processStringSync } = require("@budibase/string-templates")
const HBS_FILES = ["package.json.hbs", "schema.json.hbs", "README.md.hbs"] const HBS_FILES = ["package.json.hbs", "schema.json.hbs", "README.md.hbs"]
async function getSkeletonUrl(type) { async function getSkeletonUrl(type: string) {
const resp = await fetch( const resp = await fetch(
"https://api.github.com/repos/budibase/budibase-skeleton/releases/latest" "https://api.github.com/repos/budibase/budibase-skeleton/releases/latest"
) )
if (resp.status >= 300) { if (resp.status >= 300) {
throw new Error("Failed to retrieve skeleton metadata") throw new Error("Failed to retrieve skeleton metadata")
} }
const json = await resp.json() const json = (await resp.json()) as { assets: any[] }
for (let asset of json["assets"]) { for (let asset of json["assets"]) {
if (asset.name && asset.name.includes(type)) { if (asset.name && asset.name.includes(type)) {
return asset["browser_download_url"] return asset["browser_download_url"]
@ -24,7 +24,7 @@ async function getSkeletonUrl(type) {
throw new Error("No skeleton found in latest release.") throw new Error("No skeleton found in latest release.")
} }
exports.getSkeleton = async (type, name) => { export async function getSkeleton(type: string, name: string) {
const url = await getSkeletonUrl(type) const url = await getSkeletonUrl(type)
const tarballFile = join(os.tmpdir(), "skeleton.tar.gz") const tarballFile = join(os.tmpdir(), "skeleton.tar.gz")
@ -40,7 +40,12 @@ exports.getSkeleton = async (type, name) => {
fs.rmSync(tarballFile) fs.rmSync(tarballFile)
} }
exports.fleshOutSkeleton = async (type, name, description, version) => { export async function fleshOutSkeleton(
type: string,
name: string,
description: string,
version: string
) {
for (let file of HBS_FILES) { for (let file of HBS_FILES) {
const oldFile = join(name, file), const oldFile = join(name, file),
newFile = join(name, file.substring(0, file.length - 4)) newFile = join(name, file.substring(0, file.length - 4))

View File

@ -1,7 +1,8 @@
const os = require("os") import os from "os"
const { join } = require("path") import { join } from "path"
const fs = require("fs") import fs from "fs"
const { error } = require("./utils") import { error } from "./utils"
const PREBUILDS = "prebuilds" const PREBUILDS = "prebuilds"
const ARCH = `${os.platform()}-${os.arch()}` const ARCH = `${os.platform()}-${os.arch()}`
const PREBUILD_DIR = join(process.execPath, "..", PREBUILDS, ARCH) const PREBUILD_DIR = join(process.execPath, "..", PREBUILDS, ARCH)
@ -26,8 +27,8 @@ function checkForBinaries() {
} }
} }
function cleanup(evt) { function cleanup(evt?: number) {
if (!isNaN(evt)) { if (evt && !isNaN(evt)) {
return return
} }
if (evt) { if (evt) {

View File

@ -1,6 +1,6 @@
const inquirer = require("inquirer") const inquirer = require("inquirer")
exports.confirmation = async question => { export async function confirmation(question: string) {
const config = { const config = {
type: "confirm", type: "confirm",
message: question, message: question,
@ -10,8 +10,8 @@ exports.confirmation = async question => {
return (await inquirer.prompt(config)).confirmation return (await inquirer.prompt(config)).confirmation
} }
exports.string = async (question, defaultString = null) => { export async function string(question: string, defaultString?: string) {
const config = { const config: any = {
type: "input", type: "input",
name: "string", name: "string",
message: question, message: question,
@ -22,12 +22,12 @@ exports.string = async (question, defaultString = null) => {
return (await inquirer.prompt(config)).string return (await inquirer.prompt(config)).string
} }
exports.number = async (question, defaultNumber) => { export async function number(question: string, defaultNumber?: number) {
const config = { const config: any = {
type: "input", type: "input",
name: "number", name: "number",
message: question, message: question,
validate: value => { validate: (value: string) => {
let valid = !isNaN(parseFloat(value)) let valid = !isNaN(parseFloat(value))
return valid || "Please enter a number" return valid || "Please enter a number"
}, },

View File

@ -1,19 +1,31 @@
const { import {
getSubHelpDescription, getSubHelpDescription,
getHelpDescription, getHelpDescription,
error, error,
capitaliseFirstLetter, capitaliseFirstLetter,
} = require("../utils") } from "../utils"
class Command { type CommandOpt = {
constructor(command, func = null) { command: string
help: string
func?: Function
extras: any[]
}
export class Command {
command: string
opts: CommandOpt[]
func?: Function
help?: string
constructor(command: string, func?: Function) {
// if there are options, need to just get the command name // if there are options, need to just get the command name
this.command = command this.command = command
this.opts = [] this.opts = []
this.func = func this.func = func
} }
convertToCommander(lookup) { convertToCommander(lookup: string) {
const parts = lookup.toLowerCase().split("-") const parts = lookup.toLowerCase().split("-")
// camel case, separate out first // camel case, separate out first
const first = parts.shift() const first = parts.shift()
@ -22,21 +34,26 @@ class Command {
.join("") .join("")
} }
addHelp(help) { addHelp(help: string) {
this.help = help this.help = help
return this return this
} }
addSubOption(command, help, func, extras = []) { addSubOption(
command: string,
help: string,
func?: Function,
extras: any[] = []
) {
this.opts.push({ command, help, func, extras }) this.opts.push({ command, help, func, extras })
return this return this
} }
configure(program) { configure(program: any) {
const thisCmd = this const thisCmd = this
let command = program.command(thisCmd.command) let command = program.command(thisCmd.command)
if (this.help) { if (this.help) {
command = command.description(getHelpDescription(thisCmd.help)) command = command.description(getHelpDescription(thisCmd.help!))
} }
for (let opt of thisCmd.opts) { for (let opt of thisCmd.opts) {
command = command.option(opt.command, getSubHelpDescription(opt.help)) command = command.option(opt.command, getSubHelpDescription(opt.help))
@ -45,7 +62,7 @@ class Command {
"--help", "--help",
getSubHelpDescription(`Get help with ${this.command} options`) getSubHelpDescription(`Get help with ${this.command} options`)
) )
command.action(async options => { command.action(async (options: Record<string, string>) => {
try { try {
let executed = false, let executed = false,
found = false found = false
@ -53,7 +70,7 @@ class Command {
let lookup = opt.command.split(" ")[0].replace("--", "") let lookup = opt.command.split(" ")[0].replace("--", "")
// need to handle how commander converts watch-plugin-dir to watchPluginDir // need to handle how commander converts watch-plugin-dir to watchPluginDir
lookup = this.convertToCommander(lookup) lookup = this.convertToCommander(lookup)
found = !executed && options[lookup] found = !executed && !!options[lookup]
if (found && opt.func) { if (found && opt.func) {
const input = const input =
Object.keys(options).length > 1 ? options : options[lookup] Object.keys(options).length > 1 ? options : options[lookup]
@ -69,11 +86,9 @@ class Command {
console.log(error(`Unknown ${this.command} option.`)) console.log(error(`Unknown ${this.command} option.`))
command.help() command.help()
} }
} catch (err) { } catch (err: any) {
console.log(error(err)) console.log(error(err))
} }
}) })
} }
} }
module.exports = Command

View File

@ -3,7 +3,9 @@ const path = require("path")
const os = require("os") const os = require("os")
const { error } = require("../utils") const { error } = require("../utils")
class ConfigManager { export class ConfigManager {
path: string
constructor() { constructor() {
this.path = path.join(os.homedir(), ".budibase.json") this.path = path.join(os.homedir(), ".budibase.json")
if (!fs.existsSync(this.path)) { if (!fs.existsSync(this.path)) {
@ -24,26 +26,24 @@ class ConfigManager {
} }
} }
set config(json) { set config(json: any) {
fs.writeFileSync(this.path, JSON.stringify(json)) fs.writeFileSync(this.path, JSON.stringify(json))
} }
getValue(key) { getValue(key: string) {
return this.config[key] return this.config[key]
} }
setValue(key, value) { setValue(key: string, value: any) {
this.config = { this.config = {
...this.config, ...this.config,
[key]: value, [key]: value,
} }
} }
removeKey(key) { removeKey(key: string) {
const updated = { ...this.config } const updated = { ...this.config }
delete updated[key] delete updated[key]
this.config = updated this.config = updated
} }
} }
module.exports = ConfigManager

View File

@ -1,106 +0,0 @@
const chalk = require("chalk")
const fs = require("fs")
const axios = require("axios")
const path = require("path")
const progress = require("cli-progress")
const { join } = require("path")
exports.downloadFile = async (url, filePath) => {
filePath = path.resolve(filePath)
const writer = fs.createWriteStream(filePath)
const response = await axios({
url,
method: "GET",
responseType: "stream",
})
response.data.pipe(writer)
return new Promise((resolve, reject) => {
writer.on("finish", resolve)
writer.on("error", reject)
})
}
exports.httpCall = async (url, method) => {
const response = await axios({
url,
method,
})
return response.data
}
exports.getHelpDescription = string => {
return chalk.cyan(string)
}
exports.getSubHelpDescription = string => {
return chalk.green(string)
}
exports.error = error => {
return chalk.red(`Error - ${error}`)
}
exports.success = success => {
return chalk.green(success)
}
exports.info = info => {
return chalk.cyan(info)
}
exports.logErrorToFile = (file, error) => {
fs.writeFileSync(path.resolve(`./${file}`), `Budibase Error\n${error}`)
}
exports.parseEnv = env => {
const lines = env.toString().split("\n")
let result = {}
for (const line of lines) {
const match = line.match(/^([^=:#]+?)[=:](.*)/)
if (match) {
result[match[1].trim()] = match[2].trim()
}
}
return result
}
exports.progressBar = total => {
const bar = new progress.SingleBar({}, progress.Presets.shades_classic)
bar.start(total, 0)
return bar
}
exports.checkSlashesInUrl = url => {
return url.replace(/(https?:\/\/)|(\/)+/g, "$1$2")
}
exports.moveDirectory = (oldPath, newPath) => {
const files = fs.readdirSync(oldPath)
// check any file exists already
for (let file of files) {
if (fs.existsSync(join(newPath, file))) {
throw new Error(
"Unable to remove top level directory - some skeleton files already exist."
)
}
}
for (let file of files) {
fs.renameSync(join(oldPath, file), join(newPath, file))
}
fs.rmdirSync(oldPath)
}
exports.capitaliseFirstLetter = str => {
return str.charAt(0).toUpperCase() + str.slice(1)
}
exports.stringifyToDotEnv = json => {
let str = ""
for (let [key, value] of Object.entries(json)) {
str += `${key}=${value}\n`
}
return str
}

112
packages/cli/src/utils.ts Normal file
View File

@ -0,0 +1,112 @@
import chalk from "chalk"
import fs from "fs"
import path from "path"
import { join } from "path"
import fetch from "node-fetch"
const progress = require("cli-progress")
export function downloadFile(url: string, filePath: string) {
return new Promise((resolve, reject) => {
filePath = path.resolve(filePath)
fetch(url, {
method: "GET",
})
.then(response => {
const writer = fs.createWriteStream(filePath)
if (response.body) {
response.body.pipe(writer)
response.body.on("end", resolve)
response.body.on("error", reject)
} else {
throw new Error(
`Unable to retrieve docker-compose file - ${response.status}`
)
}
})
.catch(err => {
throw err
})
})
}
export async function httpCall(url: string, method: string) {
const response = await fetch(url, {
method,
})
return response.body
}
export function getHelpDescription(str: string) {
return chalk.cyan(str)
}
export function getSubHelpDescription(str: string) {
return chalk.green(str)
}
export function error(err: string | number) {
process.exitCode = -1
return chalk.red(`Error - ${err}`)
}
export function success(str: string) {
return chalk.green(str)
}
export function info(str: string) {
return chalk.cyan(str)
}
export function logErrorToFile(file: string, error: string) {
fs.writeFileSync(path.resolve(`./${file}`), `Budibase Error\n${error}`)
}
export function parseEnv(env: string) {
const lines = env.toString().split("\n")
let result: Record<string, string> = {}
for (const line of lines) {
const match = line.match(/^([^=:#]+?)[=:](.*)/)
if (match) {
result[match[1].trim()] = match[2].trim()
}
}
return result
}
export function progressBar(total: number) {
const bar = new progress.SingleBar({}, progress.Presets.shades_classic)
bar.start(total, 0)
return bar
}
export function checkSlashesInUrl(url: string) {
return url.replace(/(https?:\/\/)|(\/)+/g, "$1$2")
}
export function moveDirectory(oldPath: string, newPath: string) {
const files = fs.readdirSync(oldPath)
// check any file exists already
for (let file of files) {
if (fs.existsSync(join(newPath, file))) {
throw new Error(
"Unable to remove top level directory - some skeleton files already exist."
)
}
}
for (let file of files) {
fs.renameSync(join(oldPath, file), join(newPath, file))
}
fs.rmdirSync(oldPath)
}
export function capitaliseFirstLetter(str: string) {
return str.charAt(0).toUpperCase() + str.slice(1)
}
export function stringifyToDotEnv(json: Record<string, string | number>) {
let str = ""
for (let [key, value] of Object.entries(json)) {
str += `${key}=${value}\n`
}
return str
}

3
packages/cli/start.sh Executable file
View File

@ -0,0 +1,3 @@
#!/bin/bash
dir="$(dirname -- "$(readlink -f "${BASH_SOURCE}")")"
${dir}/node_modules/ts-node/dist/bin.js ${dir}/src/index.ts $@

View File

@ -0,0 +1,24 @@
{
"compilerOptions": {
"target": "es6",
"module": "commonjs",
"lib": ["es2020"],
"strict": true,
"noImplicitAny": true,
"esModuleInterop": true,
"resolveJsonModule": true,
"incremental": true,
"types": [ "node", "jest" ],
"outDir": "dist",
"skipLibCheck": true
},
"include": [
"src/**/*"
],
"exclude": [
"node_modules",
"dist",
"**/*.spec.ts",
"**/*.spec.js"
]
}

View File

@ -0,0 +1,30 @@
{
"extends": "./tsconfig.build.json",
"compilerOptions": {
"composite": true,
"declaration": true,
"sourceMap": true,
"baseUrl": ".",
"paths": {
"@budibase/types": ["../types/src"],
"@budibase/backend-core": ["../backend-core/src"],
"@budibase/backend-core/*": ["../backend-core/*"],
}
},
"ts-node": {
"require": ["tsconfig-paths/register"],
"swc": true
},
"references": [
{ "path": "../types" },
{ "path": "../backend-core" },
],
"include": [
"src/**/*",
"package.json"
],
"exclude": [
"node_modules",
"dist"
]
}

View File

@ -9,6 +9,13 @@
dependencies: dependencies:
"@babel/highlight" "^7.10.4" "@babel/highlight" "^7.10.4"
"@babel/code-frame@^7.12.13":
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/generator@7.18.2": "@babel/generator@7.18.2":
version "7.18.2" version "7.18.2"
resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.18.2.tgz#33873d6f89b21efe2da63fe554460f3df1c5880d" resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.18.2.tgz#33873d6f89b21efe2da63fe554460f3df1c5880d"
@ -33,7 +40,7 @@
resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz#7eea834cf32901ffdc1a7ee555e2f9c27e249ca2" resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz#7eea834cf32901ffdc1a7ee555e2f9c27e249ca2"
integrity sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w== integrity sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==
"@babel/highlight@^7.10.4": "@babel/highlight@^7.10.4", "@babel/highlight@^7.18.6":
version "7.18.6" version "7.18.6"
resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.18.6.tgz#81158601e93e2563795adcbfbdf5d64be3f2ecdf" resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.18.6.tgz#81158601e93e2563795adcbfbdf5d64be3f2ecdf"
integrity sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g== integrity sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==
@ -71,6 +78,13 @@
"@babel/helper-validator-identifier" "^7.19.1" "@babel/helper-validator-identifier" "^7.19.1"
to-fast-properties "^2.0.0" to-fast-properties "^2.0.0"
"@cspotcode/source-map-support@^0.8.0":
version "0.8.1"
resolved "https://registry.yarnpkg.com/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz#00629c35a688e05a88b1cda684fb9d5e73f000a1"
integrity sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==
dependencies:
"@jridgewell/trace-mapping" "0.3.9"
"@eslint/eslintrc@^0.4.3": "@eslint/eslintrc@^0.4.3":
version "0.4.3" version "0.4.3"
resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-0.4.3.tgz#9e42981ef035beb3dd49add17acb96e8ff6f394c" resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-0.4.3.tgz#9e42981ef035beb3dd49add17acb96e8ff6f394c"
@ -112,6 +126,50 @@
resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz#b520529ec21d8e5945a1851dfd1c32e94e39ff45" resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz#b520529ec21d8e5945a1851dfd1c32e94e39ff45"
integrity sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA== integrity sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==
"@jest/create-cache-key-function@^27.4.2":
version "27.5.1"
resolved "https://registry.yarnpkg.com/@jest/create-cache-key-function/-/create-cache-key-function-27.5.1.tgz#7448fae15602ea95c828f5eceed35c202a820b31"
integrity sha512-dmH1yW+makpTSURTy8VzdUwFnfQh1G8R+DxO2Ho2FFmBbKFEVm+3jWdvFhE2VqB/LATCTokkP0dotjyQyw5/AQ==
dependencies:
"@jest/types" "^27.5.1"
"@jest/expect-utils@^29.4.3":
version "29.4.3"
resolved "https://registry.yarnpkg.com/@jest/expect-utils/-/expect-utils-29.4.3.tgz#95ce4df62952f071bcd618225ac7c47eaa81431e"
integrity sha512-/6JWbkxHOP8EoS8jeeTd9dTfc9Uawi+43oLKHfp6zzux3U2hqOOVnV3ai4RpDYHOccL6g+5nrxpoc8DmJxtXVQ==
dependencies:
jest-get-type "^29.4.3"
"@jest/schemas@^29.4.3":
version "29.4.3"
resolved "https://registry.yarnpkg.com/@jest/schemas/-/schemas-29.4.3.tgz#39cf1b8469afc40b6f5a2baaa146e332c4151788"
integrity sha512-VLYKXQmtmuEz6IxJsrZwzG9NvtkQsWNnWMsKxqWNu3+CnfzJQhp0WDDKWLVV9hLKr0l3SLLFRqcYHjhtyuDVxg==
dependencies:
"@sinclair/typebox" "^0.25.16"
"@jest/types@^27.5.1":
version "27.5.1"
resolved "https://registry.yarnpkg.com/@jest/types/-/types-27.5.1.tgz#3c79ec4a8ba61c170bf937bcf9e98a9df175ec80"
integrity sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==
dependencies:
"@types/istanbul-lib-coverage" "^2.0.0"
"@types/istanbul-reports" "^3.0.0"
"@types/node" "*"
"@types/yargs" "^16.0.0"
chalk "^4.0.0"
"@jest/types@^29.4.3":
version "29.4.3"
resolved "https://registry.yarnpkg.com/@jest/types/-/types-29.4.3.tgz#9069145f4ef09adf10cec1b2901b2d390031431f"
integrity sha512-bPYfw8V65v17m2Od1cv44FH+SiKW7w2Xu7trhcdTLUmSv85rfKsP+qXSjO4KGJr4dtPSzl/gvslZBXctf1qGEA==
dependencies:
"@jest/schemas" "^29.4.3"
"@types/istanbul-lib-coverage" "^2.0.0"
"@types/istanbul-reports" "^3.0.0"
"@types/node" "*"
"@types/yargs" "^17.0.8"
chalk "^4.0.0"
"@jridgewell/gen-mapping@^0.3.0": "@jridgewell/gen-mapping@^0.3.0":
version "0.3.2" version "0.3.2"
resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz#c1aedc61e853f2bb9f5dfe6d4442d3b565b253b9" resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz#c1aedc61e853f2bb9f5dfe6d4442d3b565b253b9"
@ -121,7 +179,7 @@
"@jridgewell/sourcemap-codec" "^1.4.10" "@jridgewell/sourcemap-codec" "^1.4.10"
"@jridgewell/trace-mapping" "^0.3.9" "@jridgewell/trace-mapping" "^0.3.9"
"@jridgewell/resolve-uri@3.1.0": "@jridgewell/resolve-uri@3.1.0", "@jridgewell/resolve-uri@^3.0.3":
version "3.1.0" version "3.1.0"
resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz#2203b118c157721addfe69d47b70465463066d78" resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz#2203b118c157721addfe69d47b70465463066d78"
integrity sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w== integrity sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==
@ -136,6 +194,14 @@
resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz#add4c98d341472a289190b424efbdb096991bb24" resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz#add4c98d341472a289190b424efbdb096991bb24"
integrity sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw== integrity sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==
"@jridgewell/trace-mapping@0.3.9":
version "0.3.9"
resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz#6534fd5933a53ba7cbf3a17615e273a0d1273ff9"
integrity sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==
dependencies:
"@jridgewell/resolve-uri" "^3.0.3"
"@jridgewell/sourcemap-codec" "^1.4.10"
"@jridgewell/trace-mapping@^0.3.9": "@jridgewell/trace-mapping@^0.3.9":
version "0.3.17" version "0.3.17"
resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.17.tgz#793041277af9073b0951a7fe0f0d8c4c98c36985" resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.17.tgz#793041277af9073b0951a7fe0f0d8c4c98c36985"
@ -182,11 +248,332 @@
resolved "https://registry.yarnpkg.com/@sideway/pinpoint/-/pinpoint-2.0.0.tgz#cff8ffadc372ad29fd3f78277aeb29e632cc70df" resolved "https://registry.yarnpkg.com/@sideway/pinpoint/-/pinpoint-2.0.0.tgz#cff8ffadc372ad29fd3f78277aeb29e632cc70df"
integrity sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ== integrity sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ==
"@sinclair/typebox@^0.25.16":
version "0.25.24"
resolved "https://registry.yarnpkg.com/@sinclair/typebox/-/typebox-0.25.24.tgz#8c7688559979f7079aacaf31aa881c3aa410b718"
integrity sha512-XJfwUVUKDHF5ugKwIcxEgc9k8b7HbznCp6eUfWgu710hMPNIO4aw4/zB5RogDQz8nd6gyCDpU9O/m6qYEWY6yQ==
"@sindresorhus/is@^0.7.0": "@sindresorhus/is@^0.7.0":
version "0.7.0" version "0.7.0"
resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-0.7.0.tgz#9a06f4f137ee84d7df0460c1fdb1135ffa6c50fd" resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-0.7.0.tgz#9a06f4f137ee84d7df0460c1fdb1135ffa6c50fd"
integrity sha512-ONhaKPIufzzrlNbqtWFFd+jlnemX6lJAgq9ZeiZtS7I1PIf/la7CW4m83rTXRnVnsMbW2k56pGYu7AUFJD9Pow== integrity sha512-ONhaKPIufzzrlNbqtWFFd+jlnemX6lJAgq9ZeiZtS7I1PIf/la7CW4m83rTXRnVnsMbW2k56pGYu7AUFJD9Pow==
"@swc/core-darwin-arm64@1.3.37":
version "1.3.37"
resolved "https://registry.yarnpkg.com/@swc/core-darwin-arm64/-/core-darwin-arm64-1.3.37.tgz#a92e075ae35f18a64aaf3823ea175f03564f8da1"
integrity sha512-iIyVqqioUpVeT/hbBVfkrsjfCyL4idNH+LVKGmoTAWaTTSB0+UNhNuA7Wh2CqIHWh1Mv7IlumitWPcqsVDdoEw==
"@swc/core-darwin-x64@1.3.37":
version "1.3.37"
resolved "https://registry.yarnpkg.com/@swc/core-darwin-x64/-/core-darwin-x64-1.3.37.tgz#a3cc06c87140a2ca0b8e7ef1f3d5cc34dd080429"
integrity sha512-dao5nXPWKxtaxqak4ZkRyBoApNIelW/glantQhPhj0FjMjuIQc+v03ldJ8XDByWOG+6xuVUTheANCtEccxoQBw==
"@swc/core-linux-arm-gnueabihf@1.3.37":
version "1.3.37"
resolved "https://registry.yarnpkg.com/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.3.37.tgz#f7d8f8523830c6be653f608839d4bd5598457f1f"
integrity sha512-/mVrc8H/f062CUkqKGmBiil2VIYu4mKawHxERfeP1y38X5K/OwjG5s9MgO9TVxy+Ly6vejwj70kRhSa3hVp1Bw==
"@swc/core-linux-arm64-gnu@1.3.37":
version "1.3.37"
resolved "https://registry.yarnpkg.com/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.3.37.tgz#b162febd9de14fb08000c722b063be2bb5aefa6b"
integrity sha512-eRQ3KaZI0j5LidTfOIi/kUVOOMuVmw1HCdt/Z1TAUKoHMLVxY8xcJ3pEE3/+ednI60EmHpwpJRs6LelXyL6uzQ==
"@swc/core-linux-arm64-musl@1.3.37":
version "1.3.37"
resolved "https://registry.yarnpkg.com/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.3.37.tgz#3b1a628e880fbb1a5e2a7a46d42e8aa878c6bfdd"
integrity sha512-w2BRLODyxNQY2rfHZMZ5ir6QrrnGBPlnIslTrgKmVbn1OjZoxUCtuqhrYnCmybaAc4DOkeH02TqynEFXrm+EMw==
"@swc/core-linux-x64-gnu@1.3.37":
version "1.3.37"
resolved "https://registry.yarnpkg.com/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.3.37.tgz#ed443ad77dc90e415267d02a38e4113047b2d3d8"
integrity sha512-CfoH8EsZJZ9kunjMUjBNYD5fFuO86zw+K/o4wEw72Yg6ZEiqPmeIlCKU8tpTv4sK+CbhUXrmVzMB5tqsb2jALQ==
"@swc/core-linux-x64-musl@1.3.37":
version "1.3.37"
resolved "https://registry.yarnpkg.com/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.3.37.tgz#de607a4985458bd6e8b0e40f0d62d0e26bd8df1e"
integrity sha512-9YPrHYNdoG7PK11gV51GfL45biI2dic+YTqHUDKyykemsD7Ot1zUFX7Ty//pdvpKcKSff6SrHbfFACD5ziNirA==
"@swc/core-win32-arm64-msvc@1.3.37":
version "1.3.37"
resolved "https://registry.yarnpkg.com/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.3.37.tgz#d5851a47d7df183929b9746d56f76c282f940e6a"
integrity sha512-h17Ek8/wCDje6BrXOvCXBM80oBRmTSMMdLyt87whTl5xqYlWYYs9oQIzZndNRTlNpTgjGO8Ns2eo4kwVxIkBIA==
"@swc/core-win32-ia32-msvc@1.3.37":
version "1.3.37"
resolved "https://registry.yarnpkg.com/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.3.37.tgz#06ad7016f61b56aec4abf60eab3a91b786f9e294"
integrity sha512-1BR175E1olGy/zdt94cgdb6ps/lBNissAOaxyBk8taFpcjy3zpdP30yAoH0GIsC6isnZ5JfArbOJNRXXO5tE0Q==
"@swc/core-win32-x64-msvc@1.3.37":
version "1.3.37"
resolved "https://registry.yarnpkg.com/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.3.37.tgz#60139a7089003a7447a4efef9704ae8fde21995e"
integrity sha512-1siDQ7dccQ1pesJmgAL3BUBbRPtfbNInOWnZOkiie/DfFqGQ117QKnCVyjUvwFKfTQx1+3UUTDmMSlRd00SlXg==
"@swc/core@^1.3.25":
version "1.3.37"
resolved "https://registry.yarnpkg.com/@swc/core/-/core-1.3.37.tgz#644653fa7deb20c7c342e7fd019c7abc44ecf1bf"
integrity sha512-VOFlEQ1pReOM73N9A7R8rt561GU8Rxsq833jiimWDUB2sXEN3V6n6wFTgYmZuMz2T4/R0cQA1nV48KkaT4gkFw==
optionalDependencies:
"@swc/core-darwin-arm64" "1.3.37"
"@swc/core-darwin-x64" "1.3.37"
"@swc/core-linux-arm-gnueabihf" "1.3.37"
"@swc/core-linux-arm64-gnu" "1.3.37"
"@swc/core-linux-arm64-musl" "1.3.37"
"@swc/core-linux-x64-gnu" "1.3.37"
"@swc/core-linux-x64-musl" "1.3.37"
"@swc/core-win32-arm64-msvc" "1.3.37"
"@swc/core-win32-ia32-msvc" "1.3.37"
"@swc/core-win32-x64-msvc" "1.3.37"
"@swc/jest@^0.2.24":
version "0.2.24"
resolved "https://registry.yarnpkg.com/@swc/jest/-/jest-0.2.24.tgz#35d9377ede049613cd5fdd6c24af2b8dcf622875"
integrity sha512-fwgxQbM1wXzyKzl1+IW0aGrRvAA8k0Y3NxFhKigbPjOJ4mCKnWEcNX9HQS3gshflcxq8YKhadabGUVfdwjCr6Q==
dependencies:
"@jest/create-cache-key-function" "^27.4.2"
jsonc-parser "^3.2.0"
"@tsconfig/node10@^1.0.7":
version "1.0.9"
resolved "https://registry.yarnpkg.com/@tsconfig/node10/-/node10-1.0.9.tgz#df4907fc07a886922637b15e02d4cebc4c0021b2"
integrity sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==
"@tsconfig/node12@^1.0.7":
version "1.0.11"
resolved "https://registry.yarnpkg.com/@tsconfig/node12/-/node12-1.0.11.tgz#ee3def1f27d9ed66dac6e46a295cffb0152e058d"
integrity sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==
"@tsconfig/node14@^1.0.0":
version "1.0.3"
resolved "https://registry.yarnpkg.com/@tsconfig/node14/-/node14-1.0.3.tgz#e4386316284f00b98435bf40f72f75a09dabf6c1"
integrity sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==
"@tsconfig/node16@^1.0.2":
version "1.0.3"
resolved "https://registry.yarnpkg.com/@tsconfig/node16/-/node16-1.0.3.tgz#472eaab5f15c1ffdd7f8628bd4c4f753995ec79e"
integrity sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ==
"@types/debug@*":
version "4.1.7"
resolved "https://registry.yarnpkg.com/@types/debug/-/debug-4.1.7.tgz#7cc0ea761509124709b8b2d1090d8f6c17aadb82"
integrity sha512-9AonUzyTjXXhEOa0DnqpzZi6VHlqKMswga9EXjpXnnqxwLtdvPPtlO8evrI5D9S6asFRCQ6v+wpiUKbw+vKqyg==
dependencies:
"@types/ms" "*"
"@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0":
version "2.0.4"
resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz#8467d4b3c087805d63580480890791277ce35c44"
integrity sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==
"@types/istanbul-lib-report@*":
version "3.0.0"
resolved "https://registry.yarnpkg.com/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz#c14c24f18ea8190c118ee7562b7ff99a36552686"
integrity sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg==
dependencies:
"@types/istanbul-lib-coverage" "*"
"@types/istanbul-reports@^3.0.0":
version "3.0.1"
resolved "https://registry.yarnpkg.com/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz#9153fe98bba2bd565a63add9436d6f0d7f8468ff"
integrity sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==
dependencies:
"@types/istanbul-lib-report" "*"
"@types/jest@^29.4.0":
version "29.4.0"
resolved "https://registry.yarnpkg.com/@types/jest/-/jest-29.4.0.tgz#a8444ad1704493e84dbf07bb05990b275b3b9206"
integrity sha512-VaywcGQ9tPorCX/Jkkni7RWGFfI11whqzs8dvxF41P17Z+z872thvEvlIbznjPJ02kl1HMX3LmLOonsj2n7HeQ==
dependencies:
expect "^29.0.0"
pretty-format "^29.0.0"
"@types/ms@*":
version "0.7.31"
resolved "https://registry.yarnpkg.com/@types/ms/-/ms-0.7.31.tgz#31b7ca6407128a3d2bbc27fe2d21b345397f6197"
integrity sha512-iiUgKzV9AuaEkZqkOLDIvlQiL6ltuZd9tGcW3gwpnX8JbuiuhFlEGmmFXEXkN50Cvq7Os88IY2v0dkDqXYWVgA==
"@types/node-fetch@2.6.1":
version "2.6.1"
resolved "https://registry.yarnpkg.com/@types/node-fetch/-/node-fetch-2.6.1.tgz#8f127c50481db65886800ef496f20bbf15518975"
integrity sha512-oMqjURCaxoSIsHSr1E47QHzbmzNR5rK8McHuNb11BOM9cHcIK3Avy0s/b2JlXHoQGTYS3NsvWzV1M0iK7l0wbA==
dependencies:
"@types/node" "*"
form-data "^3.0.0"
"@types/node@*":
version "18.14.4"
resolved "https://registry.yarnpkg.com/@types/node/-/node-18.14.4.tgz#0e64ec0b35a772e1e3d849f9a0ff61782d0cb647"
integrity sha512-VhCw7I7qO2X49+jaKcAUwi3rR+hbxT5VcYF493+Z5kMLI0DL568b7JI4IDJaxWFH0D/xwmGJNoXisyX+w7GH/g==
"@types/pouchdb-adapter-cordova-sqlite@*":
version "1.0.1"
resolved "https://registry.yarnpkg.com/@types/pouchdb-adapter-cordova-sqlite/-/pouchdb-adapter-cordova-sqlite-1.0.1.tgz#49e5ee6df7cc0c23196fcb340f43a560e74eb1d6"
integrity sha512-nqlXpW1ho3KBg1mUQvZgH2755y3z/rw4UA7ZJCPMRTHofxGMY8izRVw5rHBL4/7P615or0J2udpRYxgkT3D02g==
dependencies:
"@types/pouchdb-core" "*"
"@types/pouchdb-adapter-fruitdown@*":
version "6.1.3"
resolved "https://registry.yarnpkg.com/@types/pouchdb-adapter-fruitdown/-/pouchdb-adapter-fruitdown-6.1.3.tgz#9b140ad9645cc56068728acf08ec19ac0046658e"
integrity sha512-Wz1Z1JLOW1hgmFQjqnSkmyyfH7by/iWb4abKn684WMvQfmxx6BxKJpJ4+eulkVPQzzgMMSgU1MpnQOm9FgRkbw==
dependencies:
"@types/pouchdb-core" "*"
"@types/pouchdb-adapter-http@*":
version "6.1.3"
resolved "https://registry.yarnpkg.com/@types/pouchdb-adapter-http/-/pouchdb-adapter-http-6.1.3.tgz#6e592d5f48deb6274a21ddac1498dd308096bcf3"
integrity sha512-9Z4TLbF/KJWy/D2sWRPBA+RNU0odQimfdvlDX+EY7rGcd3aVoH8qjD/X0Xcd/0dfBH5pKrNIMFFQgW/TylRCmA==
dependencies:
"@types/pouchdb-core" "*"
"@types/pouchdb-adapter-idb@*":
version "6.1.4"
resolved "https://registry.yarnpkg.com/@types/pouchdb-adapter-idb/-/pouchdb-adapter-idb-6.1.4.tgz#cb9a18864585d600820cd325f007614c5c3989cd"
integrity sha512-KIAXbkF4uYUz0ZwfNEFLtEkK44mEWopAsD76UhucH92XnJloBysav+TjI4FFfYQyTjoW3S1s6V+Z14CUJZ0F6w==
dependencies:
"@types/pouchdb-core" "*"
"@types/pouchdb-adapter-leveldb@*":
version "6.1.3"
resolved "https://registry.yarnpkg.com/@types/pouchdb-adapter-leveldb/-/pouchdb-adapter-leveldb-6.1.3.tgz#17c7e75d75b992050bca15991e97fba575c61bb3"
integrity sha512-ex8NFqQGFwEpFi7AaZ5YofmuemfZNsL3nTFZBUCAKYMBkazQij1pe2ILLStSvJr0XS0qxgXjCEW19T5Wqiiskg==
dependencies:
"@types/pouchdb-core" "*"
"@types/pouchdb-adapter-localstorage@*":
version "6.1.3"
resolved "https://registry.yarnpkg.com/@types/pouchdb-adapter-localstorage/-/pouchdb-adapter-localstorage-6.1.3.tgz#0dde02ba6b9d6073a295a20196563942ba9a54bd"
integrity sha512-oor040tye1KKiGLWYtIy7rRT7C2yoyX3Tf6elEJRpjOA7Ja/H8lKc4LaSh9ATbptIcES6MRqZDxtp7ly9hsW3Q==
dependencies:
"@types/pouchdb-core" "*"
"@types/pouchdb-adapter-memory@*":
version "6.1.3"
resolved "https://registry.yarnpkg.com/@types/pouchdb-adapter-memory/-/pouchdb-adapter-memory-6.1.3.tgz#9eabdbc890fcf58960ee8b68b8685f837e75c844"
integrity sha512-gVbsIMzDzgZYThFVT4eVNsmuZwVm/4jDxP1sjlgc3qtDIxbtBhGgyNfcskwwz9Zu5Lv1avkDsIWvcxQhnvRlHg==
dependencies:
"@types/pouchdb-core" "*"
"@types/pouchdb-adapter-node-websql@*":
version "6.1.3"
resolved "https://registry.yarnpkg.com/@types/pouchdb-adapter-node-websql/-/pouchdb-adapter-node-websql-6.1.3.tgz#aa18bc68af8cf509acd12c400010dcd5fab2243d"
integrity sha512-F/P+os6Jsa7CgHtH64+Z0HfwIcj0hIRB5z8gNhF7L7dxPWoAfkopK5H2gydrP3sQrlGyN4WInF+UJW/Zu1+FKg==
dependencies:
"@types/pouchdb-adapter-websql" "*"
"@types/pouchdb-core" "*"
"@types/pouchdb-adapter-websql@*":
version "6.1.4"
resolved "https://registry.yarnpkg.com/@types/pouchdb-adapter-websql/-/pouchdb-adapter-websql-6.1.4.tgz#359fbe42ccac0ac90b492ddb8c32fafd0aa96d79"
integrity sha512-zMJQCtXC40hBsIDRn0GhmpeGMK0f9l/OGWfLguvczROzxxcOD7REI+e6SEmX7gJKw5JuMvlfuHzkQwjmvSJbtg==
dependencies:
"@types/pouchdb-core" "*"
"@types/pouchdb-browser@*":
version "6.1.3"
resolved "https://registry.yarnpkg.com/@types/pouchdb-browser/-/pouchdb-browser-6.1.3.tgz#8f33d6ef58d6817d1f6d36979148a1c7f63244d8"
integrity sha512-EdYowrWxW9SWBMX/rux2eq7dbHi5Zeyzz+FF/IAsgQKnUxgeCO5VO2j4zTzos0SDyJvAQU+EYRc11r7xGn5tvA==
dependencies:
"@types/pouchdb-adapter-http" "*"
"@types/pouchdb-adapter-idb" "*"
"@types/pouchdb-adapter-websql" "*"
"@types/pouchdb-core" "*"
"@types/pouchdb-mapreduce" "*"
"@types/pouchdb-replication" "*"
"@types/pouchdb-core@*":
version "7.0.10"
resolved "https://registry.yarnpkg.com/@types/pouchdb-core/-/pouchdb-core-7.0.10.tgz#d1ea1549e7fad6cb579f71459b1bc27252e06a5a"
integrity sha512-mKhjLlWWXyV3PTTjDhzDV1kc2dolO7VYFa75IoKM/hr8Er9eo8RIbS7mJLfC8r/C3p6ihZu9yZs1PWC1LQ0SOA==
dependencies:
"@types/debug" "*"
"@types/pouchdb-find" "*"
"@types/pouchdb-find@*":
version "7.3.0"
resolved "https://registry.yarnpkg.com/@types/pouchdb-find/-/pouchdb-find-7.3.0.tgz#b917030e9f4bf6e56bf8c3b9fe4b2a25e989009a"
integrity sha512-sFPli5tBjGX9UfXioik1jUzPdcN84eV82n0lmEFuoPepWqkLjQcyri0eOa++HYOaNPyMDhKFBqEALEZivK2dRg==
dependencies:
"@types/pouchdb-core" "*"
"@types/pouchdb-http@*":
version "6.1.3"
resolved "https://registry.yarnpkg.com/@types/pouchdb-http/-/pouchdb-http-6.1.3.tgz#09576c0d409da1f8dee34ec5b768415e2472ea52"
integrity sha512-0e9E5SqNOyPl/3FnEIbENssB4FlJsNYuOy131nxrZk36S+y1R/6qO7ZVRypWpGTqBWSuVd7gCsq2UDwO/285+w==
dependencies:
"@types/pouchdb-adapter-http" "*"
"@types/pouchdb-core" "*"
"@types/pouchdb-mapreduce@*":
version "6.1.7"
resolved "https://registry.yarnpkg.com/@types/pouchdb-mapreduce/-/pouchdb-mapreduce-6.1.7.tgz#9ab32d1e0f234f1bf6d1e4c5d7e216e9e23ac0a3"
integrity sha512-WzBwm7tmO9QhfRzVaWT4v6JQSS/fG2OoUDrWrhX87rPe2Pn6laPvdK5li6myNRxCoI/l5e8Jd+oYBAFnaiFucA==
dependencies:
"@types/pouchdb-core" "*"
"@types/pouchdb-node@*":
version "6.1.4"
resolved "https://registry.yarnpkg.com/@types/pouchdb-node/-/pouchdb-node-6.1.4.tgz#5214c0169fcfd2237d373380bbd65a934feb5dfb"
integrity sha512-wnTCH8X1JOPpNOfVhz8HW0AvmdHh6pt40MuRj0jQnK7QEHsHS79WujsKTKSOF8QXtPwpvCNSsI7ut7H7tfxxJQ==
dependencies:
"@types/pouchdb-adapter-http" "*"
"@types/pouchdb-adapter-leveldb" "*"
"@types/pouchdb-core" "*"
"@types/pouchdb-mapreduce" "*"
"@types/pouchdb-replication" "*"
"@types/pouchdb-replication@*":
version "6.4.4"
resolved "https://registry.yarnpkg.com/@types/pouchdb-replication/-/pouchdb-replication-6.4.4.tgz#743406c90f13a988fa3e346ea74ce40acd170d00"
integrity sha512-BsE5LKpjJK4iAf6Fx5kyrMw+33V+Ip7uWldUnU2BYrrvtR+MLD22dcImm7DZN1st2wPPb91i0XEnQzvP0w1C/Q==
dependencies:
"@types/pouchdb-core" "*"
"@types/pouchdb-find" "*"
"@types/pouchdb@^6.4.0":
version "6.4.0"
resolved "https://registry.yarnpkg.com/@types/pouchdb/-/pouchdb-6.4.0.tgz#f9c41ca64b23029f9bf2eb4bf6956e6431cb79f8"
integrity sha512-eGCpX+NXhd5VLJuJMzwe3L79fa9+IDTrAG3CPaf4s/31PD56hOrhDJTSmRELSXuiqXr6+OHzzP0PldSaWsFt7w==
dependencies:
"@types/pouchdb-adapter-cordova-sqlite" "*"
"@types/pouchdb-adapter-fruitdown" "*"
"@types/pouchdb-adapter-http" "*"
"@types/pouchdb-adapter-idb" "*"
"@types/pouchdb-adapter-leveldb" "*"
"@types/pouchdb-adapter-localstorage" "*"
"@types/pouchdb-adapter-memory" "*"
"@types/pouchdb-adapter-node-websql" "*"
"@types/pouchdb-adapter-websql" "*"
"@types/pouchdb-browser" "*"
"@types/pouchdb-core" "*"
"@types/pouchdb-http" "*"
"@types/pouchdb-mapreduce" "*"
"@types/pouchdb-node" "*"
"@types/pouchdb-replication" "*"
"@types/stack-utils@^2.0.0":
version "2.0.1"
resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-2.0.1.tgz#20f18294f797f2209b5f65c8e3b5c8e8261d127c"
integrity sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==
"@types/yargs-parser@*":
version "21.0.0"
resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-21.0.0.tgz#0c60e537fa790f5f9472ed2776c2b71ec117351b"
integrity sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==
"@types/yargs@^16.0.0":
version "16.0.5"
resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-16.0.5.tgz#12cc86393985735a283e387936398c2f9e5f88e3"
integrity sha512-AxO/ADJOBFJScHbWhq2xAhlWP24rY4aCEG/NFaMvbT3X2MgRsLjhjQwsn0Zi5zn0LG9jUhCCZMeX9Dkuw6k+vQ==
dependencies:
"@types/yargs-parser" "*"
"@types/yargs@^17.0.8":
version "17.0.22"
resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-17.0.22.tgz#7dd37697691b5f17d020f3c63e7a45971ff71e9a"
integrity sha512-pet5WJ9U8yPVRhkwuEIp5ktAeAqRZOq4UdAyWLWzxbtpyXnzbtLdKiXAjJzi/KLmPGS9wk86lUFWZFN6sISo4g==
dependencies:
"@types/yargs-parser" "*"
abort-controller@3.0.0: abort-controller@3.0.0:
version "3.0.0" version "3.0.0"
resolved "https://registry.yarnpkg.com/abort-controller/-/abort-controller-3.0.0.tgz#eaf54d53b62bae4138e809ca225c8439a6efb392" resolved "https://registry.yarnpkg.com/abort-controller/-/abort-controller-3.0.0.tgz#eaf54d53b62bae4138e809ca225c8439a6efb392"
@ -221,11 +608,21 @@ acorn-jsx@^5.3.1:
resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937"
integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==
acorn-walk@^8.1.1:
version "8.2.0"
resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.2.0.tgz#741210f2e2426454508853a2f44d0ab83b7f69c1"
integrity sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==
acorn@^7.4.0: acorn@^7.4.0:
version "7.4.1" version "7.4.1"
resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa" resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa"
integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A== integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==
acorn@^8.4.1:
version "8.8.2"
resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.8.2.tgz#1b2f25db02af965399b9776b0c2c391276d37c4a"
integrity sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==
agent-base@6: agent-base@6:
version "6.0.2" version "6.0.2"
resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-6.0.2.tgz#49fff58577cfee3f37176feab4c22e00f86d7f77" resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-6.0.2.tgz#49fff58577cfee3f37176feab4c22e00f86d7f77"
@ -289,6 +686,11 @@ ansi-styles@^4.0.0, ansi-styles@^4.1.0:
dependencies: dependencies:
color-convert "^2.0.1" color-convert "^2.0.1"
ansi-styles@^5.0.0:
version "5.2.0"
resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-5.2.0.tgz#07449690ad45777d1924ac2abb2fc8895dba836b"
integrity sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==
aproba@^1.0.3: aproba@^1.0.3:
version "1.2.0" version "1.2.0"
resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a" resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a"
@ -309,6 +711,11 @@ are-we-there-yet@~1.1.2:
delegates "^1.0.0" delegates "^1.0.0"
readable-stream "^2.0.6" readable-stream "^2.0.6"
arg@^4.1.0:
version "4.1.3"
resolved "https://registry.yarnpkg.com/arg/-/arg-4.1.3.tgz#269fc7ad5b8e42cb63c896d5666017261c144089"
integrity sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==
argparse@^1.0.7: argparse@^1.0.7:
version "1.0.10" version "1.0.10"
resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911"
@ -351,6 +758,11 @@ astral-regex@^2.0.0:
resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-2.0.0.tgz#483143c567aeed4785759c0865786dc77d7d2e31" resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-2.0.0.tgz#483143c567aeed4785759c0865786dc77d7d2e31"
integrity sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ== integrity sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==
asynckit@^0.4.0:
version "0.4.0"
resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79"
integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==
at-least-node@^1.0.0: at-least-node@^1.0.0:
version "1.0.0" version "1.0.0"
resolved "https://registry.yarnpkg.com/at-least-node/-/at-least-node-1.0.0.tgz#602cd4b46e844ad4effc92a8011a3c46e0238dc2" resolved "https://registry.yarnpkg.com/at-least-node/-/at-least-node-1.0.0.tgz#602cd4b46e844ad4effc92a8011a3c46e0238dc2"
@ -519,6 +931,11 @@ chownr@^2.0.0:
resolved "https://registry.yarnpkg.com/chownr/-/chownr-2.0.0.tgz#15bfbe53d2eab4cf70f18a8cd68ebe5b3cb1dece" resolved "https://registry.yarnpkg.com/chownr/-/chownr-2.0.0.tgz#15bfbe53d2eab4cf70f18a8cd68ebe5b3cb1dece"
integrity sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ== integrity sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==
ci-info@^3.2.0:
version "3.8.0"
resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-3.8.0.tgz#81408265a5380c929f0bc665d62256628ce9ef91"
integrity sha512-eXTggHWSooYhq49F2opQhuHWgzucfF2YgODK4e1566GQs5BIfP30B0oenwBJHfWxAs2fyPB1s7Mg949zLf61Yw==
cli-cursor@^3.1.0: cli-cursor@^3.1.0:
version "3.1.0" version "3.1.0"
resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-3.1.0.tgz#264305a7ae490d1d03bf0c9ba7c925d1753af307" resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-3.1.0.tgz#264305a7ae490d1d03bf0c9ba7c925d1753af307"
@ -588,6 +1005,13 @@ color-name@~1.1.4:
resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2"
integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==
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"
command-line-args@^5.2.0: command-line-args@^5.2.0:
version "5.2.1" version "5.2.1"
resolved "https://registry.yarnpkg.com/command-line-args/-/command-line-args-5.2.1.tgz#c44c32e437a57d7c51157696893c5909e9cec42e" resolved "https://registry.yarnpkg.com/command-line-args/-/command-line-args-5.2.1.tgz#c44c32e437a57d7c51157696893c5909e9cec42e"
@ -658,6 +1082,11 @@ core-util-is@~1.0.0:
resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.3.tgz#a6042d3634c2b27e9328f837b965fac83808db85" resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.3.tgz#a6042d3634c2b27e9328f837b965fac83808db85"
integrity sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ== integrity sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==
create-require@^1.1.0:
version "1.1.1"
resolved "https://registry.yarnpkg.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333"
integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==
cross-spawn@^7.0.2: cross-spawn@^7.0.2:
version "7.0.3" version "7.0.3"
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6"
@ -774,6 +1203,11 @@ deferred-leveldown@~5.3.0:
abstract-leveldown "~6.2.1" abstract-leveldown "~6.2.1"
inherits "^2.0.3" inherits "^2.0.3"
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==
delegates@^1.0.0: delegates@^1.0.0:
version "1.0.0" version "1.0.0"
resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a"
@ -784,6 +1218,16 @@ detect-libc@^1.0.3:
resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b" resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b"
integrity sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg== integrity sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==
diff-sequences@^29.4.3:
version "29.4.3"
resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-29.4.3.tgz#9314bc1fabe09267ffeca9cbafc457d8499a13f2"
integrity sha512-ofrBgwpPhCD85kMKtE9RYFFq6OC1A89oW2vvgWZNCwxrUpRUILopY7lsYyMDSjc8g6U6aiO0Qubg6r4Wgt5ZnA==
diff@^4.0.1:
version "4.0.2"
resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d"
integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==
dir-glob@^3.0.1: dir-glob@^3.0.1:
version "3.0.1" version "3.0.1"
resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f" resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f"
@ -888,6 +1332,11 @@ escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5:
resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg== integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==
escape-string-regexp@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz#a30304e99daa32e23b2fd20f51babd07cffca344"
integrity sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==
escape-string-regexp@^4.0.0: escape-string-regexp@^4.0.0:
version "4.0.0" version "4.0.0"
resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34"
@ -1017,6 +1466,17 @@ expand-template@^2.0.3:
resolved "https://registry.yarnpkg.com/expand-template/-/expand-template-2.0.3.tgz#6e14b3fcee0f3a6340ecb57d2e8918692052a47c" resolved "https://registry.yarnpkg.com/expand-template/-/expand-template-2.0.3.tgz#6e14b3fcee0f3a6340ecb57d2e8918692052a47c"
integrity sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg== integrity sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==
expect@^29.0.0:
version "29.4.3"
resolved "https://registry.yarnpkg.com/expect/-/expect-29.4.3.tgz#5e47757316df744fe3b8926c3ae8a3ebdafff7fe"
integrity sha512-uC05+Q7eXECFpgDrHdXA4k2rpMyStAYPItEDLyQDo5Ta7fVkJnNA/4zh/OIVkVVNZ1oOK1PipQoyNjuZ6sz6Dg==
dependencies:
"@jest/expect-utils" "^29.4.3"
jest-get-type "^29.4.3"
jest-matcher-utils "^29.4.3"
jest-message-util "^29.4.3"
jest-util "^29.4.3"
ext-list@^2.0.0: ext-list@^2.0.0:
version "2.2.2" version "2.2.2"
resolved "https://registry.yarnpkg.com/ext-list/-/ext-list-2.2.2.tgz#0b98e64ed82f5acf0f2931babf69212ef52ddd37" resolved "https://registry.yarnpkg.com/ext-list/-/ext-list-2.2.2.tgz#0b98e64ed82f5acf0f2931babf69212ef52ddd37"
@ -1191,6 +1651,15 @@ follow-redirects@^1.14.0:
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.1.tgz#0ca6a452306c9b276e4d3127483e29575e207ad5" resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.1.tgz#0ca6a452306c9b276e4d3127483e29575e207ad5"
integrity sha512-yLAMQs+k0b2m7cVxpS1VKJVvoz7SS9Td1zss3XRwXj+ZDH00RJgnuLx7E44wx02kQLrdM3aOOy+FpzS7+8OizA== integrity sha512-yLAMQs+k0b2m7cVxpS1VKJVvoz7SS9Td1zss3XRwXj+ZDH00RJgnuLx7E44wx02kQLrdM3aOOy+FpzS7+8OizA==
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"
from2@^2.1.1, from2@^2.3.0: from2@^2.1.1, from2@^2.3.0:
version "2.3.0" version "2.3.0"
resolved "https://registry.yarnpkg.com/from2/-/from2-2.3.0.tgz#8bfb5502bde4a4d36cfdeea007fcca21d7e382af" resolved "https://registry.yarnpkg.com/from2/-/from2-2.3.0.tgz#8bfb5502bde4a4d36cfdeea007fcca21d7e382af"
@ -1348,7 +1817,7 @@ got@^8.3.1:
url-parse-lax "^3.0.0" url-parse-lax "^3.0.0"
url-to-options "^1.0.1" url-to-options "^1.0.1"
graceful-fs@^4.1.10, graceful-fs@^4.1.6, graceful-fs@^4.2.0: graceful-fs@^4.1.10, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.9:
version "4.2.10" version "4.2.10"
resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.10.tgz#147d3a006da4ca3ce14728c7aefc287c367d7a6c" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.10.tgz#147d3a006da4ca3ce14728c7aefc287c367d7a6c"
integrity sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA== integrity sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==
@ -1604,6 +2073,58 @@ isurl@^1.0.0-alpha5:
has-to-string-tag-x "^1.2.0" has-to-string-tag-x "^1.2.0"
is-object "^1.0.1" is-object "^1.0.1"
jest-diff@^29.4.3:
version "29.4.3"
resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-29.4.3.tgz#42f4eb34d0bf8c0fb08b0501069b87e8e84df347"
integrity sha512-YB+ocenx7FZ3T5O9lMVMeLYV4265socJKtkwgk/6YUz/VsEzYDkiMuMhWzZmxm3wDRQvayJu/PjkjjSkjoHsCA==
dependencies:
chalk "^4.0.0"
diff-sequences "^29.4.3"
jest-get-type "^29.4.3"
pretty-format "^29.4.3"
jest-get-type@^29.4.3:
version "29.4.3"
resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-29.4.3.tgz#1ab7a5207c995161100b5187159ca82dd48b3dd5"
integrity sha512-J5Xez4nRRMjk8emnTpWrlkyb9pfRQQanDrvWHhsR1+VUfbwxi30eVcZFlcdGInRibU4G5LwHXpI7IRHU0CY+gg==
jest-matcher-utils@^29.4.3:
version "29.4.3"
resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-29.4.3.tgz#ea68ebc0568aebea4c4213b99f169ff786df96a0"
integrity sha512-TTciiXEONycZ03h6R6pYiZlSkvYgT0l8aa49z/DLSGYjex4orMUcafuLXYyyEDWB1RKglq00jzwY00Ei7yFNVg==
dependencies:
chalk "^4.0.0"
jest-diff "^29.4.3"
jest-get-type "^29.4.3"
pretty-format "^29.4.3"
jest-message-util@^29.4.3:
version "29.4.3"
resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-29.4.3.tgz#65b5280c0fdc9419503b49d4f48d4999d481cb5b"
integrity sha512-1Y8Zd4ZCN7o/QnWdMmT76If8LuDv23Z1DRovBj/vcSFNlGCJGoO8D1nJDw1AdyAGUk0myDLFGN5RbNeJyCRGCw==
dependencies:
"@babel/code-frame" "^7.12.13"
"@jest/types" "^29.4.3"
"@types/stack-utils" "^2.0.0"
chalk "^4.0.0"
graceful-fs "^4.2.9"
micromatch "^4.0.4"
pretty-format "^29.4.3"
slash "^3.0.0"
stack-utils "^2.0.3"
jest-util@^29.4.3:
version "29.4.3"
resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-29.4.3.tgz#851a148e23fc2b633c55f6dad2e45d7f4579f496"
integrity sha512-ToSGORAz4SSSoqxDSylWX8JzkOQR7zoBtNRsA7e+1WUX5F8jrOwaNpuh1YfJHJKDHXLHmObv5eOjejUd+/Ws+Q==
dependencies:
"@jest/types" "^29.4.3"
"@types/node" "*"
chalk "^4.0.0"
ci-info "^3.2.0"
graceful-fs "^4.2.9"
picomatch "^2.2.3"
joi@17.6.0: joi@17.6.0:
version "17.6.0" version "17.6.0"
resolved "https://registry.yarnpkg.com/joi/-/joi-17.6.0.tgz#0bb54f2f006c09a96e75ce687957bd04290054b2" resolved "https://registry.yarnpkg.com/joi/-/joi-17.6.0.tgz#0bb54f2f006c09a96e75ce687957bd04290054b2"
@ -1663,6 +2184,11 @@ json-stringify-safe@^5.0.1:
resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb"
integrity sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA== integrity sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==
jsonc-parser@^3.2.0:
version "3.2.0"
resolved "https://registry.yarnpkg.com/jsonc-parser/-/jsonc-parser-3.2.0.tgz#31ff3f4c2b9793f89c67212627c51c6394f88e76"
integrity sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==
jsonfile@^6.0.1: jsonfile@^6.0.1:
version "6.1.0" version "6.1.0"
resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-6.1.0.tgz#bc55b2634793c679ec6403094eb13698a6ec0aae" resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-6.1.0.tgz#bc55b2634793c679ec6403094eb13698a6ec0aae"
@ -1857,6 +2383,11 @@ make-dir@^2.1.0:
pify "^4.0.1" pify "^4.0.1"
semver "^5.6.0" semver "^5.6.0"
make-error@^1.1.1:
version "1.3.6"
resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2"
integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==
md5@^2.3.0: md5@^2.3.0:
version "2.3.0" version "2.3.0"
resolved "https://registry.yarnpkg.com/md5/-/md5-2.3.0.tgz#c3da9a6aae3a30b46b7b0c349b87b110dc3bda4f" resolved "https://registry.yarnpkg.com/md5/-/md5-2.3.0.tgz#c3da9a6aae3a30b46b7b0c349b87b110dc3bda4f"
@ -1879,11 +2410,18 @@ micromatch@^4.0.4:
braces "^3.0.2" braces "^3.0.2"
picomatch "^2.3.1" picomatch "^2.3.1"
mime-db@^1.28.0: mime-db@1.52.0, mime-db@^1.28.0:
version "1.52.0" version "1.52.0"
resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70"
integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== 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"
mimic-fn@^2.1.0: mimic-fn@^2.1.0:
version "2.1.0" version "2.1.0"
resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b"
@ -1991,7 +2529,7 @@ node-abi@^2.21.0:
dependencies: dependencies:
semver "^5.4.1" semver "^5.4.1"
node-fetch@2, node-fetch@2.6.7, node-fetch@^2.6.6: node-fetch@2.6.7, node-fetch@^2.6.6:
version "2.6.7" version "2.6.7"
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.7.tgz#24de9fba827e3b4ae44dc8b20256a379160052ad" resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.7.tgz#24de9fba827e3b4ae44dc8b20256a379160052ad"
integrity sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ== integrity sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==
@ -2137,7 +2675,7 @@ pend@~1.2.0:
resolved "https://registry.yarnpkg.com/pend/-/pend-1.2.0.tgz#7a57eb550a6783f9115331fcf4663d5c8e007a50" resolved "https://registry.yarnpkg.com/pend/-/pend-1.2.0.tgz#7a57eb550a6783f9115331fcf4663d5c8e007a50"
integrity sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg== integrity sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==
picomatch@^2.3.1: picomatch@^2.2.3, picomatch@^2.3.1:
version "2.3.1" version "2.3.1"
resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42"
integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==
@ -2300,6 +2838,15 @@ prepend-http@^2.0.0:
resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-2.0.0.tgz#e92434bfa5ea8c19f41cdfd401d741a3c819d897" resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-2.0.0.tgz#e92434bfa5ea8c19f41cdfd401d741a3c819d897"
integrity sha512-ravE6m9Atw9Z/jjttRUZ+clIXogdghyZAuWJ3qEzjT+jI/dL1ifAqhZeC5VHzQp1MSt1+jxKkFNemj/iO7tVUA== integrity sha512-ravE6m9Atw9Z/jjttRUZ+clIXogdghyZAuWJ3qEzjT+jI/dL1ifAqhZeC5VHzQp1MSt1+jxKkFNemj/iO7tVUA==
pretty-format@^29.0.0, pretty-format@^29.4.3:
version "29.4.3"
resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-29.4.3.tgz#25500ada21a53c9e8423205cf0337056b201244c"
integrity sha512-cvpcHTc42lcsvOOAzd3XuNWTcvk1Jmnzqeu+WsOuiPmxUJTnkbAcFNsRKvEpBEUFVUgy/GTZLulZDcDEi+CIlA==
dependencies:
"@jest/schemas" "^29.4.3"
ansi-styles "^5.0.0"
react-is "^18.0.0"
printj@^1.3.0: printj@^1.3.0:
version "1.3.1" version "1.3.1"
resolved "https://registry.yarnpkg.com/printj/-/printj-1.3.1.tgz#9af6b1d55647a1587ac44f4c1654a4b95b8e12cb" resolved "https://registry.yarnpkg.com/printj/-/printj-1.3.1.tgz#9af6b1d55647a1587ac44f4c1654a4b95b8e12cb"
@ -2374,6 +2921,11 @@ rc@^1.2.7:
minimist "^1.2.0" minimist "^1.2.0"
strip-json-comments "~2.0.1" strip-json-comments "~2.0.1"
react-is@^18.0.0:
version "18.2.0"
resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.2.0.tgz#199431eeaaa2e09f86427efbb4f1473edb47609b"
integrity sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==
readable-stream@1.1.14, readable-stream@^1.0.27-1: readable-stream@1.1.14, readable-stream@^1.0.27-1:
version "1.1.14" version "1.1.14"
resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.1.14.tgz#7cf4c54ef648e3813084c636dd2079e166c081d9" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.1.14.tgz#7cf4c54ef648e3813084c636dd2079e166c081d9"
@ -2656,6 +3208,13 @@ sprintf-js@~1.0.2:
resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c"
integrity sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g== integrity sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==
stack-utils@^2.0.3:
version "2.0.6"
resolved "https://registry.yarnpkg.com/stack-utils/-/stack-utils-2.0.6.tgz#aaf0748169c02fc33c8232abccf933f54a1cc34f"
integrity sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==
dependencies:
escape-string-regexp "^2.0.0"
stream-meter@^1.0.4: stream-meter@^1.0.4:
version "1.0.4" version "1.0.4"
resolved "https://registry.yarnpkg.com/stream-meter/-/stream-meter-1.0.4.tgz#52af95aa5ea760a2491716704dbff90f73afdd1d" resolved "https://registry.yarnpkg.com/stream-meter/-/stream-meter-1.0.4.tgz#52af95aa5ea760a2491716704dbff90f73afdd1d"
@ -2911,6 +3470,25 @@ trim-repeated@^1.0.0:
dependencies: dependencies:
escape-string-regexp "^1.0.2" escape-string-regexp "^1.0.2"
ts-node@^10.9.1:
version "10.9.1"
resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-10.9.1.tgz#e73de9102958af9e1f0b168a6ff320e25adcff4b"
integrity sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==
dependencies:
"@cspotcode/source-map-support" "^0.8.0"
"@tsconfig/node10" "^1.0.7"
"@tsconfig/node12" "^1.0.7"
"@tsconfig/node14" "^1.0.0"
"@tsconfig/node16" "^1.0.2"
acorn "^8.4.1"
acorn-walk "^8.1.1"
arg "^4.1.0"
create-require "^1.1.0"
diff "^4.0.1"
make-error "^1.1.1"
v8-compile-cache-lib "^3.0.1"
yn "3.1.1"
tslib@^1.9.0: tslib@^1.9.0:
version "1.14.1" version "1.14.1"
resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00"
@ -2940,6 +3518,11 @@ type-fest@^0.21.3:
resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.21.3.tgz#d260a24b0198436e133fa26a524a6d65fa3b2e37" resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.21.3.tgz#d260a24b0198436e133fa26a524a6d65fa3b2e37"
integrity sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w== integrity sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==
typescript@4.7.3:
version "4.7.3"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.7.3.tgz#8364b502d5257b540f9de4c40be84c98e23a129d"
integrity sha512-WOkT3XYvrpXx4vMMqlD+8R8R37fZkjyLGlxavMc4iB8lrl8L0DeTcHbYgw/v0N/z9wAFsgBhcsF0ruoySS22mA==
typical@^4.0.0: typical@^4.0.0:
version "4.0.0" version "4.0.0"
resolved "https://registry.yarnpkg.com/typical/-/typical-4.0.0.tgz#cbeaff3b9d7ae1e2bbfaf5a4e6f11eccfde94fc4" resolved "https://registry.yarnpkg.com/typical/-/typical-4.0.0.tgz#cbeaff3b9d7ae1e2bbfaf5a4e6f11eccfde94fc4"
@ -3015,6 +3598,11 @@ uuid@8.3.2, uuid@^8.3.2:
resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2" resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2"
integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==
v8-compile-cache-lib@^3.0.1:
version "3.0.1"
resolved "https://registry.yarnpkg.com/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz#6336e8d71965cb3d35a1bbb7868445a7c05264bf"
integrity sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==
v8-compile-cache@^2.0.3: v8-compile-cache@^2.0.3:
version "2.3.0" version "2.3.0"
resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz#2de19618c66dc247dcfb6f99338035d8245a2cee" resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz#2de19618c66dc247dcfb6f99338035d8245a2cee"
@ -3131,3 +3719,8 @@ yauzl@^2.4.2:
dependencies: dependencies:
buffer-crc32 "~0.2.3" buffer-crc32 "~0.2.3"
fd-slicer "~1.1.0" fd-slicer "~1.1.0"
yn@3.1.1:
version "3.1.1"
resolved "https://registry.yarnpkg.com/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50"
integrity sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==

View File

@ -1,6 +1,6 @@
{ {
"name": "@budibase/client", "name": "@budibase/client",
"version": "2.3.18-alpha.17", "version": "2.3.21-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,9 +19,9 @@
"dev:builder": "rollup -cw" "dev:builder": "rollup -cw"
}, },
"dependencies": { "dependencies": {
"@budibase/bbui": "2.3.18-alpha.17", "@budibase/bbui": "2.3.21-alpha.1",
"@budibase/frontend-core": "2.3.18-alpha.17", "@budibase/frontend-core": "2.3.21-alpha.1",
"@budibase/string-templates": "2.3.18-alpha.17", "@budibase/string-templates": "2.3.21-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

@ -66,22 +66,27 @@ const createRouteStore = () => {
return state return state
}) })
} }
const navigate = (url, peek) => { const navigate = (url, peek, externalNewTab) => {
if (get(builderStore).inBuilder) { if (get(builderStore).inBuilder) {
return return
} }
if (url) { if (url) {
// If we're already peeking, don't peek again // If we're already peeking, don't peek again
const isPeeking = get(store).queryParams?.peek const isPeeking = get(store).queryParams?.peek
if (peek && !isPeeking) { const external = !url.startsWith("/")
if (peek && !isPeeking && !external) {
peekStore.actions.showPeek(url) peekStore.actions.showPeek(url)
} else { } else if (external) {
const external = !url.startsWith("/") if (url.startsWith("www")) {
if (external) { url = `https://${url}`
window.location.href = url
} else {
push(url)
} }
if (externalNewTab) {
window.open(url, "_blank")
} else {
window.location.href = url
}
} else {
push(url)
} }
} }
} }

View File

@ -140,8 +140,8 @@ const triggerAutomationHandler = async action => {
} }
const navigationHandler = action => { const navigationHandler = action => {
const { url, peek } = action.parameters const { url, peek, externalNewTab } = action.parameters
routeStore.actions.navigate(url, peek) routeStore.actions.navigate(url, peek, externalNewTab)
} }
const queryExecutionHandler = async action => { const queryExecutionHandler = async action => {

View File

@ -1,12 +1,12 @@
{ {
"name": "@budibase/frontend-core", "name": "@budibase/frontend-core",
"version": "2.3.18-alpha.17", "version": "2.3.21-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.3.18-alpha.17", "@budibase/bbui": "2.3.21-alpha.1",
"lodash": "^4.17.21", "lodash": "^4.17.21",
"svelte": "^3.46.2" "svelte": "^3.46.2"
} }

View File

@ -1,6 +1,6 @@
{ {
"name": "@budibase/sdk", "name": "@budibase/sdk",
"version": "2.3.18-alpha.17", "version": "2.3.21-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,7 +1,7 @@
{ {
"name": "@budibase/server", "name": "@budibase/server",
"email": "hi@budibase.com", "email": "hi@budibase.com",
"version": "2.3.18-alpha.17", "version": "2.3.21-alpha.1",
"description": "Budibase Web Server", "description": "Budibase Web Server",
"main": "src/index.ts", "main": "src/index.ts",
"repository": { "repository": {
@ -25,7 +25,7 @@
"dev:stack:down": "node scripts/dev/manage.js down", "dev:stack:down": "node scripts/dev/manage.js down",
"dev:stack:nuke": "node scripts/dev/manage.js nuke", "dev:stack:nuke": "node scripts/dev/manage.js nuke",
"dev:builder": "yarn run dev:stack:up && nodemon", "dev:builder": "yarn run dev:stack:up && nodemon",
"specs": "node specs/generate.js && openapi-typescript specs/openapi.yaml --output src/definitions/openapi.ts", "specs": "ts-node specs/generate.ts && openapi-typescript specs/openapi.yaml --output src/definitions/openapi.ts",
"initialise": "node scripts/initialise.js", "initialise": "node scripts/initialise.js",
"env:multi:enable": "node scripts/multiTenancy.js enable", "env:multi:enable": "node scripts/multiTenancy.js enable",
"env:multi:disable": "node scripts/multiTenancy.js disable", "env:multi:disable": "node scripts/multiTenancy.js disable",
@ -43,11 +43,11 @@
"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.3.18-alpha.17", "@budibase/backend-core": "2.3.21-alpha.1",
"@budibase/client": "2.3.18-alpha.17", "@budibase/client": "2.3.21-alpha.1",
"@budibase/pro": "2.3.18-alpha.17", "@budibase/pro": "2.3.21-alpha.1",
"@budibase/string-templates": "2.3.18-alpha.17", "@budibase/string-templates": "2.3.21-alpha.1",
"@budibase/types": "2.3.18-alpha.17", "@budibase/types": "2.3.21-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",

View File

@ -1,9 +1,9 @@
import { join } from "path"
import { writeFileSync } from "fs"
import { examples, schemas } from "./resources"
import * as parameters from "./parameters"
import * as security from "./security"
const swaggerJsdoc = require("swagger-jsdoc") const swaggerJsdoc = require("swagger-jsdoc")
const { join } = require("path")
const { writeFileSync } = require("fs")
const { examples, schemas } = require("./resources")
const parameters = require("./parameters")
const security = require("./security")
const VARIABLES = {} const VARIABLES = {}
@ -60,7 +60,7 @@ const options = {
apis: [join(__dirname, "..", "src", "api", "routes", "public", "*.ts")], apis: [join(__dirname, "..", "src", "api", "routes", "public", "*.ts")],
} }
function writeFile(output, filename) { function writeFile(output: any, filename: string) {
try { try {
const path = join(__dirname, filename) const path = join(__dirname, filename)
let spec = output let spec = output
@ -79,7 +79,7 @@ function writeFile(output, filename) {
} }
} }
function run() { export function run() {
const outputJSON = swaggerJsdoc(options) const outputJSON = swaggerJsdoc(options)
options.format = ".yaml" options.format = ".yaml"
const outputYAML = swaggerJsdoc(options) const outputYAML = swaggerJsdoc(options)
@ -90,5 +90,3 @@ function run() {
if (require.main === module) { if (require.main === module) {
run() run()
} }
module.exports = run

View File

@ -1829,7 +1829,7 @@
"paths": { "paths": {
"/applications": { "/applications": {
"post": { "post": {
"operationId": "create", "operationId": "appCreate",
"summary": "Create an application", "summary": "Create an application",
"tags": [ "tags": [
"applications" "applications"
@ -1870,7 +1870,7 @@
}, },
"/applications/{appId}": { "/applications/{appId}": {
"put": { "put": {
"operationId": "update", "operationId": "appUpdate",
"summary": "Update an application", "summary": "Update an application",
"tags": [ "tags": [
"applications" "applications"
@ -1909,7 +1909,7 @@
} }
}, },
"delete": { "delete": {
"operationId": "destroy", "operationId": "appDestroy",
"summary": "Delete an application", "summary": "Delete an application",
"tags": [ "tags": [
"applications" "applications"
@ -1938,7 +1938,7 @@
} }
}, },
"get": { "get": {
"operationId": "getById", "operationId": "appGetById",
"summary": "Retrieve an application", "summary": "Retrieve an application",
"tags": [ "tags": [
"applications" "applications"
@ -1969,7 +1969,7 @@
}, },
"/applications/{appId}/unpublish": { "/applications/{appId}/unpublish": {
"post": { "post": {
"operationId": "unpublish", "operationId": "appUnpublish",
"summary": "Unpublish an application", "summary": "Unpublish an application",
"tags": [ "tags": [
"applications" "applications"
@ -1988,7 +1988,7 @@
}, },
"/applications/{appId}/publish": { "/applications/{appId}/publish": {
"post": { "post": {
"operationId": "publish", "operationId": "appPublish",
"summary": "Unpublish an application", "summary": "Unpublish an application",
"tags": [ "tags": [
"applications" "applications"
@ -2019,7 +2019,7 @@
}, },
"/applications/search": { "/applications/search": {
"post": { "post": {
"operationId": "search", "operationId": "appSearch",
"summary": "Search for applications", "summary": "Search for applications",
"description": "Based on application properties (currently only name) search for applications.", "description": "Based on application properties (currently only name) search for applications.",
"tags": [ "tags": [
@ -2056,7 +2056,7 @@
}, },
"/queries/{queryId}": { "/queries/{queryId}": {
"post": { "post": {
"operationId": "execute", "operationId": "queryExecute",
"summary": "Execute a query", "summary": "Execute a query",
"description": "Queries which have been created within a Budibase app can be executed using this,", "description": "Queries which have been created within a Budibase app can be executed using this,",
"tags": [ "tags": [
@ -2104,7 +2104,7 @@
}, },
"/queries/search": { "/queries/search": {
"post": { "post": {
"operationId": "search", "operationId": "querySearch",
"summary": "Search for queries", "summary": "Search for queries",
"description": "Based on query properties (currently only name) search for queries.", "description": "Based on query properties (currently only name) search for queries.",
"tags": [ "tags": [
@ -2146,7 +2146,7 @@
}, },
"/tables/{tableId}/rows": { "/tables/{tableId}/rows": {
"post": { "post": {
"operationId": "create", "operationId": "rowCreate",
"summary": "Create a row", "summary": "Create a row",
"description": "Creates a row within the specified table.", "description": "Creates a row within the specified table.",
"tags": [ "tags": [
@ -2196,7 +2196,7 @@
}, },
"/tables/{tableId}/rows/{rowId}": { "/tables/{tableId}/rows/{rowId}": {
"put": { "put": {
"operationId": "update", "operationId": "rowUpdate",
"summary": "Update a row", "summary": "Update a row",
"description": "Updates a row within the specified table.", "description": "Updates a row within the specified table.",
"tags": [ "tags": [
@ -2247,7 +2247,7 @@
} }
}, },
"delete": { "delete": {
"operationId": "destroy", "operationId": "rowDestroy",
"summary": "Delete a row", "summary": "Delete a row",
"description": "Deletes a row within the specified table.", "description": "Deletes a row within the specified table.",
"tags": [ "tags": [
@ -2283,7 +2283,7 @@
} }
}, },
"get": { "get": {
"operationId": "getById", "operationId": "rowGetById",
"summary": "Retrieve a row", "summary": "Retrieve a row",
"description": "This gets a single row, it will be enriched with the full related rows, rather than the squashed \"primaryDisplay\" format returned by the search endpoint.", "description": "This gets a single row, it will be enriched with the full related rows, rather than the squashed \"primaryDisplay\" format returned by the search endpoint.",
"tags": [ "tags": [
@ -2321,7 +2321,7 @@
}, },
"/tables/{tableId}/rows/search": { "/tables/{tableId}/rows/search": {
"post": { "post": {
"operationId": "search", "operationId": "rowSearch",
"summary": "Search for rows", "summary": "Search for rows",
"tags": [ "tags": [
"rows" "rows"
@ -2365,7 +2365,7 @@
}, },
"/tables": { "/tables": {
"post": { "post": {
"operationId": "create", "operationId": "tableCreate",
"summary": "Create a table", "summary": "Create a table",
"description": "Create a table, this could be internal or external.", "description": "Create a table, this could be internal or external.",
"tags": [ "tags": [
@ -2411,7 +2411,7 @@
}, },
"/tables/{tableId}": { "/tables/{tableId}": {
"put": { "put": {
"operationId": "update", "operationId": "tableUpdate",
"summary": "Update a table", "summary": "Update a table",
"description": "Update a table, this could be internal or external.", "description": "Update a table, this could be internal or external.",
"tags": [ "tags": [
@ -2458,7 +2458,7 @@
} }
}, },
"delete": { "delete": {
"operationId": "destroy", "operationId": "tableDestroy",
"summary": "Delete a table", "summary": "Delete a table",
"description": "Delete a table, this could be internal or external.", "description": "Delete a table, this could be internal or external.",
"tags": [ "tags": [
@ -2491,7 +2491,7 @@
} }
}, },
"get": { "get": {
"operationId": "getById", "operationId": "tableGetById",
"summary": "Retrieve a table", "summary": "Retrieve a table",
"description": "Lookup a table, this could be internal or external.", "description": "Lookup a table, this could be internal or external.",
"tags": [ "tags": [
@ -2526,7 +2526,7 @@
}, },
"/tables/search": { "/tables/search": {
"post": { "post": {
"operationId": "search", "operationId": "tableSearch",
"summary": "Search for tables", "summary": "Search for tables",
"description": "Based on table properties (currently only name) search for tables. This could be an internal or an external table.", "description": "Based on table properties (currently only name) search for tables. This could be an internal or an external table.",
"tags": [ "tags": [
@ -2568,7 +2568,7 @@
}, },
"/users": { "/users": {
"post": { "post": {
"operationId": "create", "operationId": "userCreate",
"summary": "Create a user", "summary": "Create a user",
"tags": [ "tags": [
"users" "users"
@ -2604,7 +2604,7 @@
}, },
"/users/{userId}": { "/users/{userId}": {
"put": { "put": {
"operationId": "update", "operationId": "userUpdate",
"summary": "Update a user", "summary": "Update a user",
"tags": [ "tags": [
"users" "users"
@ -2643,7 +2643,7 @@
} }
}, },
"delete": { "delete": {
"operationId": "destroy", "operationId": "userDestroy",
"summary": "Delete a user", "summary": "Delete a user",
"tags": [ "tags": [
"users" "users"
@ -2672,7 +2672,7 @@
} }
}, },
"get": { "get": {
"operationId": "getById", "operationId": "userGetById",
"summary": "Retrieve a user", "summary": "Retrieve a user",
"tags": [ "tags": [
"users" "users"
@ -2703,7 +2703,7 @@
}, },
"/users/search": { "/users/search": {
"post": { "post": {
"operationId": "search", "operationId": "userSearch",
"summary": "Search for users", "summary": "Search for users",
"description": "Based on user properties (currently only name) search for users.", "description": "Based on user properties (currently only name) search for users.",
"tags": [ "tags": [

View File

@ -1397,7 +1397,7 @@ security:
paths: paths:
/applications: /applications:
post: post:
operationId: create operationId: appCreate
summary: Create an application summary: Create an application
tags: tags:
- applications - applications
@ -1421,7 +1421,7 @@ paths:
$ref: "#/components/examples/application" $ref: "#/components/examples/application"
"/applications/{appId}": "/applications/{appId}":
put: put:
operationId: update operationId: appUpdate
summary: Update an application summary: Update an application
tags: tags:
- applications - applications
@ -1444,7 +1444,7 @@ paths:
application: application:
$ref: "#/components/examples/application" $ref: "#/components/examples/application"
delete: delete:
operationId: destroy operationId: appDestroy
summary: Delete an application summary: Delete an application
tags: tags:
- applications - applications
@ -1461,7 +1461,7 @@ paths:
application: application:
$ref: "#/components/examples/application" $ref: "#/components/examples/application"
get: get:
operationId: getById operationId: appGetById
summary: Retrieve an application summary: Retrieve an application
tags: tags:
- applications - applications
@ -1479,7 +1479,7 @@ paths:
$ref: "#/components/examples/application" $ref: "#/components/examples/application"
"/applications/{appId}/unpublish": "/applications/{appId}/unpublish":
post: post:
operationId: unpublish operationId: appUnpublish
summary: Unpublish an application summary: Unpublish an application
tags: tags:
- applications - applications
@ -1490,7 +1490,7 @@ paths:
description: The app was published successfully. description: The app was published successfully.
"/applications/{appId}/publish": "/applications/{appId}/publish":
post: post:
operationId: publish operationId: appPublish
summary: Unpublish an application summary: Unpublish an application
tags: tags:
- applications - applications
@ -1508,7 +1508,7 @@ paths:
$ref: "#/components/examples/deploymentOutput" $ref: "#/components/examples/deploymentOutput"
/applications/search: /applications/search:
post: post:
operationId: search operationId: appSearch
summary: Search for applications summary: Search for applications
description: Based on application properties (currently only name) search for description: Based on application properties (currently only name) search for
applications. applications.
@ -1533,7 +1533,7 @@ paths:
$ref: "#/components/examples/applications" $ref: "#/components/examples/applications"
"/queries/{queryId}": "/queries/{queryId}":
post: post:
operationId: execute operationId: queryExecute
summary: Execute a query summary: Execute a query
description: Queries which have been created within a Budibase app can be description: Queries which have been created within a Budibase app can be
executed using this, executed using this,
@ -1562,7 +1562,7 @@ paths:
$ref: "#/components/examples/sqlResponse" $ref: "#/components/examples/sqlResponse"
/queries/search: /queries/search:
post: post:
operationId: search operationId: querySearch
summary: Search for queries summary: Search for queries
description: Based on query properties (currently only name) search for queries. description: Based on query properties (currently only name) search for queries.
tags: tags:
@ -1587,7 +1587,7 @@ paths:
$ref: "#/components/examples/queries" $ref: "#/components/examples/queries"
"/tables/{tableId}/rows": "/tables/{tableId}/rows":
post: post:
operationId: create operationId: rowCreate
summary: Create a row summary: Create a row
description: Creates a row within the specified table. description: Creates a row within the specified table.
tags: tags:
@ -1618,7 +1618,7 @@ paths:
$ref: "#/components/examples/row" $ref: "#/components/examples/row"
"/tables/{tableId}/rows/{rowId}": "/tables/{tableId}/rows/{rowId}":
put: put:
operationId: update operationId: rowUpdate
summary: Update a row summary: Update a row
description: Updates a row within the specified table. description: Updates a row within the specified table.
tags: tags:
@ -1648,7 +1648,7 @@ paths:
row: row:
$ref: "#/components/examples/row" $ref: "#/components/examples/row"
delete: delete:
operationId: destroy operationId: rowDestroy
summary: Delete a row summary: Delete a row
description: Deletes a row within the specified table. description: Deletes a row within the specified table.
tags: tags:
@ -1669,7 +1669,7 @@ paths:
row: row:
$ref: "#/components/examples/row" $ref: "#/components/examples/row"
get: get:
operationId: getById operationId: rowGetById
summary: Retrieve a row summary: Retrieve a row
description: This gets a single row, it will be enriched with the full related description: This gets a single row, it will be enriched with the full related
rows, rather than the squashed "primaryDisplay" format returned by the rows, rather than the squashed "primaryDisplay" format returned by the
@ -1692,7 +1692,7 @@ paths:
$ref: "#/components/examples/enrichedRow" $ref: "#/components/examples/enrichedRow"
"/tables/{tableId}/rows/search": "/tables/{tableId}/rows/search":
post: post:
operationId: search operationId: rowSearch
summary: Search for rows summary: Search for rows
tags: tags:
- rows - rows
@ -1718,7 +1718,7 @@ paths:
$ref: "#/components/examples/rows" $ref: "#/components/examples/rows"
/tables: /tables:
post: post:
operationId: create operationId: tableCreate
summary: Create a table summary: Create a table
description: Create a table, this could be internal or external. description: Create a table, this could be internal or external.
tags: tags:
@ -1746,7 +1746,7 @@ paths:
$ref: "#/components/examples/table" $ref: "#/components/examples/table"
"/tables/{tableId}": "/tables/{tableId}":
put: put:
operationId: update operationId: tableUpdate
summary: Update a table summary: Update a table
description: Update a table, this could be internal or external. description: Update a table, this could be internal or external.
tags: tags:
@ -1773,7 +1773,7 @@ paths:
table: table:
$ref: "#/components/examples/table" $ref: "#/components/examples/table"
delete: delete:
operationId: destroy operationId: tableDestroy
summary: Delete a table summary: Delete a table
description: Delete a table, this could be internal or external. description: Delete a table, this could be internal or external.
tags: tags:
@ -1792,7 +1792,7 @@ paths:
table: table:
$ref: "#/components/examples/table" $ref: "#/components/examples/table"
get: get:
operationId: getById operationId: tableGetById
summary: Retrieve a table summary: Retrieve a table
description: Lookup a table, this could be internal or external. description: Lookup a table, this could be internal or external.
tags: tags:
@ -1812,7 +1812,7 @@ paths:
$ref: "#/components/examples/table" $ref: "#/components/examples/table"
/tables/search: /tables/search:
post: post:
operationId: search operationId: tableSearch
summary: Search for tables summary: Search for tables
description: Based on table properties (currently only name) search for tables. description: Based on table properties (currently only name) search for tables.
This could be an internal or an external table. This could be an internal or an external table.
@ -1838,7 +1838,7 @@ paths:
$ref: "#/components/examples/tables" $ref: "#/components/examples/tables"
/users: /users:
post: post:
operationId: create operationId: userCreate
summary: Create a user summary: Create a user
tags: tags:
- users - users
@ -1860,7 +1860,7 @@ paths:
$ref: "#/components/examples/user" $ref: "#/components/examples/user"
"/users/{userId}": "/users/{userId}":
put: put:
operationId: update operationId: userUpdate
summary: Update a user summary: Update a user
tags: tags:
- users - users
@ -1883,7 +1883,7 @@ paths:
user: user:
$ref: "#/components/examples/user" $ref: "#/components/examples/user"
delete: delete:
operationId: destroy operationId: userDestroy
summary: Delete a user summary: Delete a user
tags: tags:
- users - users
@ -1900,7 +1900,7 @@ paths:
user: user:
$ref: "#/components/examples/user" $ref: "#/components/examples/user"
get: get:
operationId: getById operationId: userGetById
summary: Retrieve a user summary: Retrieve a user
tags: tags:
- users - users
@ -1918,7 +1918,7 @@ paths:
$ref: "#/components/examples/user" $ref: "#/components/examples/user"
/users/search: /users/search:
post: post:
operationId: search operationId: userSearch
summary: Search for users summary: Search for users
description: Based on user properties (currently only name) search for users. description: Based on user properties (currently only name) search for users.
tags: tags:

View File

@ -1,4 +1,4 @@
exports.tableId = { export const tableId = {
in: "path", in: "path",
name: "tableId", name: "tableId",
required: true, required: true,
@ -8,7 +8,7 @@ exports.tableId = {
}, },
} }
exports.rowId = { export const rowId = {
in: "path", in: "path",
name: "rowId", name: "rowId",
required: true, required: true,
@ -18,7 +18,7 @@ exports.rowId = {
}, },
} }
exports.appId = { export const appId = {
in: "header", in: "header",
name: "x-budibase-app-id", name: "x-budibase-app-id",
required: true, required: true,
@ -28,7 +28,7 @@ exports.appId = {
}, },
} }
exports.appIdUrl = { export const appIdUrl = {
in: "path", in: "path",
name: "appId", name: "appId",
required: true, required: true,
@ -38,7 +38,7 @@ exports.appIdUrl = {
}, },
} }
exports.queryId = { export const queryId = {
in: "path", in: "path",
name: "queryId", name: "queryId",
required: true, required: true,
@ -48,7 +48,7 @@ exports.queryId = {
}, },
} }
exports.userId = { export const userId = {
in: "path", in: "path",
name: "userId", name: "userId",
required: true, required: true,

View File

@ -1,6 +1,6 @@
const userResource = require("./user") import userResource from "./user"
const { object } = require("./utils") import { object } from "./utils"
const Resource = require("./utils/Resource") import Resource from "./utils/Resource"
const application = { const application = {
_id: "app_metadata", _id: "app_metadata",
@ -96,7 +96,7 @@ const deploymentOutputSchema = object({
}, },
}) })
module.exports = new Resource() export default new Resource()
.setExamples({ .setExamples({
application: { application: {
value: { value: {

View File

@ -1,11 +1,11 @@
const application = require("./application") import application from "./application"
const row = require("./row") import row from "./row"
const table = require("./table") import table from "./table"
const query = require("./query") import query from "./query"
const user = require("./user") import user from "./user"
const misc = require("./misc") import misc from "./misc"
exports.examples = { export const examples = {
...application.getExamples(), ...application.getExamples(),
...row.getExamples(), ...row.getExamples(),
...table.getExamples(), ...table.getExamples(),
@ -14,7 +14,7 @@ exports.examples = {
...misc.getExamples(), ...misc.getExamples(),
} }
exports.schemas = { export const schemas = {
...application.getSchemas(), ...application.getSchemas(),
...row.getSchemas(), ...row.getSchemas(),
...table.getSchemas(), ...table.getSchemas(),

View File

@ -1,7 +1,7 @@
const { object } = require("./utils") import { object } from "./utils"
const Resource = require("./utils/Resource") import Resource from "./utils/Resource"
module.exports = new Resource().setSchemas({ export default new Resource().setSchemas({
rowSearch: object( rowSearch: object(
{ {
query: { query: {

View File

@ -1,6 +1,6 @@
const Resource = require("./utils/Resource") import Resource from "./utils/Resource"
const { object } = require("./utils") import { object } from "./utils"
const { BaseQueryVerbs } = require("../../src/constants") import { BaseQueryVerbs } from "../../src/constants"
const query = { const query = {
_id: "query_datasource_plus_4d8be0c506b9465daf4bf84d890fdab6_454854487c574d45bc4029b1e153219e", _id: "query_datasource_plus_4d8be0c506b9465daf4bf84d890fdab6_454854487c574d45bc4029b1e153219e",
@ -189,7 +189,7 @@ const executeQueryOutputSchema = object(
{ required: ["data"] } { required: ["data"] }
) )
module.exports = new Resource() export default new Resource()
.setExamples({ .setExamples({
query: { query: {
value: { value: {

View File

@ -1,5 +1,5 @@
const { object } = require("./utils") import { object } from "./utils"
const Resource = require("./utils/Resource") import Resource from "./utils/Resource"
const baseRow = { const baseRow = {
_id: "ro_ta_5b1649e42a5b41dea4ef7742a36a7a70_e6dc7e38cf1343b2b56760265201cda4", _id: "ro_ta_5b1649e42a5b41dea4ef7742a36a7a70_e6dc7e38cf1343b2b56760265201cda4",
@ -56,7 +56,6 @@ const rowSchema = {
const rowOutputSchema = { const rowOutputSchema = {
...rowSchema, ...rowSchema,
properties: { properties: {
...rowSchema.properties,
_id: { _id: {
description: "The ID of the row.", description: "The ID of the row.",
type: "string", type: "string",
@ -93,7 +92,7 @@ const searchOutputSchema = {
}, },
} }
module.exports = new Resource() export default new Resource()
.setExamples({ .setExamples({
inputRow: { inputRow: {
value: inputRow, value: inputRow,

View File

@ -1,10 +1,10 @@
const { import {
FieldTypes, FieldTypes,
RelationshipTypes, RelationshipTypes,
FormulaTypes, FormulaTypes,
} = require("../../src/constants") } from "../../src/constants"
const { object } = require("./utils") import { object } from "./utils"
const Resource = require("./utils/Resource") import Resource from "./utils/Resource"
const table = { const table = {
_id: "ta_5b1649e42a5b41dea4ef7742a36a7a70", _id: "ta_5b1649e42a5b41dea4ef7742a36a7a70",
@ -170,7 +170,7 @@ const tableOutputSchema = {
required: [...tableSchema.required, "_id"], required: [...tableSchema.required, "_id"],
} }
module.exports = new Resource() export default new Resource()
.setExamples({ .setExamples({
table: { table: {
value: { value: {

View File

@ -1,5 +1,5 @@
const { object } = require("./utils") import { object } from "./utils"
const Resource = require("./utils/Resource") import Resource from "./utils/Resource"
const user = { const user = {
_id: "us_693a73206518477283a8d5ae31103252", _id: "us_693a73206518477283a8d5ae31103252",
@ -105,7 +105,7 @@ const userOutputSchema = {
required: [...userSchema.required, "_id"], required: [...userSchema.required, "_id"],
} }
module.exports = new Resource() export default new Resource()
.setExamples({ .setExamples({
user: { user: {
value: { value: {

View File

@ -1,26 +0,0 @@
class Resource {
constructor() {
this.examples = {}
this.schemas = {}
}
setExamples(examples) {
this.examples = examples
return this
}
setSchemas(schemas) {
this.schemas = schemas
return this
}
getExamples() {
return this.examples
}
getSchemas() {
return this.schemas
}
}
module.exports = Resource

View File

@ -0,0 +1,39 @@
type Example = {
[key: string]: {
[key: string]: any
}
}
type Schema = {
[key: string]: {
[key: string]: any
}
}
export default class Resource {
examples: Example
schemas: Schema
constructor() {
this.examples = {}
this.schemas = {}
}
setExamples(examples: Example) {
this.examples = examples
return this
}
setSchemas(schemas: Schema) {
this.schemas = schemas
return this
}
getExamples() {
return this.examples
}
getSchemas() {
return this.schemas
}
}

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