From 478e297e9e3c2944fb20b750463db89f2dea1b72 Mon Sep 17 00:00:00 2001
From: mike12345567
Date: Fri, 24 Nov 2023 18:11:53 +0000
Subject: [PATCH 001/783] Initial work towards aliasing queries for SQL.
---
.../server/src/api/controllers/row/alias.ts | 101 ++++++++++++++++++
packages/server/src/integrations/base/sql.ts | 1 +
2 files changed, 102 insertions(+)
create mode 100644 packages/server/src/api/controllers/row/alias.ts
diff --git a/packages/server/src/api/controllers/row/alias.ts b/packages/server/src/api/controllers/row/alias.ts
new file mode 100644
index 0000000000..8111396ea9
--- /dev/null
+++ b/packages/server/src/api/controllers/row/alias.ts
@@ -0,0 +1,101 @@
+import { QueryJson, SearchFilters, Table, Row } from "@budibase/types"
+import { getDatasourceAndQuery } from "../../../sdk/app/rows/utils"
+import { cloneDeep } from "lodash"
+
+class AliasTables {
+ character: string
+ aliases: Record
+ tableAliases: Record
+
+ constructor() {
+ this.character = "a"
+ this.aliases = {}
+ this.tableAliases = {}
+ }
+
+ getAlias(tableName: string) {
+ if (this.aliases[tableName]) {
+ return this.aliases[tableName]
+ }
+ this.character = String.fromCharCode(this.character.charCodeAt(0) + 1)
+ this.aliases[tableName] = this.character
+ this.tableAliases[this.character] = tableName
+ return this.character
+ }
+
+ aliasField(tableNames: string[], field: string) {
+ if (field.includes(".")) {
+ const [tableName, column] = field.split(".")
+ if (tableNames.includes(tableName)) {
+ return `${this.getAlias(tableName)}.${column}`
+ }
+ }
+ return field
+ }
+
+ reverse(tableNames: string[], rows: T): T {
+ const process = (row: Row) => {
+ const final: Row = {}
+ for (let [key, value] of Object.entries(row)) {
+ if (!key.includes(".")) {
+ final[key] = value
+ } else {
+ const [alias, column] = key.split(".")
+ const tableName = this.tableAliases[alias] || alias
+ final[`${tableName}.${column}`] = value
+ }
+ }
+ return final
+ }
+ if (Array.isArray(rows)) {
+ return rows.map(row => process(row)) as T
+ } else {
+ return process(rows) as T
+ }
+ }
+
+ async queryWithAliasing(tableNames: string[], json: QueryJson) {
+ json = cloneDeep(json)
+ const aliasField = (field: string) => this.aliasField(tableNames, field)
+ const aliasTable = (table: Table) => ({
+ ...table,
+ name: this.getAlias(table.name),
+ })
+ // run through the query json to update anywhere a table may be used
+ if (json.resource?.fields) {
+ json.resource.fields = json.resource.fields.map(field =>
+ aliasField(field)
+ )
+ }
+ if (json.filters) {
+ for (let [filterKey, filter] of Object.entries(json.filters)) {
+ if (typeof filter !== "object") {
+ continue
+ }
+ const aliasedFilters: typeof filter = {}
+ for (let key of Object.keys(filter)) {
+ aliasedFilters[aliasField(key)] = filter
+ }
+ json.filters[filterKey as keyof SearchFilters] = aliasedFilters
+ }
+ }
+ if (json.relationships) {
+ json.relationships = json.relationships.map(relationship => ({
+ ...relationship,
+ tableName: this.getAlias(relationship.tableName),
+ }))
+ }
+ if (json.meta?.table) {
+ json.meta.table = aliasTable(json.meta.table)
+ }
+ if (json.meta?.tables) {
+ const aliasedTables: Record = {}
+ for (let [tableName, table] of Object.entries(json.meta.tables)) {
+ aliasedTables[this.getAlias(tableName)] = aliasTable(table)
+ }
+ json.meta.tables = aliasedTables
+ }
+ const response = await getDatasourceAndQuery(json)
+ return this.reverse(tableNames, response)
+ }
+}
diff --git a/packages/server/src/integrations/base/sql.ts b/packages/server/src/integrations/base/sql.ts
index 29c8416b34..630c962a15 100644
--- a/packages/server/src/integrations/base/sql.ts
+++ b/packages/server/src/integrations/base/sql.ts
@@ -437,6 +437,7 @@ class InternalBuilder {
read(knex: Knex, json: QueryJson, limit: number): KnexQuery {
let { endpoint, resource, filters, paginate, relationships } = json
+
const tableName = endpoint.entityId
// select all if not specified
if (!resource) {
From c16ad8614240cbb70f21179aeb2e6239916fcce2 Mon Sep 17 00:00:00 2001
From: mike12345567
Date: Fri, 24 Nov 2023 18:12:35 +0000
Subject: [PATCH 002/783] Updating reverse function.
---
packages/server/src/api/controllers/row/alias.ts | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/packages/server/src/api/controllers/row/alias.ts b/packages/server/src/api/controllers/row/alias.ts
index 8111396ea9..d4937186d9 100644
--- a/packages/server/src/api/controllers/row/alias.ts
+++ b/packages/server/src/api/controllers/row/alias.ts
@@ -33,7 +33,7 @@ class AliasTables {
return field
}
- reverse(tableNames: string[], rows: T): T {
+ reverse(rows: T): T {
const process = (row: Row) => {
const final: Row = {}
for (let [key, value] of Object.entries(row)) {
@@ -96,6 +96,6 @@ class AliasTables {
json.meta.tables = aliasedTables
}
const response = await getDatasourceAndQuery(json)
- return this.reverse(tableNames, response)
+ return this.reverse(response)
}
}
From cb7c1898f2d29ac52f6b943dc04dd716b9ba128e Mon Sep 17 00:00:00 2001
From: mike12345567
Date: Mon, 27 Nov 2023 19:02:06 +0000
Subject: [PATCH 003/783] Getting basic aliasing working after some testing.
---
.../api/controllers/row/ExternalRequest.ts | 19 +++++++-------
.../server/src/api/controllers/row/alias.ts | 25 +++++++++++--------
packages/server/src/integrations/base/sql.ts | 11 +++++---
packages/server/src/sdk/app/rows/utils.ts | 4 +--
packages/types/src/sdk/search.ts | 2 ++
5 files changed, 36 insertions(+), 25 deletions(-)
diff --git a/packages/server/src/api/controllers/row/ExternalRequest.ts b/packages/server/src/api/controllers/row/ExternalRequest.ts
index 7c98fecb9b..29851e457f 100644
--- a/packages/server/src/api/controllers/row/ExternalRequest.ts
+++ b/packages/server/src/api/controllers/row/ExternalRequest.ts
@@ -32,6 +32,7 @@ import { processObjectSync } from "@budibase/string-templates"
import { cloneDeep } from "lodash/fp"
import { processDates, processFormulas } from "../../../utilities/rowProcessor"
import { db as dbCore } from "@budibase/backend-core"
+import AliasTables from "./alias"
import sdk from "../../../sdk"
export interface ManyRelationship {
@@ -178,13 +179,13 @@ function generateIdForRow(
function getEndpoint(tableId: string | undefined, operation: string) {
if (!tableId) {
- return {}
+ throw new Error("Cannot get endpoint information - no table ID specified")
}
const { datasourceId, tableName } = breakExternalTableId(tableId)
return {
- datasourceId,
- entityId: tableName,
- operation,
+ datasourceId: datasourceId!,
+ entityId: tableName!,
+ operation: operation as Operation,
}
}
@@ -704,7 +705,7 @@ export class ExternalRequest {
// safety check, if there are no filters on deletion bad things happen
if (Object.keys(filters).length !== 0) {
const op = isMany ? Operation.DELETE : Operation.UPDATE
- const body = isMany ? null : { [colName]: null }
+ const body = isMany ? undefined : { [colName]: null }
promises.push(
getDatasourceAndQuery({
endpoint: getEndpoint(tableId, op),
@@ -807,7 +808,7 @@ export class ExternalRequest {
}
let json = {
endpoint: {
- datasourceId,
+ datasourceId: datasourceId!,
entityId: tableName,
operation,
},
@@ -829,9 +830,9 @@ export class ExternalRequest {
},
}
- // can't really use response right now
- const response = await getDatasourceAndQuery(json)
- // handle many to many relationships now if we know the ID (could be auto increment)
+ const aliasing = new AliasTables(Object.keys(this.tables))
+ const response = await aliasing.queryWithAliasing(json)
+ // handle many-to-many relationships now if we know the ID (could be auto increment)
if (operation !== Operation.READ) {
await this.handleManyRelationships(
table._id || "",
diff --git a/packages/server/src/api/controllers/row/alias.ts b/packages/server/src/api/controllers/row/alias.ts
index d4937186d9..19be8db654 100644
--- a/packages/server/src/api/controllers/row/alias.ts
+++ b/packages/server/src/api/controllers/row/alias.ts
@@ -2,12 +2,14 @@ import { QueryJson, SearchFilters, Table, Row } from "@budibase/types"
import { getDatasourceAndQuery } from "../../../sdk/app/rows/utils"
import { cloneDeep } from "lodash"
-class AliasTables {
+export default class AliasTables {
character: string
aliases: Record
tableAliases: Record
+ tableNames: string[]
- constructor() {
+ constructor(tableNames: string[]) {
+ this.tableNames = tableNames
this.character = "a"
this.aliases = {}
this.tableAliases = {}
@@ -17,13 +19,15 @@ class AliasTables {
if (this.aliases[tableName]) {
return this.aliases[tableName]
}
- this.character = String.fromCharCode(this.character.charCodeAt(0) + 1)
- this.aliases[tableName] = this.character
- this.tableAliases[this.character] = tableName
- return this.character
+ const char = this.character
+ this.aliases[tableName] = char
+ this.tableAliases[char] = tableName
+ this.character = String.fromCharCode(char.charCodeAt(0) + 1)
+ return char
}
- aliasField(tableNames: string[], field: string) {
+ aliasField(field: string) {
+ const tableNames = this.tableNames
if (field.includes(".")) {
const [tableName, column] = field.split(".")
if (tableNames.includes(tableName)) {
@@ -54,9 +58,9 @@ class AliasTables {
}
}
- async queryWithAliasing(tableNames: string[], json: QueryJson) {
+ async queryWithAliasing(json: QueryJson) {
json = cloneDeep(json)
- const aliasField = (field: string) => this.aliasField(tableNames, field)
+ const aliasField = (field: string) => this.aliasField(field)
const aliasTable = (table: Table) => ({
...table,
name: this.getAlias(table.name),
@@ -82,7 +86,7 @@ class AliasTables {
if (json.relationships) {
json.relationships = json.relationships.map(relationship => ({
...relationship,
- tableName: this.getAlias(relationship.tableName),
+ alias: this.getAlias(relationship.tableName),
}))
}
if (json.meta?.table) {
@@ -95,6 +99,7 @@ class AliasTables {
}
json.meta.tables = aliasedTables
}
+ json.endpoint.alias = this.getAlias(json.endpoint.entityId)
const response = await getDatasourceAndQuery(json)
return this.reverse(response)
}
diff --git a/packages/server/src/integrations/base/sql.ts b/packages/server/src/integrations/base/sql.ts
index 630c962a15..3147e8c670 100644
--- a/packages/server/src/integrations/base/sql.ts
+++ b/packages/server/src/integrations/base/sql.ts
@@ -439,6 +439,9 @@ class InternalBuilder {
let { endpoint, resource, filters, paginate, relationships } = json
const tableName = endpoint.entityId
+ const alias = endpoint.alias
+ const aliased = alias ? alias : tableName
+ const tableAliased = alias ? `${tableName} as ${alias}` : tableName
// select all if not specified
if (!resource) {
resource = { fields: [] }
@@ -463,20 +466,20 @@ class InternalBuilder {
foundLimit = paginate.limit
}
// start building the query
- let query: KnexQuery = knex(tableName).limit(foundLimit)
+ let query: KnexQuery = knex(tableAliased).limit(foundLimit)
if (endpoint.schema) {
query = query.withSchema(endpoint.schema)
}
if (foundOffset) {
query = query.offset(foundOffset)
}
- query = this.addFilters(query, filters, { tableName })
+ query = this.addFilters(query, filters, { tableName: aliased })
// add sorting to pre-query
query = this.addSorting(query, json)
// @ts-ignore
let preQuery: KnexQuery = knex({
// @ts-ignore
- [tableName]: query,
+ [aliased]: query,
}).select(selectStatement)
// have to add after as well (this breaks MS-SQL)
if (this.client !== SqlClient.MS_SQL) {
@@ -485,7 +488,7 @@ class InternalBuilder {
// handle joins
query = this.addRelationships(
preQuery,
- tableName,
+ aliased,
relationships,
endpoint.schema
)
diff --git a/packages/server/src/sdk/app/rows/utils.ts b/packages/server/src/sdk/app/rows/utils.ts
index d0227c7c6b..c160aaba3f 100644
--- a/packages/server/src/sdk/app/rows/utils.ts
+++ b/packages/server/src/sdk/app/rows/utils.ts
@@ -1,13 +1,13 @@
import cloneDeep from "lodash/cloneDeep"
import validateJs from "validate.js"
-import { Row, Table, TableSchema } from "@budibase/types"
+import { QueryJson, Row, Table, TableSchema } from "@budibase/types"
import { FieldTypes } from "../../../constants"
import { makeExternalQuery } from "../../../integrations/base/query"
import { Format } from "../../../api/controllers/view/exporters"
import sdk from "../.."
import { isRelationshipColumn } from "../../../db/utils"
-export async function getDatasourceAndQuery(json: any) {
+export async function getDatasourceAndQuery(json: QueryJson) {
const datasourceId = json.endpoint.datasourceId
const datasource = await sdk.datasources.get(datasourceId)
return makeExternalQuery(datasource, json)
diff --git a/packages/types/src/sdk/search.ts b/packages/types/src/sdk/search.ts
index 35fd148c05..1f9aa6c375 100644
--- a/packages/types/src/sdk/search.ts
+++ b/packages/types/src/sdk/search.ts
@@ -67,6 +67,7 @@ export interface RelationshipsJson {
fromPrimary?: string
toPrimary?: string
tableName: string
+ alias?: string
column: string
}
@@ -74,6 +75,7 @@ export interface QueryJson {
endpoint: {
datasourceId: string
entityId: string
+ alias?: string
operation: Operation
schema?: string
}
From 65cddae9dac4f511c70634e4885987b672989c13 Mon Sep 17 00:00:00 2001
From: mike12345567
Date: Tue, 28 Nov 2023 18:43:38 +0000
Subject: [PATCH 004/783] Getting relationship aliasing working.
---
.../server/src/api/controllers/row/alias.ts | 16 +++++++-
packages/server/src/integrations/base/sql.ts | 39 ++++++++++++++-----
packages/types/src/sdk/search.ts | 2 +-
3 files changed, 46 insertions(+), 11 deletions(-)
diff --git a/packages/server/src/api/controllers/row/alias.ts b/packages/server/src/api/controllers/row/alias.ts
index 19be8db654..0c7a4bb8a0 100644
--- a/packages/server/src/api/controllers/row/alias.ts
+++ b/packages/server/src/api/controllers/row/alias.ts
@@ -58,6 +58,16 @@ export default class AliasTables {
}
}
+ aliasMap(tableNames: (string | undefined)[]) {
+ const map: Record = {}
+ for (let tableName of tableNames) {
+ if (tableName) {
+ map[tableName] = this.getAlias(tableName)
+ }
+ }
+ return map
+ }
+
async queryWithAliasing(json: QueryJson) {
json = cloneDeep(json)
const aliasField = (field: string) => this.aliasField(field)
@@ -86,7 +96,11 @@ export default class AliasTables {
if (json.relationships) {
json.relationships = json.relationships.map(relationship => ({
...relationship,
- alias: this.getAlias(relationship.tableName),
+ aliases: this.aliasMap([
+ relationship.through,
+ relationship.tableName,
+ json.endpoint.entityId,
+ ]),
}))
}
if (json.meta?.table) {
diff --git a/packages/server/src/integrations/base/sql.ts b/packages/server/src/integrations/base/sql.ts
index 3147e8c670..f3f574b1af 100644
--- a/packages/server/src/integrations/base/sql.ts
+++ b/packages/server/src/integrations/base/sql.ts
@@ -330,6 +330,17 @@ class InternalBuilder {
return query
}
+ tableNameWithSchema(
+ tableName: string,
+ opts?: { alias?: string; schema?: string }
+ ) {
+ let withSchema = opts?.schema ? `${opts.schema}.${tableName}` : tableName
+ if (opts?.alias) {
+ withSchema += ` as ${opts.alias}`
+ }
+ return withSchema
+ }
+
addRelationships(
query: KnexQuery,
fromTable: string,
@@ -339,9 +350,12 @@ class InternalBuilder {
if (!relationships) {
return query
}
- const tableSets: Record = {}
+ const tableSets: Record = {}
+ // add up all aliases
+ let aliases: Record = {}
// aggregate into table sets (all the same to tables)
for (let relationship of relationships) {
+ aliases = { ...aliases, ...relationship.aliases }
const keyObj: { toTable: string; throughTable: string | undefined } = {
toTable: relationship.tableName,
throughTable: undefined,
@@ -358,10 +372,17 @@ class InternalBuilder {
}
for (let [key, relationships] of Object.entries(tableSets)) {
const { toTable, throughTable } = JSON.parse(key)
- const toTableWithSchema = schema ? `${schema}.${toTable}` : toTable
- const throughTableWithSchema = schema
- ? `${schema}.${throughTable}`
- : throughTable
+ const toAlias = aliases[toTable],
+ throughAlias = aliases[throughTable],
+ fromAlias = aliases[fromTable]
+ let toTableWithSchema = this.tableNameWithSchema(toTable, {
+ alias: toAlias,
+ schema,
+ })
+ let throughTableWithSchema = this.tableNameWithSchema(throughTable, {
+ alias: throughAlias,
+ schema,
+ })
if (!throughTable) {
// @ts-ignore
query = query.leftJoin(toTableWithSchema, function () {
@@ -369,7 +390,7 @@ class InternalBuilder {
const from = relationship.from,
to = relationship.to
// @ts-ignore
- this.orOn(`${fromTable}.${from}`, "=", `${toTable}.${to}`)
+ this.orOn(`${fromTable}.${from}`, "=", `${toAlias}.${to}`)
}
})
} else {
@@ -381,9 +402,9 @@ class InternalBuilder {
const from = relationship.from
// @ts-ignore
this.orOn(
- `${fromTable}.${fromPrimary}`,
+ `${fromAlias}.${fromPrimary}`,
"=",
- `${throughTable}.${from}`
+ `${throughAlias}.${from}`
)
}
})
@@ -392,7 +413,7 @@ class InternalBuilder {
const toPrimary = relationship.toPrimary
const to = relationship.to
// @ts-ignore
- this.orOn(`${toTable}.${toPrimary}`, `${throughTable}.${to}`)
+ this.orOn(`${toAlias}.${toPrimary}`, `${throughAlias}.${to}`)
}
})
}
diff --git a/packages/types/src/sdk/search.ts b/packages/types/src/sdk/search.ts
index 1f9aa6c375..a4045c2558 100644
--- a/packages/types/src/sdk/search.ts
+++ b/packages/types/src/sdk/search.ts
@@ -67,7 +67,7 @@ export interface RelationshipsJson {
fromPrimary?: string
toPrimary?: string
tableName: string
- alias?: string
+ aliases?: Record
column: string
}
From 649025ca124a4b9b7f0714d9621edcb3c4ae3424 Mon Sep 17 00:00:00 2001
From: mike12345567
Date: Tue, 28 Nov 2023 18:45:05 +0000
Subject: [PATCH 005/783] Fixing missed from.
---
packages/server/src/integrations/base/sql.ts | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/packages/server/src/integrations/base/sql.ts b/packages/server/src/integrations/base/sql.ts
index f3f574b1af..c419edc805 100644
--- a/packages/server/src/integrations/base/sql.ts
+++ b/packages/server/src/integrations/base/sql.ts
@@ -390,7 +390,7 @@ class InternalBuilder {
const from = relationship.from,
to = relationship.to
// @ts-ignore
- this.orOn(`${fromTable}.${from}`, "=", `${toAlias}.${to}`)
+ this.orOn(`${fromAlias}.${from}`, "=", `${toAlias}.${to}`)
}
})
} else {
From 5c4dc0dc8351310f6ab9c022594386a4543c47f6 Mon Sep 17 00:00:00 2001
From: mike12345567
Date: Fri, 1 Dec 2023 14:14:44 +0000
Subject: [PATCH 006/783] Fixing issue with aliasing.
---
packages/server/src/integrations/base/sql.ts | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/packages/server/src/integrations/base/sql.ts b/packages/server/src/integrations/base/sql.ts
index c419edc805..57af95eabb 100644
--- a/packages/server/src/integrations/base/sql.ts
+++ b/packages/server/src/integrations/base/sql.ts
@@ -372,9 +372,9 @@ class InternalBuilder {
}
for (let [key, relationships] of Object.entries(tableSets)) {
const { toTable, throughTable } = JSON.parse(key)
- const toAlias = aliases[toTable],
- throughAlias = aliases[throughTable],
- fromAlias = aliases[fromTable]
+ const toAlias = aliases[toTable] || toTable,
+ throughAlias = aliases[throughTable] || throughTable,
+ fromAlias = aliases[fromTable] || fromTable
let toTableWithSchema = this.tableNameWithSchema(toTable, {
alias: toAlias,
schema,
From 7eccbb851dac11b36e936ae52a67500f99cc7a52 Mon Sep 17 00:00:00 2001
From: mike12345567
Date: Fri, 1 Dec 2023 15:27:49 +0000
Subject: [PATCH 007/783] Fixing issues with other SQL functions than just
reading.
---
.../server/src/api/controllers/row/alias.ts | 2 +-
packages/server/src/integrations/base/sql.ts | 46 +++++++++----------
2 files changed, 23 insertions(+), 25 deletions(-)
diff --git a/packages/server/src/api/controllers/row/alias.ts b/packages/server/src/api/controllers/row/alias.ts
index 0c7a4bb8a0..fc00b505c4 100644
--- a/packages/server/src/api/controllers/row/alias.ts
+++ b/packages/server/src/api/controllers/row/alias.ts
@@ -88,7 +88,7 @@ export default class AliasTables {
}
const aliasedFilters: typeof filter = {}
for (let key of Object.keys(filter)) {
- aliasedFilters[aliasField(key)] = filter
+ aliasedFilters[aliasField(key)] = filter[key]
}
json.filters[filterKey as keyof SearchFilters] = aliasedFilters
}
diff --git a/packages/server/src/integrations/base/sql.ts b/packages/server/src/integrations/base/sql.ts
index 57af95eabb..14bcb532cc 100644
--- a/packages/server/src/integrations/base/sql.ts
+++ b/packages/server/src/integrations/base/sql.ts
@@ -421,12 +421,24 @@ class InternalBuilder {
return query.limit(BASE_LIMIT)
}
- create(knex: Knex, json: QueryJson, opts: QueryOptions): KnexQuery {
- const { endpoint, body } = json
- let query: KnexQuery = knex(endpoint.entityId)
+ knexWithAlias(
+ knex: Knex,
+ endpoint: { entityId: string; alias?: string; schema?: string }
+ ): { query: KnexQuery; name: string } {
+ const tableName = endpoint.entityId
+ const alias = endpoint.alias
+ const aliased = alias ? alias : tableName
+ const tableAliased = alias ? `${tableName} as ${alias}` : tableName
+ let query = knex(tableAliased)
if (endpoint.schema) {
query = query.withSchema(endpoint.schema)
}
+ return { query, name: aliased }
+ }
+
+ create(knex: Knex, json: QueryJson, opts: QueryOptions): KnexQuery {
+ const { endpoint, body } = json
+ let { query } = this.knexWithAlias(knex, endpoint)
const parsedBody = parseBody(body)
// make sure no null values in body for creation
for (let [key, value] of Object.entries(parsedBody)) {
@@ -445,10 +457,7 @@ class InternalBuilder {
bulkCreate(knex: Knex, json: QueryJson): KnexQuery {
const { endpoint, body } = json
- let query: KnexQuery = knex(endpoint.entityId)
- if (endpoint.schema) {
- query = query.withSchema(endpoint.schema)
- }
+ let { query } = this.knexWithAlias(knex, endpoint)
if (!Array.isArray(body)) {
return query
}
@@ -459,10 +468,6 @@ class InternalBuilder {
read(knex: Knex, json: QueryJson, limit: number): KnexQuery {
let { endpoint, resource, filters, paginate, relationships } = json
- const tableName = endpoint.entityId
- const alias = endpoint.alias
- const aliased = alias ? alias : tableName
- const tableAliased = alias ? `${tableName} as ${alias}` : tableName
// select all if not specified
if (!resource) {
resource = { fields: [] }
@@ -487,10 +492,9 @@ class InternalBuilder {
foundLimit = paginate.limit
}
// start building the query
- let query: KnexQuery = knex(tableAliased).limit(foundLimit)
- if (endpoint.schema) {
- query = query.withSchema(endpoint.schema)
- }
+
+ let { query, name: aliased } = this.knexWithAlias(knex, endpoint)
+ query = query.limit(foundLimit)
if (foundOffset) {
query = query.offset(foundOffset)
}
@@ -518,10 +522,7 @@ class InternalBuilder {
update(knex: Knex, json: QueryJson, opts: QueryOptions): KnexQuery {
const { endpoint, body, filters } = json
- let query: KnexQuery = knex(endpoint.entityId)
- if (endpoint.schema) {
- query = query.withSchema(endpoint.schema)
- }
+ let { query } = this.knexWithAlias(knex, endpoint)
const parsedBody = parseBody(body)
query = this.addFilters(query, filters, { tableName: endpoint.entityId })
// mysql can't use returning
@@ -534,11 +535,8 @@ class InternalBuilder {
delete(knex: Knex, json: QueryJson, opts: QueryOptions): KnexQuery {
const { endpoint, filters } = json
- let query: KnexQuery = knex(endpoint.entityId)
- if (endpoint.schema) {
- query = query.withSchema(endpoint.schema)
- }
- query = this.addFilters(query, filters, { tableName: endpoint.entityId })
+ let { query, name: aliased } = this.knexWithAlias(knex, endpoint)
+ query = this.addFilters(query, filters, { tableName: aliased })
// mysql can't use returning
if (opts.disableReturning) {
return query.delete()
From ed403fd79daebbb8649566c5d10dfd7bbe1192a1 Mon Sep 17 00:00:00 2001
From: Andrew Kingston
Date: Fri, 8 Dec 2023 13:45:51 +0000
Subject: [PATCH 008/783] WIP
---
packages/builder/src/builderStore/store/frontend.js | 8 +++++++-
.../components/common/bindings/BindingPanel.svelte | 3 +++
.../components/common/bindings/BindingPicker.svelte | 13 +++++++++----
.../common/bindings/ClientBindingPanel.svelte | 3 ++-
.../common/bindings/DrawerBindableInput.svelte | 4 +++-
.../design/settings/controls/PropertyControl.svelte | 2 ++
.../Component/ComponentSettingsSection.svelte | 9 +++++++++
.../design/[screenId]/_components/AppPreview.svelte | 10 ++++++++++
packages/client/src/index.js | 6 ++++++
9 files changed, 51 insertions(+), 7 deletions(-)
diff --git a/packages/builder/src/builderStore/store/frontend.js b/packages/builder/src/builderStore/store/frontend.js
index 2e22276e50..83f72669ee 100644
--- a/packages/builder/src/builderStore/store/frontend.js
+++ b/packages/builder/src/builderStore/store/frontend.js
@@ -88,7 +88,7 @@ const INITIAL_FRONTEND_STATE = {
selectedLayoutId: null,
// Client state
- selectedComponentInstance: null,
+ selectedComponentContext: null,
// Onboarding
onboarding: false,
@@ -504,6 +504,12 @@ export const getFrontendStore = () => {
return state
})
},
+ setSelectedComponentContext: context => {
+ store.update(state => {
+ state.selectedComponentContext = context
+ return state
+ })
+ },
},
layouts: {
select: layoutId => {
diff --git a/packages/builder/src/components/common/bindings/BindingPanel.svelte b/packages/builder/src/components/common/bindings/BindingPanel.svelte
index 4df26c5d03..927b5cb82a 100644
--- a/packages/builder/src/components/common/bindings/BindingPanel.svelte
+++ b/packages/builder/src/components/common/bindings/BindingPanel.svelte
@@ -45,6 +45,7 @@
export let valid
export let allowJS = false
export let allowHelpers = true
+ export let context = null
const drawerActions = getContext("drawer-actions")
const bindingDrawerActions = getContext("binding-drawer-actions")
@@ -250,6 +251,7 @@
import groupBy from "lodash/fp/groupBy"
- import { convertToJS } from "@budibase/string-templates"
+ import { convertToJS, processStringSync } from "@budibase/string-templates"
import { Input, Layout, ActionButton, Icon, Popover } from "@budibase/bbui"
import { handlebarsCompletions } from "constants/completions"
@@ -9,6 +9,7 @@
export let bindings
export let mode
export let allowHelpers
+ export let context = null
let search = ""
let popover
@@ -95,6 +96,9 @@
{#if hoverTarget.example}
{hoverTarget.example}
{/if}
+ {#if hoverTarget.val}
+ {hoverTarget.val}
+ {/if}
@@ -165,13 +169,14 @@
{
+ const hbs = `{{ ${binding.runtimeBinding} }}`
+ const val = processStringSync(hbs, context)
+ console.log(binding.runtimeBinding, val)
popoverAnchor = e.target
- if (!binding.description) {
- return
- }
hoverTarget = {
title: binding.display?.name || binding.fieldSchema?.name,
description: binding.description,
+ val,
}
popover.show()
e.stopPropagation()
diff --git a/packages/builder/src/components/common/bindings/ClientBindingPanel.svelte b/packages/builder/src/components/common/bindings/ClientBindingPanel.svelte
index 74e14574ab..a46c18af27 100644
--- a/packages/builder/src/components/common/bindings/ClientBindingPanel.svelte
+++ b/packages/builder/src/components/common/bindings/ClientBindingPanel.svelte
@@ -6,7 +6,7 @@
export let value = ""
export let allowJS = false
export let allowHelpers = true
-
+ export let context = null
$: enrichedBindings = enrichBindings(bindings)
// Ensure bindings have the correct categories
@@ -24,6 +24,7 @@
(tempValue = event.detail)}
+ {context}
{bindings}
{allowJS}
{allowHelpers}
diff --git a/packages/builder/src/components/design/settings/controls/PropertyControl.svelte b/packages/builder/src/components/design/settings/controls/PropertyControl.svelte
index a6f3d1b218..2195e8a1b9 100644
--- a/packages/builder/src/components/design/settings/controls/PropertyControl.svelte
+++ b/packages/builder/src/components/design/settings/controls/PropertyControl.svelte
@@ -24,6 +24,7 @@
export let propertyFocus = false
export let info = null
export let disableBindings = false
+ export let context = null
$: nullishValue = value == null || value === ""
$: allBindings = getAllBindings(bindings, componentBindings, nested)
@@ -97,6 +98,7 @@
onChange={handleChange}
bindings={allBindings}
name={key}
+ {context}
{nested}
{key}
{type}
diff --git a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/[componentId]/_components/Component/ComponentSettingsSection.svelte b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/[componentId]/_components/Component/ComponentSettingsSection.svelte
index 6093d2a45e..eb69756626 100644
--- a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/[componentId]/_components/Component/ComponentSettingsSection.svelte
+++ b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/[componentId]/_components/Component/ComponentSettingsSection.svelte
@@ -8,6 +8,7 @@
import { getComponentForSetting } from "components/design/settings/componentSettings"
import InfoDisplay from "./InfoDisplay.svelte"
import analytics, { Events } from "analytics"
+ import { onMount } from "svelte"
export let componentDefinition
export let componentInstance
@@ -26,6 +27,7 @@
tag,
includeHidden
)
+ $: context = $store.selectedComponentContext
const getSections = (instance, definition, isScreen, tag, includeHidden) => {
const settings = definition?.settings ?? []
@@ -145,6 +147,12 @@
}
return shouldDisplay(instance, setting)
}
+
+ onMount(() => {
+ store.actions.preview.sendEvent("request-context")
+ })
+
+ $: console.log(context)
{#each sections as section, idx (section.name)}
@@ -191,6 +199,7 @@
min: setting.min ?? null,
max: setting.max ?? null,
}}
+ {context}
{bindings}
{componentBindings}
{componentInstance}
diff --git a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/_components/AppPreview.svelte b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/_components/AppPreview.svelte
index 45fe005ceb..a6820cb551 100644
--- a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/_components/AppPreview.svelte
+++ b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/_components/AppPreview.svelte
@@ -181,6 +181,16 @@
} else if (type === "add-parent-component") {
const { componentId, parentType } = data
await store.actions.components.addParent(componentId, parentType)
+ } else if (type === "provide-context") {
+ let context = data?.context
+ if (context) {
+ try {
+ context = JSON.parse(context)
+ } catch (error) {
+ context = null
+ }
+ }
+ store.actions.preview.setSelectedComponentContext(context)
} else {
console.warn(`Client sent unknown event type: ${type}`)
}
diff --git a/packages/client/src/index.js b/packages/client/src/index.js
index 415d9fa5f2..2d2419eeca 100644
--- a/packages/client/src/index.js
+++ b/packages/client/src/index.js
@@ -75,6 +75,12 @@ const loadBudibase = async () => {
} else {
dndStore.actions.reset()
}
+ } else if (type === "request-context") {
+ const { selectedComponentInstance } = get(componentStore)
+ const context = selectedComponentInstance?.getDataContext()
+ eventStore.actions.dispatchEvent("provide-context", {
+ context: JSON.stringify(context),
+ })
}
}
From 3ce00c42a2e9751bcfb17d906b8b8a8c85f04752 Mon Sep 17 00:00:00 2001
From: mike12345567
Date: Thu, 18 Jan 2024 18:13:11 +0000
Subject: [PATCH 009/783] Adding SQL logging capabilities.
---
packages/server/src/environment.ts | 1 +
packages/server/src/integrations/base/sql.ts | 12 +
.../src/integrations/microsoftSqlServer.ts | 1 +
packages/server/src/integrations/mysql.ts | 1 +
packages/server/src/integrations/oracle.ts | 1 +
packages/server/src/integrations/postgres.ts | 4 +-
yarn.lock | 660 +-----------------
7 files changed, 55 insertions(+), 625 deletions(-)
diff --git a/packages/server/src/environment.ts b/packages/server/src/environment.ts
index f692a8b6cf..f46abe5b16 100644
--- a/packages/server/src/environment.ts
+++ b/packages/server/src/environment.ts
@@ -67,6 +67,7 @@ const environment = {
DISABLE_RATE_LIMITING: process.env.DISABLE_RATE_LIMITING,
MULTI_TENANCY: process.env.MULTI_TENANCY,
ENABLE_ANALYTICS: process.env.ENABLE_ANALYTICS,
+ ENABLE_SQL_LOGGING: process.env.ENABLE_SQL_LOGGING,
SELF_HOSTED: process.env.SELF_HOSTED,
HTTP_MB_LIMIT: process.env.HTTP_MB_LIMIT,
FORKED_PROCESS_NAME: process.env.FORKED_PROCESS_NAME || "main",
diff --git a/packages/server/src/integrations/base/sql.ts b/packages/server/src/integrations/base/sql.ts
index 14bcb532cc..3375e175e6 100644
--- a/packages/server/src/integrations/base/sql.ts
+++ b/packages/server/src/integrations/base/sql.ts
@@ -671,6 +671,18 @@ class SqlQueryBuilder extends SqlTableQueryBuilder {
}
return results.length ? results : [{ [operation.toLowerCase()]: true }]
}
+
+ log(query: string, values?: any[]) {
+ if (!environment.ENABLE_SQL_LOGGING) {
+ return
+ }
+ const sqlClient = this.getSqlClient()
+ let string = `[SQL] [${sqlClient.toUpperCase()}] query="${query}"`
+ if (values) {
+ string += ` values="${values.join(", ")}"`
+ }
+ console.log(string)
+ }
}
export default SqlQueryBuilder
diff --git a/packages/server/src/integrations/microsoftSqlServer.ts b/packages/server/src/integrations/microsoftSqlServer.ts
index d0a06d4476..e063933503 100644
--- a/packages/server/src/integrations/microsoftSqlServer.ts
+++ b/packages/server/src/integrations/microsoftSqlServer.ts
@@ -329,6 +329,7 @@ class SqlServerIntegration extends Sql implements DatasourcePlus {
operation === Operation.CREATE
? `${query.sql}; SELECT SCOPE_IDENTITY() AS id;`
: query.sql
+ this.log(sql, query.bindings)
return await request.query(sql)
} catch (err: any) {
let readableMessage = getReadableErrorMessage(
diff --git a/packages/server/src/integrations/mysql.ts b/packages/server/src/integrations/mysql.ts
index 8ec73307f4..6eebda8df5 100644
--- a/packages/server/src/integrations/mysql.ts
+++ b/packages/server/src/integrations/mysql.ts
@@ -261,6 +261,7 @@ class MySQLIntegration extends Sql implements DatasourcePlus {
const bindings = opts?.disableCoercion
? baseBindings
: bindingTypeCoerce(baseBindings)
+ this.log(query.sql, bindings)
// Node MySQL is callback based, so we must wrap our call in a promise
const response = await this.client!.query(query.sql, bindings)
return response[0]
diff --git a/packages/server/src/integrations/oracle.ts b/packages/server/src/integrations/oracle.ts
index e9a2dc7998..1a1e440410 100644
--- a/packages/server/src/integrations/oracle.ts
+++ b/packages/server/src/integrations/oracle.ts
@@ -368,6 +368,7 @@ class OracleIntegration extends Sql implements DatasourcePlus {
const options: ExecuteOptions = { autoCommit: true }
const bindings: BindParameters = query.bindings || []
+ this.log(query.sql, bindings)
return await connection.execute(query.sql, bindings, options)
} finally {
if (connection) {
diff --git a/packages/server/src/integrations/postgres.ts b/packages/server/src/integrations/postgres.ts
index 78955c06dc..f8cd2b62fc 100644
--- a/packages/server/src/integrations/postgres.ts
+++ b/packages/server/src/integrations/postgres.ts
@@ -262,7 +262,9 @@ class PostgresIntegration extends Sql implements DatasourcePlus {
}
}
try {
- return await client.query(query.sql, query.bindings || [])
+ const bindings = query.bindings || []
+ this.log(query.sql, bindings)
+ return await client.query(query.sql, bindings)
} catch (err: any) {
await this.closeConnection()
let readableMessage = getReadableErrorMessage(
diff --git a/yarn.lock b/yarn.lock
index 91697cd151..fa746b9d72 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -625,13 +625,6 @@
dependencies:
tslib "^2.5.0"
-"@aws/dynamodb-auto-marshaller@^0.7.1":
- version "0.7.1"
- resolved "https://registry.yarnpkg.com/@aws/dynamodb-auto-marshaller/-/dynamodb-auto-marshaller-0.7.1.tgz#70676c056e4ecb798c08ec2e398a3d93e703858d"
- integrity sha512-LeURlf6/avrfFo9+4Yht9J3CUTJ72yoBpm1FOUmlexuHNW4Ka61tG30w3ZDCXXXmCO2rG0k3ywAgNJEo3WPbyw==
- dependencies:
- tslib "^1.8.1"
-
"@azure/abort-controller@^1.0.0", "@azure/abort-controller@^1.0.4":
version "1.1.0"
resolved "https://registry.yarnpkg.com/@azure/abort-controller/-/abort-controller-1.1.0.tgz#788ee78457a55af8a1ad342acb182383d2119249"
@@ -1980,7 +1973,7 @@
resolved "https://registry.yarnpkg.com/@babel/regjsgen/-/regjsgen-0.8.0.tgz#f0ba69b075e1f05fb2825b7fad991e7adbb18310"
integrity sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA==
-"@babel/runtime@^7.12.5", "@babel/runtime@^7.13.10", "@babel/runtime@^7.15.4", "@babel/runtime@^7.7.2", "@babel/runtime@^7.8.4", "@babel/runtime@^7.9.2":
+"@babel/runtime@^7.12.5", "@babel/runtime@^7.15.4", "@babel/runtime@^7.7.2", "@babel/runtime@^7.8.4", "@babel/runtime@^7.9.2":
version "7.23.8"
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.23.8.tgz#8ee6fe1ac47add7122902f257b8ddf55c898f650"
integrity sha512-Y7KbAP984rn1VGMbGqKmBLio9V7y5Je9GvU4rQPCPinCyNfUcToxIXl06d59URp/F3LwinvODxab5N/G6qggkw==
@@ -2638,14 +2631,6 @@
teeny-request "^8.0.0"
uuid "^8.0.0"
-"@grpc/grpc-js@1.9.7":
- version "1.9.7"
- resolved "https://registry.yarnpkg.com/@grpc/grpc-js/-/grpc-js-1.9.7.tgz#7d0e29bc162287bee2523901c9bc9320d8402397"
- integrity sha512-yMaA/cIsRhGzW3ymCNpdlPcInXcovztlgu/rirThj2b87u3RzWUszliOqZ/pldy7yhmJPS8uwog+kZSTa4A0PQ==
- dependencies:
- "@grpc/proto-loader" "^0.7.8"
- "@types/node" ">=12.12.47"
-
"@grpc/grpc-js@~1.8.0":
version "1.8.21"
resolved "https://registry.yarnpkg.com/@grpc/grpc-js/-/grpc-js-1.8.21.tgz#d282b122c71227859bf6c5866f4c40f4a2696513"
@@ -2654,7 +2639,7 @@
"@grpc/proto-loader" "^0.7.0"
"@types/node" ">=12.12.47"
-"@grpc/proto-loader@0.7.10", "@grpc/proto-loader@^0.7.0", "@grpc/proto-loader@^0.7.8":
+"@grpc/proto-loader@^0.7.0":
version "0.7.10"
resolved "https://registry.yarnpkg.com/@grpc/proto-loader/-/proto-loader-0.7.10.tgz#6bf26742b1b54d0a473067743da5d3189d06d720"
integrity sha512-CAqDfoaQ8ykFd9zqBDn4k6iWT9loLAlc2ETmDFS9JCD70gDcnA4L3AFEo2iV7KyAtAAHFW9ftq1Fz+Vsgq80RQ==
@@ -2676,20 +2661,6 @@
dependencies:
"@hapi/hoek" "^9.0.0"
-"@hubspot/api-client@7.1.2":
- version "7.1.2"
- resolved "https://registry.yarnpkg.com/@hubspot/api-client/-/api-client-7.1.2.tgz#a405b0a18b8caa27f129fd510b2555e5a5cc2708"
- integrity sha512-JVQqh0fdHf97ePk0Hg/7BJsiXNlS9HQRPiM/CLgvVWt5CIviSLQ/kHLZXREmZqTWu7BisjCgHxnSx/d7gRdr2g==
- dependencies:
- bluebird "^3.7.2"
- bottleneck "^2.19.5"
- btoa "^1.2.1"
- es6-promise "^4.2.4"
- form-data "^2.5.0"
- lodash "^4.17.21"
- node-fetch "^2.6.0"
- url-parse "^1.4.3"
-
"@humanwhocodes/config-array@^0.11.13":
version "0.11.13"
resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.11.13.tgz#075dc9684f40a531d9b26b0822153c1e832ee297"
@@ -3341,13 +3312,6 @@
dependencies:
lodash "^4.17.21"
-"@koa/cors@^3.1.0":
- version "3.4.3"
- resolved "https://registry.yarnpkg.com/@koa/cors/-/cors-3.4.3.tgz#d669ee6e8d6e4f0ec4a7a7b0a17e7a3ed3752ebb"
- integrity sha512-WPXQUaAeAMVaLTEFpoq3T2O1C+FstkjJnDQqy95Ck1UdILajsRhu6mhJ8H2f4NFPRBoCNN+qywTJfq/gGki5mw==
- dependencies:
- vary "^1.1.2"
-
"@koa/router@8.0.8":
version "8.0.8"
resolved "https://registry.yarnpkg.com/@koa/router/-/router-8.0.8.tgz#95f32d11373d03d89dcb63fabe9ac6f471095236"
@@ -3956,14 +3920,6 @@
is-module "^1.0.0"
resolve "^1.19.0"
-"@rollup/plugin-replace@^2.4.2":
- version "2.4.2"
- resolved "https://registry.yarnpkg.com/@rollup/plugin-replace/-/plugin-replace-2.4.2.tgz#a2d539314fbc77c244858faa523012825068510a"
- integrity sha512-IGcu+cydlUMZ5En85jxHH4qj2hta/11BHq95iHEyb2sbgiN0eCdzvUcHw5gt9pBL5lTi4JDYJ1acCoMGpTvEZg==
- dependencies:
- "@rollup/pluginutils" "^3.1.0"
- magic-string "^0.25.7"
-
"@rollup/plugin-replace@^5.0.2", "@rollup/plugin-replace@^5.0.3":
version "5.0.5"
resolved "https://registry.yarnpkg.com/@rollup/plugin-replace/-/plugin-replace-5.0.5.tgz#33d5653dce6d03cb24ef98bef7f6d25b57faefdf"
@@ -4006,23 +3962,6 @@
estree-walker "^2.0.2"
picomatch "^2.3.1"
-"@roxi/routify@2.18.0":
- version "2.18.0"
- resolved "https://registry.yarnpkg.com/@roxi/routify/-/routify-2.18.0.tgz#8f88bedd936312d0dbe44cbc11ab179b1f938ec2"
- integrity sha512-MVB50HN+VQWLzfjLplcBjsSBvwOiExKOmht2DuWR3WQ60JxQi9pSejkB06tFVkFKNXz2X5iYtKDqKBTdae/gRg==
- dependencies:
- "@roxi/ssr" "^0.2.1"
- "@types/node" ">=4.2.0 < 13"
- chalk "^4.0.0"
- cheap-watch "^1.0.2"
- commander "^7.1.0"
- configent "^2.1.4"
- esm "^3.2.25"
- fs-extra "^9.0.1"
- log-symbols "^3.0.0"
- picomatch "^2.2.2"
- rollup-pluginutils "^2.8.2"
-
"@roxi/routify@2.18.12":
version "2.18.12"
resolved "https://registry.yarnpkg.com/@roxi/routify/-/routify-2.18.12.tgz#901ca95b96f274ddddaefbf18424557ee1ae3fae"
@@ -4104,11 +4043,6 @@
resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-0.7.0.tgz#9a06f4f137ee84d7df0460c1fdb1135ffa6c50fd"
integrity sha512-ONhaKPIufzzrlNbqtWFFd+jlnemX6lJAgq9ZeiZtS7I1PIf/la7CW4m83rTXRnVnsMbW2k56pGYu7AUFJD9Pow==
-"@sindresorhus/is@^4.0.0":
- version "4.6.0"
- resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-4.6.0.tgz#3c7c9c46e678feefe7a2e5bb609d3dbd665ffb3f"
- integrity sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==
-
"@sinonjs/commons@^2.0.0":
version "2.0.0"
resolved "https://registry.yarnpkg.com/@sinonjs/commons/-/commons-2.0.0.tgz#fd4ca5b063554307e8327b4564bd56d3b73924a3"
@@ -4932,13 +4866,6 @@
dependencies:
defer-to-connect "^1.0.1"
-"@szmarczak/http-timer@^4.0.5":
- version "4.0.6"
- resolved "https://registry.yarnpkg.com/@szmarczak/http-timer/-/http-timer-4.0.6.tgz#b4a914bb62e7c272d4e5989fe4440f812ab1d807"
- integrity sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w==
- dependencies:
- defer-to-connect "^2.0.0"
-
"@techpass/passport-openidconnect@0.3.2":
version "0.3.2"
resolved "https://registry.yarnpkg.com/@techpass/passport-openidconnect/-/passport-openidconnect-0.3.2.tgz#f8fd5d97256286665dbf26dac92431f977ab1e63"
@@ -4950,17 +4877,6 @@
request "^2.88.0"
webfinger "^0.4.2"
-"@techpass/passport-openidconnect@^0.3.0":
- version "0.3.3"
- resolved "https://registry.yarnpkg.com/@techpass/passport-openidconnect/-/passport-openidconnect-0.3.3.tgz#6c01c78bd8da0ca8917378dfbe18024702620352"
- integrity sha512-i2X/CofjnGBqpTmw6b+Ex3Co/NrR2xjnIHvnOJk62XIlJJHNSTwmhJ1PkXoA5RGKlxZWchADFGjLTJnebvRj7A==
- dependencies:
- base64url "^3.0.1"
- oauth "^0.9.15"
- passport-strategy "^1.0.0"
- request "^2.88.0"
- webfinger "^0.4.2"
-
"@techteamer/ocsp@1.0.0":
version "1.0.0"
resolved "https://registry.yarnpkg.com/@techteamer/ocsp/-/ocsp-1.0.0.tgz#7b82b02093fbe351e915bb37685ac1ac5a1233d3"
@@ -5133,16 +5049,6 @@
"@types/connect" "*"
"@types/node" "*"
-"@types/cacheable-request@^6.0.1":
- version "6.0.3"
- resolved "https://registry.yarnpkg.com/@types/cacheable-request/-/cacheable-request-6.0.3.tgz#a430b3260466ca7b5ca5bfd735693b36e7a9d183"
- integrity sha512-IQ3EbTzGxIigb1I3qPZc1rWJnH0BmSKv5QYTalEwweFvyBDLSAe24zP0le/hyi7ecGfZVlIVAg4BZqb8WBwKqw==
- dependencies:
- "@types/http-cache-semantics" "*"
- "@types/keyv" "^3.1.4"
- "@types/node" "*"
- "@types/responselike" "^1.0.0"
-
"@types/caseless@*":
version "0.12.2"
resolved "https://registry.yarnpkg.com/@types/caseless/-/caseless-0.12.2.tgz#f65d3d6389e01eeb458bd54dc8f52b95a9463bc8"
@@ -5307,11 +5213,6 @@
resolved "https://registry.yarnpkg.com/@types/http-assert/-/http-assert-1.5.3.tgz#ef8e3d1a8d46c387f04ab0f2e8ab8cb0c5078661"
integrity sha512-FyAOrDuQmBi8/or3ns4rwPno7/9tJTijVW6aQQjK02+kOQ8zmoNg2XJtAuQhvQcy1ASJq38wirX5//9J1EqoUA==
-"@types/http-cache-semantics@*":
- version "4.0.4"
- resolved "https://registry.yarnpkg.com/@types/http-cache-semantics/-/http-cache-semantics-4.0.4.tgz#b979ebad3919799c979b17c72621c0bc0a31c6c4"
- integrity sha512-1m0bIFVc7eJWyve9S0RnuRgcQqF/Xd5QsUZAZeQFr1Q3/p9JWoQQEqmVy+DPTNpGXwhgIetAoYF8JSc33q29QA==
-
"@types/http-errors@*":
version "2.0.1"
resolved "https://registry.yarnpkg.com/@types/http-errors/-/http-errors-2.0.1.tgz#20172f9578b225f6c7da63446f56d4ce108d5a65"
@@ -5373,13 +5274,6 @@
resolved "https://registry.yarnpkg.com/@types/keygrip/-/keygrip-1.0.2.tgz#513abfd256d7ad0bf1ee1873606317b33b1b2a72"
integrity sha512-GJhpTepz2udxGexqos8wgaBx4I/zWIDPh/KOGEwAqtuGDkOUJu5eFvwmdBX4AmB8Odsr+9pHCQqiAqDL/yKMKw==
-"@types/keyv@^3.1.4":
- version "3.1.4"
- resolved "https://registry.yarnpkg.com/@types/keyv/-/keyv-3.1.4.tgz#3ccdb1c6751b0c7e52300bcdacd5bcbf8faa75b6"
- integrity sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==
- dependencies:
- "@types/node" "*"
-
"@types/koa-compose@*":
version "3.2.5"
resolved "https://registry.yarnpkg.com/@types/koa-compose/-/koa-compose-3.2.5.tgz#85eb2e80ac50be95f37ccf8c407c09bbe3468e9d"
@@ -5387,29 +5281,13 @@
dependencies:
"@types/koa" "*"
-"@types/koa-passport@^4.0.3":
- version "4.0.3"
- resolved "https://registry.yarnpkg.com/@types/koa-passport/-/koa-passport-4.0.3.tgz#063ec6310edee76cf854aadaa717b97f04b104fb"
- integrity sha512-tNMYd/bcv0Zw7fc0CzEBYM9uUzVtn4XWzdUYfkTgSkEljP6nap7eI4E5x43ukrUQvztgXSYFkz3Uk+ujFeUzTg==
- dependencies:
- "@types/koa" "*"
- "@types/passport" "*"
-
-"@types/koa-send@*", "@types/koa-send@^4.1.6":
+"@types/koa-send@^4.1.6":
version "4.1.6"
resolved "https://registry.yarnpkg.com/@types/koa-send/-/koa-send-4.1.6.tgz#15d90e95e3ccce669a15b6a3c56c3a650a167cea"
integrity sha512-vgnNGoOJkx7FrF0Jl6rbK1f8bBecqAchKpXtKuXzqIEdXTDO6dsSTjr+eZ5m7ltSjH4K/E7auNJEQCAd0McUPA==
dependencies:
"@types/koa" "*"
-"@types/koa-static@^4.0.2":
- version "4.0.4"
- resolved "https://registry.yarnpkg.com/@types/koa-static/-/koa-static-4.0.4.tgz#ce6f2a5d14cc7ef19f9bf6ee8e4f3eadfcc77323"
- integrity sha512-j1AUzzl7eJYEk9g01hNTlhmipFh8RFbOQmaMNLvLcNNAkPw0bdTs3XTa3V045XFlrWN0QYnblbDJv2RzawTn6A==
- dependencies:
- "@types/koa" "*"
- "@types/koa-send" "*"
-
"@types/koa@*":
version "2.13.5"
resolved "https://registry.yarnpkg.com/@types/koa/-/koa-2.13.5.tgz#64b3ca4d54e08c0062e89ec666c9f45443b21a61"
@@ -5438,13 +5316,6 @@
"@types/koa-compose" "*"
"@types/node" "*"
-"@types/koa__cors@^3.1.1":
- version "3.3.1"
- resolved "https://registry.yarnpkg.com/@types/koa__cors/-/koa__cors-3.3.1.tgz#0ec7543c4c620fd23451bfdd3e21b9a6aadedccd"
- integrity sha512-aFGYhTFW7651KhmZZ05VG0QZJre7QxBxDj2LF1lf6GA/wSXEfKVAJxiQQWzRV4ZoMzQIO8vJBXKsUcRuvYK9qw==
- dependencies:
- "@types/koa" "*"
-
"@types/koa__router@8.0.8":
version "8.0.8"
resolved "https://registry.yarnpkg.com/@types/koa__router/-/koa__router-8.0.8.tgz#b1e0e9a512498777d3366bbdf0e853df27ec831c"
@@ -5546,42 +5417,21 @@
dependencies:
undici-types "~5.26.4"
-"@types/node@>=4.2.0 < 13", "@types/node@^12.20.52":
- version "12.20.55"
- resolved "https://registry.yarnpkg.com/@types/node/-/node-12.20.55.tgz#c329cbd434c42164f846b909bd6f85b5537f6240"
- integrity sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ==
-
"@types/node@>=8.0.0 <15":
version "14.18.37"
resolved "https://registry.yarnpkg.com/@types/node/-/node-14.18.37.tgz#0bfcd173e8e1e328337473a8317e37b3b14fd30d"
integrity sha512-7GgtHCs/QZrBrDzgIJnQtuSvhFSwhyYSI2uafSwZoNt1iOGhEN5fwNrQMjtONyHm9+/LoA4453jH0CMYcr06Pg==
-"@types/node@>=8.1.0":
- version "20.11.2"
- resolved "https://registry.yarnpkg.com/@types/node/-/node-20.11.2.tgz#39cea3fe02fbbc2f80ed283e94e1d24f2d3856fb"
- integrity sha512-cZShBaVa+UO1LjWWBPmWRR4+/eY/JR/UIEcDlVsw3okjWEu+rB7/mH6X3B/L+qJVHDLjk9QW/y2upp9wp1yDXA==
- dependencies:
- undici-types "~5.26.4"
-
-"@types/nodemailer@^6.4.4":
- version "6.4.14"
- resolved "https://registry.yarnpkg.com/@types/nodemailer/-/nodemailer-6.4.14.tgz#5c81a5e856db7f8ede80013e6dbad7c5fb2283e2"
- integrity sha512-fUWthHO9k9DSdPCSPRqcu6TWhYyxTBg382vlNIttSe9M7XfsT06y0f24KHXtbnijPGGRIcVvdKHTNikOI6qiHA==
- dependencies:
- "@types/node" "*"
+"@types/node@^12.20.52":
+ version "12.20.55"
+ resolved "https://registry.yarnpkg.com/@types/node/-/node-12.20.55.tgz#c329cbd434c42164f846b909bd6f85b5537f6240"
+ integrity sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ==
"@types/normalize-package-data@^2.4.0":
version "2.4.1"
resolved "https://registry.yarnpkg.com/@types/normalize-package-data/-/normalize-package-data-2.4.1.tgz#d3357479a0fdfdd5907fe67e17e0a85c906e1301"
integrity sha512-Gj7cI7z+98M282Tqmp2K5EIsoouUEzbBJhQQzDE3jSIRk6r9gsz0oUokqIUR4u1R3dMHo0pDHM7sNOHyhulypw==
-"@types/oauth@*":
- version "0.9.4"
- resolved "https://registry.yarnpkg.com/@types/oauth/-/oauth-0.9.4.tgz#dcbab5efa2f34f312b915f80685760ccc8111e0a"
- integrity sha512-qk9orhti499fq5XxKCCEbd0OzdPZuancneyse3KtR+vgMiHRbh+mn8M4G6t64ob/Fg+GZGpa565MF/2dKWY32A==
- dependencies:
- "@types/node" "*"
-
"@types/oracledb@5.2.2":
version "5.2.2"
resolved "https://registry.yarnpkg.com/@types/oracledb/-/oracledb-5.2.2.tgz#ae7ba795969e3bbd8d57ab141873a1aa012b86cd"
@@ -5590,37 +5440,6 @@
"@types/node" "*"
dotenv "^8.2.0"
-"@types/passport-google-oauth@^1.0.42":
- version "1.0.45"
- resolved "https://registry.yarnpkg.com/@types/passport-google-oauth/-/passport-google-oauth-1.0.45.tgz#c986c787ec9706b4a596d2bae43342b50b54973d"
- integrity sha512-O3Y3DDKnf9lR8+DSaUOCEGF6aFjVYdI8TLhQYtySZ3Sq75c5tGYJ0KJRDZw0GsyLD/Que0nqFkP/GnDVwZZL9w==
- dependencies:
- "@types/express" "*"
- "@types/passport" "*"
-
-"@types/passport-microsoft@1.0.0":
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/@types/passport-microsoft/-/passport-microsoft-1.0.0.tgz#a2ddc2200843570d38c35c53f6388e33df915b58"
- integrity sha512-vD9ajSUc9Sz/8gdCj0ODUbPYQDxcI/imIDdgMPh//c5yMK/PgV6SNUXFLBzJo89Y30LU6bYAfXKn40WJqtMBiA==
- dependencies:
- "@types/passport-oauth2" "*"
-
-"@types/passport-oauth2@*":
- version "1.4.15"
- resolved "https://registry.yarnpkg.com/@types/passport-oauth2/-/passport-oauth2-1.4.15.tgz#34f2684f53aad36e664cd01ca9879224229f47e7"
- integrity sha512-9cUTP/HStNSZmhxXGuRrBJfEWzIEJRub2eyJu3CvkA+8HAMc9W3aKdFhVq+Qz1hi42qn+GvSAnz3zwacDSYWpw==
- dependencies:
- "@types/express" "*"
- "@types/oauth" "*"
- "@types/passport" "*"
-
-"@types/passport@*":
- version "1.0.16"
- resolved "https://registry.yarnpkg.com/@types/passport/-/passport-1.0.16.tgz#5a2918b180a16924c4d75c31254c31cdca5ce6cf"
- integrity sha512-FD0qD5hbPWQzaM0wHUnJ/T0BBCJBxCeemtnCwc/ThhTg3x9jfrAcRUmj5Dopza+MfFS9acTe3wk7rcVnRIp/0A==
- dependencies:
- "@types/express" "*"
-
"@types/pg@8.6.6":
version "8.6.6"
resolved "https://registry.yarnpkg.com/@types/pg/-/pg-8.6.6.tgz#21cdf873a3e345a6e78f394677e3b3b1b543cb80"
@@ -5825,13 +5644,6 @@
dependencies:
"@types/node" "*"
-"@types/responselike@^1.0.0":
- version "1.0.3"
- resolved "https://registry.yarnpkg.com/@types/responselike/-/responselike-1.0.3.tgz#cc29706f0a397cfe6df89debfe4bf5cea159db50"
- integrity sha512-H/+L+UkTV33uf49PH5pCAUBVPNj2nDBXTN+qS1dOwyyg24l3CcicicCA7ca+HMvJBZcFgl5r8e+RR6elsb4Lyw==
- dependencies:
- "@types/node" "*"
-
"@types/rimraf@^3.0.2":
version "3.0.2"
resolved "https://registry.yarnpkg.com/@types/rimraf/-/rimraf-3.0.2.tgz#a63d175b331748e5220ad48c901d7bbf1f44eef8"
@@ -5860,13 +5672,6 @@
dependencies:
"@types/node" "*"
-"@types/server-destroy@^1.0.1":
- version "1.0.3"
- resolved "https://registry.yarnpkg.com/@types/server-destroy/-/server-destroy-1.0.3.tgz#2460932ea3a02a70ec99669c8f40ff089a5b8a2b"
- integrity sha512-Qq0fn70C7TLDG1W9FCblKufNWW1OckQ41dVKV2Dku5KdZF7bexezG4e2WBaBKhdwL3HZ+cYCEIKwg2BRgzrWmA==
- dependencies:
- "@types/node" "*"
-
"@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"
@@ -5948,7 +5753,7 @@
dependencies:
"@types/node" "*"
-"@types/uuid@8.3.4", "@types/uuid@^8.3.4":
+"@types/uuid@8.3.4":
version "8.3.4"
resolved "https://registry.yarnpkg.com/@types/uuid/-/uuid-8.3.4.tgz#bd86a43617df0594787d38b735f55c805becf1bc"
integrity sha512-c/I8ZRb51j+pYGAu5CrFMRxqZ2ke4y2grEBO5AUjgSkSk+qT2Ea+OdWElz/OiMf5MNpn2b17kuVBwZLQJXzihw==
@@ -6290,6 +6095,11 @@
js-yaml "^3.10.0"
tslib "^2.4.0"
+"@zerodevx/svelte-json-view@^1.0.7":
+ version "1.0.7"
+ resolved "https://registry.yarnpkg.com/@zerodevx/svelte-json-view/-/svelte-json-view-1.0.7.tgz#abf3efa71dedcb3e9d16bc9cc61d5ea98c8d00b1"
+ integrity sha512-yW0MV+9BCKOwzt3h86y3xDqYdI5st+Rxk+L5pa0Utq7nlPD+VvxyhL7R1gJoLxQvWwjyAvY/fyUCFTdwDyI14w==
+
"@zkochan/js-yaml@0.0.6":
version "0.0.6"
resolved "https://registry.yarnpkg.com/@zkochan/js-yaml/-/js-yaml-0.0.6.tgz#975f0b306e705e28b8068a07737fa46d3fc04826"
@@ -6332,7 +6142,7 @@ abortcontroller-polyfill@^1.4.0:
resolved "https://registry.yarnpkg.com/abortcontroller-polyfill/-/abortcontroller-polyfill-1.7.5.tgz#6738495f4e901fbb57b6c0611d0c75f76c485bed"
integrity sha512-JMJ5soJWP18htbbxJjG7bG6yuI6pRhgJ0scHHTfkUjf6wjP912xZWvM+A4sJK3gqd9E8fcPbDnOefbA9Th/FIQ==
-abstract-leveldown@^6.2.1, abstract-leveldown@^6.3.0:
+abstract-leveldown@^6.2.1:
version "6.3.0"
resolved "https://registry.yarnpkg.com/abstract-leveldown/-/abstract-leveldown-6.3.0.tgz#d25221d1e6612f820c35963ba4bd739928f6026a"
integrity sha512-TU5nlYgta8YrBMNpc9FwQzRbiXsj49gsALsXadbGHt9CROPzX5fB0rWDR5mtdpOOKa5XqRFpbj1QroPAoPzVjQ==
@@ -6854,13 +6664,6 @@ async-retry@^1.3.3:
dependencies:
retry "0.13.1"
-async@^2.6.3:
- version "2.6.4"
- resolved "https://registry.yarnpkg.com/async/-/async-2.6.4.tgz#706b7ff6084664cd7eae713f6f965433b5504221"
- integrity sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==
- dependencies:
- lodash "^4.17.14"
-
async@^3.2.1, async@^3.2.3:
version "3.2.4"
resolved "https://registry.yarnpkg.com/async/-/async-3.2.4.tgz#2d22e00f8cddeb5fde5dd33522b56d1cf569a81c"
@@ -7234,11 +7037,6 @@ bootstrap@3.4.1:
resolved "https://registry.yarnpkg.com/bootstrap/-/bootstrap-3.4.1.tgz#c3a347d419e289ad11f4033e3c4132b87c081d72"
integrity sha512-yN5oZVmRCwe5aKwzRj6736nSmKDX7pLYwsXiCj/EYmo16hODaBiT4En5btW/jhBF/seV+XMx3aYwukYC3A49DA==
-bottleneck@^2.19.5:
- version "2.19.5"
- resolved "https://registry.yarnpkg.com/bottleneck/-/bottleneck-2.19.5.tgz#5df0b90f59fd47656ebe63c78a98419205cadd91"
- integrity sha512-VHiNCbI1lKdl44tGrhNfU3lup0Tj/ZBMJB5/2ZbNXRCPuRCO7ed2mgcK4r17y+KB2EfuYuRaVlwNbAeaWGSpbw==
-
bowser@^2.11.0:
version "2.11.0"
resolved "https://registry.yarnpkg.com/bowser/-/bowser-2.11.0.tgz#5ca3c35757a7aa5771500c70a73a9f91ef420a8f"
@@ -7387,11 +7185,6 @@ bson@^5.4.0:
resolved "https://registry.yarnpkg.com/bson/-/bson-5.4.0.tgz#0eea77276d490953ad8616b483298dbff07384c6"
integrity sha512-WRZ5SQI5GfUuKnPTNmAYPiKIof3ORXAF4IRU5UcgmivNIon01rWQlw5RUH954dpu8yGL8T59YShVddIPaU/gFA==
-btoa@^1.2.1:
- version "1.2.1"
- resolved "https://registry.yarnpkg.com/btoa/-/btoa-1.2.1.tgz#01a9909f8b2c93f6bf680ba26131eb30f7fa3d73"
- integrity sha512-SB4/MIGlsiVkMcHmT+pSmIPoNDoHg+7cMzmt3Uxt628MTz2487DKSqK/fuhFBrkuqrYv5UCEnACpF4dTFNKc/g==
-
buffer-alloc-unsafe@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz#bd7dc26ae2972d0eda253be061dba992349c19f0"
@@ -7405,7 +7198,7 @@ buffer-alloc@^1.2.0:
buffer-alloc-unsafe "^1.1.0"
buffer-fill "^1.0.0"
-buffer-crc32@^0.2.13, buffer-crc32@~0.2.3:
+buffer-crc32@~0.2.3:
version "0.2.13"
resolved "https://registry.yarnpkg.com/buffer-crc32/-/buffer-crc32-0.2.13.tgz#0d333e3f00eac50aa1454abd30ef8c2a5d9a7242"
integrity sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==
@@ -7590,11 +7383,6 @@ cache-content-type@^1.0.0:
mime-types "^2.1.18"
ylru "^1.2.0"
-cacheable-lookup@^5.0.3:
- version "5.0.4"
- resolved "https://registry.yarnpkg.com/cacheable-lookup/-/cacheable-lookup-5.0.4.tgz#5a6b865b2c44357be3d5ebc2a467b032719a7005"
- integrity sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA==
-
cacheable-request@^2.1.1:
version "2.1.4"
resolved "https://registry.yarnpkg.com/cacheable-request/-/cacheable-request-2.1.4.tgz#0d808801b6342ad33c91df9d0b44dc09b91e5c3d"
@@ -7621,19 +7409,6 @@ cacheable-request@^6.0.0:
normalize-url "^4.1.0"
responselike "^1.0.2"
-cacheable-request@^7.0.2:
- version "7.0.4"
- resolved "https://registry.yarnpkg.com/cacheable-request/-/cacheable-request-7.0.4.tgz#7a33ebf08613178b403635be7b899d3e69bbe817"
- integrity sha512-v+p6ongsrp0yTGbJXjgxPow2+DL93DASP4kXCDKb8/bwRtt9OEF3whggkkDkGNzgcWy2XaF4a8nZglC7uElscg==
- dependencies:
- clone-response "^1.0.2"
- get-stream "^5.1.0"
- http-cache-semantics "^4.0.0"
- keyv "^4.0.0"
- lowercase-keys "^2.0.0"
- normalize-url "^6.0.1"
- responselike "^2.0.0"
-
call-bind@^1.0.0, call-bind@^1.0.2, call-bind@^1.0.4, call-bind@^1.0.5:
version "1.0.5"
resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.5.tgz#6fa2b7845ce0ea49bf4d8b9ef64727a2c2e2e513"
@@ -7672,52 +7447,6 @@ camelcase@^6.2.0:
resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.3.0.tgz#5685b95eb209ac9c0c177467778c9c84df58ba9a"
integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==
-camunda-8-credentials-from-env@^1.1.1, camunda-8-credentials-from-env@^1.2.2:
- version "1.2.2"
- resolved "https://registry.yarnpkg.com/camunda-8-credentials-from-env/-/camunda-8-credentials-from-env-1.2.2.tgz#abe5d216e7e4cfc970e0463e9aa5e802487b1062"
- integrity sha512-uj2PY5/IoAgu0cHmeEUp+qmSXCtpQafStzGJ8ORYvyupBN/gVpdP9X+A+UlQRCGmApcaIuPUw8/9FsXig5NWXg==
- dependencies:
- neon-env "^0.1.1"
-
-camunda-8-sdk@^0.15.0:
- version "0.15.0"
- resolved "https://registry.yarnpkg.com/camunda-8-sdk/-/camunda-8-sdk-0.15.0.tgz#13754dca499d16802675b6f2790e2d06bd8034d6"
- integrity sha512-felyQU+rD8uupPjBArmyy0E/k9mrmeZvfFliF3y/pxYkGBoaC5kjDHDsx+hNpbnIwShET0RLjklit7f+98yIBw==
- dependencies:
- camunda-console-client "^0.9.1"
- camunda-tasklist-client "0.9.5"
- operate-api-client "1.2.3"
- optimize-api-client "^1.0.3"
- zeebe-node "^8.2.5"
-
-camunda-console-client@^0.9.1:
- version "0.9.2"
- resolved "https://registry.yarnpkg.com/camunda-console-client/-/camunda-console-client-0.9.2.tgz#137dbd2e61bb5bbfff38aebe5d53e775653aabb8"
- integrity sha512-ni+7lSc5oG0FevCagrBV6juZzwcQ4ciATBZxyOMFQK0yVTmZxOUz5efN9XWP4E36PGpuqALQXsViUDlGZcfZBA==
- dependencies:
- camunda-8-credentials-from-env "^1.2.2"
- camunda-saas-oauth "^1.2.4"
- debug "^4.3.4"
- dotenv "^16.3.1"
- got "^11.8.6"
-
-camunda-saas-oauth@^1.2.0, camunda-saas-oauth@^1.2.4:
- version "1.2.4"
- resolved "https://registry.yarnpkg.com/camunda-saas-oauth/-/camunda-saas-oauth-1.2.4.tgz#348a8422f266dafed98cf2a73046aa62c89d03f2"
- integrity sha512-AO/kcnZXcsodwM3qgMZj/5wn8SBoKmSDpuFYUpPS+HqQhG9GvWY8noBx/4pvX3gYPKiPTYi9/e9ApAe02NARzA==
- dependencies:
- camunda-8-credentials-from-env "^1.2.2"
- got "^11.8.5"
-
-camunda-tasklist-client@0.9.5:
- version "0.9.5"
- resolved "https://registry.yarnpkg.com/camunda-tasklist-client/-/camunda-tasklist-client-0.9.5.tgz#c0f2685ef7fb7fdb198a37e5b35a911e3b233b28"
- integrity sha512-gipH8ON/ttTgLfleWecQith1g9SpC5Q8CoLXFq2yw3cVJ1JVrcn0ArtgCxA1QCgtZBlV7EuGt9QWGc9UCfbbGw==
- dependencies:
- camunda-8-credentials-from-env "^1.1.1"
- camunda-saas-oauth "^1.2.0"
- gotql "^2.1.0-alpha1"
-
caniuse-api@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/caniuse-api/-/caniuse-api-3.0.0.tgz#5e4d90e2274961d46291997df599e3ed008ee4c0"
@@ -7811,7 +7540,7 @@ charenc@0.0.2:
resolved "https://registry.yarnpkg.com/charenc/-/charenc-0.0.2.tgz#c0a1d2f3a7092e03774bfa83f14c0fc5790a8667"
integrity sha512-yrLQ/yVUFXkzg7EDQsPieE/53+0RlaWTs+wBrvW36cyilJ2SaDWfl4Yj7MtLTXleV9uEKefbAGUPv2/iWSooRA==
-cheap-watch@^1.0.2, cheap-watch@^1.0.4:
+cheap-watch@^1.0.4:
version "1.0.4"
resolved "https://registry.yarnpkg.com/cheap-watch/-/cheap-watch-1.0.4.tgz#0bcb4a3a8fbd9d5327936493f6b56baa668d8fef"
integrity sha512-QR/9FrtRL5fjfUJBhAKCdi0lSRQ3rVRRum3GF9wDKp2TJbEIMGhUEr2yU8lORzm9Isdjx7/k9S0DFDx+z5VGtw==
@@ -8138,7 +7867,7 @@ commander@^5.1.0:
resolved "https://registry.yarnpkg.com/commander/-/commander-5.1.0.tgz#46abbd1652f8e059bddaef99bbdcb2ad9cf179ae"
integrity sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==
-commander@^7.0.0, commander@^7.1.0, commander@^7.2.0:
+commander@^7.0.0, commander@^7.2.0:
version "7.2.0"
resolved "https://registry.yarnpkg.com/commander/-/commander-7.2.0.tgz#a36cb57d0b501ce108e4d20559a150a391d97ab7"
integrity sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==
@@ -8247,7 +7976,7 @@ config-chain@^1.1.13:
ini "^1.3.4"
proto-list "~1.2.1"
-configent@^2.1.4, configent@^2.2.0:
+configent@^2.2.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/configent/-/configent-2.2.0.tgz#2de230fc43f22c47cfd99016aa6962d6f9546994"
integrity sha512-yIN6zfOWk2nycNJ2JFNiWEai0oiqAhISIht8+pbEBP8bdcpwoQ74AhCZPbUv9aRVJwo7wh1MbCBDUV44UJa7Kw==
@@ -8271,14 +8000,6 @@ console-control-strings@^1.0.0, console-control-strings@^1.1.0:
resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e"
integrity sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==
-console-stamp@^3.0.2:
- version "3.1.2"
- resolved "https://registry.yarnpkg.com/console-stamp/-/console-stamp-3.1.2.tgz#35dac393e16069a4d9d37b71ca6d5d13d7f3f8fd"
- integrity sha512-ab66x3NxOTxPuq71dI6gXEiw2X6ql4Le5gZz0bm7FW3FSCB00eztra/oQUuCoCGlsyKOxtULnHwphzMrRtzMBg==
- dependencies:
- chalk "^4.1.2"
- dateformat "^4.6.3"
-
consolidate@^0.16.0:
version "0.16.0"
resolved "https://registry.yarnpkg.com/consolidate/-/consolidate-0.16.0.tgz#a11864768930f2f19431660a65906668f5fbdc16"
@@ -8771,7 +8492,7 @@ dateformat@^4.6.3:
resolved "https://registry.yarnpkg.com/dateformat/-/dateformat-4.6.3.tgz#556fa6497e5217fedb78821424f8a1c22fa3f4b5"
integrity sha512-2P0p0pFGzHS5EMnhdxQi7aJN+iMheud0UhG4dlE1DLAlvL8JHjJJTX/CSm4JXwV0Ka5nGk3zC5mcb5bUQUxxMA==
-dayjs@^1.10.8, dayjs@^1.8.15:
+dayjs@^1.10.8:
version "1.11.10"
resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.11.10.tgz#68acea85317a6e164457d6d6947564029a6a16a0"
integrity sha512-vjAczensTgRcqDERK0SR2XMwsF/tSvnvlv6VcF2GIhg6Sx4yOIt/irsr1RDJsKiIyBzJDpCoXiWWq28MqH2cnQ==
@@ -8821,7 +8542,7 @@ dd-trace@5.0.0:
semver "^7.5.4"
tlhunter-sorted-set "^0.1.0"
-debug@4, debug@4.3.4, debug@^4.0.0, debug@^4.0.1, debug@^4.1.0, debug@^4.1.1, debug@^4.2.0, debug@^4.3.1, debug@^4.3.2, debug@^4.3.3, debug@^4.3.4, debug@~4.3.1, debug@~4.3.2:
+debug@4, debug@4.3.4, debug@^4.0.0, debug@^4.0.1, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.3, debug@^4.3.4, debug@~4.3.1, debug@~4.3.2:
version "4.3.4"
resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865"
integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==
@@ -8870,13 +8591,6 @@ decompress-response@^3.3.0:
dependencies:
mimic-response "^1.0.0"
-decompress-response@^6.0.0:
- version "6.0.0"
- resolved "https://registry.yarnpkg.com/decompress-response/-/decompress-response-6.0.0.tgz#ca387612ddb7e104bd16d85aab00d5ecf09c66fc"
- integrity sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==
- dependencies:
- mimic-response "^3.1.0"
-
decompress-tar@^4.0.0, decompress-tar@^4.1.0, decompress-tar@^4.1.1:
version "4.1.1"
resolved "https://registry.yarnpkg.com/decompress-tar/-/decompress-tar-4.1.1.tgz#718cbd3fcb16209716e70a26b84e7ba4592e5af1"
@@ -9002,11 +8716,6 @@ defer-to-connect@^1.0.1:
resolved "https://registry.yarnpkg.com/defer-to-connect/-/defer-to-connect-1.1.3.tgz#331ae050c08dcf789f8c83a7b81f0ed94f4ac591"
integrity sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ==
-defer-to-connect@^2.0.0:
- version "2.0.1"
- resolved "https://registry.yarnpkg.com/defer-to-connect/-/defer-to-connect-2.0.1.tgz#8016bdb4143e4632b77a3449c6236277de520587"
- integrity sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==
-
deferred-leveldown@~0.2.0:
version "0.2.0"
resolved "https://registry.yarnpkg.com/deferred-leveldown/-/deferred-leveldown-0.2.0.tgz#2cef1f111e1c57870d8bbb8af2650e587cd2f5b4"
@@ -9050,11 +8759,6 @@ defined@^1.0.0:
resolved "https://registry.yarnpkg.com/defined/-/defined-1.0.1.tgz#c0b9db27bfaffd95d6f61399419b893df0f91ebf"
integrity sha512-hsBd2qSVCRE+5PmNdHt1uzyrFu5d3RwmFDKzyNZMFq/EwDNJF7Ee5+D5oEKF0hU6LhtoUF1macFvOe4AskQC1Q==
-defined@~0.0.0:
- version "0.0.0"
- resolved "https://registry.yarnpkg.com/defined/-/defined-0.0.0.tgz#f35eea7d705e933baf13b2f03b3f83d921403b3e"
- integrity sha512-zpqiCT8bODLu3QSmLLic8xJnYWBFjOSu/fBCm189oAiTtPq/PSanNACKZDS7kgSyCJY7P+IcODzlIogBK/9RBg==
-
delay@^5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/delay/-/delay-5.0.0.tgz#137045ef1b96e5071060dd5be60bf9334436bd1d"
@@ -9350,7 +9054,7 @@ docker-compose@0.24.0:
dependencies:
yaml "^1.10.2"
-docker-compose@^0.23.5, docker-compose@^0.23.6:
+docker-compose@^0.23.5:
version "0.23.19"
resolved "https://registry.yarnpkg.com/docker-compose/-/docker-compose-0.23.19.tgz#9947726e2fe67bdfa9e8efe1ff15aa0de2e10eb8"
integrity sha512-v5vNLIdUqwj4my80wxFDkNH+4S85zsRuH29SO7dCWVWPCMt/ohZBsGN6g6KXWifT0pzQ7uOxqEKCYCDPJ8Vz4g==
@@ -9491,11 +9195,6 @@ dotenv@8.6.0, dotenv@^8.2.0:
resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-8.6.0.tgz#061af664d19f7f4d8fc6e4ff9b584ce237adcb8b"
integrity sha512-IrPdXQsk2BbzvCBGBOTmmSH5SodmqZNt4ERAZDmW4CT+tL8VtvinqywuANaFu4bOMWki16nqf0e4oC0QIaDr/g==
-dotenv@^16.3.1:
- version "16.3.1"
- resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-16.3.1.tgz#369034de7d7e5b120972693352a3bf112172cc3e"
- integrity sha512-IPzF4w4/Rd94bA9imS68tZBaYyBWSCE47V1RGuMrB94iyTOIEwRmVL2x/4An+6mETpLrKJ5hQkB8W4kFAadeIQ==
-
dotenv@~10.0.0:
version "10.0.0"
resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-10.0.0.tgz#3d4227b8fb95f81096cdd2b66653fb2c7085ba81"
@@ -9548,24 +9247,6 @@ duplexify@^4.0.0, duplexify@^4.1.2:
readable-stream "^3.1.1"
stream-shift "^1.0.0"
-dynalite@^3.2.1:
- version "3.2.2"
- resolved "https://registry.yarnpkg.com/dynalite/-/dynalite-3.2.2.tgz#34b4f4dd69638f17c0f7551a867959972c892441"
- integrity sha512-sx9ZjTgMs/D4gHnba4rnBkw29648dHwHmywJet132KAbiq1ZyWx9W1fMd/eP9cPwTKDXyCBuTYOChE0qMDjaXQ==
- dependencies:
- async "^2.6.3"
- big.js "^5.2.2"
- buffer-crc32 "^0.2.13"
- lazy "^1.0.11"
- levelup "^4.4.0"
- lock "^1.1.0"
- memdown "^5.1.0"
- minimist "^1.2.5"
- once "^1.4.0"
- subleveldown "^5.0.1"
- optionalDependencies:
- leveldown "^5.6.0"
-
eastasianwidth@^0.2.0:
version "0.2.0"
resolved "https://registry.yarnpkg.com/eastasianwidth/-/eastasianwidth-0.2.0.tgz#696ce2ec0aa0e6ea93a397ffcf24aa7840c827cb"
@@ -9672,7 +9353,7 @@ encodeurl@^1.0.2:
resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59"
integrity sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==
-encoding-down@^6.2.0, encoding-down@^6.3.0:
+encoding-down@^6.3.0:
version "6.3.0"
resolved "https://registry.yarnpkg.com/encoding-down/-/encoding-down-6.3.0.tgz#b1c4eb0e1728c146ecaef8e32963c549e76d082b"
integrity sha512-QKrV0iKR6MZVJV08QY0wp1e7vF6QbhnbQhb07bwpEyuz4uZiZgPlEGdkCROuFkUwdxlFaiPIhjyarH1ee/3vhw==
@@ -9780,11 +9461,6 @@ envinfo@7.8.1, envinfo@^7.7.3:
resolved "https://registry.yarnpkg.com/envinfo/-/envinfo-7.8.1.tgz#06377e3e5f4d379fea7ac592d5ad8927e0c4d475"
integrity sha512-/o+BXHmB7ocbHEAs6F2EnG0ogybVVUdkRunTT2glZU9XAaGmhqskrvKwqXuDfNjEO0LZKWdejEEpnq8aM0tOaw==
-err-code@^1.0.0:
- version "1.1.2"
- resolved "https://registry.yarnpkg.com/err-code/-/err-code-1.1.2.tgz#06e0116d3028f6aef4806849eb0ea6a748ae6960"
- integrity sha512-CJAN+O0/yA1CKfRn9SXOGctSpEM7DCon/r/5r2eXFMY2zCCJBasFhcM5I+1kh3Ap11FsQCX+vGHceNPvpWKhoA==
-
err-code@^2.0.2:
version "2.0.3"
resolved "https://registry.yarnpkg.com/err-code/-/err-code-2.0.3.tgz#23c2f3b756ffdfc608d30e27c9a941024807e7f9"
@@ -9922,11 +9598,6 @@ es6-error@^4.0.1, es6-error@^4.1.1:
resolved "https://registry.yarnpkg.com/es6-error/-/es6-error-4.1.1.tgz#9e3af407459deed47e9a91f9b885a84eb05c561d"
integrity sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==
-es6-promise@^4.2.4:
- version "4.2.8"
- resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.2.8.tgz#4eb21594c972bc40553d276e510539143db53e0a"
- integrity sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==
-
esbuild-loader@^2.16.0:
version "2.21.0"
resolved "https://registry.yarnpkg.com/esbuild-loader/-/esbuild-loader-2.21.0.tgz#2698a3e565b0db2bb19a3dd91c2b6c9aad526c80"
@@ -10525,13 +10196,6 @@ fast-xml-parser@4.2.5:
dependencies:
strnum "^1.0.5"
-fast-xml-parser@^4.1.3:
- version "4.3.3"
- resolved "https://registry.yarnpkg.com/fast-xml-parser/-/fast-xml-parser-4.3.3.tgz#aeaf5778392329f17168c40c51bcbfec8ff965be"
- integrity sha512-coV/D1MhrShMvU6D0I+VAK3umz6hUaxxhL0yp/9RjfiYUfAv14rDhGQL+PLForhMdr0wq3PiV07WtkkNjJjNHg==
- dependencies:
- strnum "^1.0.5"
-
fast-xml-parser@^4.2.2, fast-xml-parser@^4.2.5:
version "4.3.2"
resolved "https://registry.yarnpkg.com/fast-xml-parser/-/fast-xml-parser-4.3.2.tgz#761e641260706d6e13251c4ef8e3f5694d4b0d79"
@@ -10872,11 +10536,6 @@ formidable@^2.1.2:
once "^1.4.0"
qs "^6.11.0"
-fp-ts@^2.5.1:
- version "2.16.2"
- resolved "https://registry.yarnpkg.com/fp-ts/-/fp-ts-2.16.2.tgz#7faa90f6fc2e8cf84c711d2c4e606afe2be9e342"
- integrity sha512-CkqAjnIKFqvo3sCyoBTqgJvF+bHrSik584S9nhTjtBESLx26cbtVMR/T9a6ApChOcSDAaM3JydDmWDUn4EEXng==
-
fresh@^0.5.2, fresh@~0.5.2:
version "0.5.2"
resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7"
@@ -10918,7 +10577,7 @@ fs-extra@^11.1.0, fs-extra@^11.1.1:
jsonfile "^6.0.1"
universalify "^2.0.0"
-fs-extra@^9.0.0, fs-extra@^9.0.1, fs-extra@^9.1.0:
+fs-extra@^9.0.0, fs-extra@^9.1.0:
version "9.1.0"
resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-9.1.0.tgz#5954460c764a8da2094ba3554bf839e6b9a7c86d"
integrity sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==
@@ -10967,7 +10626,7 @@ function.prototype.name@^1.1.6:
es-abstract "^1.22.1"
functions-have-names "^1.2.3"
-functional-red-black-tree@^1.0.1, functional-red-black-tree@~1.0.1:
+functional-red-black-tree@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327"
integrity sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=
@@ -11561,23 +11220,6 @@ gopd@^1.0.1:
dependencies:
get-intrinsic "^1.1.3"
-got@^11.5.1, got@^11.8.5, got@^11.8.6:
- version "11.8.6"
- resolved "https://registry.yarnpkg.com/got/-/got-11.8.6.tgz#276e827ead8772eddbcfc97170590b841823233a"
- integrity sha512-6tfZ91bOr7bOXnK7PRDCGBLa1H4U080YHNaAQ2KsMGlLEzRbk44nsZF2E1IeRc3vtJHPVbKCYgdFbaGO2ljd8g==
- dependencies:
- "@sindresorhus/is" "^4.0.0"
- "@szmarczak/http-timer" "^4.0.5"
- "@types/cacheable-request" "^6.0.1"
- "@types/responselike" "^1.0.0"
- cacheable-lookup "^5.0.3"
- cacheable-request "^7.0.2"
- decompress-response "^6.0.0"
- http2-wrapper "^1.0.0-beta.5.2"
- lowercase-keys "^2.0.0"
- p-cancelable "^2.0.0"
- responselike "^2.0.0"
-
got@^8.3.1:
version "8.3.2"
resolved "https://registry.yarnpkg.com/got/-/got-8.3.2.tgz#1d23f64390e97f776cac52e5b936e5f514d2e937"
@@ -11618,15 +11260,6 @@ got@^9.6.0:
to-readable-stream "^1.0.0"
url-parse-lax "^3.0.0"
-gotql@^2.1.0-alpha1:
- version "2.1.0-alpha1"
- resolved "https://registry.yarnpkg.com/gotql/-/gotql-2.1.0-alpha1.tgz#b04e9adb0d1751a0c2de05bd4399f5c57aec79ba"
- integrity sha512-4xG1AczSpK+tdKUDM4kB1ah/2LoNlmFU5IhGNktuYNBLgyWB5iDs4OE36NE7k59iTKYi2B7vudQz2Itw1ZXrRg==
- dependencies:
- debug "^4.1.1"
- got "^11.5.1"
- prepend-http "^3.0.1"
-
graceful-fs@4.2.11, graceful-fs@^4.1.10, graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.1.9, graceful-fs@^4.2.0, graceful-fs@^4.2.4, graceful-fs@^4.2.6, graceful-fs@^4.2.9:
version "4.2.11"
resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3"
@@ -11991,14 +11624,6 @@ http-signature@~1.2.0:
jsprim "^1.2.2"
sshpk "^1.7.0"
-http2-wrapper@^1.0.0-beta.5.2:
- version "1.0.3"
- resolved "https://registry.yarnpkg.com/http2-wrapper/-/http2-wrapper-1.0.3.tgz#b8f55e0c1f25d4ebd08b3b0c2c079f9590800b3d"
- integrity sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg==
- dependencies:
- quick-lru "^5.1.1"
- resolve-alpn "^1.0.0"
-
https-proxy-agent@^5.0.0, https-proxy-agent@^5.0.1:
version "5.0.1"
resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz#c59ef224a04fe8b754f3db0063a25ea30d0005d6"
@@ -12118,11 +11743,6 @@ immediate@~3.0.5:
resolved "https://registry.yarnpkg.com/immediate/-/immediate-3.0.6.tgz#9db1dbd0faf8de6fbe0f5dd5e56bb606280de69b"
integrity sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==
-immediate@~3.2.3:
- version "3.2.3"
- resolved "https://registry.yarnpkg.com/immediate/-/immediate-3.2.3.tgz#d140fa8f614659bd6541233097ddaac25cdd991c"
- integrity sha512-RrGCXRm/fRVqMIhqXrGEX9rRADavPiDFSoMb/k64i9XMk8uH4r/Omi5Ctierj6XzNecwDbO4WuFbDD1zmpl3Tg==
-
import-cwd@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/import-cwd/-/import-cwd-3.0.0.tgz#20845547718015126ea9b3676b7592fb8bd4cf92"
@@ -13048,15 +12668,6 @@ jest-docblock@^29.7.0:
dependencies:
detect-newline "^3.0.0"
-jest-dynalite@^3.6.1:
- version "3.6.1"
- resolved "https://registry.yarnpkg.com/jest-dynalite/-/jest-dynalite-3.6.1.tgz#8bae305a3c33d9a8036f563827b173b54a323ca5"
- integrity sha512-MERtTt8Pj39vFmbItMC3YuIaqLf1kh/pJIE0DRcjeP/2Fa8Nni9IxwN6XWIMgXNbFKtlOM6ppH+Bsy0rWIdPiw==
- dependencies:
- "@aws/dynamodb-auto-marshaller" "^0.7.1"
- dynalite "^3.2.1"
- setimmediate "^1.0.5"
-
jest-each@^29.7.0:
version "29.7.0"
resolved "https://registry.yarnpkg.com/jest-each/-/jest-each-29.7.0.tgz#162a9b3f2328bdd991beaabffbb74745e56577d1"
@@ -13576,11 +13187,6 @@ json-buffer@3.0.0:
resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.0.tgz#5b1f397afc75d677bde8bcfc0e47e1f9a3d9a898"
integrity sha512-CuUqjv0FUZIdXkHPI8MezCnFCdaTAacej1TZYulLoAg1h/PhwkdXFN4V/gzY4g+fMBCOV2xF+rp7t2XD2ns/NQ==
-json-buffer@3.0.1:
- version "3.0.1"
- resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.1.tgz#9338802a30d3b6605fbe0613e094008ca8c05a13"
- integrity sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==
-
json-parse-better-errors@^1.0.1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9"
@@ -13749,13 +13355,6 @@ keyv@^3.0.0:
dependencies:
json-buffer "3.0.0"
-keyv@^4.0.0:
- version "4.5.4"
- resolved "https://registry.yarnpkg.com/keyv/-/keyv-4.5.4.tgz#a879a99e29452f942439f2a405e3af8b31d4de93"
- integrity sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==
- dependencies:
- json-buffer "3.0.1"
-
kill-port@^1.6.1:
version "1.6.1"
resolved "https://registry.yarnpkg.com/kill-port/-/kill-port-1.6.1.tgz#560fe79484583bdf3a5e908557dae614447618aa"
@@ -13871,7 +13470,7 @@ koa-mount@^4.0.0:
debug "^4.0.1"
koa-compose "^4.1.0"
-koa-passport@4.1.4, koa-passport@^4.1.4:
+koa-passport@4.1.4:
version "4.1.4"
resolved "https://registry.yarnpkg.com/koa-passport/-/koa-passport-4.1.4.tgz#5f1665c1c2a37ace79af9f970b770885ca30ccfa"
integrity sha512-dJBCkl4X+zdYxbI2V2OtoGy0PUenpvp2ZLLWObc8UJhsId0iQpTFT8RVcuA0709AL2txGwRHnSPoT1bYNGa6Kg==
@@ -13905,7 +13504,7 @@ koa-send@5.0.1, koa-send@^5.0.0:
http-errors "^1.7.3"
resolve-path "^1.4.0"
-koa-session@5.13.1, koa-session@^5.12.0:
+koa-session@5.13.1:
version "5.13.1"
resolved "https://registry.yarnpkg.com/koa-session/-/koa-session-5.13.1.tgz#a47e39015a4b464e21e3e1e2deeca48eb83916ee"
integrity sha512-TfYiun6xiFosyfIJKnEw0aoG5XmLIwM+K3OVWfkz84qY0NP2gbk0F/olRn0/Hrxq0f14s8amHVXeWyKYH3Cx3Q==
@@ -13923,7 +13522,7 @@ koa-static@5.0.0, koa-static@^5.0.0:
debug "^3.1.0"
koa-send "^5.0.0"
-koa-useragent@4.1.0, koa-useragent@^4.1.0:
+koa-useragent@^4.1.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/koa-useragent/-/koa-useragent-4.1.0.tgz#d3f128b552c6da3e5e9e9e9c887b2922b16e4468"
integrity sha512-x/HUDZ1zAmNNh5hA9hHbPm9p3UVg2prlpHzxCXQCzbibrNS0kmj7MkCResCbAbG7ZT6FVxNSMjR94ZGamdMwxA==
@@ -14023,11 +13622,6 @@ latest-version@^5.1.0:
dependencies:
package-json "^6.3.0"
-lazy@^1.0.11:
- version "1.0.11"
- resolved "https://registry.yarnpkg.com/lazy/-/lazy-1.0.11.tgz#daa068206282542c088288e975c297c1ae77b690"
- integrity sha512-Y+CjUfLmIpoUCCRl0ub4smrYtGGr5AOa2AKOaWelGHOGz33X/Y/KizefGqbkwfz44+cnq/+9habclf8vOmu2LA==
-
lcid@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/lcid/-/lcid-2.0.0.tgz#6ef5d2df60e52f82eb228a4c373e8d1f397253cf"
@@ -14213,13 +13807,6 @@ level-js@^5.0.0:
inherits "^2.0.3"
ltgt "^2.1.2"
-level-option-wrap@^1.1.0:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/level-option-wrap/-/level-option-wrap-1.1.0.tgz#ad20e68d9f3c22c8897531cc6aa7af596b1ed129"
- integrity sha512-gQouC22iCqHuBLNl4BHxEZUxLvUKALAtT/Q0c6ziOxZQ8c02G/gyxHWNbLbxUzRNfMrRnbt6TZT3gNe8VBqQeg==
- dependencies:
- defined "~0.0.0"
-
level-packager@^5.1.0:
version "5.1.1"
resolved "https://registry.yarnpkg.com/level-packager/-/level-packager-5.1.1.tgz#323ec842d6babe7336f70299c14df2e329c18939"
@@ -14268,7 +13855,7 @@ level@6.0.1:
level-packager "^5.1.0"
leveldown "^5.4.0"
-leveldown@5.6.0, leveldown@^5.4.0, leveldown@^5.6.0:
+leveldown@5.6.0, leveldown@^5.4.0:
version "5.6.0"
resolved "https://registry.yarnpkg.com/leveldown/-/leveldown-5.6.0.tgz#16ba937bb2991c6094e13ac5a6898ee66d3eee98"
integrity sha512-iB8O/7Db9lPaITU1aA2txU/cBEXAt4vWwKQRrrWuS6XDgbP4QZGj9BL2aNbwb002atoQ/lIotJkfyzz+ygQnUQ==
@@ -14277,7 +13864,7 @@ leveldown@5.6.0, leveldown@^5.4.0, leveldown@^5.6.0:
napi-macros "~2.0.0"
node-gyp-build "~4.1.0"
-levelup@4.4.0, levelup@^4.3.2, levelup@^4.4.0:
+levelup@4.4.0, levelup@^4.3.2:
version "4.4.0"
resolved "https://registry.yarnpkg.com/levelup/-/levelup-4.4.0.tgz#f89da3a228c38deb49c48f88a70fb71f01cafed6"
integrity sha512-94++VFO3qN95cM/d6eBXvd894oJE0w3cInq9USsyQzzoJxmiYzPAocNcuGCPGGjoXqDVJcr3C1jzt1TSjyaiLQ==
@@ -14466,11 +14053,6 @@ locate-path@^6.0.0:
dependencies:
p-locate "^5.0.0"
-lock@^1.1.0:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/lock/-/lock-1.1.0.tgz#53157499d1653b136ca66451071fca615703fa55"
- integrity sha512-NZQIJJL5Rb9lMJ0Yl1JoVr9GSdo4HTPsUEWsSFzB8dE8DSoiLCVavWZPi7Rnlv/o73u6I24S/XYc/NmG4l8EKA==
-
lodash-es@^4.17.21:
version "4.17.21"
resolved "https://registry.yarnpkg.com/lodash-es/-/lodash-es-4.17.21.tgz#43e626c46e6591b7750beb2b50117390c609e3ee"
@@ -14611,7 +14193,7 @@ lodash.xor@^4.5.0:
resolved "https://registry.yarnpkg.com/lodash.xor/-/lodash.xor-4.5.0.tgz#4d48ed7e98095b0632582ba714d3ff8ae8fb1db6"
integrity sha512-sVN2zimthq7aZ5sPGXnSz32rZPuqcparVW50chJQe+mzTYV+IsxSsl/2gnkWWE2Of7K3myBQBqtLKOUEHJKRsQ==
-lodash@4.17.21, lodash@^4.17.11, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.21, lodash@^4.17.3, lodash@^4.7.0:
+lodash@4.17.21, lodash@^4.17.11, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.21, lodash@^4.17.3, lodash@^4.7.0:
version "4.17.21"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c"
integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==
@@ -14965,18 +14547,6 @@ memdown@1.4.1:
ltgt "~2.2.0"
safe-buffer "~5.1.1"
-memdown@^5.1.0:
- version "5.1.0"
- resolved "https://registry.yarnpkg.com/memdown/-/memdown-5.1.0.tgz#608e91a9f10f37f5b5fe767667a8674129a833cb"
- integrity sha512-B3J+UizMRAlEArDjWHTMmadet+UKwHd3UjMgGBkZcKAxAYVPS9o0Yeiha4qvz7iGiL2Sb3igUft6p7nbFWctpw==
- dependencies:
- abstract-leveldown "~6.2.1"
- functional-red-black-tree "~1.0.1"
- immediate "~3.2.3"
- inherits "~2.0.1"
- ltgt "~2.2.0"
- safe-buffer "~5.2.0"
-
memory-pager@^1.0.2:
version "1.5.0"
resolved "https://registry.yarnpkg.com/memory-pager/-/memory-pager-1.5.0.tgz#d8751655d22d384682741c972f2c3d6dfa3e66b5"
@@ -15085,11 +14655,6 @@ mimic-response@^1.0.0, mimic-response@^1.0.1:
resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-1.0.1.tgz#4923538878eef42063cb8a3e3b0798781487ab1b"
integrity sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==
-mimic-response@^3.1.0:
- version "3.1.0"
- resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-3.1.0.tgz#2d1d59af9c1b129815accc2c46a022a5ce1fa3c9"
- integrity sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==
-
min-document@^2.19.0:
version "2.19.0"
resolved "https://registry.yarnpkg.com/min-document/-/min-document-2.19.0.tgz#7bd282e3f5842ed295bb748cdd9f1ffa2c824685"
@@ -15533,11 +15098,6 @@ neo-async@^2.6.0, neo-async@^2.6.2:
resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.2.tgz#b4aafb93e3aeb2d8174ca53cf163ab7d7308305f"
integrity sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==
-neon-env@^0.1.1:
- version "0.1.3"
- resolved "https://registry.yarnpkg.com/neon-env/-/neon-env-0.1.3.tgz#071e86fde3c698e9314f057d209e0b79ddab16e9"
- integrity sha512-Zo+L6Nm19gJrjyfhxn/ZDm8eIIDzr75o64ZhijBau4LNuhLzjEAteRg3gchIvgaN8XTo5BxN6iTNP5clZQ0agA==
-
nice-try@^1.0.4:
version "1.0.5"
resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366"
@@ -16255,23 +15815,6 @@ opentracing@>=0.12.1:
resolved "https://registry.yarnpkg.com/opentracing/-/opentracing-0.14.7.tgz#25d472bd0296dc0b64d7b94cbc995219031428f5"
integrity sha512-vz9iS7MJ5+Bp1URw8Khvdyw1H/hGvzHWlKQ7eRrQojSCDL1/SrWfrY9QebLw97n2deyRtzHRC3MkQfVNUCo91Q==
-operate-api-client@1.2.3:
- version "1.2.3"
- resolved "https://registry.yarnpkg.com/operate-api-client/-/operate-api-client-1.2.3.tgz#c884ab09fe07360ac5ce5b58ae470ba1e91db879"
- integrity sha512-8FWfDsHVxgYIBe4p4fB6e7SSiYdW/PPTCCLFcGnbqdUxlhcUq9ncYu6ZMMm6E3A3WKxagdInYQbxOhtTeVGhVQ==
- dependencies:
- camunda-saas-oauth "^1.2.0"
- got "^11.8.5"
-
-optimize-api-client@^1.0.3:
- version "1.0.4"
- resolved "https://registry.yarnpkg.com/optimize-api-client/-/optimize-api-client-1.0.4.tgz#a2e653780fd1e9e54a38912418b0ea27bd0484ef"
- integrity sha512-2XBW+sv6eENOCHMc5v0XmH2DaaSETAb/qH5BsfpTDD8Pmeu10ZR61W7Pc/rBqauy96vPP/MfgmMphx5CjHb2xg==
- dependencies:
- camunda-8-credentials-from-env "^1.1.1"
- camunda-saas-oauth "^1.2.4"
- got "^11.8.5"
-
optionator@^0.8.1:
version "0.8.3"
resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.3.tgz#84fa1d036fe9d3c7e21d99884b601167ec8fb495"
@@ -16345,11 +15888,6 @@ p-cancelable@^1.0.0:
resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-1.1.0.tgz#d078d15a3af409220c886f1d9a0ca2e441ab26cc"
integrity sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw==
-p-cancelable@^2.0.0:
- version "2.1.1"
- resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-2.1.1.tgz#aab7fbd416582fa32a3db49859c122487c5ed2cf"
- integrity sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg==
-
p-defer@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/p-defer/-/p-defer-1.0.0.tgz#9f6eb182f6c9aa8cd743004a7d4f96b196b0fb0c"
@@ -16662,7 +16200,7 @@ passport-google-oauth20@2.x.x:
dependencies:
passport-oauth2 "1.x.x"
-passport-google-oauth@2.0.0, passport-google-oauth@^2.0.0:
+passport-google-oauth@2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/passport-google-oauth/-/passport-google-oauth-2.0.0.tgz#f6eb4bc96dd6c16ec0ecfdf4e05ec48ca54d4dae"
integrity sha512-JKxZpBx6wBQXX1/a1s7VmdBgwOugohH+IxCy84aPTZNq/iIPX6u7Mqov1zY7MKRz3niFPol0KJz8zPLBoHKtYA==
@@ -16677,14 +16215,6 @@ passport-local@1.0.0:
dependencies:
passport-strategy "1.x.x"
-passport-microsoft@1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/passport-microsoft/-/passport-microsoft-1.0.0.tgz#78954cf3201fdce61beeb6587a3b158f8e9db86c"
- integrity sha512-L1JHeCbSObSZZXiG7jU2KoKie6nzZLwGt38HXz1GasKrsCQdOnf5kH8ltV4BWNUfBL2Pt1csWn1iuBSerprrcg==
- dependencies:
- passport-oauth2 "1.6.1"
- pkginfo "0.4.x"
-
passport-oauth1@1.x.x:
version "1.3.0"
resolved "https://registry.yarnpkg.com/passport-oauth1/-/passport-oauth1-1.3.0.tgz#5d57f1415c8e28e46b461a12ec1b492934f7c354"
@@ -16699,17 +16229,6 @@ passport-oauth2-refresh@^2.1.0:
resolved "https://registry.yarnpkg.com/passport-oauth2-refresh/-/passport-oauth2-refresh-2.1.0.tgz#c31cd133826383f5539d16ad8ab4f35ca73ce4a4"
integrity sha512-4ML7ooCESCqiTgdDBzNUFTBcPR8zQq9iM6eppEUGMMvLdsjqRL93jKwWm4Az3OJcI+Q2eIVyI8sVRcPFvxcF/A==
-passport-oauth2@1.6.1:
- version "1.6.1"
- resolved "https://registry.yarnpkg.com/passport-oauth2/-/passport-oauth2-1.6.1.tgz#c5aee8f849ce8bd436c7f81d904a3cd1666f181b"
- integrity sha512-ZbV43Hq9d/SBSYQ22GOiglFsjsD1YY/qdiptA+8ej+9C1dL1TVB+mBE5kDH/D4AJo50+2i8f4bx0vg4/yDDZCQ==
- dependencies:
- base64url "3.x.x"
- oauth "0.9.x"
- passport-strategy "1.x.x"
- uid2 "0.0.x"
- utils-merge "1.x.x"
-
passport-oauth2@1.x.x:
version "1.7.0"
resolved "https://registry.yarnpkg.com/passport-oauth2/-/passport-oauth2-1.7.0.tgz#5c4766c8531ac45ffe9ec2c09de9809e2c841fc4"
@@ -17086,11 +16605,6 @@ pkg-types@^1.0.3:
mlly "^1.2.0"
pathe "^1.1.0"
-pkginfo@0.4.x:
- version "0.4.1"
- resolved "https://registry.yarnpkg.com/pkginfo/-/pkginfo-0.4.1.tgz#b5418ef0439de5425fc4995042dced14fb2a84ff"
- integrity sha512-8xCNE/aT/EXKenuMDZ+xTVwkT8gsoHN2z/Q29l80u0ppGEXVvsKRzNMbtKhg8LS8k1tJLAHHylf6p4VFmP6XUQ==
-
pluralize@^8.0.0:
version "8.0.0"
resolved "https://registry.yarnpkg.com/pluralize/-/pluralize-8.0.0.tgz#1a6fa16a38d12a1901e0320fa017051c539ce3b1"
@@ -17420,13 +16934,6 @@ postgres-interval@^1.1.0:
dependencies:
xtend "^4.0.0"
-posthog-js@^1.13.4:
- version "1.100.0"
- resolved "https://registry.yarnpkg.com/posthog-js/-/posthog-js-1.100.0.tgz#687b9a6e4ed226aa6572f4040b418ea0c8b3d353"
- integrity sha512-r2XZEiHQ9mBK7D1G9k57I8uYZ2kZTAJ0OCX6K/OOdCWN8jKPhw3h5F9No5weilP6eVAn+hrsy7NvPV7SCX7gMg==
- dependencies:
- fflate "^0.4.1"
-
posthog-js@^1.36.0:
version "1.96.1"
resolved "https://registry.yarnpkg.com/posthog-js/-/posthog-js-1.96.1.tgz#4f9719a24e4e14037b0e72d430194d7cdb576447"
@@ -17723,11 +17230,6 @@ prepend-http@^2.0.0:
resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-2.0.0.tgz#e92434bfa5ea8c19f41cdfd401d741a3c819d897"
integrity sha512-ravE6m9Atw9Z/jjttRUZ+clIXogdghyZAuWJ3qEzjT+jI/dL1ifAqhZeC5VHzQp1MSt1+jxKkFNemj/iO7tVUA==
-prepend-http@^3.0.1:
- version "3.0.1"
- resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-3.0.1.tgz#3e724d58fd5867465b300bb9615009fa2f8ee3b6"
- integrity sha512-BLxfZh+m6UiAiCPZFJ4+vYoL7NrRs5XgCTRrjseATAggXhdZKKxn+JUNmuVYWY23bDHgaEHodxw8mnmtVEDtHw==
-
prettier-plugin-svelte@^2.3.0:
version "2.6.0"
resolved "https://registry.yarnpkg.com/prettier-plugin-svelte/-/prettier-plugin-svelte-2.6.0.tgz#0e845b560b55cd1d951d6c50431b4949f8591746"
@@ -17827,14 +17329,6 @@ promise-inflight@^1.0.1:
resolved "https://registry.yarnpkg.com/promise-inflight/-/promise-inflight-1.0.1.tgz#98472870bf228132fcbdd868129bad12c3c029e3"
integrity sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g==
-promise-retry@^1.1.1:
- version "1.1.1"
- resolved "https://registry.yarnpkg.com/promise-retry/-/promise-retry-1.1.1.tgz#6739e968e3051da20ce6497fb2b50f6911df3d6d"
- integrity sha512-StEy2osPr28o17bIW776GtwO6+Q+M9zPiZkYfosciUUMYqjhU/ffwRAH0zN2+uvGyUsn8/YICIHRzLbPacpZGw==
- dependencies:
- err-code "^1.0.0"
- retry "^0.10.0"
-
promise-retry@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/promise-retry/-/promise-retry-2.0.1.tgz#ff747a13620ab57ba688f5fc67855410c370da22"
@@ -18026,7 +17520,7 @@ q@^1.1.2:
resolved "https://registry.yarnpkg.com/q/-/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7"
integrity sha512-kV/CThkXo6xyFEZUugw/+pIOywXcDbFYgSct5cT3gqlbkBE1SJdwy6UQoZvodiWF/ckQLZyDE/Bu1M6gVu5lVw==
-qs@^6.10.3, qs@^6.11.0, qs@^6.4.0:
+qs@^6.11.0, qs@^6.4.0:
version "6.11.2"
resolved "https://registry.yarnpkg.com/qs/-/qs-6.11.2.tgz#64bea51f12c1f5da1bc01496f48ffcff7c69d7d9"
integrity sha512-tDNIz22aBzCDxLtVH++VnTfzxlfeK5CbqohpSqpJgj1Wg/cQbStNAz3NuqCs5vV+pjBsK4x4pN9HlVh7rcYRiA==
@@ -18082,11 +17576,6 @@ quick-lru@^4.0.1:
resolved "https://registry.yarnpkg.com/quick-lru/-/quick-lru-4.0.1.tgz#5b8878f113a58217848c6482026c73e1ba57727f"
integrity sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g==
-quick-lru@^5.1.1:
- version "5.1.1"
- resolved "https://registry.yarnpkg.com/quick-lru/-/quick-lru-5.1.1.tgz#366493e6b3e42a3a6885e2e99d18f80fb7a8c932"
- integrity sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==
-
quote-unquote@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/quote-unquote/-/quote-unquote-1.0.0.tgz#67a9a77148effeaf81a4d428404a710baaac8a0b"
@@ -18139,11 +17628,6 @@ rc@1.2.8, rc@^1.2.7, rc@^1.2.8:
minimist "^1.2.0"
strip-json-comments "~2.0.1"
-reachdown@^1.1.0:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/reachdown/-/reachdown-1.1.0.tgz#c3b85b459dbd0fe2c79782233a0a38e66a9b5454"
- integrity sha512-6LsdRe4cZyOjw4NnvbhUd/rGG7WQ9HMopPr+kyL018Uci4kijtxcGR5kVb5Ln13k4PEE+fEFQbjfOvNw7cnXmA==
-
react-is@^17.0.1:
version "17.0.2"
resolved "https://registry.yarnpkg.com/react-is/-/react-is-17.0.2.tgz#e691d4a8e9c789365655539ab372762b0efb54f0"
@@ -18541,11 +18025,6 @@ requizzle@^0.2.3:
dependencies:
lodash "^4.17.21"
-resolve-alpn@^1.0.0:
- version "1.2.1"
- resolved "https://registry.yarnpkg.com/resolve-alpn/-/resolve-alpn-1.2.1.tgz#b7adbdac3546aaaec20b45e7d8265927072726f9"
- integrity sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==
-
resolve-cwd@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-3.0.0.tgz#0f0075f1bb2544766cf73ba6a6e2adfebcb13f2d"
@@ -18605,13 +18084,6 @@ responselike@1.0.2, responselike@^1.0.2:
dependencies:
lowercase-keys "^1.0.0"
-responselike@^2.0.0:
- version "2.0.1"
- resolved "https://registry.yarnpkg.com/responselike/-/responselike-2.0.1.tgz#9a0bc8fdc252f3fb1cca68b016591059ba1422bc"
- integrity sha512-4gl03wn3hj1HP3yzgdI7d3lCkF95F21Pz4BPGvKHinyQzALR5CapwC8yIi0Rh58DEMQ/SguC03wFj2k0M/mHhw==
- dependencies:
- lowercase-keys "^2.0.0"
-
restore-cursor@^3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-3.1.0.tgz#39f67c54b3a7a58cea5236d95cf0034239631f7e"
@@ -18633,11 +18105,6 @@ retry@0.13.1, retry@^0.13.1:
resolved "https://registry.yarnpkg.com/retry/-/retry-0.13.1.tgz#185b1587acf67919d63b357349e03537b2484658"
integrity "sha1-GFsVh6z2eRnWOzVzSeA1N7JIRlg= sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg=="
-retry@^0.10.0:
- version "0.10.1"
- resolved "https://registry.yarnpkg.com/retry/-/retry-0.10.1.tgz#e76388d217992c252750241d3d3956fed98d8ff4"
- integrity sha512-ZXUSQYTHdl3uS7IuCehYfMzKyIDBNoAuUblvy5oGO5UJSUTmStUUVPXbA9Qxd173Bgre53yCQczQuHgRWAdvJQ==
-
retry@^0.12.0:
version "0.12.0"
resolved "https://registry.yarnpkg.com/retry/-/retry-0.12.0.tgz#1b42a6266a21f07421d1b0b54b7dc167b01c013b"
@@ -19094,7 +18561,7 @@ serialize-javascript@^6.0.1:
dependencies:
randombytes "^2.1.0"
-server-destroy@1.0.1, server-destroy@^1.0.1:
+server-destroy@1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/server-destroy/-/server-destroy-1.0.1.tgz#f13bf928e42b9c3e79383e61cc3998b5d14e6cdd"
integrity sha512-rb+9B5YBIEzYcD6x2VKidaa+cqYBJQKnU4oe4E3ANwRRN56yk/ua1YCJT1n21NTS8w6CcOclAKNP3PhdCXKYtQ==
@@ -19123,11 +18590,6 @@ set-function-name@^2.0.0, set-function-name@^2.0.1:
functions-have-names "^1.2.3"
has-property-descriptors "^1.0.0"
-setimmediate@^1.0.5:
- version "1.0.5"
- resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285"
- integrity sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==
-
setprototypeof@1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.0.tgz#d0bd85536887b6fe7c0d818cb962d9d91c54e656"
@@ -19603,7 +19065,7 @@ stable@^0.1.8:
resolved "https://registry.yarnpkg.com/stable/-/stable-0.1.8.tgz#836eb3c8382fe2936feaf544631017ce7d47a3cf"
integrity sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w==
-stack-trace@0.0.10, stack-trace@0.0.x:
+stack-trace@0.0.x:
version "0.0.10"
resolved "https://registry.yarnpkg.com/stack-trace/-/stack-trace-0.0.10.tgz#547c70b347e8d32b4e108ea1a2a159e5fdde19c0"
integrity sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg==
@@ -19885,14 +19347,6 @@ strip-outer@^1.0.0:
dependencies:
escape-string-regexp "^1.0.2"
-stripe@9.16.0:
- version "9.16.0"
- resolved "https://registry.yarnpkg.com/stripe/-/stripe-9.16.0.tgz#94c24549c91fced457b9e3259e8a1a1bdb6dbd0e"
- integrity sha512-Dn8K+jSoQcXjxCobRI4HXUdHjOXsiF/KszK49fJnkbeCFjZ3EZxLG2JiM/CX+Hcq27NBDtv/Sxhvy+HhTmvyaQ==
- dependencies:
- "@types/node" ">=8.1.0"
- qs "^6.10.3"
-
striptags@^3.1.1:
version "3.2.0"
resolved "https://registry.yarnpkg.com/striptags/-/striptags-3.2.0.tgz#cc74a137db2de8b0b9a370006334161f7dd67052"
@@ -19966,18 +19420,6 @@ sublevel-pouchdb@7.2.2:
ltgt "2.2.1"
readable-stream "1.1.14"
-subleveldown@^5.0.1:
- version "5.0.1"
- resolved "https://registry.yarnpkg.com/subleveldown/-/subleveldown-5.0.1.tgz#aa2b4e4698a48d9a86856b2c4df1b6bce2d2ce53"
- integrity sha512-cVqd/URpp7si1HWu5YqQ3vqQkjuolAwHypY1B4itPlS71/lsf6TQPZ2Y0ijT22EYVkvH5ove9JFJf4u7VGPuZw==
- dependencies:
- abstract-leveldown "^6.3.0"
- encoding-down "^6.2.0"
- inherits "^2.0.3"
- level-option-wrap "^1.1.0"
- levelup "^4.4.0"
- reachdown "^1.1.0"
-
superagent@^8.0.5:
version "8.1.2"
resolved "https://registry.yarnpkg.com/superagent/-/superagent-8.1.2.tgz#03cb7da3ec8b32472c9d20f6c2a57c7f3765f30b"
@@ -20844,11 +20286,6 @@ typed-array-length@^1.0.4:
for-each "^0.3.3"
is-typed-array "^1.1.9"
-typed-duration@^1.0.12:
- version "1.0.13"
- resolved "https://registry.yarnpkg.com/typed-duration/-/typed-duration-1.0.13.tgz#a40f9ba563b6e20674cac491e15ecbf6811d85a7"
- integrity sha512-HLwA+hNq/2eXe03isJSfa7YJt6NikplBGdNKvlhyuR6WL5iZi2uXJIZv1SSOMEIukCZbeQ8QwIcQ801S0/Qulw==
-
typedarray-to-buffer@^3.1.5:
version "3.1.5"
resolved "https://registry.yarnpkg.com/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz#a97ee7a9ff42691b9f783ff1bc5112fe3fca9080"
@@ -21062,7 +20499,7 @@ update-browserslist-db@^1.0.10:
escalade "^3.1.1"
picocolors "^1.0.0"
-update-dotenv@1.1.1, update-dotenv@^1.1.1:
+update-dotenv@1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/update-dotenv/-/update-dotenv-1.1.1.tgz#17146f302f216c3c92419d5a327a45be910050ca"
integrity sha512-3cIC18In/t0X/yH793c00qqxcKD8jVCgNOPif/fGQkFpYMGecM9YAc+kaAKXuZsM2dE9I9wFI7KvAuNX22SGMQ==
@@ -21106,7 +20543,7 @@ url-parse-lax@^3.0.0:
dependencies:
prepend-http "^2.0.0"
-url-parse@^1.4.3, url-parse@^1.5.3:
+url-parse@^1.5.3:
version "1.5.10"
resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.5.10.tgz#9d3c2f736c1d75dd3bd2be507dcc111f1e2ea9c1"
integrity sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==
@@ -21176,11 +20613,6 @@ uuid@^3.3.2:
resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee"
integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==
-uuid@^7.0.3:
- version "7.0.3"
- resolved "https://registry.yarnpkg.com/uuid/-/uuid-7.0.3.tgz#c5c9f2c8cf25dc0a372c4df1441c41f5bd0c680b"
- integrity sha512-DPSke0pXhTZgoF/d+WSt2QaKMCFSfx7QegxEWT+JOuHF5aWrKEn0G+ztjuJg/gG8/ItK+rbPCD/yNv8yyih6Cg==
-
uuid@^9.0.0, uuid@^9.0.1:
version "9.0.1"
resolved "https://registry.yarnpkg.com/uuid/-/uuid-9.0.1.tgz#e188d4c8853cc722220392c424cd637f32293f30"
@@ -22079,23 +21511,3 @@ z-schema@^5.0.1:
validator "^13.7.0"
optionalDependencies:
commander "^9.4.1"
-
-zeebe-node@^8.2.5:
- version "8.3.1"
- resolved "https://registry.yarnpkg.com/zeebe-node/-/zeebe-node-8.3.1.tgz#e100bf3708464e305305b4efa1ffde53f9786c45"
- integrity sha512-68ascWO3g7g+9WwDzvfa3I9TkLKHku5auEgSINP+k5ktNfsfGW68ELDmEJA+XHZgzvGsdGILZqGRzVd5SC8aaQ==
- dependencies:
- "@grpc/grpc-js" "1.9.7"
- "@grpc/proto-loader" "0.7.10"
- chalk "^2.4.2"
- console-stamp "^3.0.2"
- dayjs "^1.8.15"
- debug "^4.2.0"
- fast-xml-parser "^4.1.3"
- fp-ts "^2.5.1"
- got "^11.8.5"
- long "^4.0.0"
- promise-retry "^1.1.1"
- stack-trace "0.0.10"
- typed-duration "^1.0.12"
- uuid "^7.0.3"
From 6964e2d146de1a51eb55ffbf8a40052bce090575 Mon Sep 17 00:00:00 2001
From: mike12345567
Date: Mon, 29 Jan 2024 13:43:51 +0000
Subject: [PATCH 010/783] Fixing update aliasing.
---
.../server/scripts/integrations/postgres/reset.sh | 1 +
packages/server/src/integrations/base/sql.ts | 12 ++++++------
2 files changed, 7 insertions(+), 6 deletions(-)
diff --git a/packages/server/scripts/integrations/postgres/reset.sh b/packages/server/scripts/integrations/postgres/reset.sh
index 32778bd11f..29a5db0181 100755
--- a/packages/server/scripts/integrations/postgres/reset.sh
+++ b/packages/server/scripts/integrations/postgres/reset.sh
@@ -1,3 +1,4 @@
#!/bin/bash
docker-compose down
docker volume prune -f
+docker volume rm postgres_pg_data
diff --git a/packages/server/src/integrations/base/sql.ts b/packages/server/src/integrations/base/sql.ts
index 3375e175e6..d33c077ee5 100644
--- a/packages/server/src/integrations/base/sql.ts
+++ b/packages/server/src/integrations/base/sql.ts
@@ -424,7 +424,7 @@ class InternalBuilder {
knexWithAlias(
knex: Knex,
endpoint: { entityId: string; alias?: string; schema?: string }
- ): { query: KnexQuery; name: string } {
+ ): { query: KnexQuery; aliased: string } {
const tableName = endpoint.entityId
const alias = endpoint.alias
const aliased = alias ? alias : tableName
@@ -433,7 +433,7 @@ class InternalBuilder {
if (endpoint.schema) {
query = query.withSchema(endpoint.schema)
}
- return { query, name: aliased }
+ return { query, aliased }
}
create(knex: Knex, json: QueryJson, opts: QueryOptions): KnexQuery {
@@ -493,7 +493,7 @@ class InternalBuilder {
}
// start building the query
- let { query, name: aliased } = this.knexWithAlias(knex, endpoint)
+ let { query, aliased } = this.knexWithAlias(knex, endpoint)
query = query.limit(foundLimit)
if (foundOffset) {
query = query.offset(foundOffset)
@@ -522,9 +522,9 @@ class InternalBuilder {
update(knex: Knex, json: QueryJson, opts: QueryOptions): KnexQuery {
const { endpoint, body, filters } = json
- let { query } = this.knexWithAlias(knex, endpoint)
+ let { query, aliased } = this.knexWithAlias(knex, endpoint)
const parsedBody = parseBody(body)
- query = this.addFilters(query, filters, { tableName: endpoint.entityId })
+ query = this.addFilters(query, filters, { tableName: aliased })
// mysql can't use returning
if (opts.disableReturning) {
return query.update(parsedBody)
@@ -535,7 +535,7 @@ class InternalBuilder {
delete(knex: Knex, json: QueryJson, opts: QueryOptions): KnexQuery {
const { endpoint, filters } = json
- let { query, name: aliased } = this.knexWithAlias(knex, endpoint)
+ let { query, aliased } = this.knexWithAlias(knex, endpoint)
query = this.addFilters(query, filters, { tableName: aliased })
// mysql can't use returning
if (opts.disableReturning) {
From 5d2ba68fae4b39086686c41999b903c05c352ba4 Mon Sep 17 00:00:00 2001
From: mike12345567
Date: Tue, 30 Jan 2024 13:35:45 +0000
Subject: [PATCH 011/783] Adding test case based on capture of real failing
query.
---
.../server/src/integrations/tests/sql.spec.ts | 107 ++++++++++++++++++
1 file changed, 107 insertions(+)
diff --git a/packages/server/src/integrations/tests/sql.spec.ts b/packages/server/src/integrations/tests/sql.spec.ts
index 5cc4849d03..580a8117cb 100644
--- a/packages/server/src/integrations/tests/sql.spec.ts
+++ b/packages/server/src/integrations/tests/sql.spec.ts
@@ -683,3 +683,110 @@ describe("SQL query builder", () => {
})
})
})
+
+describe("Captures of real examples", () => {
+ const limit = 5000
+
+ it("should handle filtering by relationship", () => {
+ const queryJson = {
+ endpoint: {
+ datasourceId: "datasource_plus_8066e56456784eb2a00129d31be5c3e7",
+ entityId: "products",
+ operation: "READ",
+ alias: "a",
+ },
+ resource: {
+ fields: [
+ "a.productname",
+ "a.productid",
+ "b.executorid",
+ "b.taskname",
+ "b.taskid",
+ "b.completed",
+ "b.qaid",
+ ],
+ },
+ filters: {
+ equal: {
+ "1:tasks.taskname": "assembling",
+ },
+ onEmptyFilter: "all",
+ },
+ sort: {
+ productname: {
+ direction: "ASCENDING",
+ },
+ },
+ paginate: {
+ limit: 100,
+ page: 1,
+ },
+ relationships: [
+ {
+ tableName: "tasks",
+ column: "tasks",
+ through: "products_tasks",
+ from: "productid",
+ to: "taskid",
+ fromPrimary: "productid",
+ toPrimary: "taskid",
+ aliases: {
+ products_tasks: "c",
+ tasks: "b",
+ products: "a",
+ },
+ },
+ ],
+ meta: {
+ table: {
+ type: "table",
+ _id: "datasource_plus_8066e56456784eb2a00129d31be5c3e7__products",
+ primary: ["productid"],
+ name: "a",
+ schema: {
+ productname: {
+ type: "string",
+ externalType: "character varying",
+ autocolumn: false,
+ name: "productname",
+ constraints: {
+ presence: false,
+ },
+ },
+ productid: {
+ type: "number",
+ externalType: "integer",
+ autocolumn: true,
+ name: "productid",
+ constraints: {
+ presence: false,
+ },
+ },
+ tasks: {
+ tableId:
+ "datasource_plus_8066e56456784eb2a00129d31be5c3e7__tasks",
+ name: "tasks",
+ relationshipType: "many-to-many",
+ fieldName: "taskid",
+ through:
+ "datasource_plus_8066e56456784eb2a00129d31be5c3e7__products_tasks",
+ throughFrom: "taskid",
+ throughTo: "productid",
+ type: "link",
+ main: true,
+ _id: "ca6862d9ba09146dd8a68e3b5b7055a09",
+ },
+ },
+ sourceId: "datasource_plus_8066e56456784eb2a00129d31be5c3e7",
+ sourceType: "external",
+ primaryDisplay: "productname",
+ },
+ },
+ }
+ let query = new Sql(SqlClient.POSTGRES, limit)._query(queryJson)
+ expect(query).toEqual({
+ bindings: [100, "assembling", limit],
+ sql: `select "a"."productname" as "a.productname", "a"."productid" as "a.productid", "b"."executorid" as "b.executorid", "b"."taskname" as "b.taskname", "b"."taskid" as "b.taskid", "b"."completed" as "b.completed", "b"."qaid" as "b.qaid" from (select * from "products" as "a" order by "a"."productname" asc limit $1) as "a" left join "products_tasks" as "c" on "a"."productid" = "c"."productid" left join "tasks" as "b" on "b"."taskid" = "c"."taskid" where "b"."taskname" = $2 order by "a"."productname" asc limit $3`,
+ })
+ })
+})
From 09a0d00aa7df535454cb3eafe49714dcd1adf3e9 Mon Sep 17 00:00:00 2001
From: mike12345567
Date: Tue, 30 Jan 2024 13:50:36 +0000
Subject: [PATCH 012/783] Fixing some test cases.
---
packages/server/src/integrations/tests/sql.spec.ts | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/packages/server/src/integrations/tests/sql.spec.ts b/packages/server/src/integrations/tests/sql.spec.ts
index 580a8117cb..bca0cf5422 100644
--- a/packages/server/src/integrations/tests/sql.spec.ts
+++ b/packages/server/src/integrations/tests/sql.spec.ts
@@ -502,7 +502,7 @@ describe("SQL query builder", () => {
const query = sql._query(generateRelationshipJson({ schema: "production" }))
expect(query).toEqual({
bindings: [500, 5000],
- sql: `select "brands"."brand_id" as "brands.brand_id", "brands"."brand_name" as "brands.brand_name", "products"."product_id" as "products.product_id", "products"."product_name" as "products.product_name", "products"."brand_id" as "products.brand_id" from (select * from "production"."brands" limit $1) as "brands" left join "production"."products" on "brands"."brand_id" = "products"."brand_id" limit $2`,
+ sql: `select "brands"."brand_id" as "brands.brand_id", "brands"."brand_name" as "brands.brand_name", "products"."product_id" as "products.product_id", "products"."product_name" as "products.product_name", "products"."brand_id" as "products.brand_id" from (select * from "production"."brands" limit $1) as "brands" left join "production"."products" as "products" on "brands"."brand_id" = "products"."brand_id" limit $2`,
})
})
@@ -510,7 +510,7 @@ describe("SQL query builder", () => {
const query = sql._query(generateRelationshipJson())
expect(query).toEqual({
bindings: [500, 5000],
- sql: `select "brands"."brand_id" as "brands.brand_id", "brands"."brand_name" as "brands.brand_name", "products"."product_id" as "products.product_id", "products"."product_name" as "products.product_name", "products"."brand_id" as "products.brand_id" from (select * from "brands" limit $1) as "brands" left join "products" on "brands"."brand_id" = "products"."brand_id" limit $2`,
+ sql: `select "brands"."brand_id" as "brands.brand_id", "brands"."brand_name" as "brands.brand_name", "products"."product_id" as "products.product_id", "products"."product_name" as "products.product_name", "products"."brand_id" as "products.brand_id" from (select * from "brands" limit $1) as "brands" left join "products" as "products" on "brands"."brand_id" = "products"."brand_id" limit $2`,
})
})
@@ -520,7 +520,7 @@ describe("SQL query builder", () => {
)
expect(query).toEqual({
bindings: [500, 5000],
- sql: `select "stores"."store_id" as "stores.store_id", "stores"."store_name" as "stores.store_name", "products"."product_id" as "products.product_id", "products"."product_name" as "products.product_name" from (select * from "production"."stores" limit $1) as "stores" left join "production"."stocks" on "stores"."store_id" = "stocks"."store_id" left join "production"."products" on "products"."product_id" = "stocks"."product_id" limit $2`,
+ sql: `select "stores"."store_id" as "stores.store_id", "stores"."store_name" as "stores.store_name", "products"."product_id" as "products.product_id", "products"."product_name" as "products.product_name" from (select * from "production"."stores" limit $1) as "stores" left join "production"."stocks" as "stocks" on "stores"."store_id" = "stocks"."store_id" left join "production"."products" as "products" on "products"."product_id" = "stocks"."product_id" limit $2`,
})
})
From a268e5560718e317180f8da7c71667b218c59cc1 Mon Sep 17 00:00:00 2001
From: Sam Rose
Date: Tue, 30 Jan 2024 17:31:11 +0000
Subject: [PATCH 013/783] Plumbing for showing a maintenance page when SQS is
required but missing.
---
.../builder/src/pages/builder/_layout.svelte | 4 +++
.../pages/builder/maintenance/index.svelte | 27 +++++++++++++++++++
.../portal/_components/BudibaseLogo.svelte | 13 +++++++++
packages/builder/src/stores/portal/admin.js | 2 ++
packages/types/src/core/installation.ts | 4 +++
.../src/api/controllers/system/environment.ts | 19 ++++++++++---
.../routes/system/tests/environment.spec.ts | 4 +--
7 files changed, 67 insertions(+), 6 deletions(-)
create mode 100644 packages/builder/src/pages/builder/maintenance/index.svelte
create mode 100644 packages/builder/src/pages/builder/portal/_components/BudibaseLogo.svelte
diff --git a/packages/builder/src/pages/builder/_layout.svelte b/packages/builder/src/pages/builder/_layout.svelte
index 62d3951fb5..95ca05b87b 100644
--- a/packages/builder/src/pages/builder/_layout.svelte
+++ b/packages/builder/src/pages/builder/_layout.svelte
@@ -71,6 +71,10 @@
await auth.getSelf()
await admin.init()
+ if ($admin.maintenance.length > 0) {
+ $redirect("./maintenance")
+ }
+
if ($auth.user) {
await licensing.init()
}
diff --git a/packages/builder/src/pages/builder/maintenance/index.svelte b/packages/builder/src/pages/builder/maintenance/index.svelte
new file mode 100644
index 0000000000..bdadd98c42
--- /dev/null
+++ b/packages/builder/src/pages/builder/maintenance/index.svelte
@@ -0,0 +1,27 @@
+
+
+{#each $admin.maintenance as maintenance}
+ {#if maintenance.type === MaintenanceType.SQS_MISSING}
+
+
+
+ Please upgrade your Budibase installation
+
+ We've detected that the version of Budibase you're using depends on a
+ more recent version of the CouchDB database than what you have
+ installed.
+
+
+ To resolve this, you can either rollback to a previous version of
+ Budibase, or follow the migration guide here
+ to update to a later version of CouchDB.
+
+
+
+ {/if}
+{/each}
diff --git a/packages/builder/src/pages/builder/portal/_components/BudibaseLogo.svelte b/packages/builder/src/pages/builder/portal/_components/BudibaseLogo.svelte
new file mode 100644
index 0000000000..8276510201
--- /dev/null
+++ b/packages/builder/src/pages/builder/portal/_components/BudibaseLogo.svelte
@@ -0,0 +1,13 @@
+
+
+ $goto("./apps")} />
+
+
diff --git a/packages/builder/src/stores/portal/admin.js b/packages/builder/src/stores/portal/admin.js
index 2106acac27..29d4585c06 100644
--- a/packages/builder/src/stores/portal/admin.js
+++ b/packages/builder/src/stores/portal/admin.js
@@ -17,6 +17,7 @@ export const DEFAULT_CONFIG = {
adminUser: { checked: false },
sso: { checked: false },
},
+ maintenance: [],
offlineMode: false,
}
@@ -48,6 +49,7 @@ export function createAdminStore() {
store.isDev = environment.isDev
store.baseUrl = environment.baseUrl
store.offlineMode = environment.offlineMode
+ store.maintenance = environment.maintenance
return store
})
}
diff --git a/packages/types/src/core/installation.ts b/packages/types/src/core/installation.ts
index 7679290f36..ec89e439d9 100644
--- a/packages/types/src/core/installation.ts
+++ b/packages/types/src/core/installation.ts
@@ -2,3 +2,7 @@ export enum ServiceType {
WORKER = "worker",
APPS = "apps",
}
+
+export enum MaintenanceType {
+ SQS_MISSING = "sqs_missing",
+}
diff --git a/packages/worker/src/api/controllers/system/environment.ts b/packages/worker/src/api/controllers/system/environment.ts
index bf9270607f..6171ccf4db 100644
--- a/packages/worker/src/api/controllers/system/environment.ts
+++ b/packages/worker/src/api/controllers/system/environment.ts
@@ -1,10 +1,18 @@
-import { Ctx } from "@budibase/types"
+import { Ctx, MaintenanceType } from "@budibase/types"
import env from "../../../environment"
import { env as coreEnv } from "@budibase/backend-core"
import nodeFetch from "node-fetch"
+// When we come to move to SQS fully and move away from Clouseau, we will need
+// to flip this to true (or remove it entirely). This will then be used to
+// determine if we should show the maintenance page that links to the SQS
+// migration docs.
+const sqsRequired = false
+
let sqsAvailable: boolean
async function isSqsAvailable() {
+ // We cache this value for the duration of the Node process because we don't
+ // want every page load to be making this relatively expensive check.
if (sqsAvailable !== undefined) {
return sqsAvailable
}
@@ -21,6 +29,10 @@ async function isSqsAvailable() {
}
}
+async function isSqsMissing() {
+ return sqsRequired && !(await isSqsAvailable())
+}
+
export const fetch = async (ctx: Ctx) => {
ctx.body = {
multiTenancy: !!env.MULTI_TENANCY,
@@ -33,8 +45,9 @@ export const fetch = async (ctx: Ctx) => {
}
if (env.SELF_HOSTED) {
- ctx.body.infrastructure = {
- sqs: await isSqsAvailable(),
+ ctx.body.maintenance = []
+ if (await isSqsMissing()) {
+ ctx.body.maintenance.push({ type: MaintenanceType.SQS_MISSING })
}
}
}
diff --git a/packages/worker/src/api/routes/system/tests/environment.spec.ts b/packages/worker/src/api/routes/system/tests/environment.spec.ts
index 2efbfa07c9..4dee77d3a9 100644
--- a/packages/worker/src/api/routes/system/tests/environment.spec.ts
+++ b/packages/worker/src/api/routes/system/tests/environment.spec.ts
@@ -40,9 +40,7 @@ describe("/api/system/environment", () => {
multiTenancy: true,
baseUrl: "http://localhost:10000",
offlineMode: false,
- infrastructure: {
- sqs: false,
- },
+ maintenance: [],
})
})
})
From bb0b776684e29a529ac5198451472e8981cadd1f Mon Sep 17 00:00:00 2001
From: mike12345567
Date: Tue, 30 Jan 2024 17:57:10 +0000
Subject: [PATCH 014/783] Updating how aliasing is handled.
---
.../server/src/api/controllers/row/alias.ts | 2 +-
packages/server/src/integrations/base/sql.ts | 86 ++++++++------
.../server/src/integrations/tests/sql.spec.ts | 110 ++----------------
.../sqlQueryJson/filterByRelationship.json | 94 +++++++++++++++
packages/types/src/sdk/search.ts | 3 +-
5 files changed, 158 insertions(+), 137 deletions(-)
create mode 100644 packages/server/src/integrations/tests/sqlQueryJson/filterByRelationship.json
diff --git a/packages/server/src/api/controllers/row/alias.ts b/packages/server/src/api/controllers/row/alias.ts
index fc00b505c4..589431cc1a 100644
--- a/packages/server/src/api/controllers/row/alias.ts
+++ b/packages/server/src/api/controllers/row/alias.ts
@@ -113,7 +113,7 @@ export default class AliasTables {
}
json.meta.tables = aliasedTables
}
- json.endpoint.alias = this.getAlias(json.endpoint.entityId)
+ json.tableAliases = this.tableAliases
const response = await getDatasourceAndQuery(json)
return this.reverse(response)
}
diff --git a/packages/server/src/integrations/base/sql.ts b/packages/server/src/integrations/base/sql.ts
index d33c077ee5..c9be2e1ae6 100644
--- a/packages/server/src/integrations/base/sql.ts
+++ b/packages/server/src/integrations/base/sql.ts
@@ -129,8 +129,13 @@ class InternalBuilder {
addFilters(
query: KnexQuery,
filters: SearchFilters | undefined,
- opts: { relationship?: boolean; tableName?: string }
+ tableName: string,
+ opts: { aliases?: Record; relationship?: boolean }
): KnexQuery {
+ function getTableName(name: string) {
+ const alias = opts.aliases?.[name]
+ return alias || name
+ }
function iterate(
structure: { [key: string]: any },
fn: (key: string, value: any) => void
@@ -139,10 +144,11 @@ class InternalBuilder {
const updatedKey = dbCore.removeKeyNumbering(key)
const isRelationshipField = updatedKey.includes(".")
if (!opts.relationship && !isRelationshipField) {
- fn(`${opts.tableName}.${updatedKey}`, value)
+ fn(`${getTableName(tableName)}.${updatedKey}`, value)
}
if (opts.relationship && isRelationshipField) {
- fn(updatedKey, value)
+ const [filterTableName, property] = updatedKey.split(".")
+ fn(`${getTableName(filterTableName)}.${property}`, value)
}
}
}
@@ -345,17 +351,15 @@ class InternalBuilder {
query: KnexQuery,
fromTable: string,
relationships: RelationshipsJson[] | undefined,
- schema: string | undefined
+ schema: string | undefined,
+ aliases?: Record
): KnexQuery {
if (!relationships) {
return query
}
const tableSets: Record = {}
- // add up all aliases
- let aliases: Record = {}
// aggregate into table sets (all the same to tables)
for (let relationship of relationships) {
- aliases = { ...aliases, ...relationship.aliases }
const keyObj: { toTable: string; throughTable: string | undefined } = {
toTable: relationship.tableName,
throughTable: undefined,
@@ -372,9 +376,9 @@ class InternalBuilder {
}
for (let [key, relationships] of Object.entries(tableSets)) {
const { toTable, throughTable } = JSON.parse(key)
- const toAlias = aliases[toTable] || toTable,
- throughAlias = aliases[throughTable] || throughTable,
- fromAlias = aliases[fromTable] || fromTable
+ const toAlias = aliases?.[toTable] || toTable,
+ throughAlias = aliases?.[throughTable] || throughTable,
+ fromAlias = aliases?.[fromTable] || fromTable
let toTableWithSchema = this.tableNameWithSchema(toTable, {
alias: toAlias,
schema,
@@ -423,22 +427,23 @@ class InternalBuilder {
knexWithAlias(
knex: Knex,
- endpoint: { entityId: string; alias?: string; schema?: string }
- ): { query: KnexQuery; aliased: string } {
+ endpoint: QueryJson["endpoint"],
+ aliases?: QueryJson["tableAliases"]
+ ): KnexQuery {
const tableName = endpoint.entityId
- const alias = endpoint.alias
- const aliased = alias ? alias : tableName
- const tableAliased = alias ? `${tableName} as ${alias}` : tableName
+ const tableAliased = aliases?.[tableName]
+ ? `${tableName} as ${aliases?.[tableName]}`
+ : tableName
let query = knex(tableAliased)
if (endpoint.schema) {
query = query.withSchema(endpoint.schema)
}
- return { query, aliased }
+ return query
}
create(knex: Knex, json: QueryJson, opts: QueryOptions): KnexQuery {
const { endpoint, body } = json
- let { query } = this.knexWithAlias(knex, endpoint)
+ let query = this.knexWithAlias(knex, endpoint)
const parsedBody = parseBody(body)
// make sure no null values in body for creation
for (let [key, value] of Object.entries(parsedBody)) {
@@ -457,7 +462,7 @@ class InternalBuilder {
bulkCreate(knex: Knex, json: QueryJson): KnexQuery {
const { endpoint, body } = json
- let { query } = this.knexWithAlias(knex, endpoint)
+ let query = this.knexWithAlias(knex, endpoint)
if (!Array.isArray(body)) {
return query
}
@@ -466,8 +471,10 @@ class InternalBuilder {
}
read(knex: Knex, json: QueryJson, limit: number): KnexQuery {
- let { endpoint, resource, filters, paginate, relationships } = json
+ let { endpoint, resource, filters, paginate, relationships, tableAliases } =
+ json
+ const tableName = endpoint.entityId
// select all if not specified
if (!resource) {
resource = { fields: [] }
@@ -493,19 +500,20 @@ class InternalBuilder {
}
// start building the query
- let { query, aliased } = this.knexWithAlias(knex, endpoint)
+ let query = this.knexWithAlias(knex, endpoint, tableAliases)
query = query.limit(foundLimit)
if (foundOffset) {
query = query.offset(foundOffset)
}
- query = this.addFilters(query, filters, { tableName: aliased })
+ query = this.addFilters(query, filters, tableName, {
+ aliases: tableAliases,
+ })
// add sorting to pre-query
query = this.addSorting(query, json)
- // @ts-ignore
- let preQuery: KnexQuery = knex({
- // @ts-ignore
- [aliased]: query,
- }).select(selectStatement)
+ const alias = tableAliases?.[tableName] || tableName
+ let preQuery = knex({
+ [alias]: query,
+ } as any).select(selectStatement) as any
// have to add after as well (this breaks MS-SQL)
if (this.client !== SqlClient.MS_SQL) {
preQuery = this.addSorting(preQuery, json)
@@ -513,18 +521,24 @@ class InternalBuilder {
// handle joins
query = this.addRelationships(
preQuery,
- aliased,
+ tableName,
relationships,
- endpoint.schema
+ endpoint.schema,
+ tableAliases
)
- return this.addFilters(query, filters, { relationship: true })
+ return this.addFilters(query, filters, tableName, {
+ relationship: true,
+ aliases: tableAliases,
+ })
}
update(knex: Knex, json: QueryJson, opts: QueryOptions): KnexQuery {
- const { endpoint, body, filters } = json
- let { query, aliased } = this.knexWithAlias(knex, endpoint)
+ const { endpoint, body, filters, tableAliases } = json
+ let query = this.knexWithAlias(knex, endpoint, tableAliases)
const parsedBody = parseBody(body)
- query = this.addFilters(query, filters, { tableName: aliased })
+ query = this.addFilters(query, filters, endpoint.entityId, {
+ aliases: tableAliases,
+ })
// mysql can't use returning
if (opts.disableReturning) {
return query.update(parsedBody)
@@ -534,9 +548,11 @@ class InternalBuilder {
}
delete(knex: Knex, json: QueryJson, opts: QueryOptions): KnexQuery {
- const { endpoint, filters } = json
- let { query, aliased } = this.knexWithAlias(knex, endpoint)
- query = this.addFilters(query, filters, { tableName: aliased })
+ const { endpoint, filters, tableAliases } = json
+ let query = this.knexWithAlias(knex, endpoint, tableAliases)
+ query = this.addFilters(query, filters, endpoint.entityId, {
+ aliases: tableAliases,
+ })
// mysql can't use returning
if (opts.disableReturning) {
return query.delete()
diff --git a/packages/server/src/integrations/tests/sql.spec.ts b/packages/server/src/integrations/tests/sql.spec.ts
index bca0cf5422..0e7257242c 100644
--- a/packages/server/src/integrations/tests/sql.spec.ts
+++ b/packages/server/src/integrations/tests/sql.spec.ts
@@ -1,5 +1,7 @@
-const Sql = require("../base/sql").default
-const { SqlClient } = require("../utils")
+import { SqlClient } from "../utils"
+import Sql from "../base/sql"
+import { QueryJson } from "@budibase/types"
+import { join } from "path"
const TABLE_NAME = "test"
@@ -17,7 +19,7 @@ function generateReadJson({
filters,
sort,
paginate,
-}: any = {}) {
+}: any = {}): QueryJson {
return {
endpoint: endpoint(table || TABLE_NAME, "READ"),
resource: {
@@ -30,7 +32,7 @@ function generateReadJson({
table: {
name: table || TABLE_NAME,
primary: ["id"],
- },
+ } as any,
},
}
}
@@ -687,102 +689,12 @@ describe("SQL query builder", () => {
describe("Captures of real examples", () => {
const limit = 5000
+ function getJson(name: string): QueryJson {
+ return require(join(__dirname, "sqlQueryJson", name)) as QueryJson
+ }
+
it("should handle filtering by relationship", () => {
- const queryJson = {
- endpoint: {
- datasourceId: "datasource_plus_8066e56456784eb2a00129d31be5c3e7",
- entityId: "products",
- operation: "READ",
- alias: "a",
- },
- resource: {
- fields: [
- "a.productname",
- "a.productid",
- "b.executorid",
- "b.taskname",
- "b.taskid",
- "b.completed",
- "b.qaid",
- ],
- },
- filters: {
- equal: {
- "1:tasks.taskname": "assembling",
- },
- onEmptyFilter: "all",
- },
- sort: {
- productname: {
- direction: "ASCENDING",
- },
- },
- paginate: {
- limit: 100,
- page: 1,
- },
- relationships: [
- {
- tableName: "tasks",
- column: "tasks",
- through: "products_tasks",
- from: "productid",
- to: "taskid",
- fromPrimary: "productid",
- toPrimary: "taskid",
- aliases: {
- products_tasks: "c",
- tasks: "b",
- products: "a",
- },
- },
- ],
- meta: {
- table: {
- type: "table",
- _id: "datasource_plus_8066e56456784eb2a00129d31be5c3e7__products",
- primary: ["productid"],
- name: "a",
- schema: {
- productname: {
- type: "string",
- externalType: "character varying",
- autocolumn: false,
- name: "productname",
- constraints: {
- presence: false,
- },
- },
- productid: {
- type: "number",
- externalType: "integer",
- autocolumn: true,
- name: "productid",
- constraints: {
- presence: false,
- },
- },
- tasks: {
- tableId:
- "datasource_plus_8066e56456784eb2a00129d31be5c3e7__tasks",
- name: "tasks",
- relationshipType: "many-to-many",
- fieldName: "taskid",
- through:
- "datasource_plus_8066e56456784eb2a00129d31be5c3e7__products_tasks",
- throughFrom: "taskid",
- throughTo: "productid",
- type: "link",
- main: true,
- _id: "ca6862d9ba09146dd8a68e3b5b7055a09",
- },
- },
- sourceId: "datasource_plus_8066e56456784eb2a00129d31be5c3e7",
- sourceType: "external",
- primaryDisplay: "productname",
- },
- },
- }
+ const queryJson = getJson(`filterByRelationship.json`)
let query = new Sql(SqlClient.POSTGRES, limit)._query(queryJson)
expect(query).toEqual({
bindings: [100, "assembling", limit],
diff --git a/packages/server/src/integrations/tests/sqlQueryJson/filterByRelationship.json b/packages/server/src/integrations/tests/sqlQueryJson/filterByRelationship.json
new file mode 100644
index 0000000000..eb1025f382
--- /dev/null
+++ b/packages/server/src/integrations/tests/sqlQueryJson/filterByRelationship.json
@@ -0,0 +1,94 @@
+{
+ "endpoint": {
+ "datasourceId": "datasource_plus_8066e56456784eb2a00129d31be5c3e7",
+ "entityId": "products",
+ "operation": "READ"
+ },
+ "resource": {
+ "fields": [
+ "a.productname",
+ "a.productid",
+ "b.executorid",
+ "b.taskname",
+ "b.taskid",
+ "b.completed",
+ "b.qaid"
+ ]
+ },
+ "filters": {
+ "equal": {
+ "1:tasks.taskname": "assembling"
+ },
+ "onEmptyFilter": "all"
+ },
+ "sort": {
+ "productname": {
+ "direction": "ASCENDING"
+ }
+ },
+ "paginate": {
+ "limit": 100,
+ "page": 1
+ },
+ "relationships": [
+ {
+ "tableName": "tasks",
+ "column": "tasks",
+ "through": "products_tasks",
+ "from": "productid",
+ "to": "taskid",
+ "fromPrimary": "productid",
+ "toPrimary": "taskid"
+ }
+ ],
+ "tableAliases": {
+ "products_tasks": "c",
+ "tasks": "b",
+ "products": "a"
+ },
+ "meta": {
+ "table": {
+ "type": "table",
+ "_id": "datasource_plus_8066e56456784eb2a00129d31be5c3e7__products",
+ "primary": [
+ "productid"
+ ],
+ "name": "a",
+ "schema": {
+ "productname": {
+ "type": "string",
+ "externalType": "character varying",
+ "autocolumn": false,
+ "name": "productname",
+ "constraints": {
+ "presence": false
+ }
+ },
+ "productid": {
+ "type": "number",
+ "externalType": "integer",
+ "autocolumn": true,
+ "name": "productid",
+ "constraints": {
+ "presence": false
+ }
+ },
+ "tasks": {
+ "tableId": "datasource_plus_8066e56456784eb2a00129d31be5c3e7__tasks",
+ "name": "tasks",
+ "relationshipType": "many-to-many",
+ "fieldName": "taskid",
+ "through": "datasource_plus_8066e56456784eb2a00129d31be5c3e7__products_tasks",
+ "throughFrom": "taskid",
+ "throughTo": "productid",
+ "type": "link",
+ "main": true,
+ "_id": "ca6862d9ba09146dd8a68e3b5b7055a09"
+ }
+ },
+ "sourceId": "datasource_plus_8066e56456784eb2a00129d31be5c3e7",
+ "sourceType": "external",
+ "primaryDisplay": "productname"
+ }
+ }
+}
\ No newline at end of file
diff --git a/packages/types/src/sdk/search.ts b/packages/types/src/sdk/search.ts
index a4045c2558..67c344d845 100644
--- a/packages/types/src/sdk/search.ts
+++ b/packages/types/src/sdk/search.ts
@@ -67,7 +67,6 @@ export interface RelationshipsJson {
fromPrimary?: string
toPrimary?: string
tableName: string
- aliases?: Record
column: string
}
@@ -75,7 +74,6 @@ export interface QueryJson {
endpoint: {
datasourceId: string
entityId: string
- alias?: string
operation: Operation
schema?: string
}
@@ -96,6 +94,7 @@ export interface QueryJson {
idFilter?: SearchFilters
}
relationships?: RelationshipsJson[]
+ tableAliases?: Record
}
export interface SqlQuery {
From 09ff8a06624c3c99ac0c5b5dfc046f6538a08a43 Mon Sep 17 00:00:00 2001
From: Mitch-Budibase
Date: Wed, 31 Jan 2024 15:00:32 +0000
Subject: [PATCH 015/783] License Test Changes
License.manage.spec.ts/StripeAPI.ts
- Test updated and now successfully updates from Free plan to premium
- createCheckoutSession updated to support this plan upgrade
---
qa-core/src/account-api/api/apis/StripeAPI.ts | 4 ++--
.../tests/licensing/license.manage.spec.ts | 11 ++++++-----
2 files changed, 8 insertions(+), 7 deletions(-)
diff --git a/qa-core/src/account-api/api/apis/StripeAPI.ts b/qa-core/src/account-api/api/apis/StripeAPI.ts
index 5a4e810655..aeb027f428 100644
--- a/qa-core/src/account-api/api/apis/StripeAPI.ts
+++ b/qa-core/src/account-api/api/apis/StripeAPI.ts
@@ -11,12 +11,12 @@ export default class StripeAPI extends BaseAPI {
}
async createCheckoutSession(
- priceId: string,
+ price: object,
opts: APIRequestOpts = { status: 200 }
) {
return this.doRequest(() => {
return this.client.post(`/api/stripe/checkout-session`, {
- body: { priceId },
+ body: { prices: [price] },
})
}, opts)
}
diff --git a/qa-core/src/account-api/tests/licensing/license.manage.spec.ts b/qa-core/src/account-api/tests/licensing/license.manage.spec.ts
index 9a8662ea3b..2d5b9332c6 100644
--- a/qa-core/src/account-api/tests/licensing/license.manage.spec.ts
+++ b/qa-core/src/account-api/tests/licensing/license.manage.spec.ts
@@ -36,11 +36,11 @@ describe("license management", () => {
const [plansRes, planBody] = await config.api.licenses.getPlans()
// Select priceId from premium plan
- let premiumPriceId = null
- let businessPriceId = ""
+ let premiumPrice = null
+ let businessPriceId: ""
for (const plan of planBody) {
if (plan.type === PlanType.PREMIUM_PLUS) {
- premiumPriceId = plan.prices[0].priceId
+ premiumPrice = plan.prices[0]
}
if (plan.type === PlanType.ENTERPRISE_BASIC) {
businessPriceId = plan.prices[0].priceId
@@ -49,7 +49,7 @@ describe("license management", () => {
// Create checkout session for price
const checkoutSessionRes = await config.api.stripe.createCheckoutSession(
- premiumPriceId
+ { id: premiumPrice.priceId, type: premiumPrice.type }
)
const checkoutSessionUrl = checkoutSessionRes[1].url
expect(checkoutSessionUrl).toContain("checkout.stripe.com")
@@ -84,7 +84,7 @@ describe("license management", () => {
customer: customer.id,
items: [
{
- price: premiumPriceId,
+ price: premiumPrice.priceId,
quantity: 1,
},
],
@@ -105,6 +105,7 @@ describe("license management", () => {
expect(portalSessionBody.url).toContain("billing.stripe.com")
// Update subscription from premium to business license
+ //await config.api.licenses.updatePlan(businessPriceId.priceId)
await config.api.licenses.updatePlan(businessPriceId)
// License updated to Business
From 281b88a86adac77f06e6295cb584095aec87d046 Mon Sep 17 00:00:00 2001
From: Sam Rose
Date: Wed, 31 Jan 2024 15:54:36 +0000
Subject: [PATCH 016/783] Respond to PR feedback.
---
packages/worker/src/api/controllers/system/environment.ts | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/packages/worker/src/api/controllers/system/environment.ts b/packages/worker/src/api/controllers/system/environment.ts
index 6171ccf4db..203d3d41ff 100644
--- a/packages/worker/src/api/controllers/system/environment.ts
+++ b/packages/worker/src/api/controllers/system/environment.ts
@@ -42,10 +42,10 @@ export const fetch = async (ctx: Ctx) => {
disableAccountPortal: env.DISABLE_ACCOUNT_PORTAL,
baseUrl: env.PLATFORM_URL,
isDev: env.isDev() && !env.isTest(),
+ maintenance: [],
}
if (env.SELF_HOSTED) {
- ctx.body.maintenance = []
if (await isSqsMissing()) {
ctx.body.maintenance.push({ type: MaintenanceType.SQS_MISSING })
}
From b52ba43979b2d7a397356300c5e291edf0d3b35a Mon Sep 17 00:00:00 2001
From: Sam Rose
Date: Wed, 31 Jan 2024 15:56:17 +0000
Subject: [PATCH 017/783] Fix tests.
---
packages/worker/src/api/routes/system/tests/environment.spec.ts | 1 +
1 file changed, 1 insertion(+)
diff --git a/packages/worker/src/api/routes/system/tests/environment.spec.ts b/packages/worker/src/api/routes/system/tests/environment.spec.ts
index 4dee77d3a9..dbe9be7374 100644
--- a/packages/worker/src/api/routes/system/tests/environment.spec.ts
+++ b/packages/worker/src/api/routes/system/tests/environment.spec.ts
@@ -27,6 +27,7 @@ describe("/api/system/environment", () => {
multiTenancy: true,
baseUrl: "http://localhost:10000",
offlineMode: false,
+ maintenance: [],
})
})
From 06556325a1595389faf5db9d829b0e3d14782c4a Mon Sep 17 00:00:00 2001
From: Andrew Kingston
Date: Thu, 1 Feb 2024 14:45:16 +0000
Subject: [PATCH 018/783] Remove proxying of context changes up the chain
---
.../src/components/context/Provider.svelte | 4 +-
packages/client/src/stores/context.js | 53 +++++--------------
2 files changed, 15 insertions(+), 42 deletions(-)
diff --git a/packages/client/src/components/context/Provider.svelte b/packages/client/src/components/context/Provider.svelte
index 1b6a073512..ad5b580c4f 100644
--- a/packages/client/src/components/context/Provider.svelte
+++ b/packages/client/src/components/context/Provider.svelte
@@ -33,7 +33,7 @@
const provideData = newData => {
const dataKey = JSON.stringify(newData)
if (dataKey !== lastDataKey) {
- context.actions.provideData(providerKey, newData, scope)
+ context.actions.provideData(providerKey, newData)
lastDataKey = dataKey
}
}
@@ -43,7 +43,7 @@
if (actionsKey !== lastActionsKey) {
lastActionsKey = actionsKey
newActions?.forEach(({ type, callback, metadata }) => {
- context.actions.provideAction(providerKey, type, callback, scope)
+ context.actions.provideAction(providerKey, type, callback)
// Register any "refresh datasource" actions with a singleton store
// so we can easily refresh data at all levels for any datasource
diff --git a/packages/client/src/stores/context.js b/packages/client/src/stores/context.js
index e54c773591..c1ec18ef13 100644
--- a/packages/client/src/stores/context.js
+++ b/packages/client/src/stores/context.js
@@ -1,5 +1,4 @@
import { writable, derived } from "svelte/store"
-import { ContextScopes } from "constants"
export const createContextStore = parentContext => {
const context = writable({})
@@ -20,60 +19,34 @@ export const createContextStore = parentContext => {
}
// Provide some data in context
- const provideData = (providerId, data, scope = ContextScopes.Global) => {
+ const provideData = (providerId, data) => {
if (!providerId || data === undefined) {
return
}
- // Proxy message up the chain if we have a parent and are providing global
- // context
- if (scope === ContextScopes.Global && parentContext) {
- parentContext.actions.provideData(providerId, data, scope)
- }
-
// Otherwise this is either the context root, or we're providing a local
// context override, so we need to update the local context instead
- else {
- context.update(state => {
- state[providerId] = data
- return state
- })
- broadcastChange(providerId)
- }
+ context.update(state => {
+ state[providerId] = data
+ return state
+ })
+ broadcastChange(providerId)
}
// Provides some action in context
- const provideAction = (
- providerId,
- actionType,
- callback,
- scope = ContextScopes.Global
- ) => {
+ const provideAction = (providerId, actionType, callback) => {
if (!providerId || !actionType) {
return
}
- // Proxy message up the chain if we have a parent and are providing global
- // context
- if (scope === ContextScopes.Global && parentContext) {
- parentContext.actions.provideAction(
- providerId,
- actionType,
- callback,
- scope
- )
- }
-
// Otherwise this is either the context root, or we're providing a local
// context override, so we need to update the local context instead
- else {
- const key = `${providerId}_${actionType}`
- context.update(state => {
- state[key] = callback
- return state
- })
- broadcastChange(key)
- }
+ const key = `${providerId}_${actionType}`
+ context.update(state => {
+ state[key] = callback
+ return state
+ })
+ broadcastChange(key)
}
const observeChanges = callback => {
From ba002f96492fd311cb0396262b4f77c2edb6f8f5 Mon Sep 17 00:00:00 2001
From: Sam Rose
Date: Fri, 2 Feb 2024 09:30:33 +0000
Subject: [PATCH 019/783] Clean up isolates when a request is finished.
---
packages/backend-core/src/context/types.ts | 1 +
packages/server/src/jsRunner/index.ts | 8 ++++++++
packages/server/src/middleware/cleanup.ts | 16 ++++++++++++++++
3 files changed, 25 insertions(+)
create mode 100644 packages/server/src/middleware/cleanup.ts
diff --git a/packages/backend-core/src/context/types.ts b/packages/backend-core/src/context/types.ts
index cc052ca505..dad1af3bf8 100644
--- a/packages/backend-core/src/context/types.ts
+++ b/packages/backend-core/src/context/types.ts
@@ -15,4 +15,5 @@ export type ContextMap = {
jsContext: Context
helpersModule: Module
}
+ cleanup?: (() => void | Promise)[]
}
diff --git a/packages/server/src/jsRunner/index.ts b/packages/server/src/jsRunner/index.ts
index 8e529d533d..9441a74d07 100644
--- a/packages/server/src/jsRunner/index.ts
+++ b/packages/server/src/jsRunner/index.ts
@@ -115,6 +115,14 @@ export function init() {
}
bbCtx.isolateRefs = { jsContext, jsIsolate, helpersModule }
+ if (!bbCtx.cleanup) {
+ bbCtx.cleanup = []
+ }
+ bbCtx.cleanup.push(() => {
+ helpersModule.release()
+ jsContext.release()
+ jsIsolate.dispose()
+ })
}
let { jsIsolate, jsContext, helpersModule } = bbCtx.isolateRefs!
diff --git a/packages/server/src/middleware/cleanup.ts b/packages/server/src/middleware/cleanup.ts
new file mode 100644
index 0000000000..5204d5cfb1
--- /dev/null
+++ b/packages/server/src/middleware/cleanup.ts
@@ -0,0 +1,16 @@
+import { Ctx } from "@budibase/types"
+import { context } from "@budibase/backend-core"
+
+export default async (ctx: Ctx, next: any) => {
+ const resp = next()
+
+ const current = context.getCurrentContext()
+ if (current?.cleanup) {
+ for (let fn of current.cleanup || []) {
+ await fn()
+ }
+ delete current.cleanup
+ }
+
+ return resp
+}
From 21dfbe75ffa19c4be85d4a8fb785f028a47a8aa3 Mon Sep 17 00:00:00 2001
From: Sam Rose
Date: Fri, 2 Feb 2024 09:32:07 +0000
Subject: [PATCH 020/783] Use new cleanup middleware.
---
packages/server/src/api/index.ts | 3 +++
1 file changed, 3 insertions(+)
diff --git a/packages/server/src/api/index.ts b/packages/server/src/api/index.ts
index ad3d8307da..92cee95ea6 100644
--- a/packages/server/src/api/index.ts
+++ b/packages/server/src/api/index.ts
@@ -1,6 +1,7 @@
import Router from "@koa/router"
import { auth, middleware, env as envCore } from "@budibase/backend-core"
import currentApp from "../middleware/currentapp"
+import cleanup from "../middleware/cleanup"
import zlib from "zlib"
import { mainRoutes, staticRoutes, publicRoutes } from "./routes"
import { middleware as pro } from "@budibase/pro"
@@ -62,6 +63,8 @@ if (apiEnabled()) {
.use(auth.auditLog)
// @ts-ignore
.use(migrations)
+ // @ts-ignore
+ .use(cleanup)
// authenticated routes
for (let route of mainRoutes) {
From a880c5e62a5aceb3c4a207ad55cedaee9d6834d8 Mon Sep 17 00:00:00 2001
From: Andrew Kingston
Date: Fri, 2 Feb 2024 10:27:23 +0000
Subject: [PATCH 021/783] Update outside popover styles
---
packages/bbui/src/Actions/position_dropdown.js | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/packages/bbui/src/Actions/position_dropdown.js b/packages/bbui/src/Actions/position_dropdown.js
index cc169eac09..14bb209b97 100644
--- a/packages/bbui/src/Actions/position_dropdown.js
+++ b/packages/bbui/src/Actions/position_dropdown.js
@@ -38,8 +38,9 @@ export default function positionDropdown(element, opts) {
styles = customUpdate(anchorBounds, elementBounds, styles)
} else {
// Determine vertical styles
- if (align === "right-outside") {
- styles.top = anchorBounds.top
+ if (align === "right-outside" || align === "left-outside") {
+ styles.top = anchorBounds.bottom - elementBounds.height
+ styles.maxHeight = maxHeight
} else if (
window.innerHeight - anchorBounds.bottom <
(maxHeight || 100)
From daec133f792e89499700510949a0d3b15aac6262 Mon Sep 17 00:00:00 2001
From: Andrew Kingston
Date: Fri, 2 Feb 2024 10:27:29 +0000
Subject: [PATCH 022/783] Add live eval of bindings
---
.../common/bindings/BindingPanel.svelte | 37 +++++++-
.../common/bindings/BindingPicker.svelte | 91 +++++++++----------
.../Component/ComponentSettingsSection.svelte | 2 -
3 files changed, 79 insertions(+), 51 deletions(-)
diff --git a/packages/builder/src/components/common/bindings/BindingPanel.svelte b/packages/builder/src/components/common/bindings/BindingPanel.svelte
index 1dba55c733..3b64c918d0 100644
--- a/packages/builder/src/components/common/bindings/BindingPanel.svelte
+++ b/packages/builder/src/components/common/bindings/BindingPanel.svelte
@@ -15,6 +15,7 @@
decodeJSBinding,
encodeJSBinding,
convertToJS,
+ processStringSync,
} from "@budibase/string-templates"
import {
readableToRuntimeBinding,
@@ -59,15 +60,21 @@
let hbsValue = initialValueJS ? null : value
let sidebar = true
let targetMode = null
+ let expressionResult
$: usingJS = mode === "JavaScript"
- $: editorMode = mode == "JavaScript" ? EditorModes.JS : EditorModes.Handlebars
+ $: editorMode =
+ mode === "JavaScript" ? EditorModes.JS : EditorModes.Handlebars
$: bindingCompletions = bindingsToCompletions(bindings, editorMode)
+ $: runtimeExpression = readableToRuntimeBinding(bindings, value)
+ $: expressionResult = processStringSync(runtimeExpression || "", context)
const updateValue = val => {
- valid = isValid(readableToRuntimeBinding(bindings, val))
+ const runtimeExpression = readableToRuntimeBinding(bindings, val)
+ valid = isValid(runtimeExpression)
if (valid) {
dispatch("change", val)
+ expressionResult = processStringSync(runtimeExpression || "", context)
}
}
@@ -114,7 +121,7 @@
}
const switchMode = () => {
- if (targetMode == "Text") {
+ if (targetMode === "Text") {
jsValue = null
updateValue(jsValue)
} else {
@@ -204,6 +211,11 @@
autofocus={autofocusEditor}
/>
+ {#if expressionResult}
+
+ {expressionResult}
+
+ {/if}
@@ -387,8 +400,14 @@
padding: 0;
margin: 0;
font-size: 12px;
- white-space: pre-wrap;
- word-break: break-all;
+ white-space: pre;
+ text-overflow: ellipsis;
+ overflow: hidden;
+ }
+ .helper pre :global(span) {
+ overflow: hidden !important;
+ text-overflow: ellipsis !important;
+ white-space: nowrap !important;
}
.helper :global(p) {
padding: 0;
From 14b2bfa8d690802877058b3b5b1faf7b6ad2582d Mon Sep 17 00:00:00 2001
From: Andrew Kingston
Date: Fri, 16 Feb 2024 16:24:46 +0000
Subject: [PATCH 068/783] Update lock
---
yarn.lock | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/yarn.lock b/yarn.lock
index 1937482837..3e147eed34 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -13765,6 +13765,11 @@ json-buffer@3.0.1:
resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.1.tgz#9338802a30d3b6605fbe0613e094008ca8c05a13"
integrity sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==
+json-format-highlight@^1.0.4:
+ version "1.0.4"
+ resolved "https://registry.yarnpkg.com/json-format-highlight/-/json-format-highlight-1.0.4.tgz#2e44277edabcec79a3d2c84e984c62e2258037b9"
+ integrity sha512-RqenIjKr1I99XfXPAml9G7YlEZg/GnsH7emWyWJh2yuGXqHW8spN7qx6/ME+MoIBb35/fxrMC9Jauj6nvGe4Mg==
+
json-parse-better-errors@^1.0.1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9"
From 4f05bc619b4c2cd8627b965326389bfaee6bf199 Mon Sep 17 00:00:00 2001
From: Peter Clement
Date: Mon, 19 Feb 2024 09:51:10 +0000
Subject: [PATCH 069/783] Handle branding cookies with different tenant ids
---
.../builder/src/pages/builder/auth/_layout.svelte | 11 ++++++++---
1 file changed, 8 insertions(+), 3 deletions(-)
diff --git a/packages/builder/src/pages/builder/auth/_layout.svelte b/packages/builder/src/pages/builder/auth/_layout.svelte
index f5484182e8..8902e9ac61 100644
--- a/packages/builder/src/pages/builder/auth/_layout.svelte
+++ b/packages/builder/src/pages/builder/auth/_layout.svelte
@@ -10,13 +10,18 @@
$redirect("../")
}
- if ($admin?.checklist?.branding) {
+ if ($admin.cloud && $admin?.checklist?.branding) {
let url = new URL(window.location.href)
let hostname = url.hostname
let parts = hostname.split(".")
- let tenantId = parts[0]
+ let newTenantId = parts[0]
let domain = parts.slice(-2).join(".")
- CookieUtils.setCookie("tenantId", tenantId, domain)
+
+ let existingTenantId = CookieUtils.getCookie("tenantId")
+
+ if (!existingTenantId || existingTenantId !== newTenantId) {
+ CookieUtils.setCookie("tenantId", newTenantId, domain)
+ }
}
if (
From d81ecbd7cf5e7f0b7d4628b6c15c7c40231d7d58 Mon Sep 17 00:00:00 2001
From: Adria Navarro
Date: Mon, 19 Feb 2024 16:40:32 +0100
Subject: [PATCH 070/783] Add environment
---
packages/server/src/environment.ts | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/packages/server/src/environment.ts b/packages/server/src/environment.ts
index 20142776b8..bc4b9eb35b 100644
--- a/packages/server/src/environment.ts
+++ b/packages/server/src/environment.ts
@@ -126,6 +126,10 @@ const environment = {
getDefaults: () => {
return DEFAULTS
},
+ useIsolatedVM: {
+ QUERY_TRANSFORMERS: !!process.env.QUERY_TRANSFORMERS_ISOLATEDVM,
+ JS_RUNNER: !!process.env.JS_RUNNER_ISOLATEDVM,
+ },
}
// clean up any environment variable edge cases
From 09dbc694fab39a24b15db2c3e3cb3f30b6fb6c49 Mon Sep 17 00:00:00 2001
From: Adria Navarro
Date: Mon, 19 Feb 2024 17:01:27 +0100
Subject: [PATCH 071/783] Fix imports
---
packages/server/src/threads/query.ts | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/packages/server/src/threads/query.ts b/packages/server/src/threads/query.ts
index 11714c9c52..a8aa428b0a 100644
--- a/packages/server/src/threads/query.ts
+++ b/packages/server/src/threads/query.ts
@@ -18,7 +18,7 @@ import { Datasource, Query, SourceName, VM } from "@budibase/types"
import { isSQL } from "../integrations/utils"
import { interpolateSQL } from "../integrations/queries/sql"
-import environment from "src/environment"
+import environment from "../environment"
class QueryRunner {
datasource: Datasource
From 433c3a6306fdd161da70d145b4ac73885f215757 Mon Sep 17 00:00:00 2001
From: Andrew Kingston
Date: Mon, 19 Feb 2024 16:22:23 +0000
Subject: [PATCH 072/783] Debounce hiding binding values to enable interacting
with them
---
packages/bbui/src/Popover/Popover.svelte | 2 +
.../common/bindings/BindingPicker.svelte | 51 +++++++++++++------
2 files changed, 38 insertions(+), 15 deletions(-)
diff --git a/packages/bbui/src/Popover/Popover.svelte b/packages/bbui/src/Popover/Popover.svelte
index 5066e3aa05..7ff5ae5f03 100644
--- a/packages/bbui/src/Popover/Popover.svelte
+++ b/packages/bbui/src/Popover/Popover.svelte
@@ -101,6 +101,8 @@
role="presentation"
style="height: {customHeight}; --customZindex: {customZindex};"
transition:fly|local={{ y: -20, duration: animate ? 200 : 0 }}
+ on:mouseenter
+ on:mouseleave
>
diff --git a/packages/builder/src/components/common/bindings/BindingPicker.svelte b/packages/builder/src/components/common/bindings/BindingPicker.svelte
index 4f08cd5306..342855f427 100644
--- a/packages/builder/src/components/common/bindings/BindingPicker.svelte
+++ b/packages/builder/src/components/common/bindings/BindingPicker.svelte
@@ -18,6 +18,7 @@
let hoverTarget
let helpers = handlebarsCompletions()
let selectedCategory
+ let hideTimeout
$: bindingIcons = bindings?.reduce((acc, ele) => {
if (ele.icon) {
@@ -86,6 +87,37 @@
nullColor: "#c678dd",
})
}
+
+ const showPopover = (target, binding) => {
+ if (hideTimeout) {
+ clearTimeout(hideTimeout)
+ hideTimeout = null
+ }
+ let val = getBindingValue(binding)
+ if (val !== "") {
+ popoverAnchor = target
+ hoverTarget = {
+ code: val,
+ }
+ popover.show()
+ }
+ }
+
+ const hidePopover = () => {
+ hideTimeout = setTimeout(() => {
+ popover.hide()
+ popoverAnchor = null
+ hoverTarget = null
+ hideTimeout = null
+ }, 100)
+ }
+
+ const stopHiding = () => {
+ if (hideTimeout) {
+ clearTimeout(hideTimeout)
+ hideTimeout = null
+ }
+ }
@@ -175,21 +209,8 @@
{#each category.bindings as binding}
{
- let val = getBindingValue(binding)
- if (val !== "") {
- popoverAnchor = e.target
- hoverTarget = {
- code: val,
- }
- popover.show()
- }
- }}
- on:mouseleave={() => {
- popover.hide()
- popoverAnchor = null
- hoverTarget = null
- }}
+ on:mouseenter={e => showPopover(e.target, binding)}
+ on:mouseleave={hidePopover}
on:focus={() => {}}
on:blur={() => {}}
on:click={() => addBinding(binding)}
From ae7a978998d3a52a85557c006a5e87045a6a5f00 Mon Sep 17 00:00:00 2001
From: Adria Navarro
Date: Mon, 19 Feb 2024 17:27:01 +0100
Subject: [PATCH 073/783] Fix tests
---
packages/server/src/environment.ts | 33 ++++++++++---------
packages/server/src/jsRunner/index.ts | 3 +-
.../src/jsRunner/tests/jsRunner.spec.ts | 14 ++++++--
packages/server/src/threads/query.ts | 2 +-
4 files changed, 33 insertions(+), 19 deletions(-)
diff --git a/packages/server/src/environment.ts b/packages/server/src/environment.ts
index bc4b9eb35b..e137c342e6 100644
--- a/packages/server/src/environment.ts
+++ b/packages/server/src/environment.ts
@@ -113,6 +113,7 @@ const environment = {
process.env[key] = value
// @ts-ignore
environment[key] = value
+ cleanVariables()
},
isTest: coreEnv.isTest,
isJest: coreEnv.isJest,
@@ -126,24 +127,26 @@ const environment = {
getDefaults: () => {
return DEFAULTS
},
- useIsolatedVM: {
- QUERY_TRANSFORMERS: !!process.env.QUERY_TRANSFORMERS_ISOLATEDVM,
- JS_RUNNER: !!process.env.JS_RUNNER_ISOLATEDVM,
- },
+ ISOLATEDVM_QUERY_TRANSFORMERS: !!process.env.ISOLATEDVM_QUERY_TRANSFORMERS,
+ ISOLATEDVM_JS_RUNNER: !!process.env.ISOLATEDVM_JS_RUNNER,
}
-// clean up any environment variable edge cases
-for (let [key, value] of Object.entries(environment)) {
- // handle the edge case of "0" to disable an environment variable
- if (value === "0") {
- // @ts-ignore
- environment[key] = 0
- }
- // handle the edge case of "false" to disable an environment variable
- if (value === "false") {
- // @ts-ignore
- environment[key] = 0
+function cleanVariables() {
+ // clean up any environment variable edge cases
+ for (let [key, value] of Object.entries(environment)) {
+ // handle the edge case of "0" to disable an environment variable
+ if (value === "0") {
+ // @ts-ignore
+ environment[key] = 0
+ }
+ // handle the edge case of "false" to disable an environment variable
+ if (value === "false") {
+ // @ts-ignore
+ environment[key] = 0
+ }
}
}
+cleanVariables()
+
export default environment
diff --git a/packages/server/src/jsRunner/index.ts b/packages/server/src/jsRunner/index.ts
index 5c863e2855..362dde1fb2 100644
--- a/packages/server/src/jsRunner/index.ts
+++ b/packages/server/src/jsRunner/index.ts
@@ -7,7 +7,8 @@ import { BuiltInVM, IsolatedVM } from "./vm"
export function init() {
setJSRunner((js: string, ctx: Record) => {
return tracer.trace("runJS", {}, span => {
- if (!env.useIsolatedVM.JS_RUNNER) {
+ const useIsolatedVm = env.ISOLATEDVM_JS_RUNNER
+ if (!useIsolatedVm) {
const vm = new BuiltInVM(ctx, span)
return vm.execute(js)
}
diff --git a/packages/server/src/jsRunner/tests/jsRunner.spec.ts b/packages/server/src/jsRunner/tests/jsRunner.spec.ts
index 285ade7097..3baf049eae 100644
--- a/packages/server/src/jsRunner/tests/jsRunner.spec.ts
+++ b/packages/server/src/jsRunner/tests/jsRunner.spec.ts
@@ -7,18 +7,28 @@ const { runJsHelpersTests } = require("@budibase/string-templates/test/utils")
import tk from "timekeeper"
import { init } from ".."
import TestConfiguration from "../../tests/utilities/TestConfiguration"
+import environment from "../../environment"
tk.freeze("2021-01-21T12:00:00")
-describe("jsRunner", () => {
+describe.each([
+ ["vm", false],
+ ["isolated-vm", true],
+])("jsRunner (using %s)", (_, useIsolatedVM) => {
const config = new TestConfiguration()
beforeAll(async () => {
+ environment._set("ISOLATEDVM_JS_RUNNER", useIsolatedVM)
+
// Register js runner
init()
await config.init()
})
+ afterAll(() => {
+ config.end()
+ })
+
const processJS = (js: string, context?: object) => {
return config.doInContext(config.getAppId(), async () =>
processStringSync(encodeJSBinding(js), context || {})
@@ -30,7 +40,7 @@ describe("jsRunner", () => {
expect(output).toBe(3)
})
- it("should prevent sandbox escape", async () => {
+ it.only("should prevent sandbox escape", async () => {
const output = await processJS(
`return this.constructor.constructor("return process")()`
)
diff --git a/packages/server/src/threads/query.ts b/packages/server/src/threads/query.ts
index a8aa428b0a..2c8e59ce64 100644
--- a/packages/server/src/threads/query.ts
+++ b/packages/server/src/threads/query.ts
@@ -129,7 +129,7 @@ class QueryRunner {
// transform as required
if (transformer) {
let runner: VM
- if (!environment.useIsolatedVM.QUERY_TRANSFORMERS) {
+ if (!environment.ISOLATEDVM_QUERY_TRANSFORMERS) {
runner = new VM2({
data: rows,
params: enrichedParameters,
From 602f35537d9f0438014c0600ae3afcb89f6a94d8 Mon Sep 17 00:00:00 2001
From: Andrew Kingston
Date: Mon, 19 Feb 2024 16:28:23 +0000
Subject: [PATCH 074/783] Support custom min widths for popovers
---
packages/bbui/src/Actions/position_dropdown.js | 3 ++-
packages/bbui/src/Popover/Popover.svelte | 3 ++-
.../src/components/common/bindings/BindingPicker.svelte | 4 ++--
3 files changed, 6 insertions(+), 4 deletions(-)
diff --git a/packages/bbui/src/Actions/position_dropdown.js b/packages/bbui/src/Actions/position_dropdown.js
index 14bb209b97..31a1044ba4 100644
--- a/packages/bbui/src/Actions/position_dropdown.js
+++ b/packages/bbui/src/Actions/position_dropdown.js
@@ -15,6 +15,7 @@ export default function positionDropdown(element, opts) {
align,
maxHeight,
maxWidth,
+ minWidth,
useAnchorWidth,
offset = 5,
customUpdate,
@@ -28,7 +29,7 @@ export default function positionDropdown(element, opts) {
const elementBounds = element.getBoundingClientRect()
let styles = {
maxHeight: null,
- minWidth: null,
+ minWidth,
maxWidth,
left: null,
top: null,
diff --git a/packages/bbui/src/Popover/Popover.svelte b/packages/bbui/src/Popover/Popover.svelte
index 7ff5ae5f03..407fb0b153 100644
--- a/packages/bbui/src/Popover/Popover.svelte
+++ b/packages/bbui/src/Popover/Popover.svelte
@@ -12,6 +12,7 @@
export let anchor
export let align = "right"
export let portalTarget
+ export let minWidth
export let maxWidth
export let maxHeight
export let open = false
@@ -21,7 +22,6 @@
export let customHeight
export let animate = true
export let customZindex
-
export let handlePostionUpdate
export let showPopover = true
export let clickOutsideOverride = false
@@ -86,6 +86,7 @@
align,
maxHeight,
maxWidth,
+ minWidth,
useAnchorWidth,
offset,
customUpdate: handlePostionUpdate,
diff --git a/packages/builder/src/components/common/bindings/BindingPicker.svelte b/packages/builder/src/components/common/bindings/BindingPicker.svelte
index 342855f427..9c0522ce5a 100644
--- a/packages/builder/src/components/common/bindings/BindingPicker.svelte
+++ b/packages/builder/src/components/common/bindings/BindingPicker.svelte
@@ -124,11 +124,11 @@
align="left-outside"
bind:this={popover}
anchor={popoverAnchor}
- maxWidth={600}
+ minWidth={0}
+ maxWidth={480}
maxHeight={300}
dismissible={false}
on:mouseenter={stopHiding}
- on:mouseleave={hidePopover}
>
From 7a278234b55d82b4407e51edc4d46b0b7c342eb5 Mon Sep 17 00:00:00 2001
From: Andrew Kingston
Date: Mon, 19 Feb 2024 16:30:29 +0000
Subject: [PATCH 075/783] Suppress warning
---
.../src/components/common/bindings/BindingPicker.svelte | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/packages/builder/src/components/common/bindings/BindingPicker.svelte b/packages/builder/src/components/common/bindings/BindingPicker.svelte
index 9c0522ce5a..60ca6abf7c 100644
--- a/packages/builder/src/components/common/bindings/BindingPicker.svelte
+++ b/packages/builder/src/components/common/bindings/BindingPicker.svelte
@@ -139,7 +139,10 @@
{/if}
{#if hoverTarget.code}
- {@html highlight(hoverTarget.code)}
+
+
+ {@html highlight(hoverTarget.code)}
+
{/if}
From 804f061a7014568f5f6e3ff2a1bd6d2f3d65a81b Mon Sep 17 00:00:00 2001
From: Adria Navarro
Date: Mon, 19 Feb 2024 17:32:33 +0100
Subject: [PATCH 076/783] Fix test
---
packages/server/src/jsRunner/tests/jsRunner.spec.ts | 13 ++++++++++---
1 file changed, 10 insertions(+), 3 deletions(-)
diff --git a/packages/server/src/jsRunner/tests/jsRunner.spec.ts b/packages/server/src/jsRunner/tests/jsRunner.spec.ts
index 3baf049eae..e7fe658737 100644
--- a/packages/server/src/jsRunner/tests/jsRunner.spec.ts
+++ b/packages/server/src/jsRunner/tests/jsRunner.spec.ts
@@ -1,3 +1,5 @@
+import vm from "vm"
+
import { validate as isValidUUID } from "uuid"
import { processStringSync, encodeJSBinding } from "@budibase/string-templates"
@@ -40,11 +42,16 @@ describe.each([
expect(output).toBe(3)
})
- it.only("should prevent sandbox escape", async () => {
+ it("should prevent sandbox escape", async () => {
const output = await processJS(
- `return this.constructor.constructor("return process")()`
+ `return this.constructor.constructor("return process.env")()`
)
- expect(output).toBe("Error while executing JS")
+ if (useIsolatedVM) {
+ expect(output).toBe("Error while executing JS")
+ } else {
+ expect(output).not.toBe("Error while executing JS")
+ expect(output).toEqual(process.env)
+ }
})
describe("helpers", () => {
From c3c39b1c1b6973d943946c9f157ac6ed126f66d0 Mon Sep 17 00:00:00 2001
From: Adria Navarro
Date: Mon, 19 Feb 2024 17:32:55 +0100
Subject: [PATCH 077/783] Add comment
---
packages/server/src/jsRunner/tests/jsRunner.spec.ts | 1 +
1 file changed, 1 insertion(+)
diff --git a/packages/server/src/jsRunner/tests/jsRunner.spec.ts b/packages/server/src/jsRunner/tests/jsRunner.spec.ts
index e7fe658737..9f2a7c61d7 100644
--- a/packages/server/src/jsRunner/tests/jsRunner.spec.ts
+++ b/packages/server/src/jsRunner/tests/jsRunner.spec.ts
@@ -49,6 +49,7 @@ describe.each([
if (useIsolatedVM) {
expect(output).toBe("Error while executing JS")
} else {
+ // This was not an issue without isolated-vm
expect(output).not.toBe("Error while executing JS")
expect(output).toEqual(process.env)
}
From 6cd6b21f83c62e7a1a022c606f2317b34c9270f4 Mon Sep 17 00:00:00 2001
From: Adria Navarro
Date: Mon, 19 Feb 2024 17:37:25 +0100
Subject: [PATCH 078/783] Fix build
---
packages/server/src/jsRunner/vm/isolated-vm.ts | 10 +++++++---
1 file changed, 7 insertions(+), 3 deletions(-)
diff --git a/packages/server/src/jsRunner/vm/isolated-vm.ts b/packages/server/src/jsRunner/vm/isolated-vm.ts
index 0285af8620..12559df0b7 100644
--- a/packages/server/src/jsRunner/vm/isolated-vm.ts
+++ b/packages/server/src/jsRunner/vm/isolated-vm.ts
@@ -7,6 +7,7 @@ import querystring from "querystring"
import { BundleType, loadBundle } from "../bundles"
import { VM } from "@budibase/types"
+import environment from "../../environment"
class ExecutionTimeoutError extends Error {
constructor(message: string) {
@@ -33,10 +34,13 @@ export class IsolatedVM implements VM {
invocationTimeout,
isolateAccumulatedTimeout,
}: {
- memoryLimit: number
- invocationTimeout: number
+ memoryLimit?: number
+ invocationTimeout?: number
isolateAccumulatedTimeout?: number
- }) {
+ } = {}) {
+ memoryLimit = memoryLimit || environment.JS_RUNNER_MEMORY_LIMIT
+ invocationTimeout = memoryLimit || 1000
+
this.isolate = new ivm.Isolate({ memoryLimit })
this.vm = this.isolate.createContextSync()
this.jail = this.vm.global
From 865e9ac1112ad5150d865e79a3d84bd8681b2c1b Mon Sep 17 00:00:00 2001
From: mike12345567
Date: Mon, 19 Feb 2024 17:50:27 +0000
Subject: [PATCH 079/783] Setting environment variables for isolated-vm to
always be used.
---
packages/server/src/environment.ts | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/packages/server/src/environment.ts b/packages/server/src/environment.ts
index e137c342e6..bb3349c7b4 100644
--- a/packages/server/src/environment.ts
+++ b/packages/server/src/environment.ts
@@ -107,6 +107,8 @@ const environment = {
parseIntSafe(process.env.JS_RUNNER_MEMORY_LIMIT) ||
DEFAULTS.JS_RUNNER_MEMORY_LIMIT,
LOG_JS_ERRORS: process.env.LOG_JS_ERRORS,
+ ISOLATEDVM_QUERY_TRANSFORMERS: true,
+ ISOLATEDVM_JS_RUNNER: true,
// old
CLIENT_ID: process.env.CLIENT_ID,
_set(key: string, value: any) {
@@ -127,8 +129,6 @@ const environment = {
getDefaults: () => {
return DEFAULTS
},
- ISOLATEDVM_QUERY_TRANSFORMERS: !!process.env.ISOLATEDVM_QUERY_TRANSFORMERS,
- ISOLATEDVM_JS_RUNNER: !!process.env.ISOLATEDVM_JS_RUNNER,
}
function cleanVariables() {
From 87d60ca5f2a56777d50d565332ab393d617c2741 Mon Sep 17 00:00:00 2001
From: mike12345567
Date: Mon, 19 Feb 2024 17:55:04 +0000
Subject: [PATCH 080/783] Removing env vars to disable isolated-vm usage.
---
packages/server/src/jsRunner/index.ts | 8 ++++----
.../src/jsRunner/tests/jsRunner.spec.ts | 19 ++-----------------
packages/server/src/threads/query.ts | 5 +++--
3 files changed, 9 insertions(+), 23 deletions(-)
diff --git a/packages/server/src/jsRunner/index.ts b/packages/server/src/jsRunner/index.ts
index 362dde1fb2..c70c239c48 100644
--- a/packages/server/src/jsRunner/index.ts
+++ b/packages/server/src/jsRunner/index.ts
@@ -4,11 +4,12 @@ import { context } from "@budibase/backend-core"
import tracer from "dd-trace"
import { BuiltInVM, IsolatedVM } from "./vm"
+const USE_ISOLATED_VM = true
+
export function init() {
setJSRunner((js: string, ctx: Record) => {
return tracer.trace("runJS", {}, span => {
- const useIsolatedVm = env.ISOLATEDVM_JS_RUNNER
- if (!useIsolatedVm) {
+ if (!USE_ISOLATED_VM) {
const vm = new BuiltInVM(ctx, span)
return vm.execute(js)
}
@@ -31,8 +32,7 @@ export function init() {
bbCtx.vm = vm
}
- const result = vm.execute(js)
- return result
+ return vm.execute(js)
} catch (error: any) {
if (error.message === "Script execution timed out.") {
throw new JsErrorTimeout()
diff --git a/packages/server/src/jsRunner/tests/jsRunner.spec.ts b/packages/server/src/jsRunner/tests/jsRunner.spec.ts
index 18dc694b3c..30e29885b1 100644
--- a/packages/server/src/jsRunner/tests/jsRunner.spec.ts
+++ b/packages/server/src/jsRunner/tests/jsRunner.spec.ts
@@ -1,7 +1,4 @@
-import vm from "vm"
-
import { validate as isValidUUID } from "uuid"
-
import { processStringSync, encodeJSBinding } from "@budibase/string-templates"
const { runJsHelpersTests } = require("@budibase/string-templates/test/utils")
@@ -9,19 +6,13 @@ const { runJsHelpersTests } = require("@budibase/string-templates/test/utils")
import tk from "timekeeper"
import { init } from ".."
import TestConfiguration from "../../tests/utilities/TestConfiguration"
-import environment from "../../environment"
tk.freeze("2021-01-21T12:00:00")
-describe.each([
- ["vm", false],
- ["isolated-vm", true],
-])("jsRunner (using %s)", (_, useIsolatedVM) => {
+describe("jsRunner (using isolated-vm)", () => {
const config = new TestConfiguration()
beforeAll(async () => {
- environment._set("ISOLATEDVM_JS_RUNNER", useIsolatedVM)
-
// Register js runner
init()
await config.init()
@@ -51,13 +42,7 @@ describe.each([
const output = await processJS(
`return this.constructor.constructor("return process.env")()`
)
- if (useIsolatedVM) {
- expect(output).toBe("Error while executing JS")
- } else {
- // This was not an issue without isolated-vm
- expect(output).not.toBe("Error while executing JS")
- expect(output).toEqual(process.env)
- }
+ expect(output).toBe("Error while executing JS")
})
describe("helpers", () => {
diff --git a/packages/server/src/threads/query.ts b/packages/server/src/threads/query.ts
index 2c8e59ce64..1f28034f60 100644
--- a/packages/server/src/threads/query.ts
+++ b/packages/server/src/threads/query.ts
@@ -18,7 +18,8 @@ import { Datasource, Query, SourceName, VM } from "@budibase/types"
import { isSQL } from "../integrations/utils"
import { interpolateSQL } from "../integrations/queries/sql"
-import environment from "../environment"
+
+const USE_ISOLATED_VM = true
class QueryRunner {
datasource: Datasource
@@ -129,7 +130,7 @@ class QueryRunner {
// transform as required
if (transformer) {
let runner: VM
- if (!environment.ISOLATEDVM_QUERY_TRANSFORMERS) {
+ if (!USE_ISOLATED_VM) {
runner = new VM2({
data: rows,
params: enrichedParameters,
From 74fbb901f9aa7e9165dfa477c5b3e934a0c54da6 Mon Sep 17 00:00:00 2001
From: mike12345567
Date: Mon, 19 Feb 2024 17:57:16 +0000
Subject: [PATCH 081/783] Removing unused environment variables.
---
packages/server/src/environment.ts | 2 --
1 file changed, 2 deletions(-)
diff --git a/packages/server/src/environment.ts b/packages/server/src/environment.ts
index bb3349c7b4..873c392942 100644
--- a/packages/server/src/environment.ts
+++ b/packages/server/src/environment.ts
@@ -107,8 +107,6 @@ const environment = {
parseIntSafe(process.env.JS_RUNNER_MEMORY_LIMIT) ||
DEFAULTS.JS_RUNNER_MEMORY_LIMIT,
LOG_JS_ERRORS: process.env.LOG_JS_ERRORS,
- ISOLATEDVM_QUERY_TRANSFORMERS: true,
- ISOLATEDVM_JS_RUNNER: true,
// old
CLIENT_ID: process.env.CLIENT_ID,
_set(key: string, value: any) {
From 85052ca36124b3a460e10f44a18988987849c2b9 Mon Sep 17 00:00:00 2001
From: Adria Navarro
Date: Mon, 19 Feb 2024 19:34:15 +0100
Subject: [PATCH 082/783] Fix query
---
packages/server/src/threads/query.ts | 1 +
1 file changed, 1 insertion(+)
diff --git a/packages/server/src/threads/query.ts b/packages/server/src/threads/query.ts
index 1f28034f60..c159f24268 100644
--- a/packages/server/src/threads/query.ts
+++ b/packages/server/src/threads/query.ts
@@ -136,6 +136,7 @@ class QueryRunner {
params: enrichedParameters,
})
} else {
+ transformer = `(function(){\n${transformer}\n})();`
let isolatedVm = new IsolatedVM().withContext({
data: rows,
params: enrichedParameters,
From 0b84957ad0958d65167f84bfa5da8cd285a1b479 Mon Sep 17 00:00:00 2001
From: Adria Navarro
Date: Mon, 19 Feb 2024 19:42:28 +0100
Subject: [PATCH 083/783] Remove vm2 usage from script controllers
---
packages/server/src/api/controllers/script.ts | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/packages/server/src/api/controllers/script.ts b/packages/server/src/api/controllers/script.ts
index f00383615e..7b07b97ba9 100644
--- a/packages/server/src/api/controllers/script.ts
+++ b/packages/server/src/api/controllers/script.ts
@@ -1,9 +1,9 @@
import { Ctx } from "@budibase/types"
-import { VM2 } from "../../jsRunner/vm"
+import { IsolatedVM } from "../../jsRunner/vm"
export async function execute(ctx: Ctx) {
const { script, context } = ctx.request.body
- const runner = new VM2(context)
+ const runner = new IsolatedVM(context)
const result = runner.execute(script)
ctx.body = result
}
From 9f5d4811ba9ad8f111f9457c09279d7c1f686e04 Mon Sep 17 00:00:00 2001
From: Adria Navarro
Date: Mon, 19 Feb 2024 19:53:36 +0100
Subject: [PATCH 084/783] Improve js logging error message
---
packages/server/src/jsRunner/index.ts | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/packages/server/src/jsRunner/index.ts b/packages/server/src/jsRunner/index.ts
index c572c112c9..21f1be3c90 100644
--- a/packages/server/src/jsRunner/index.ts
+++ b/packages/server/src/jsRunner/index.ts
@@ -16,7 +16,9 @@ export function init() {
if (env.LOG_JS_ERRORS) {
setOnErrorLog((error: Error) => {
- logging.logWarn(JSON.stringify(serializeError(error)))
+ logging.logWarn(
+ `Error while executing js: ${JSON.stringify(serializeError(error))}`
+ )
})
}
}
From 282a3ee3b943c1d9e8e4a82b3ca56b69e18c67ca Mon Sep 17 00:00:00 2001
From: Adria Navarro
Date: Mon, 19 Feb 2024 19:58:41 +0100
Subject: [PATCH 085/783] Fix test
---
packages/server/src/api/controllers/script.ts | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/packages/server/src/api/controllers/script.ts b/packages/server/src/api/controllers/script.ts
index 7b07b97ba9..9a404da9fb 100644
--- a/packages/server/src/api/controllers/script.ts
+++ b/packages/server/src/api/controllers/script.ts
@@ -4,7 +4,8 @@ import { IsolatedVM } from "../../jsRunner/vm"
export async function execute(ctx: Ctx) {
const { script, context } = ctx.request.body
const runner = new IsolatedVM(context)
- const result = runner.execute(script)
+
+ const result = runner.execute(`(function(){\n${script}\n})();`)
ctx.body = result
}
From 2042a9580575b04620ed8d6afbc3fc915d9b3a6c Mon Sep 17 00:00:00 2001
From: Adria Navarro
Date: Mon, 19 Feb 2024 20:12:46 +0100
Subject: [PATCH 086/783] Fix runs
---
packages/server/src/api/controllers/script.ts | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/packages/server/src/api/controllers/script.ts b/packages/server/src/api/controllers/script.ts
index 9a404da9fb..bdca2d6e18 100644
--- a/packages/server/src/api/controllers/script.ts
+++ b/packages/server/src/api/controllers/script.ts
@@ -3,7 +3,7 @@ import { IsolatedVM } from "../../jsRunner/vm"
export async function execute(ctx: Ctx) {
const { script, context } = ctx.request.body
- const runner = new IsolatedVM(context)
+ const runner = new IsolatedVM().withContext(context)
const result = runner.execute(`(function(){\n${script}\n})();`)
ctx.body = result
From c52b6aa0d1e7f836401deebfd16d198d738f4162 Mon Sep 17 00:00:00 2001
From: mike12345567
Date: Mon, 19 Feb 2024 19:37:18 +0000
Subject: [PATCH 087/783] Some initial test cases for isolated VM.
---
.../src/jsRunner/tests/isolatedVM.spec.ts | 33 +
.../src/jsRunner/tests/jsRunner.spec.ts | 75 +
packages/server/src/jsRunner/tests/marked.txt | 3018 +++++++++++++++++
3 files changed, 3126 insertions(+)
create mode 100644 packages/server/src/jsRunner/tests/isolatedVM.spec.ts
create mode 100644 packages/server/src/jsRunner/tests/marked.txt
diff --git a/packages/server/src/jsRunner/tests/isolatedVM.spec.ts b/packages/server/src/jsRunner/tests/isolatedVM.spec.ts
new file mode 100644
index 0000000000..0bd400c8d7
--- /dev/null
+++ b/packages/server/src/jsRunner/tests/isolatedVM.spec.ts
@@ -0,0 +1,33 @@
+import fs from "fs"
+import path from "path"
+import { IsolatedVM, VM2 } from "../vm"
+
+function runJSWithIsolatedVM(script: string, context?: any) {
+ const runner = new IsolatedVM()
+ if (context) {
+ runner.withContext(context)
+ }
+ return runner.execute(`(function(){\n${script}\n})();`)
+}
+
+function runJSWithVM2(script: string, context?: any) {
+ const runner = new VM2(context)
+ return runner.execute(script)
+}
+
+function compare(script: string, context?: any) {
+ const resultIsolated = runJSWithIsolatedVM(script, context)
+ const resultVM = runJSWithVM2(script, context)
+ expect(resultIsolated).toEqual(resultVM)
+ return resultIsolated
+}
+
+describe("Test isolated vm directly", () => {
+ it("should handle a very large file", () => {
+ const marked = fs.readFileSync(path.join(__dirname, "marked.txt"), "utf-8")
+ const result = compare(marked, {
+ trigger: { row: { Message: "dddd" } },
+ })
+ expect(result).toBe("dddd
\n")
+ })
+})
diff --git a/packages/server/src/jsRunner/tests/jsRunner.spec.ts b/packages/server/src/jsRunner/tests/jsRunner.spec.ts
index 30e29885b1..9bb9052eda 100644
--- a/packages/server/src/jsRunner/tests/jsRunner.spec.ts
+++ b/packages/server/src/jsRunner/tests/jsRunner.spec.ts
@@ -1,5 +1,7 @@
import { validate as isValidUUID } from "uuid"
import { processStringSync, encodeJSBinding } from "@budibase/string-templates"
+import fs from "fs"
+import path from "path"
const { runJsHelpersTests } = require("@budibase/string-templates/test/utils")
@@ -70,4 +72,77 @@ describe("jsRunner (using isolated-vm)", () => {
})
})
})
+
+ // the test cases here were extracted from templates/real world examples of JS in Budibase
+ describe("should real world tests of JS", () => {
+ const context = {
+ "Unit Value": 2,
+ Quantity: 1,
+ }
+ it("handle test case 1", async () => {
+ const result = await processJS(
+ `
+ var Gross = $("[Unit Value]") * $("[Quantity]")
+ return Gross.toFixed(2)`,
+ context
+ )
+ expect(result).toBeDefined()
+ expect(result).toBe("2.00")
+ })
+
+ it("handle test case 2", async () => {
+ const context = {
+ "Purchase Date": "2021-01-21T12:00:00",
+ }
+ const result = await processJS(
+ `
+ var purchase = new Date($("[Purchase Date]"));
+ let purchaseyear = purchase.getFullYear();
+ let purchasemonth = purchase.getMonth();
+
+ var today = new Date ();
+ let todayyear = today.getFullYear();
+ let todaymonth = today.getMonth();
+
+ var age = todayyear - purchaseyear
+
+ if (((todaymonth - purchasemonth) < 6) == true){
+ return age
+ }
+ `,
+ context
+ )
+ expect(result).toBeDefined()
+ expect(result).toBe(3)
+ })
+
+ it("should handle test case 3", async () => {
+ const context = {
+ Escalate: true,
+ "Budget ($)": 1100,
+ }
+ const result = await processJS(
+ `
+ if ($("[Escalate]") == true) {
+ if ($("Budget ($)") <= 1000)
+ {return 2;}
+ if ($("Budget ($)") > 1000)
+ {return 3;}
+ }
+ else {
+ if ($("Budget ($)") <= 1000)
+ {return 1;}
+ if ($("Budget ($)") > 1000)
+ if ($("Budget ($)") < 10000)
+ {return 2;}
+ else
+ {return 3}
+ }
+ `,
+ context
+ )
+ expect(result).toBeDefined()
+ expect(result).toBe(3)
+ })
+ })
})
diff --git a/packages/server/src/jsRunner/tests/marked.txt b/packages/server/src/jsRunner/tests/marked.txt
new file mode 100644
index 0000000000..c5c01d7f0f
--- /dev/null
+++ b/packages/server/src/jsRunner/tests/marked.txt
@@ -0,0 +1,3018 @@
+/**
+ * marked - a markdown parser
+ * Copyright (c) 2011-2022, Christopher Jeffrey. (MIT Licensed)
+ * https://github.com/markedjs/marked
+ */
+
+/**
+ * DO NOT EDIT THIS FILE
+ * The code in this file is generated from files in ./src/
+ */
+
+function getDefaults() {
+ return {
+ baseUrl: null,
+ breaks: false,
+ extensions: null,
+ gfm: true,
+ headerIds: true,
+ headerPrefix: "",
+ highlight: null,
+ langPrefix: "language-",
+ mangle: true,
+ pedantic: false,
+ renderer: null,
+ sanitize: false,
+ sanitizer: null,
+ silent: false,
+ smartLists: false,
+ smartypants: false,
+ tokenizer: null,
+ walkTokens: null,
+ xhtml: false,
+ }
+}
+
+let defaults = getDefaults()
+
+function changeDefaults(newDefaults) {
+ defaults = newDefaults
+}
+
+/**
+ * Helpers
+ */
+const escapeTest = /[&<>"']/
+const escapeReplace = /[&<>"']/g
+const escapeTestNoEncode = /[<>"']|&(?!#?\w+;)/
+const escapeReplaceNoEncode = /[<>"']|&(?!#?\w+;)/g
+const escapeReplacements = {
+ "&": "&",
+ "<": "<",
+ ">": ">",
+ '"': """,
+ "'": "'",
+}
+const getEscapeReplacement = ch => escapeReplacements[ch]
+function escape(html, encode) {
+ if (encode) {
+ if (escapeTest.test(html)) {
+ return html.replace(escapeReplace, getEscapeReplacement)
+ }
+ } else {
+ if (escapeTestNoEncode.test(html)) {
+ return html.replace(escapeReplaceNoEncode, getEscapeReplacement)
+ }
+ }
+
+ return html
+}
+
+const unescapeTest = /&(#(?:\d+)|(?:#x[0-9A-Fa-f]+)|(?:\w+));?/gi
+
+/**
+ * @param {string} html
+ */
+function unescape(html) {
+ // explicitly match decimal, hex, and named HTML entities
+ return html.replace(unescapeTest, (_, n) => {
+ n = n.toLowerCase()
+ if (n === "colon") return ":"
+ if (n.charAt(0) === "#") {
+ return n.charAt(1) === "x"
+ ? String.fromCharCode(parseInt(n.substring(2), 16))
+ : String.fromCharCode(+n.substring(1))
+ }
+ return ""
+ })
+}
+
+const caret = /(^|[^\[])\^/g
+
+/**
+ * @param {string | RegExp} regex
+ * @param {string} opt
+ */
+function edit(regex, opt) {
+ regex = typeof regex === "string" ? regex : regex.source
+ opt = opt || ""
+ const obj = {
+ replace: (name, val) => {
+ val = val.source || val
+ val = val.replace(caret, "$1")
+ regex = regex.replace(name, val)
+ return obj
+ },
+ getRegex: () => {
+ return new RegExp(regex, opt)
+ },
+ }
+ return obj
+}
+
+const nonWordAndColonTest = /[^\w:]/g
+const originIndependentUrl = /^$|^[a-z][a-z0-9+.-]*:|^[?#]/i
+
+/**
+ * @param {boolean} sanitize
+ * @param {string} base
+ * @param {string} href
+ */
+function cleanUrl(sanitize, base, href) {
+ if (sanitize) {
+ let prot
+ try {
+ prot = decodeURIComponent(unescape(href))
+ .replace(nonWordAndColonTest, "")
+ .toLowerCase()
+ } catch (e) {
+ return null
+ }
+ if (
+ prot.indexOf("javascript:") === 0 ||
+ prot.indexOf("vbscript:") === 0 ||
+ prot.indexOf("data:") === 0
+ ) {
+ return null
+ }
+ }
+ if (base && !originIndependentUrl.test(href)) {
+ href = resolveUrl(base, href)
+ }
+ try {
+ href = encodeURI(href).replace(/%25/g, "%")
+ } catch (e) {
+ return null
+ }
+ return href
+}
+
+const baseUrls = {}
+const justDomain = /^[^:]+:\/*[^/]*$/
+const protocol = /^([^:]+:)[\s\S]*$/
+const domain = /^([^:]+:\/*[^/]*)[\s\S]*$/
+
+/**
+ * @param {string} base
+ * @param {string} href
+ */
+function resolveUrl(base, href) {
+ if (!baseUrls[" " + base]) {
+ // we can ignore everything in base after the last slash of its path component,
+ // but we might need to add _that_
+ // https://tools.ietf.org/html/rfc3986#section-3
+ if (justDomain.test(base)) {
+ baseUrls[" " + base] = base + "/"
+ } else {
+ baseUrls[" " + base] = rtrim(base, "/", true)
+ }
+ }
+ base = baseUrls[" " + base]
+ const relativeBase = base.indexOf(":") === -1
+
+ if (href.substring(0, 2) === "//") {
+ if (relativeBase) {
+ return href
+ }
+ return base.replace(protocol, "$1") + href
+ } else if (href.charAt(0) === "/") {
+ if (relativeBase) {
+ return href
+ }
+ return base.replace(domain, "$1") + href
+ } else {
+ return base + href
+ }
+}
+
+const noopTest = { exec: function noopTest() {} }
+
+function merge(obj) {
+ let i = 1,
+ target,
+ key
+
+ for (; i < arguments.length; i++) {
+ target = arguments[i]
+ for (key in target) {
+ if (Object.prototype.hasOwnProperty.call(target, key)) {
+ obj[key] = target[key]
+ }
+ }
+ }
+
+ return obj
+}
+
+function splitCells(tableRow, count) {
+ // ensure that every cell-delimiting pipe has a space
+ // before it to distinguish it from an escaped pipe
+ const row = tableRow.replace(/\|/g, (match, offset, str) => {
+ let escaped = false,
+ curr = offset
+ while (--curr >= 0 && str[curr] === "\\") escaped = !escaped
+ if (escaped) {
+ // odd number of slashes means | is escaped
+ // so we leave it alone
+ return "|"
+ } else {
+ // add space before unescaped |
+ return " |"
+ }
+ }),
+ cells = row.split(/ \|/)
+ let i = 0
+
+ // First/last cell in a row cannot be empty if it has no leading/trailing pipe
+ if (!cells[0].trim()) {
+ cells.shift()
+ }
+ if (cells.length > 0 && !cells[cells.length - 1].trim()) {
+ cells.pop()
+ }
+
+ if (cells.length > count) {
+ cells.splice(count)
+ } else {
+ while (cells.length < count) cells.push("")
+ }
+
+ for (; i < cells.length; i++) {
+ // leading or trailing whitespace is ignored per the gfm spec
+ cells[i] = cells[i].trim().replace(/\\\|/g, "|")
+ }
+ return cells
+}
+
+/**
+ * Remove trailing 'c's. Equivalent to str.replace(/c*$/, '').
+ * /c*$/ is vulnerable to REDOS.
+ *
+ * @param {string} str
+ * @param {string} c
+ * @param {boolean} invert Remove suffix of non-c chars instead. Default falsey.
+ */
+function rtrim(str, c, invert) {
+ const l = str.length
+ if (l === 0) {
+ return ""
+ }
+
+ // Length of suffix matching the invert condition.
+ let suffLen = 0
+
+ // Step left until we fail to match the invert condition.
+ while (suffLen < l) {
+ const currChar = str.charAt(l - suffLen - 1)
+ if (currChar === c && !invert) {
+ suffLen++
+ } else if (currChar !== c && invert) {
+ suffLen++
+ } else {
+ break
+ }
+ }
+
+ return str.slice(0, l - suffLen)
+}
+
+function findClosingBracket(str, b) {
+ if (str.indexOf(b[1]) === -1) {
+ return -1
+ }
+ const l = str.length
+ let level = 0,
+ i = 0
+ for (; i < l; i++) {
+ if (str[i] === "\\") {
+ i++
+ } else if (str[i] === b[0]) {
+ level++
+ } else if (str[i] === b[1]) {
+ level--
+ if (level < 0) {
+ return i
+ }
+ }
+ }
+ return -1
+}
+
+function checkSanitizeDeprecation(opt) {
+ if (opt && opt.sanitize && !opt.silent) {
+ console.warn(
+ "marked(): sanitize and sanitizer parameters are deprecated since version 0.7.0, should not be used and will be removed in the future. Read more here: https://marked.js.org/#/USING_ADVANCED.md#options"
+ )
+ }
+}
+
+// copied from https://stackoverflow.com/a/5450113/806777
+/**
+ * @param {string} pattern
+ * @param {number} count
+ */
+function repeatString(pattern, count) {
+ if (count < 1) {
+ return ""
+ }
+ let result = ""
+ while (count > 1) {
+ if (count & 1) {
+ result += pattern
+ }
+ count >>= 1
+ pattern += pattern
+ }
+ return result + pattern
+}
+
+function outputLink(cap, link, raw, lexer) {
+ const href = link.href
+ const title = link.title ? escape(link.title) : null
+ const text = cap[1].replace(/\\([\[\]])/g, "$1")
+
+ if (cap[0].charAt(0) !== "!") {
+ lexer.state.inLink = true
+ const token = {
+ type: "link",
+ raw,
+ href,
+ title,
+ text,
+ tokens: lexer.inlineTokens(text, []),
+ }
+ lexer.state.inLink = false
+ return token
+ }
+ return {
+ type: "image",
+ raw,
+ href,
+ title,
+ text: escape(text),
+ }
+}
+
+function indentCodeCompensation(raw, text) {
+ const matchIndentToCode = raw.match(/^(\s+)(?:```)/)
+
+ if (matchIndentToCode === null) {
+ return text
+ }
+
+ const indentToCode = matchIndentToCode[1]
+
+ return text
+ .split("\n")
+ .map(node => {
+ const matchIndentInNode = node.match(/^\s+/)
+ if (matchIndentInNode === null) {
+ return node
+ }
+
+ const [indentInNode] = matchIndentInNode
+
+ if (indentInNode.length >= indentToCode.length) {
+ return node.slice(indentToCode.length)
+ }
+
+ return node
+ })
+ .join("\n")
+}
+
+/**
+ * Tokenizer
+ */
+class Tokenizer {
+ constructor(options) {
+ this.options = options || defaults
+ }
+
+ space(src) {
+ const cap = this.rules.block.newline.exec(src)
+ if (cap && cap[0].length > 0) {
+ return {
+ type: "space",
+ raw: cap[0],
+ }
+ }
+ }
+
+ code(src) {
+ const cap = this.rules.block.code.exec(src)
+ if (cap) {
+ const text = cap[0].replace(/^ {1,4}/gm, "")
+ return {
+ type: "code",
+ raw: cap[0],
+ codeBlockStyle: "indented",
+ text: !this.options.pedantic ? rtrim(text, "\n") : text,
+ }
+ }
+ }
+
+ fences(src) {
+ const cap = this.rules.block.fences.exec(src)
+ if (cap) {
+ const raw = cap[0]
+ const text = indentCodeCompensation(raw, cap[3] || "")
+
+ return {
+ type: "code",
+ raw,
+ lang: cap[2] ? cap[2].trim() : cap[2],
+ text,
+ }
+ }
+ }
+
+ heading(src) {
+ const cap = this.rules.block.heading.exec(src)
+ if (cap) {
+ let text = cap[2].trim()
+
+ // remove trailing #s
+ if (/#$/.test(text)) {
+ const trimmed = rtrim(text, "#")
+ if (this.options.pedantic) {
+ text = trimmed.trim()
+ } else if (!trimmed || / $/.test(trimmed)) {
+ // CommonMark requires space before trailing #s
+ text = trimmed.trim()
+ }
+ }
+
+ const token = {
+ type: "heading",
+ raw: cap[0],
+ depth: cap[1].length,
+ text,
+ tokens: [],
+ }
+ this.lexer.inline(token.text, token.tokens)
+ return token
+ }
+ }
+
+ hr(src) {
+ const cap = this.rules.block.hr.exec(src)
+ if (cap) {
+ return {
+ type: "hr",
+ raw: cap[0],
+ }
+ }
+ }
+
+ blockquote(src) {
+ const cap = this.rules.block.blockquote.exec(src)
+ if (cap) {
+ const text = cap[0].replace(/^ *>[ \t]?/gm, "")
+
+ return {
+ type: "blockquote",
+ raw: cap[0],
+ tokens: this.lexer.blockTokens(text, []),
+ text,
+ }
+ }
+ }
+
+ list(src) {
+ let cap = this.rules.block.list.exec(src)
+ if (cap) {
+ let raw,
+ istask,
+ ischecked,
+ indent,
+ i,
+ blankLine,
+ endsWithBlankLine,
+ line,
+ nextLine,
+ rawLine,
+ itemContents,
+ endEarly
+
+ let bull = cap[1].trim()
+ const isordered = bull.length > 1
+
+ const list = {
+ type: "list",
+ raw: "",
+ ordered: isordered,
+ start: isordered ? +bull.slice(0, -1) : "",
+ loose: false,
+ items: [],
+ }
+
+ bull = isordered ? `\\d{1,9}\\${bull.slice(-1)}` : `\\${bull}`
+
+ if (this.options.pedantic) {
+ bull = isordered ? bull : "[*+-]"
+ }
+
+ // Get next list item
+ const itemRegex = new RegExp(
+ `^( {0,3}${bull})((?:[\t ][^\\n]*)?(?:\\n|$))`
+ )
+
+ // Check if current bullet point can start a new List Item
+ while (src) {
+ endEarly = false
+ if (!(cap = itemRegex.exec(src))) {
+ break
+ }
+
+ if (this.rules.block.hr.test(src)) {
+ // End list if bullet was actually HR (possibly move into itemRegex?)
+ break
+ }
+
+ raw = cap[0]
+ src = src.substring(raw.length)
+
+ line = cap[2].split("\n", 1)[0]
+ nextLine = src.split("\n", 1)[0]
+
+ if (this.options.pedantic) {
+ indent = 2
+ itemContents = line.trimLeft()
+ } else {
+ indent = cap[2].search(/[^ ]/) // Find first non-space char
+ indent = indent > 4 ? 1 : indent // Treat indented code blocks (> 4 spaces) as having only 1 indent
+ itemContents = line.slice(indent)
+ indent += cap[1].length
+ }
+
+ blankLine = false
+
+ if (!line && /^ *$/.test(nextLine)) {
+ // Items begin with at most one blank line
+ raw += nextLine + "\n"
+ src = src.substring(nextLine.length + 1)
+ endEarly = true
+ }
+
+ if (!endEarly) {
+ const nextBulletRegex = new RegExp(
+ `^ {0,${Math.min(
+ 3,
+ indent - 1
+ )}}(?:[*+-]|\\d{1,9}[.)])((?: [^\\n]*)?(?:\\n|$))`
+ )
+ const hrRegex = new RegExp(
+ `^ {0,${Math.min(
+ 3,
+ indent - 1
+ )}}((?:- *){3,}|(?:_ *){3,}|(?:\\* *){3,})(?:\\n+|$)`
+ )
+
+ // Check if following lines should be included in List Item
+ while (src) {
+ rawLine = src.split("\n", 1)[0]
+ line = rawLine
+
+ // Re-align to follow commonmark nesting rules
+ if (this.options.pedantic) {
+ line = line.replace(/^ {1,4}(?=( {4})*[^ ])/g, " ")
+ }
+
+ // End list item if found start of new bullet
+ if (nextBulletRegex.test(line)) {
+ break
+ }
+
+ // Horizontal rule found
+ if (hrRegex.test(src)) {
+ break
+ }
+
+ if (line.search(/[^ ]/) >= indent || !line.trim()) {
+ // Dedent if possible
+ itemContents += "\n" + line.slice(indent)
+ } else if (!blankLine) {
+ // Until blank line, item doesn't need indentation
+ itemContents += "\n" + line
+ } else {
+ // Otherwise, improper indentation ends this item
+ break
+ }
+
+ if (!blankLine && !line.trim()) {
+ // Check if current line is blank
+ blankLine = true
+ }
+
+ raw += rawLine + "\n"
+ src = src.substring(rawLine.length + 1)
+ }
+ }
+
+ if (!list.loose) {
+ // If the previous item ended with a blank line, the list is loose
+ if (endsWithBlankLine) {
+ list.loose = true
+ } else if (/\n *\n *$/.test(raw)) {
+ endsWithBlankLine = true
+ }
+ }
+
+ // Check for task list items
+ if (this.options.gfm) {
+ istask = /^\[[ xX]\] /.exec(itemContents)
+ if (istask) {
+ ischecked = istask[0] !== "[ ] "
+ itemContents = itemContents.replace(/^\[[ xX]\] +/, "")
+ }
+ }
+
+ list.items.push({
+ type: "list_item",
+ raw,
+ task: !!istask,
+ checked: ischecked,
+ loose: false,
+ text: itemContents,
+ })
+
+ list.raw += raw
+ }
+
+ // Do not consume newlines at end of final item. Alternatively, make itemRegex *start* with any newlines to simplify/speed up endsWithBlankLine logic
+ list.items[list.items.length - 1].raw = raw.trimRight()
+ list.items[list.items.length - 1].text = itemContents.trimRight()
+ list.raw = list.raw.trimRight()
+
+ const l = list.items.length
+
+ // Item child tokens handled here at end because we needed to have the final item to trim it first
+ for (i = 0; i < l; i++) {
+ this.lexer.state.top = false
+ list.items[i].tokens = this.lexer.blockTokens(list.items[i].text, [])
+ const spacers = list.items[i].tokens.filter(t => t.type === "space")
+ const hasMultipleLineBreaks = spacers.every(t => {
+ const chars = t.raw.split("")
+ let lineBreaks = 0
+ for (const char of chars) {
+ if (char === "\n") {
+ lineBreaks += 1
+ }
+ if (lineBreaks > 1) {
+ return true
+ }
+ }
+
+ return false
+ })
+
+ if (!list.loose && spacers.length && hasMultipleLineBreaks) {
+ // Having a single line break doesn't mean a list is loose. A single line break is terminating the last list item
+ list.loose = true
+ list.items[i].loose = true
+ }
+ }
+
+ return list
+ }
+ }
+
+ html(src) {
+ const cap = this.rules.block.html.exec(src)
+ if (cap) {
+ const token = {
+ type: "html",
+ raw: cap[0],
+ pre:
+ !this.options.sanitizer &&
+ (cap[1] === "pre" || cap[1] === "script" || cap[1] === "style"),
+ text: cap[0],
+ }
+ if (this.options.sanitize) {
+ token.type = "paragraph"
+ token.text = this.options.sanitizer
+ ? this.options.sanitizer(cap[0])
+ : escape(cap[0])
+ token.tokens = []
+ this.lexer.inline(token.text, token.tokens)
+ }
+ return token
+ }
+ }
+
+ def(src) {
+ const cap = this.rules.block.def.exec(src)
+ if (cap) {
+ if (cap[3]) cap[3] = cap[3].substring(1, cap[3].length - 1)
+ const tag = cap[1].toLowerCase().replace(/\s+/g, " ")
+ return {
+ type: "def",
+ tag,
+ raw: cap[0],
+ href: cap[2],
+ title: cap[3],
+ }
+ }
+ }
+
+ table(src) {
+ const cap = this.rules.block.table.exec(src)
+ if (cap) {
+ const item = {
+ type: "table",
+ header: splitCells(cap[1]).map(c => {
+ return { text: c }
+ }),
+ align: cap[2].replace(/^ *|\| *$/g, "").split(/ *\| */),
+ rows:
+ cap[3] && cap[3].trim()
+ ? cap[3].replace(/\n[ \t]*$/, "").split("\n")
+ : [],
+ }
+
+ if (item.header.length === item.align.length) {
+ item.raw = cap[0]
+
+ let l = item.align.length
+ let i, j, k, row
+ for (i = 0; i < l; i++) {
+ if (/^ *-+: *$/.test(item.align[i])) {
+ item.align[i] = "right"
+ } else if (/^ *:-+: *$/.test(item.align[i])) {
+ item.align[i] = "center"
+ } else if (/^ *:-+ *$/.test(item.align[i])) {
+ item.align[i] = "left"
+ } else {
+ item.align[i] = null
+ }
+ }
+
+ l = item.rows.length
+ for (i = 0; i < l; i++) {
+ item.rows[i] = splitCells(item.rows[i], item.header.length).map(c => {
+ return { text: c }
+ })
+ }
+
+ // parse child tokens inside headers and cells
+
+ // header child tokens
+ l = item.header.length
+ for (j = 0; j < l; j++) {
+ item.header[j].tokens = []
+ this.lexer.inline(item.header[j].text, item.header[j].tokens)
+ }
+
+ // cell child tokens
+ l = item.rows.length
+ for (j = 0; j < l; j++) {
+ row = item.rows[j]
+ for (k = 0; k < row.length; k++) {
+ row[k].tokens = []
+ this.lexer.inline(row[k].text, row[k].tokens)
+ }
+ }
+
+ return item
+ }
+ }
+ }
+
+ lheading(src) {
+ const cap = this.rules.block.lheading.exec(src)
+ if (cap) {
+ const token = {
+ type: "heading",
+ raw: cap[0],
+ depth: cap[2].charAt(0) === "=" ? 1 : 2,
+ text: cap[1],
+ tokens: [],
+ }
+ this.lexer.inline(token.text, token.tokens)
+ return token
+ }
+ }
+
+ paragraph(src) {
+ const cap = this.rules.block.paragraph.exec(src)
+ if (cap) {
+ const token = {
+ type: "paragraph",
+ raw: cap[0],
+ text:
+ cap[1].charAt(cap[1].length - 1) === "\n"
+ ? cap[1].slice(0, -1)
+ : cap[1],
+ tokens: [],
+ }
+ this.lexer.inline(token.text, token.tokens)
+ return token
+ }
+ }
+
+ text(src) {
+ const cap = this.rules.block.text.exec(src)
+ if (cap) {
+ const token = {
+ type: "text",
+ raw: cap[0],
+ text: cap[0],
+ tokens: [],
+ }
+ this.lexer.inline(token.text, token.tokens)
+ return token
+ }
+ }
+
+ escape(src) {
+ const cap = this.rules.inline.escape.exec(src)
+ if (cap) {
+ return {
+ type: "escape",
+ raw: cap[0],
+ text: escape(cap[1]),
+ }
+ }
+ }
+
+ tag(src) {
+ const cap = this.rules.inline.tag.exec(src)
+ if (cap) {
+ if (!this.lexer.state.inLink && /^/i.test(cap[0])) {
+ this.lexer.state.inLink = false
+ }
+ if (
+ !this.lexer.state.inRawBlock &&
+ /^<(pre|code|kbd|script)(\s|>)/i.test(cap[0])
+ ) {
+ this.lexer.state.inRawBlock = true
+ } else if (
+ this.lexer.state.inRawBlock &&
+ /^<\/(pre|code|kbd|script)(\s|>)/i.test(cap[0])
+ ) {
+ this.lexer.state.inRawBlock = false
+ }
+
+ return {
+ type: this.options.sanitize ? "text" : "html",
+ raw: cap[0],
+ inLink: this.lexer.state.inLink,
+ inRawBlock: this.lexer.state.inRawBlock,
+ text: this.options.sanitize
+ ? this.options.sanitizer
+ ? this.options.sanitizer(cap[0])
+ : escape(cap[0])
+ : cap[0],
+ }
+ }
+ }
+
+ link(src) {
+ const cap = this.rules.inline.link.exec(src)
+ if (cap) {
+ const trimmedUrl = cap[2].trim()
+ if (!this.options.pedantic && /^$/.test(trimmedUrl)) {
+ return
+ }
+
+ // ending angle bracket cannot be escaped
+ const rtrimSlash = rtrim(trimmedUrl.slice(0, -1), "\\")
+ if ((trimmedUrl.length - rtrimSlash.length) % 2 === 0) {
+ return
+ }
+ } else {
+ // find closing parenthesis
+ const lastParenIndex = findClosingBracket(cap[2], "()")
+ if (lastParenIndex > -1) {
+ const start = cap[0].indexOf("!") === 0 ? 5 : 4
+ const linkLen = start + cap[1].length + lastParenIndex
+ cap[2] = cap[2].substring(0, lastParenIndex)
+ cap[0] = cap[0].substring(0, linkLen).trim()
+ cap[3] = ""
+ }
+ }
+ let href = cap[2]
+ let title = ""
+ if (this.options.pedantic) {
+ // split pedantic href and title
+ const link = /^([^'"]*[^\s])\s+(['"])(.*)\2/.exec(href)
+
+ if (link) {
+ href = link[1]
+ title = link[3]
+ }
+ } else {
+ title = cap[3] ? cap[3].slice(1, -1) : ""
+ }
+
+ href = href.trim()
+ if (/^$/.test(trimmedUrl)) {
+ // pedantic allows starting angle bracket without ending angle bracket
+ href = href.slice(1)
+ } else {
+ href = href.slice(1, -1)
+ }
+ }
+ return outputLink(
+ cap,
+ {
+ href: href ? href.replace(this.rules.inline._escapes, "$1") : href,
+ title: title
+ ? title.replace(this.rules.inline._escapes, "$1")
+ : title,
+ },
+ cap[0],
+ this.lexer
+ )
+ }
+ }
+
+ reflink(src, links) {
+ let cap
+ if (
+ (cap = this.rules.inline.reflink.exec(src)) ||
+ (cap = this.rules.inline.nolink.exec(src))
+ ) {
+ let link = (cap[2] || cap[1]).replace(/\s+/g, " ")
+ link = links[link.toLowerCase()]
+ if (!link || !link.href) {
+ const text = cap[0].charAt(0)
+ return {
+ type: "text",
+ raw: text,
+ text,
+ }
+ }
+ return outputLink(cap, link, cap[0], this.lexer)
+ }
+ }
+
+ emStrong(src, maskedSrc, prevChar = "") {
+ let match = this.rules.inline.emStrong.lDelim.exec(src)
+ if (!match) return
+
+ // _ can't be between two alphanumerics. \p{L}\p{N} includes non-english alphabet/numbers as well
+ if (match[3] && prevChar.match(/[\p{L}\p{N}]/u)) return
+
+ const nextChar = match[1] || match[2] || ""
+
+ if (
+ !nextChar ||
+ (nextChar &&
+ (prevChar === "" || this.rules.inline.punctuation.exec(prevChar)))
+ ) {
+ const lLength = match[0].length - 1
+ let rDelim,
+ rLength,
+ delimTotal = lLength,
+ midDelimTotal = 0
+
+ const endReg =
+ match[0][0] === "*"
+ ? this.rules.inline.emStrong.rDelimAst
+ : this.rules.inline.emStrong.rDelimUnd
+ endReg.lastIndex = 0
+
+ // Clip maskedSrc to same section of string as src (move to lexer?)
+ maskedSrc = maskedSrc.slice(-1 * src.length + lLength)
+
+ while ((match = endReg.exec(maskedSrc)) != null) {
+ rDelim =
+ match[1] || match[2] || match[3] || match[4] || match[5] || match[6]
+
+ if (!rDelim) continue // skip single * in __abc*abc__
+
+ rLength = rDelim.length
+
+ if (match[3] || match[4]) {
+ // found another Left Delim
+ delimTotal += rLength
+ continue
+ } else if (match[5] || match[6]) {
+ // either Left or Right Delim
+ if (lLength % 3 && !((lLength + rLength) % 3)) {
+ midDelimTotal += rLength
+ continue // CommonMark Emphasis Rules 9-10
+ }
+ }
+
+ delimTotal -= rLength
+
+ if (delimTotal > 0) continue // Haven't found enough closing delimiters
+
+ // Remove extra characters. *a*** -> *a*
+ rLength = Math.min(rLength, rLength + delimTotal + midDelimTotal)
+
+ // Create `em` if smallest delimiter has odd char count. *a***
+ if (Math.min(lLength, rLength) % 2) {
+ const text = src.slice(1, lLength + match.index + rLength)
+ return {
+ type: "em",
+ raw: src.slice(0, lLength + match.index + rLength + 1),
+ text,
+ tokens: this.lexer.inlineTokens(text, []),
+ }
+ }
+
+ // Create 'strong' if smallest delimiter has even char count. **a***
+ const text = src.slice(2, lLength + match.index + rLength - 1)
+ return {
+ type: "strong",
+ raw: src.slice(0, lLength + match.index + rLength + 1),
+ text,
+ tokens: this.lexer.inlineTokens(text, []),
+ }
+ }
+ }
+ }
+
+ codespan(src) {
+ const cap = this.rules.inline.code.exec(src)
+ if (cap) {
+ let text = cap[2].replace(/\n/g, " ")
+ const hasNonSpaceChars = /[^ ]/.test(text)
+ const hasSpaceCharsOnBothEnds = /^ /.test(text) && / $/.test(text)
+ if (hasNonSpaceChars && hasSpaceCharsOnBothEnds) {
+ text = text.substring(1, text.length - 1)
+ }
+ text = escape(text, true)
+ return {
+ type: "codespan",
+ raw: cap[0],
+ text,
+ }
+ }
+ }
+
+ br(src) {
+ const cap = this.rules.inline.br.exec(src)
+ if (cap) {
+ return {
+ type: "br",
+ raw: cap[0],
+ }
+ }
+ }
+
+ del(src) {
+ const cap = this.rules.inline.del.exec(src)
+ if (cap) {
+ return {
+ type: "del",
+ raw: cap[0],
+ text: cap[2],
+ tokens: this.lexer.inlineTokens(cap[2], []),
+ }
+ }
+ }
+
+ autolink(src, mangle) {
+ const cap = this.rules.inline.autolink.exec(src)
+ if (cap) {
+ let text, href
+ if (cap[2] === "@") {
+ text = escape(this.options.mangle ? mangle(cap[1]) : cap[1])
+ href = "mailto:" + text
+ } else {
+ text = escape(cap[1])
+ href = text
+ }
+
+ return {
+ type: "link",
+ raw: cap[0],
+ text,
+ href,
+ tokens: [
+ {
+ type: "text",
+ raw: text,
+ text,
+ },
+ ],
+ }
+ }
+ }
+
+ url(src, mangle) {
+ let cap
+ if ((cap = this.rules.inline.url.exec(src))) {
+ let text, href
+ if (cap[2] === "@") {
+ text = escape(this.options.mangle ? mangle(cap[0]) : cap[0])
+ href = "mailto:" + text
+ } else {
+ // do extended autolink path validation
+ let prevCapZero
+ do {
+ prevCapZero = cap[0]
+ cap[0] = this.rules.inline._backpedal.exec(cap[0])[0]
+ } while (prevCapZero !== cap[0])
+ text = escape(cap[0])
+ if (cap[1] === "www.") {
+ href = "http://" + text
+ } else {
+ href = text
+ }
+ }
+ return {
+ type: "link",
+ raw: cap[0],
+ text,
+ href,
+ tokens: [
+ {
+ type: "text",
+ raw: text,
+ text,
+ },
+ ],
+ }
+ }
+ }
+
+ inlineText(src, smartypants) {
+ const cap = this.rules.inline.text.exec(src)
+ if (cap) {
+ let text
+ if (this.lexer.state.inRawBlock) {
+ text = this.options.sanitize
+ ? this.options.sanitizer
+ ? this.options.sanitizer(cap[0])
+ : escape(cap[0])
+ : cap[0]
+ } else {
+ text = escape(this.options.smartypants ? smartypants(cap[0]) : cap[0])
+ }
+ return {
+ type: "text",
+ raw: cap[0],
+ text,
+ }
+ }
+ }
+}
+
+/**
+ * Block-Level Grammar
+ */
+const block = {
+ newline: /^(?: *(?:\n|$))+/,
+ code: /^( {4}[^\n]+(?:\n(?: *(?:\n|$))*)?)+/,
+ fences:
+ /^ {0,3}(`{3,}(?=[^`\n]*\n)|~{3,})([^\n]*)\n(?:|([\s\S]*?)\n)(?: {0,3}\1[~`]* *(?=\n|$)|$)/,
+ hr: /^ {0,3}((?:-[\t ]*){3,}|(?:_[ \t]*){3,}|(?:\*[ \t]*){3,})(?:\n+|$)/,
+ heading: /^ {0,3}(#{1,6})(?=\s|$)(.*)(?:\n+|$)/,
+ blockquote: /^( {0,3}> ?(paragraph|[^\n]*)(?:\n|$))+/,
+ list: /^( {0,3}bull)([ \t][^\n]+?)?(?:\n|$)/,
+ html:
+ "^ {0,3}(?:" + // optional indentation
+ "<(script|pre|style|textarea)[\\s>][\\s\\S]*?(?:\\1>[^\\n]*\\n+|$)" + // (1)
+ "|comment[^\\n]*(\\n+|$)" + // (2)
+ "|<\\?[\\s\\S]*?(?:\\?>\\n*|$)" + // (3)
+ "|\\n*|$)" + // (4)
+ "|\\n*|$)" + // (5)
+ "|?(tag)(?: +|\\n|/?>)[\\s\\S]*?(?:(?:\\n *)+\\n|$)" + // (6)
+ "|<(?!script|pre|style|textarea)([a-z][\\w-]*)(?:attribute)*? */?>(?=[ \\t]*(?:\\n|$))[\\s\\S]*?(?:(?:\\n *)+\\n|$)" + // (7) open tag
+ "|(?!script|pre|style|textarea)[a-z][\\w-]*\\s*>(?=[ \\t]*(?:\\n|$))[\\s\\S]*?(?:(?:\\n *)+\\n|$)" + // (7) closing tag
+ ")",
+ def: /^ {0,3}\[(label)\]: *(?:\n *)?([^\s>]+)>?(?:(?: +(?:\n *)?| *\n *)(title))? *(?:\n+|$)/,
+ table: noopTest,
+ lheading: /^([^\n]+)\n {0,3}(=+|-+) *(?:\n+|$)/,
+ // regex template, placeholders will be replaced according to different paragraph
+ // interruption rules of commonmark and the original markdown spec:
+ _paragraph:
+ /^([^\n]+(?:\n(?!hr|heading|lheading|blockquote|fences|list|html|table| +\n)[^\n]+)*)/,
+ text: /^[^\n]+/,
+}
+
+block._label = /(?!\s*\])(?:\\.|[^\[\]\\])+/
+block._title = /(?:"(?:\\"?|[^"\\])*"|'[^'\n]*(?:\n[^'\n]+)*\n?'|\([^()]*\))/
+block.def = edit(block.def)
+ .replace("label", block._label)
+ .replace("title", block._title)
+ .getRegex()
+
+block.bullet = /(?:[*+-]|\d{1,9}[.)])/
+block.listItemStart = edit(/^( *)(bull) */)
+ .replace("bull", block.bullet)
+ .getRegex()
+
+block.list = edit(block.list)
+ .replace(/bull/g, block.bullet)
+ .replace(
+ "hr",
+ "\\n+(?=\\1?(?:(?:- *){3,}|(?:_ *){3,}|(?:\\* *){3,})(?:\\n+|$))"
+ )
+ .replace("def", "\\n+(?=" + block.def.source + ")")
+ .getRegex()
+
+block._tag =
+ "address|article|aside|base|basefont|blockquote|body|caption" +
+ "|center|col|colgroup|dd|details|dialog|dir|div|dl|dt|fieldset|figcaption" +
+ "|figure|footer|form|frame|frameset|h[1-6]|head|header|hr|html|iframe" +
+ "|legend|li|link|main|menu|menuitem|meta|nav|noframes|ol|optgroup|option" +
+ "|p|param|section|source|summary|table|tbody|td|tfoot|th|thead|title|tr" +
+ "|track|ul"
+block._comment = /|$)/
+block.html = edit(block.html, "i")
+ .replace("comment", block._comment)
+ .replace("tag", block._tag)
+ .replace(
+ "attribute",
+ / +[a-zA-Z:_][\w.:-]*(?: *= *"[^"\n]*"| *= *'[^'\n]*'| *= *[^\s"'=<>`]+)?/
+ )
+ .getRegex()
+
+block.paragraph = edit(block._paragraph)
+ .replace("hr", block.hr)
+ .replace("heading", " {0,3}#{1,6} ")
+ .replace("|lheading", "") // setex headings don't interrupt commonmark paragraphs
+ .replace("|table", "")
+ .replace("blockquote", " {0,3}>")
+ .replace("fences", " {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n")
+ .replace("list", " {0,3}(?:[*+-]|1[.)]) ") // only lists starting from 1 can interrupt
+ .replace(
+ "html",
+ "?(?:tag)(?: +|\\n|/?>)|<(?:script|pre|style|textarea|!--)"
+ )
+ .replace("tag", block._tag) // pars can be interrupted by type (6) html blocks
+ .getRegex()
+
+block.blockquote = edit(block.blockquote)
+ .replace("paragraph", block.paragraph)
+ .getRegex()
+
+/**
+ * Normal Block Grammar
+ */
+
+block.normal = merge({}, block)
+
+/**
+ * GFM Block Grammar
+ */
+
+block.gfm = merge({}, block.normal, {
+ table:
+ "^ *([^\\n ].*\\|.*)\\n" + // Header
+ " {0,3}(?:\\| *)?(:?-+:? *(?:\\| *:?-+:? *)*)(?:\\| *)?" + // Align
+ "(?:\\n((?:(?! *\\n|hr|heading|blockquote|code|fences|list|html).*(?:\\n|$))*)\\n*|$)", // Cells
+})
+
+block.gfm.table = edit(block.gfm.table)
+ .replace("hr", block.hr)
+ .replace("heading", " {0,3}#{1,6} ")
+ .replace("blockquote", " {0,3}>")
+ .replace("code", " {4}[^\\n]")
+ .replace("fences", " {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n")
+ .replace("list", " {0,3}(?:[*+-]|1[.)]) ") // only lists starting from 1 can interrupt
+ .replace(
+ "html",
+ "?(?:tag)(?: +|\\n|/?>)|<(?:script|pre|style|textarea|!--)"
+ )
+ .replace("tag", block._tag) // tables can be interrupted by type (6) html blocks
+ .getRegex()
+
+block.gfm.paragraph = edit(block._paragraph)
+ .replace("hr", block.hr)
+ .replace("heading", " {0,3}#{1,6} ")
+ .replace("|lheading", "") // setex headings don't interrupt commonmark paragraphs
+ .replace("table", block.gfm.table) // interrupt paragraphs with table
+ .replace("blockquote", " {0,3}>")
+ .replace("fences", " {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n")
+ .replace("list", " {0,3}(?:[*+-]|1[.)]) ") // only lists starting from 1 can interrupt
+ .replace(
+ "html",
+ "?(?:tag)(?: +|\\n|/?>)|<(?:script|pre|style|textarea|!--)"
+ )
+ .replace("tag", block._tag) // pars can be interrupted by type (6) html blocks
+ .getRegex()
+/**
+ * Pedantic grammar (original John Gruber's loose markdown specification)
+ */
+
+block.pedantic = merge({}, block.normal, {
+ html: edit(
+ "^ *(?:comment *(?:\\n|\\s*$)" +
+ "|<(tag)[\\s\\S]+?\\1> *(?:\\n{2,}|\\s*$)" + // closed tag
+ "|\\s]*)*?/?> *(?:\\n{2,}|\\s*$))"
+ )
+ .replace("comment", block._comment)
+ .replace(
+ /tag/g,
+ "(?!(?:" +
+ "a|em|strong|small|s|cite|q|dfn|abbr|data|time|code|var|samp|kbd|sub" +
+ "|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo|span|br|wbr|ins|del|img)" +
+ "\\b)\\w+(?!:|[^\\w\\s@]*@)\\b"
+ )
+ .getRegex(),
+ def: /^ *\[([^\]]+)\]: *([^\s>]+)>?(?: +(["(][^\n]+[")]))? *(?:\n+|$)/,
+ heading: /^(#{1,6})(.*)(?:\n+|$)/,
+ fences: noopTest, // fences not supported
+ paragraph: edit(block.normal._paragraph)
+ .replace("hr", block.hr)
+ .replace("heading", " *#{1,6} *[^\n]")
+ .replace("lheading", block.lheading)
+ .replace("blockquote", " {0,3}>")
+ .replace("|fences", "")
+ .replace("|list", "")
+ .replace("|html", "")
+ .getRegex(),
+})
+
+/**
+ * Inline-Level Grammar
+ */
+const inline = {
+ escape: /^\\([!"#$%&'()*+,\-./:;<=>?@\[\]\\^_`{|}~])/,
+ autolink: /^<(scheme:[^\s\x00-\x1f<>]*|email)>/,
+ url: noopTest,
+ tag:
+ "^comment" +
+ "|^[a-zA-Z][\\w:-]*\\s*>" + // self-closing tag
+ "|^<[a-zA-Z][\\w-]*(?:attribute)*?\\s*/?>" + // open tag
+ "|^<\\?[\\s\\S]*?\\?>" + // processing instruction, e.g.
+ "|^" + // declaration, e.g.
+ "|^", // CDATA section
+ link: /^!?\[(label)\]\(\s*(href)(?:\s+(title))?\s*\)/,
+ reflink: /^!?\[(label)\]\[(ref)\]/,
+ nolink: /^!?\[(ref)\](?:\[\])?/,
+ reflinkSearch: "reflink|nolink(?!\\()",
+ emStrong: {
+ lDelim: /^(?:\*+(?:([punct_])|[^\s*]))|^_+(?:([punct*])|([^\s_]))/,
+ // (1) and (2) can only be a Right Delimiter. (3) and (4) can only be Left. (5) and (6) can be either Left or Right.
+ // () Skip orphan inside strong () Consume to delim (1) #*** (2) a***#, a*** (3) #***a, ***a (4) ***# (5) #***# (6) a***a
+ rDelimAst:
+ /^[^_*]*?\_\_[^_*]*?\*[^_*]*?(?=\_\_)|[^*]+(?=[^*])|[punct_](\*+)(?=[\s]|$)|[^punct*_\s](\*+)(?=[punct_\s]|$)|[punct_\s](\*+)(?=[^punct*_\s])|[\s](\*+)(?=[punct_])|[punct_](\*+)(?=[punct_])|[^punct*_\s](\*+)(?=[^punct*_\s])/,
+ rDelimUnd:
+ /^[^_*]*?\*\*[^_*]*?\_[^_*]*?(?=\*\*)|[^_]+(?=[^_])|[punct*](\_+)(?=[\s]|$)|[^punct*_\s](\_+)(?=[punct*\s]|$)|[punct*\s](\_+)(?=[^punct*_\s])|[\s](\_+)(?=[punct*])|[punct*](\_+)(?=[punct*])/, // ^- Not allowed for _
+ },
+ code: /^(`+)([^`]|[^`][\s\S]*?[^`])\1(?!`)/,
+ br: /^( {2,}|\\)\n(?!\s*$)/,
+ del: noopTest,
+ text: /^(`+|[^`])(?:(?= {2,}\n)|[\s\S]*?(?:(?=[\\?@\\[\\]`^{|}~"
+inline.punctuation = edit(inline.punctuation)
+ .replace(/punctuation/g, inline._punctuation)
+ .getRegex()
+
+// sequences em should skip over [title](link), `code`,
+inline.blockSkip = /\[[^\]]*?\]\([^\)]*?\)|`[^`]*?`|<[^>]*?>/g
+inline.escapedEmSt = /\\\*|\\_/g
+
+inline._comment = edit(block._comment).replace("(?:-->|$)", "-->").getRegex()
+
+inline.emStrong.lDelim = edit(inline.emStrong.lDelim)
+ .replace(/punct/g, inline._punctuation)
+ .getRegex()
+
+inline.emStrong.rDelimAst = edit(inline.emStrong.rDelimAst, "g")
+ .replace(/punct/g, inline._punctuation)
+ .getRegex()
+
+inline.emStrong.rDelimUnd = edit(inline.emStrong.rDelimUnd, "g")
+ .replace(/punct/g, inline._punctuation)
+ .getRegex()
+
+inline._escapes = /\\([!"#$%&'()*+,\-./:;<=>?@\[\]\\^_`{|}~])/g
+
+inline._scheme = /[a-zA-Z][a-zA-Z0-9+.-]{1,31}/
+inline._email =
+ /[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+(@)[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)+(?![-_])/
+inline.autolink = edit(inline.autolink)
+ .replace("scheme", inline._scheme)
+ .replace("email", inline._email)
+ .getRegex()
+
+inline._attribute =
+ /\s+[a-zA-Z:_][\w.:-]*(?:\s*=\s*"[^"]*"|\s*=\s*'[^']*'|\s*=\s*[^\s"'=<>`]+)?/
+
+inline.tag = edit(inline.tag)
+ .replace("comment", inline._comment)
+ .replace("attribute", inline._attribute)
+ .getRegex()
+
+inline._label = /(?:\[(?:\\.|[^\[\]\\])*\]|\\.|`[^`]*`|[^\[\]\\`])*?/
+inline._href = /<(?:\\.|[^\n<>\\])+>|[^\s\x00-\x1f]*/
+inline._title = /"(?:\\"?|[^"\\])*"|'(?:\\'?|[^'\\])*'|\((?:\\\)?|[^)\\])*\)/
+
+inline.link = edit(inline.link)
+ .replace("label", inline._label)
+ .replace("href", inline._href)
+ .replace("title", inline._title)
+ .getRegex()
+
+inline.reflink = edit(inline.reflink)
+ .replace("label", inline._label)
+ .replace("ref", block._label)
+ .getRegex()
+
+inline.nolink = edit(inline.nolink).replace("ref", block._label).getRegex()
+
+inline.reflinkSearch = edit(inline.reflinkSearch, "g")
+ .replace("reflink", inline.reflink)
+ .replace("nolink", inline.nolink)
+ .getRegex()
+
+/**
+ * Normal Inline Grammar
+ */
+
+inline.normal = merge({}, inline)
+
+/**
+ * Pedantic Inline Grammar
+ */
+
+inline.pedantic = merge({}, inline.normal, {
+ strong: {
+ start: /^__|\*\*/,
+ middle: /^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,
+ endAst: /\*\*(?!\*)/g,
+ endUnd: /__(?!_)/g,
+ },
+ em: {
+ start: /^_|\*/,
+ middle: /^()\*(?=\S)([\s\S]*?\S)\*(?!\*)|^_(?=\S)([\s\S]*?\S)_(?!_)/,
+ endAst: /\*(?!\*)/g,
+ endUnd: /_(?!_)/g,
+ },
+ link: edit(/^!?\[(label)\]\((.*?)\)/)
+ .replace("label", inline._label)
+ .getRegex(),
+ reflink: edit(/^!?\[(label)\]\s*\[([^\]]*)\]/)
+ .replace("label", inline._label)
+ .getRegex(),
+})
+
+/**
+ * GFM Inline Grammar
+ */
+
+inline.gfm = merge({}, inline.normal, {
+ escape: edit(inline.escape).replace("])", "~|])").getRegex(),
+ _extended_email:
+ /[A-Za-z0-9._+-]+(@)[a-zA-Z0-9-_]+(?:\.[a-zA-Z0-9-_]*[a-zA-Z0-9])+(?![-_])/,
+ url: /^((?:ftp|https?):\/\/|www\.)(?:[a-zA-Z0-9\-]+\.?)+[^\s<]*|^email/,
+ _backpedal:
+ /(?:[^?!.,:;*_~()&]+|\([^)]*\)|&(?![a-zA-Z0-9]+;$)|[?!.,:;*_~)]+(?!$))+/,
+ del: /^(~~?)(?=[^\s~])([\s\S]*?[^\s~])\1(?=[^~]|$)/,
+ text: /^([`~]+|[^`~])(?:(?= {2,}\n)|(?=[a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-]+@)|[\s\S]*?(?:(?=[\\ 0.5) {
+ ch = "x" + ch.toString(16)
+ }
+ out += "" + ch + ";"
+ }
+
+ return out
+}
+
+/**
+ * Block Lexer
+ */
+class Lexer {
+ constructor(options) {
+ this.tokens = []
+ this.tokens.links = Object.create(null)
+ this.options = options || defaults
+ this.options.tokenizer = this.options.tokenizer || new Tokenizer()
+ this.tokenizer = this.options.tokenizer
+ this.tokenizer.options = this.options
+ this.tokenizer.lexer = this
+ this.inlineQueue = []
+ this.state = {
+ inLink: false,
+ inRawBlock: false,
+ top: true,
+ }
+
+ const rules = {
+ block: block.normal,
+ inline: inline.normal,
+ }
+
+ if (this.options.pedantic) {
+ rules.block = block.pedantic
+ rules.inline = inline.pedantic
+ } else if (this.options.gfm) {
+ rules.block = block.gfm
+ if (this.options.breaks) {
+ rules.inline = inline.breaks
+ } else {
+ rules.inline = inline.gfm
+ }
+ }
+ this.tokenizer.rules = rules
+ }
+
+ /**
+ * Expose Rules
+ */
+ static get rules() {
+ return {
+ block,
+ inline,
+ }
+ }
+
+ /**
+ * Static Lex Method
+ */
+ static lex(src, options) {
+ const lexer = new Lexer(options)
+ return lexer.lex(src)
+ }
+
+ /**
+ * Static Lex Inline Method
+ */
+ static lexInline(src, options) {
+ const lexer = new Lexer(options)
+ return lexer.inlineTokens(src)
+ }
+
+ /**
+ * Preprocessing
+ */
+ lex(src) {
+ src = src.replace(/\r\n|\r/g, "\n")
+
+ this.blockTokens(src, this.tokens)
+
+ let next
+ while ((next = this.inlineQueue.shift())) {
+ this.inlineTokens(next.src, next.tokens)
+ }
+
+ return this.tokens
+ }
+
+ /**
+ * Lexing
+ */
+ blockTokens(src, tokens = []) {
+ if (this.options.pedantic) {
+ src = src.replace(/\t/g, " ").replace(/^ +$/gm, "")
+ } else {
+ src = src.replace(/^( *)(\t+)/gm, (_, leading, tabs) => {
+ return leading + " ".repeat(tabs.length)
+ })
+ }
+
+ let token, lastToken, cutSrc, lastParagraphClipped
+
+ while (src) {
+ if (
+ this.options.extensions &&
+ this.options.extensions.block &&
+ this.options.extensions.block.some(extTokenizer => {
+ if ((token = extTokenizer.call({ lexer: this }, src, tokens))) {
+ src = src.substring(token.raw.length)
+ tokens.push(token)
+ return true
+ }
+ return false
+ })
+ ) {
+ continue
+ }
+
+ // newline
+ if ((token = this.tokenizer.space(src))) {
+ src = src.substring(token.raw.length)
+ if (token.raw.length === 1 && tokens.length > 0) {
+ // if there's a single \n as a spacer, it's terminating the last line,
+ // so move it there so that we don't get unecessary paragraph tags
+ tokens[tokens.length - 1].raw += "\n"
+ } else {
+ tokens.push(token)
+ }
+ continue
+ }
+
+ // code
+ if ((token = this.tokenizer.code(src))) {
+ src = src.substring(token.raw.length)
+ lastToken = tokens[tokens.length - 1]
+ // An indented code block cannot interrupt a paragraph.
+ if (
+ lastToken &&
+ (lastToken.type === "paragraph" || lastToken.type === "text")
+ ) {
+ lastToken.raw += "\n" + token.raw
+ lastToken.text += "\n" + token.text
+ this.inlineQueue[this.inlineQueue.length - 1].src = lastToken.text
+ } else {
+ tokens.push(token)
+ }
+ continue
+ }
+
+ // fences
+ if ((token = this.tokenizer.fences(src))) {
+ src = src.substring(token.raw.length)
+ tokens.push(token)
+ continue
+ }
+
+ // heading
+ if ((token = this.tokenizer.heading(src))) {
+ src = src.substring(token.raw.length)
+ tokens.push(token)
+ continue
+ }
+
+ // hr
+ if ((token = this.tokenizer.hr(src))) {
+ src = src.substring(token.raw.length)
+ tokens.push(token)
+ continue
+ }
+
+ // blockquote
+ if ((token = this.tokenizer.blockquote(src))) {
+ src = src.substring(token.raw.length)
+ tokens.push(token)
+ continue
+ }
+
+ // list
+ if ((token = this.tokenizer.list(src))) {
+ src = src.substring(token.raw.length)
+ tokens.push(token)
+ continue
+ }
+
+ // html
+ if ((token = this.tokenizer.html(src))) {
+ src = src.substring(token.raw.length)
+ tokens.push(token)
+ continue
+ }
+
+ // def
+ if ((token = this.tokenizer.def(src))) {
+ src = src.substring(token.raw.length)
+ lastToken = tokens[tokens.length - 1]
+ if (
+ lastToken &&
+ (lastToken.type === "paragraph" || lastToken.type === "text")
+ ) {
+ lastToken.raw += "\n" + token.raw
+ lastToken.text += "\n" + token.raw
+ this.inlineQueue[this.inlineQueue.length - 1].src = lastToken.text
+ } else if (!this.tokens.links[token.tag]) {
+ this.tokens.links[token.tag] = {
+ href: token.href,
+ title: token.title,
+ }
+ }
+ continue
+ }
+
+ // table (gfm)
+ if ((token = this.tokenizer.table(src))) {
+ src = src.substring(token.raw.length)
+ tokens.push(token)
+ continue
+ }
+
+ // lheading
+ if ((token = this.tokenizer.lheading(src))) {
+ src = src.substring(token.raw.length)
+ tokens.push(token)
+ continue
+ }
+
+ // top-level paragraph
+ // prevent paragraph consuming extensions by clipping 'src' to extension start
+ cutSrc = src
+ if (this.options.extensions && this.options.extensions.startBlock) {
+ let startIndex = Infinity
+ const tempSrc = src.slice(1)
+ let tempStart
+ this.options.extensions.startBlock.forEach(function (getStartIndex) {
+ tempStart = getStartIndex.call({ lexer: this }, tempSrc)
+ if (typeof tempStart === "number" && tempStart >= 0) {
+ startIndex = Math.min(startIndex, tempStart)
+ }
+ })
+ if (startIndex < Infinity && startIndex >= 0) {
+ cutSrc = src.substring(0, startIndex + 1)
+ }
+ }
+ if (this.state.top && (token = this.tokenizer.paragraph(cutSrc))) {
+ lastToken = tokens[tokens.length - 1]
+ if (lastParagraphClipped && lastToken.type === "paragraph") {
+ lastToken.raw += "\n" + token.raw
+ lastToken.text += "\n" + token.text
+ this.inlineQueue.pop()
+ this.inlineQueue[this.inlineQueue.length - 1].src = lastToken.text
+ } else {
+ tokens.push(token)
+ }
+ lastParagraphClipped = cutSrc.length !== src.length
+ src = src.substring(token.raw.length)
+ continue
+ }
+
+ // text
+ if ((token = this.tokenizer.text(src))) {
+ src = src.substring(token.raw.length)
+ lastToken = tokens[tokens.length - 1]
+ if (lastToken && lastToken.type === "text") {
+ lastToken.raw += "\n" + token.raw
+ lastToken.text += "\n" + token.text
+ this.inlineQueue.pop()
+ this.inlineQueue[this.inlineQueue.length - 1].src = lastToken.text
+ } else {
+ tokens.push(token)
+ }
+ continue
+ }
+
+ if (src) {
+ const errMsg = "Infinite loop on byte: " + src.charCodeAt(0)
+ if (this.options.silent) {
+ console.error(errMsg)
+ break
+ } else {
+ throw new Error(errMsg)
+ }
+ }
+ }
+
+ this.state.top = true
+ return tokens
+ }
+
+ inline(src, tokens) {
+ this.inlineQueue.push({ src, tokens })
+ }
+
+ /**
+ * Lexing/Compiling
+ */
+ inlineTokens(src, tokens = []) {
+ let token, lastToken, cutSrc
+
+ // String with links masked to avoid interference with em and strong
+ let maskedSrc = src
+ let match
+ let keepPrevChar, prevChar
+
+ // Mask out reflinks
+ if (this.tokens.links) {
+ const links = Object.keys(this.tokens.links)
+ if (links.length > 0) {
+ while (
+ (match = this.tokenizer.rules.inline.reflinkSearch.exec(maskedSrc)) !=
+ null
+ ) {
+ if (
+ links.includes(match[0].slice(match[0].lastIndexOf("[") + 1, -1))
+ ) {
+ maskedSrc =
+ maskedSrc.slice(0, match.index) +
+ "[" +
+ repeatString("a", match[0].length - 2) +
+ "]" +
+ maskedSrc.slice(
+ this.tokenizer.rules.inline.reflinkSearch.lastIndex
+ )
+ }
+ }
+ }
+ }
+ // Mask out other blocks
+ while (
+ (match = this.tokenizer.rules.inline.blockSkip.exec(maskedSrc)) != null
+ ) {
+ maskedSrc =
+ maskedSrc.slice(0, match.index) +
+ "[" +
+ repeatString("a", match[0].length - 2) +
+ "]" +
+ maskedSrc.slice(this.tokenizer.rules.inline.blockSkip.lastIndex)
+ }
+
+ // Mask out escaped em & strong delimiters
+ while (
+ (match = this.tokenizer.rules.inline.escapedEmSt.exec(maskedSrc)) != null
+ ) {
+ maskedSrc =
+ maskedSrc.slice(0, match.index) +
+ "++" +
+ maskedSrc.slice(this.tokenizer.rules.inline.escapedEmSt.lastIndex)
+ }
+
+ while (src) {
+ if (!keepPrevChar) {
+ prevChar = ""
+ }
+ keepPrevChar = false
+
+ // extensions
+ if (
+ this.options.extensions &&
+ this.options.extensions.inline &&
+ this.options.extensions.inline.some(extTokenizer => {
+ if ((token = extTokenizer.call({ lexer: this }, src, tokens))) {
+ src = src.substring(token.raw.length)
+ tokens.push(token)
+ return true
+ }
+ return false
+ })
+ ) {
+ continue
+ }
+
+ // escape
+ if ((token = this.tokenizer.escape(src))) {
+ src = src.substring(token.raw.length)
+ tokens.push(token)
+ continue
+ }
+
+ // tag
+ if ((token = this.tokenizer.tag(src))) {
+ src = src.substring(token.raw.length)
+ lastToken = tokens[tokens.length - 1]
+ if (lastToken && token.type === "text" && lastToken.type === "text") {
+ lastToken.raw += token.raw
+ lastToken.text += token.text
+ } else {
+ tokens.push(token)
+ }
+ continue
+ }
+
+ // link
+ if ((token = this.tokenizer.link(src))) {
+ src = src.substring(token.raw.length)
+ tokens.push(token)
+ continue
+ }
+
+ // reflink, nolink
+ if ((token = this.tokenizer.reflink(src, this.tokens.links))) {
+ src = src.substring(token.raw.length)
+ lastToken = tokens[tokens.length - 1]
+ if (lastToken && token.type === "text" && lastToken.type === "text") {
+ lastToken.raw += token.raw
+ lastToken.text += token.text
+ } else {
+ tokens.push(token)
+ }
+ continue
+ }
+
+ // em & strong
+ if ((token = this.tokenizer.emStrong(src, maskedSrc, prevChar))) {
+ src = src.substring(token.raw.length)
+ tokens.push(token)
+ continue
+ }
+
+ // code
+ if ((token = this.tokenizer.codespan(src))) {
+ src = src.substring(token.raw.length)
+ tokens.push(token)
+ continue
+ }
+
+ // br
+ if ((token = this.tokenizer.br(src))) {
+ src = src.substring(token.raw.length)
+ tokens.push(token)
+ continue
+ }
+
+ // del (gfm)
+ if ((token = this.tokenizer.del(src))) {
+ src = src.substring(token.raw.length)
+ tokens.push(token)
+ continue
+ }
+
+ // autolink
+ if ((token = this.tokenizer.autolink(src, mangle))) {
+ src = src.substring(token.raw.length)
+ tokens.push(token)
+ continue
+ }
+
+ // url (gfm)
+ if (!this.state.inLink && (token = this.tokenizer.url(src, mangle))) {
+ src = src.substring(token.raw.length)
+ tokens.push(token)
+ continue
+ }
+
+ // text
+ // prevent inlineText consuming extensions by clipping 'src' to extension start
+ cutSrc = src
+ if (this.options.extensions && this.options.extensions.startInline) {
+ let startIndex = Infinity
+ const tempSrc = src.slice(1)
+ let tempStart
+ this.options.extensions.startInline.forEach(function (getStartIndex) {
+ tempStart = getStartIndex.call({ lexer: this }, tempSrc)
+ if (typeof tempStart === "number" && tempStart >= 0) {
+ startIndex = Math.min(startIndex, tempStart)
+ }
+ })
+ if (startIndex < Infinity && startIndex >= 0) {
+ cutSrc = src.substring(0, startIndex + 1)
+ }
+ }
+ if ((token = this.tokenizer.inlineText(cutSrc, smartypants))) {
+ src = src.substring(token.raw.length)
+ if (token.raw.slice(-1) !== "_") {
+ // Track prevChar before string of ____ started
+ prevChar = token.raw.slice(-1)
+ }
+ keepPrevChar = true
+ lastToken = tokens[tokens.length - 1]
+ if (lastToken && lastToken.type === "text") {
+ lastToken.raw += token.raw
+ lastToken.text += token.text
+ } else {
+ tokens.push(token)
+ }
+ continue
+ }
+
+ if (src) {
+ const errMsg = "Infinite loop on byte: " + src.charCodeAt(0)
+ if (this.options.silent) {
+ console.error(errMsg)
+ break
+ } else {
+ throw new Error(errMsg)
+ }
+ }
+ }
+
+ return tokens
+ }
+}
+
+/**
+ * Renderer
+ */
+class Renderer {
+ constructor(options) {
+ this.options = options || defaults
+ }
+
+ code(code, infostring, escaped) {
+ const lang = (infostring || "").match(/\S*/)[0]
+ if (this.options.highlight) {
+ const out = this.options.highlight(code, lang)
+ if (out != null && out !== code) {
+ escaped = true
+ code = out
+ }
+ }
+
+ code = code.replace(/\n$/, "") + "\n"
+
+ if (!lang) {
+ return (
+ "" +
+ (escaped ? code : escape(code, true)) +
+ "
\n"
+ )
+ }
+
+ return (
+ '' +
+ (escaped ? code : escape(code, true)) +
+ "
\n"
+ )
+ }
+
+ /**
+ * @param {string} quote
+ */
+ blockquote(quote) {
+ return `\n${quote}
\n`
+ }
+
+ html(html) {
+ return html
+ }
+
+ /**
+ * @param {string} text
+ * @param {string} level
+ * @param {string} raw
+ * @param {any} slugger
+ */
+ heading(text, level, raw, slugger) {
+ if (this.options.headerIds) {
+ const id = this.options.headerPrefix + slugger.slug(raw)
+ return `${text}\n`
+ }
+
+ // ignore IDs
+ return `${text}\n`
+ }
+
+ hr() {
+ return this.options.xhtml ? "
\n" : "
\n"
+ }
+
+ list(body, ordered, start) {
+ const type = ordered ? "ol" : "ul",
+ startatt = ordered && start !== 1 ? ' start="' + start + '"' : ""
+ return "<" + type + startatt + ">\n" + body + "" + type + ">\n"
+ }
+
+ /**
+ * @param {string} text
+ */
+ listitem(text) {
+ return `${text}\n`
+ }
+
+ checkbox(checked) {
+ return (
+ " "
+ )
+ }
+
+ /**
+ * @param {string} text
+ */
+ paragraph(text) {
+ return `${text}
\n`
+ }
+
+ /**
+ * @param {string} header
+ * @param {string} body
+ */
+ table(header, body) {
+ if (body) body = `${body}`
+
+ return (
+ "\n" + "\n" + header + "\n" + body + "
\n"
+ )
+ }
+
+ /**
+ * @param {string} content
+ */
+ tablerow(content) {
+ return `\n${content}
\n`
+ }
+
+ tablecell(content, flags) {
+ const type = flags.header ? "th" : "td"
+ const tag = flags.align ? `<${type} align="${flags.align}">` : `<${type}>`
+ return tag + content + `${type}>\n`
+ }
+
+ /**
+ * span level renderer
+ * @param {string} text
+ */
+ strong(text) {
+ return `${text}`
+ }
+
+ /**
+ * @param {string} text
+ */
+ em(text) {
+ return `${text}`
+ }
+
+ /**
+ * @param {string} text
+ */
+ codespan(text) {
+ return `${text}
`
+ }
+
+ br() {
+ return this.options.xhtml ? "
" : "
"
+ }
+
+ /**
+ * @param {string} text
+ */
+ del(text) {
+ return `${text}`
+ }
+
+ /**
+ * @param {string} href
+ * @param {string} title
+ * @param {string} text
+ */
+ link(href, title, text) {
+ href = cleanUrl(this.options.sanitize, this.options.baseUrl, href)
+ if (href === null) {
+ return text
+ }
+ let out = '" + text + ""
+ return out
+ }
+
+ /**
+ * @param {string} href
+ * @param {string} title
+ * @param {string} text
+ */
+ image(href, title, text) {
+ href = cleanUrl(this.options.sanitize, this.options.baseUrl, href)
+ if (href === null) {
+ return text
+ }
+
+ let out = `" : ">"
+ return out
+ }
+
+ text(text) {
+ return text
+ }
+}
+
+/**
+ * TextRenderer
+ * returns only the textual part of the token
+ */
+class TextRenderer {
+ // no need for block level renderers
+ strong(text) {
+ return text
+ }
+
+ em(text) {
+ return text
+ }
+
+ codespan(text) {
+ return text
+ }
+
+ del(text) {
+ return text
+ }
+
+ html(text) {
+ return text
+ }
+
+ text(text) {
+ return text
+ }
+
+ link(href, title, text) {
+ return "" + text
+ }
+
+ image(href, title, text) {
+ return "" + text
+ }
+
+ br() {
+ return ""
+ }
+}
+
+/**
+ * Slugger generates header id
+ */
+class Slugger {
+ constructor() {
+ this.seen = {}
+ }
+
+ /**
+ * @param {string} value
+ */
+ serialize(value) {
+ return (
+ value
+ .toLowerCase()
+ .trim()
+ // remove html tags
+ .replace(/<[!\/a-z].*?>/gi, "")
+ // remove unwanted chars
+ .replace(
+ /[\u2000-\u206F\u2E00-\u2E7F\\'!"#$%&()*+,./:;<=>?@[\]^`{|}~]/g,
+ ""
+ )
+ .replace(/\s/g, "-")
+ )
+ }
+
+ /**
+ * Finds the next safe (unique) slug to use
+ * @param {string} originalSlug
+ * @param {boolean} isDryRun
+ */
+ getNextSafeSlug(originalSlug, isDryRun) {
+ let slug = originalSlug
+ let occurenceAccumulator = 0
+ if (this.seen.hasOwnProperty(slug)) {
+ occurenceAccumulator = this.seen[originalSlug]
+ do {
+ occurenceAccumulator++
+ slug = originalSlug + "-" + occurenceAccumulator
+ } while (this.seen.hasOwnProperty(slug))
+ }
+ if (!isDryRun) {
+ this.seen[originalSlug] = occurenceAccumulator
+ this.seen[slug] = 0
+ }
+ return slug
+ }
+
+ /**
+ * Convert string to unique id
+ * @param {object} [options]
+ * @param {boolean} [options.dryrun] Generates the next unique slug without
+ * updating the internal accumulator.
+ */
+ slug(value, options = {}) {
+ const slug = this.serialize(value)
+ return this.getNextSafeSlug(slug, options.dryrun)
+ }
+}
+
+/**
+ * Parsing & Compiling
+ */
+class Parser {
+ constructor(options) {
+ this.options = options || defaults
+ this.options.renderer = this.options.renderer || new Renderer()
+ this.renderer = this.options.renderer
+ this.renderer.options = this.options
+ this.textRenderer = new TextRenderer()
+ this.slugger = new Slugger()
+ }
+
+ /**
+ * Static Parse Method
+ */
+ static parse(tokens, options) {
+ const parser = new Parser(options)
+ return parser.parse(tokens)
+ }
+
+ /**
+ * Static Parse Inline Method
+ */
+ static parseInline(tokens, options) {
+ const parser = new Parser(options)
+ return parser.parseInline(tokens)
+ }
+
+ /**
+ * Parse Loop
+ */
+ parse(tokens, top = true) {
+ let out = "",
+ i,
+ j,
+ k,
+ l2,
+ l3,
+ row,
+ cell,
+ header,
+ body,
+ token,
+ ordered,
+ start,
+ loose,
+ itemBody,
+ item,
+ checked,
+ task,
+ checkbox,
+ ret
+
+ const l = tokens.length
+ for (i = 0; i < l; i++) {
+ token = tokens[i]
+
+ // Run any renderer extensions
+ if (
+ this.options.extensions &&
+ this.options.extensions.renderers &&
+ this.options.extensions.renderers[token.type]
+ ) {
+ ret = this.options.extensions.renderers[token.type].call(
+ { parser: this },
+ token
+ )
+ if (
+ ret !== false ||
+ ![
+ "space",
+ "hr",
+ "heading",
+ "code",
+ "table",
+ "blockquote",
+ "list",
+ "html",
+ "paragraph",
+ "text",
+ ].includes(token.type)
+ ) {
+ out += ret || ""
+ continue
+ }
+ }
+
+ switch (token.type) {
+ case "space": {
+ continue
+ }
+ case "hr": {
+ out += this.renderer.hr()
+ continue
+ }
+ case "heading": {
+ out += this.renderer.heading(
+ this.parseInline(token.tokens),
+ token.depth,
+ unescape(this.parseInline(token.tokens, this.textRenderer)),
+ this.slugger
+ )
+ continue
+ }
+ case "code": {
+ out += this.renderer.code(token.text, token.lang, token.escaped)
+ continue
+ }
+ case "table": {
+ header = ""
+
+ // header
+ cell = ""
+ l2 = token.header.length
+ for (j = 0; j < l2; j++) {
+ cell += this.renderer.tablecell(
+ this.parseInline(token.header[j].tokens),
+ { header: true, align: token.align[j] }
+ )
+ }
+ header += this.renderer.tablerow(cell)
+
+ body = ""
+ l2 = token.rows.length
+ for (j = 0; j < l2; j++) {
+ row = token.rows[j]
+
+ cell = ""
+ l3 = row.length
+ for (k = 0; k < l3; k++) {
+ cell += this.renderer.tablecell(this.parseInline(row[k].tokens), {
+ header: false,
+ align: token.align[k],
+ })
+ }
+
+ body += this.renderer.tablerow(cell)
+ }
+ out += this.renderer.table(header, body)
+ continue
+ }
+ case "blockquote": {
+ body = this.parse(token.tokens)
+ out += this.renderer.blockquote(body)
+ continue
+ }
+ case "list": {
+ ordered = token.ordered
+ start = token.start
+ loose = token.loose
+ l2 = token.items.length
+
+ body = ""
+ for (j = 0; j < l2; j++) {
+ item = token.items[j]
+ checked = item.checked
+ task = item.task
+
+ itemBody = ""
+ if (item.task) {
+ checkbox = this.renderer.checkbox(checked)
+ if (loose) {
+ if (
+ item.tokens.length > 0 &&
+ item.tokens[0].type === "paragraph"
+ ) {
+ item.tokens[0].text = checkbox + " " + item.tokens[0].text
+ if (
+ item.tokens[0].tokens &&
+ item.tokens[0].tokens.length > 0 &&
+ item.tokens[0].tokens[0].type === "text"
+ ) {
+ item.tokens[0].tokens[0].text =
+ checkbox + " " + item.tokens[0].tokens[0].text
+ }
+ } else {
+ item.tokens.unshift({
+ type: "text",
+ text: checkbox,
+ })
+ }
+ } else {
+ itemBody += checkbox
+ }
+ }
+
+ itemBody += this.parse(item.tokens, loose)
+ body += this.renderer.listitem(itemBody, task, checked)
+ }
+
+ out += this.renderer.list(body, ordered, start)
+ continue
+ }
+ case "html": {
+ // TODO parse inline content if parameter markdown=1
+ out += this.renderer.html(token.text)
+ continue
+ }
+ case "paragraph": {
+ out += this.renderer.paragraph(this.parseInline(token.tokens))
+ continue
+ }
+ case "text": {
+ body = token.tokens ? this.parseInline(token.tokens) : token.text
+ while (i + 1 < l && tokens[i + 1].type === "text") {
+ token = tokens[++i]
+ body +=
+ "\n" +
+ (token.tokens ? this.parseInline(token.tokens) : token.text)
+ }
+ out += top ? this.renderer.paragraph(body) : body
+ continue
+ }
+
+ default: {
+ const errMsg = 'Token with "' + token.type + '" type was not found.'
+ if (this.options.silent) {
+ console.error(errMsg)
+ return
+ } else {
+ throw new Error(errMsg)
+ }
+ }
+ }
+ }
+
+ return out
+ }
+
+ /**
+ * Parse Inline Tokens
+ */
+ parseInline(tokens, renderer) {
+ renderer = renderer || this.renderer
+ let out = "",
+ i,
+ token,
+ ret
+
+ const l = tokens.length
+ for (i = 0; i < l; i++) {
+ token = tokens[i]
+
+ // Run any renderer extensions
+ if (
+ this.options.extensions &&
+ this.options.extensions.renderers &&
+ this.options.extensions.renderers[token.type]
+ ) {
+ ret = this.options.extensions.renderers[token.type].call(
+ { parser: this },
+ token
+ )
+ if (
+ ret !== false ||
+ ![
+ "escape",
+ "html",
+ "link",
+ "image",
+ "strong",
+ "em",
+ "codespan",
+ "br",
+ "del",
+ "text",
+ ].includes(token.type)
+ ) {
+ out += ret || ""
+ continue
+ }
+ }
+
+ switch (token.type) {
+ case "escape": {
+ out += renderer.text(token.text)
+ break
+ }
+ case "html": {
+ out += renderer.html(token.text)
+ break
+ }
+ case "link": {
+ out += renderer.link(
+ token.href,
+ token.title,
+ this.parseInline(token.tokens, renderer)
+ )
+ break
+ }
+ case "image": {
+ out += renderer.image(token.href, token.title, token.text)
+ break
+ }
+ case "strong": {
+ out += renderer.strong(this.parseInline(token.tokens, renderer))
+ break
+ }
+ case "em": {
+ out += renderer.em(this.parseInline(token.tokens, renderer))
+ break
+ }
+ case "codespan": {
+ out += renderer.codespan(token.text)
+ break
+ }
+ case "br": {
+ out += renderer.br()
+ break
+ }
+ case "del": {
+ out += renderer.del(this.parseInline(token.tokens, renderer))
+ break
+ }
+ case "text": {
+ out += renderer.text(token.text)
+ break
+ }
+ default: {
+ const errMsg = 'Token with "' + token.type + '" type was not found.'
+ if (this.options.silent) {
+ console.error(errMsg)
+ return
+ } else {
+ throw new Error(errMsg)
+ }
+ }
+ }
+ }
+ return out
+ }
+}
+
+/**
+ * Marked
+ */
+function marked(src, opt, callback) {
+ // throw error in case of non string input
+ if (typeof src === "undefined" || src === null) {
+ throw new Error("marked(): input parameter is undefined or null")
+ }
+ if (typeof src !== "string") {
+ throw new Error(
+ "marked(): input parameter is of type " +
+ Object.prototype.toString.call(src) +
+ ", string expected"
+ )
+ }
+
+ if (typeof opt === "function") {
+ callback = opt
+ opt = null
+ }
+
+ opt = merge({}, marked.defaults, opt || {})
+ checkSanitizeDeprecation(opt)
+
+ if (callback) {
+ const highlight = opt.highlight
+ let tokens
+
+ try {
+ tokens = Lexer.lex(src, opt)
+ } catch (e) {
+ return callback(e)
+ }
+
+ const done = function (err) {
+ let out
+
+ if (!err) {
+ try {
+ if (opt.walkTokens) {
+ marked.walkTokens(tokens, opt.walkTokens)
+ }
+ out = Parser.parse(tokens, opt)
+ } catch (e) {
+ err = e
+ }
+ }
+
+ opt.highlight = highlight
+
+ return err ? callback(err) : callback(null, out)
+ }
+
+ if (!highlight || highlight.length < 3) {
+ return done()
+ }
+
+ delete opt.highlight
+
+ if (!tokens.length) return done()
+
+ let pending = 0
+ marked.walkTokens(tokens, function (token) {
+ if (token.type === "code") {
+ pending++
+ setTimeout(() => {
+ highlight(token.text, token.lang, function (err, code) {
+ if (err) {
+ return done(err)
+ }
+ if (code != null && code !== token.text) {
+ token.text = code
+ token.escaped = true
+ }
+
+ pending--
+ if (pending === 0) {
+ done()
+ }
+ })
+ }, 0)
+ }
+ })
+
+ if (pending === 0) {
+ done()
+ }
+
+ return
+ }
+
+ try {
+ const tokens = Lexer.lex(src, opt)
+ if (opt.walkTokens) {
+ marked.walkTokens(tokens, opt.walkTokens)
+ }
+ return Parser.parse(tokens, opt)
+ } catch (e) {
+ e.message += "\nPlease report this to https://github.com/markedjs/marked."
+ if (opt.silent) {
+ return (
+ "An error occurred:
" +
+ escape(e.message + "", true) +
+ "
"
+ )
+ }
+ throw e
+ }
+}
+
+/**
+ * Options
+ */
+
+marked.options = marked.setOptions = function (opt) {
+ merge(marked.defaults, opt)
+ changeDefaults(marked.defaults)
+ return marked
+}
+
+marked.getDefaults = getDefaults
+
+marked.defaults = defaults
+
+/**
+ * Use Extension
+ */
+
+marked.use = function (...args) {
+ const opts = merge({}, ...args)
+ const extensions = marked.defaults.extensions || {
+ renderers: {},
+ childTokens: {},
+ }
+ let hasExtensions
+
+ args.forEach(pack => {
+ // ==-- Parse "addon" extensions --== //
+ if (pack.extensions) {
+ hasExtensions = true
+ pack.extensions.forEach(ext => {
+ if (!ext.name) {
+ throw new Error("extension name required")
+ }
+ if (ext.renderer) {
+ // Renderer extensions
+ const prevRenderer = extensions.renderers
+ ? extensions.renderers[ext.name]
+ : null
+ if (prevRenderer) {
+ // Replace extension with func to run new extension but fall back if false
+ extensions.renderers[ext.name] = function (...args) {
+ let ret = ext.renderer.apply(this, args)
+ if (ret === false) {
+ ret = prevRenderer.apply(this, args)
+ }
+ return ret
+ }
+ } else {
+ extensions.renderers[ext.name] = ext.renderer
+ }
+ }
+ if (ext.tokenizer) {
+ // Tokenizer Extensions
+ if (!ext.level || (ext.level !== "block" && ext.level !== "inline")) {
+ throw new Error("extension level must be 'block' or 'inline'")
+ }
+ if (extensions[ext.level]) {
+ extensions[ext.level].unshift(ext.tokenizer)
+ } else {
+ extensions[ext.level] = [ext.tokenizer]
+ }
+ if (ext.start) {
+ // Function to check for start of token
+ if (ext.level === "block") {
+ if (extensions.startBlock) {
+ extensions.startBlock.push(ext.start)
+ } else {
+ extensions.startBlock = [ext.start]
+ }
+ } else if (ext.level === "inline") {
+ if (extensions.startInline) {
+ extensions.startInline.push(ext.start)
+ } else {
+ extensions.startInline = [ext.start]
+ }
+ }
+ }
+ }
+ if (ext.childTokens) {
+ // Child tokens to be visited by walkTokens
+ extensions.childTokens[ext.name] = ext.childTokens
+ }
+ })
+ }
+
+ // ==-- Parse "overwrite" extensions --== //
+ if (pack.renderer) {
+ const renderer = marked.defaults.renderer || new Renderer()
+ for (const prop in pack.renderer) {
+ const prevRenderer = renderer[prop]
+ // Replace renderer with func to run extension, but fall back if false
+ renderer[prop] = (...args) => {
+ let ret = pack.renderer[prop].apply(renderer, args)
+ if (ret === false) {
+ ret = prevRenderer.apply(renderer, args)
+ }
+ return ret
+ }
+ }
+ opts.renderer = renderer
+ }
+ if (pack.tokenizer) {
+ const tokenizer = marked.defaults.tokenizer || new Tokenizer()
+ for (const prop in pack.tokenizer) {
+ const prevTokenizer = tokenizer[prop]
+ // Replace tokenizer with func to run extension, but fall back if false
+ tokenizer[prop] = (...args) => {
+ let ret = pack.tokenizer[prop].apply(tokenizer, args)
+ if (ret === false) {
+ ret = prevTokenizer.apply(tokenizer, args)
+ }
+ return ret
+ }
+ }
+ opts.tokenizer = tokenizer
+ }
+
+ // ==-- Parse WalkTokens extensions --== //
+ if (pack.walkTokens) {
+ const walkTokens = marked.defaults.walkTokens
+ opts.walkTokens = function (token) {
+ pack.walkTokens.call(this, token)
+ if (walkTokens) {
+ walkTokens.call(this, token)
+ }
+ }
+ }
+
+ if (hasExtensions) {
+ opts.extensions = extensions
+ }
+
+ marked.setOptions(opts)
+ })
+}
+
+/**
+ * Run callback for every token
+ */
+
+marked.walkTokens = function (tokens, callback) {
+ for (const token of tokens) {
+ callback.call(marked, token)
+ switch (token.type) {
+ case "table": {
+ for (const cell of token.header) {
+ marked.walkTokens(cell.tokens, callback)
+ }
+ for (const row of token.rows) {
+ for (const cell of row) {
+ marked.walkTokens(cell.tokens, callback)
+ }
+ }
+ break
+ }
+ case "list": {
+ marked.walkTokens(token.items, callback)
+ break
+ }
+ default: {
+ if (
+ marked.defaults.extensions &&
+ marked.defaults.extensions.childTokens &&
+ marked.defaults.extensions.childTokens[token.type]
+ ) {
+ // Walk any extensions
+ marked.defaults.extensions.childTokens[token.type].forEach(function (
+ childTokens
+ ) {
+ marked.walkTokens(token[childTokens], callback)
+ })
+ } else if (token.tokens) {
+ marked.walkTokens(token.tokens, callback)
+ }
+ }
+ }
+ }
+}
+
+/**
+ * Parse Inline
+ * @param {string} src
+ */
+marked.parseInline = function (src, opt) {
+ // throw error in case of non string input
+ if (typeof src === "undefined" || src === null) {
+ throw new Error(
+ "marked.parseInline(): input parameter is undefined or null"
+ )
+ }
+ if (typeof src !== "string") {
+ throw new Error(
+ "marked.parseInline(): input parameter is of type " +
+ Object.prototype.toString.call(src) +
+ ", string expected"
+ )
+ }
+
+ opt = merge({}, marked.defaults, opt || {})
+ checkSanitizeDeprecation(opt)
+
+ try {
+ const tokens = Lexer.lexInline(src, opt)
+ if (opt.walkTokens) {
+ marked.walkTokens(tokens, opt.walkTokens)
+ }
+ return Parser.parseInline(tokens, opt)
+ } catch (e) {
+ e.message += "\nPlease report this to https://github.com/markedjs/marked."
+ if (opt.silent) {
+ return (
+ "An error occurred:
" +
+ escape(e.message + "", true) +
+ "
"
+ )
+ }
+ throw e
+ }
+}
+
+/**
+ * Expose
+ */
+marked.Parser = Parser
+marked.parser = Parser.parse
+marked.Renderer = Renderer
+marked.TextRenderer = TextRenderer
+marked.Lexer = Lexer
+marked.lexer = Lexer.lex
+marked.Tokenizer = Tokenizer
+marked.Slugger = Slugger
+marked.parse = marked
+
+const options = marked.options
+const setOptions = marked.setOptions
+const use = marked.use
+const walkTokens = marked.walkTokens
+const parseInline = marked.parseInline
+const parse = marked
+const parser = Parser.parse
+const lexer = Lexer.lex
+
+const email = trigger.row
+return marked(email.Message)
From 43a284283367d78726d3fd43f252eaa5ea085270 Mon Sep 17 00:00:00 2001
From: Adria Navarro
Date: Mon, 19 Feb 2024 21:04:33 +0100
Subject: [PATCH 088/783] Fix defaulting values
---
packages/server/src/jsRunner/vm/isolated-vm.ts | 9 ++++-----
1 file changed, 4 insertions(+), 5 deletions(-)
diff --git a/packages/server/src/jsRunner/vm/isolated-vm.ts b/packages/server/src/jsRunner/vm/isolated-vm.ts
index 12559df0b7..83a7646cfa 100644
--- a/packages/server/src/jsRunner/vm/isolated-vm.ts
+++ b/packages/server/src/jsRunner/vm/isolated-vm.ts
@@ -38,10 +38,9 @@ export class IsolatedVM implements VM {
invocationTimeout?: number
isolateAccumulatedTimeout?: number
} = {}) {
- memoryLimit = memoryLimit || environment.JS_RUNNER_MEMORY_LIMIT
- invocationTimeout = memoryLimit || 1000
-
- this.isolate = new ivm.Isolate({ memoryLimit })
+ this.isolate = new ivm.Isolate({
+ memoryLimit: memoryLimit || environment.JS_RUNNER_MEMORY_LIMIT,
+ })
this.vm = this.isolate.createContextSync()
this.jail = this.vm.global
this.jail.setSync("global", this.jail.derefInto())
@@ -51,7 +50,7 @@ export class IsolatedVM implements VM {
[this.resultKey]: { [this.runResultKey]: "" },
})
- this.invocationTimeout = invocationTimeout
+ this.invocationTimeout = invocationTimeout || 1000
this.isolateAccumulatedTimeout = isolateAccumulatedTimeout
}
From d1e0b37dc21313a65187387afc7d549ef238b539 Mon Sep 17 00:00:00 2001
From: Adria Navarro
Date: Mon, 19 Feb 2024 21:07:45 +0100
Subject: [PATCH 089/783] Remove magic number
---
packages/server/src/jsRunner/vm/isolated-vm.ts | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/packages/server/src/jsRunner/vm/isolated-vm.ts b/packages/server/src/jsRunner/vm/isolated-vm.ts
index 83a7646cfa..f431ff644b 100644
--- a/packages/server/src/jsRunner/vm/isolated-vm.ts
+++ b/packages/server/src/jsRunner/vm/isolated-vm.ts
@@ -50,7 +50,8 @@ export class IsolatedVM implements VM {
[this.resultKey]: { [this.runResultKey]: "" },
})
- this.invocationTimeout = invocationTimeout || 1000
+ this.invocationTimeout =
+ invocationTimeout || environment.JS_PER_INVOCATION_TIMEOUT_MS
this.isolateAccumulatedTimeout = isolateAccumulatedTimeout
}
From 634bf5f8ba7851d58dd8781dc0b124b45bfcb48e Mon Sep 17 00:00:00 2001
From: Budibase Staging Release Bot <>
Date: Mon, 19 Feb 2024 20:26:23 +0000
Subject: [PATCH 090/783] Bump version to 2.20.0
---
lerna.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/lerna.json b/lerna.json
index 62068e25a8..3386214dcf 100644
--- a/lerna.json
+++ b/lerna.json
@@ -1,5 +1,5 @@
{
- "version": "2.19.6",
+ "version": "2.20.0",
"npmClient": "yarn",
"packages": [
"packages/*",
From 335228e8782f9a9e7044c9869250c05d1c2817ba Mon Sep 17 00:00:00 2001
From: Michael Drury
Date: Mon, 19 Feb 2024 21:08:26 +0000
Subject: [PATCH 091/783] isolated VM test cases.
---
.../src/jsRunner/tests/isolatedVM.spec.ts | 53 +++++++++++++++++++
.../src/jsRunner/tests/jsRunner.spec.ts | 21 ++++++++
2 files changed, 74 insertions(+)
diff --git a/packages/server/src/jsRunner/tests/isolatedVM.spec.ts b/packages/server/src/jsRunner/tests/isolatedVM.spec.ts
index 0bd400c8d7..fd26246de5 100644
--- a/packages/server/src/jsRunner/tests/isolatedVM.spec.ts
+++ b/packages/server/src/jsRunner/tests/isolatedVM.spec.ts
@@ -30,4 +30,57 @@ describe("Test isolated vm directly", () => {
})
expect(result).toBe("dddd
\n")
})
+
+ it("handle a mapping case", async () => {
+ const context = {
+ data: {
+ data: {
+ searchProducts: {
+ results: [
+ { imageLinks: ["_S/"] }
+ ]
+ }
+ }
+ }
+ }
+ const result = await compare(`
+ const dataUnnested = data.data.searchProducts.results
+ const emptyLink = "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcRRC3hpq0MXqXssA28Lm5NrzcOYAyr--q3xyg&usqp=CAU"
+ let pImage = emptyLink
+ let sImage = emptyLink
+ let uImage = emptyLink
+ let lImage = emptyLink
+ let b1Image = emptyLink
+ let b2Image = emptyLink
+
+ const dataTransformed = dataUnnested.map(x=> {
+ let imageLinks = x.imageLinks
+ for (let i = 0; i < imageLinks.length; i++){
+ if(imageLinks[i].includes("_P/") || imageLinks[i].includes("_p/")){
+ pImage = imageLinks[i]
+ } else if (imageLinks[i].includes("_S/") || imageLinks[i].includes("_s/")){
+ sImage = imageLinks[i]
+ } else if (imageLinks[i].includes("_U/") || imageLinks[i].includes("_u/")){
+ uImage = imageLinks[i]
+ } else if (imageLinks[i].includes("_L/") || imageLinks[i].includes("_l/")){
+ lImage = imageLinks[i]
+ } else if (imageLinks[i].includes("_B/") || imageLinks[i].includes("_b/")){
+ b1Image = imageLinks[i]
+ } else if (imageLinks[i].includes("_B2/") || imageLinks[i].includes("_b2/")){
+ b2Image = imageLinks[i]
+ }
+ }
+
+ const arrangedLinks = [pImage, sImage, uImage, lImage, b1Image, b2Image]
+ x.imageLinks = arrangedLinks
+
+ return x
+ })
+
+ return dataTransformed
+ `, context)
+ expect(result).toBeDefined()
+ expect(result.length).toBe(1)
+ expect(result[0].imageLinks.length).toBe(6)
+ })
})
diff --git a/packages/server/src/jsRunner/tests/jsRunner.spec.ts b/packages/server/src/jsRunner/tests/jsRunner.spec.ts
index 9bb9052eda..6dc6fd0887 100644
--- a/packages/server/src/jsRunner/tests/jsRunner.spec.ts
+++ b/packages/server/src/jsRunner/tests/jsRunner.spec.ts
@@ -144,5 +144,26 @@ describe("jsRunner (using isolated-vm)", () => {
expect(result).toBeDefined()
expect(result).toBe(3)
})
+
+ it("should handle test case 4", async () => {
+ const context = {
+ "Time Sheets": ["a", "b"]
+ }
+ const result = await processJS(`
+ let hours = 0
+ if (($("[Time Sheets]") != null) == true){
+ for (i = 0; i < $("[Time Sheets]").length; i++){
+ let hoursLogged = "Time Sheets." + i + ".Hours"
+ hours += $(hoursLogged)
+ }
+ return hours
+ }
+ if (($("[Time Sheets]") != null) == false){
+ return hours
+ }
+ `, context)
+ expect(result).toBeDefined()
+ expect(result).toBe("0ab")
+ })
})
})
From f99dbeb2ffe5457a71421ec9c9c3f719750a1f05 Mon Sep 17 00:00:00 2001
From: Martin McKeaveney
Date: Mon, 19 Feb 2024 18:28:43 -0300
Subject: [PATCH 092/783] update pro submodule
---
packages/pro | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/packages/pro b/packages/pro
index aaf7101cd1..32e4d4f946 160000
--- a/packages/pro
+++ b/packages/pro
@@ -1 +1 @@
-Subproject commit aaf7101cd1493215155cc8f83124c70d53eb1be4
+Subproject commit 32e4d4f946c881bd87777d99b17f13ca4a38ea99
From 9443a113ecb4b098b38898105d6f0eaeed0d24e3 Mon Sep 17 00:00:00 2001
From: Martin McKeaveney
Date: Mon, 19 Feb 2024 18:44:58 -0300
Subject: [PATCH 093/783] update reference
---
packages/pro | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/packages/pro b/packages/pro
index 32e4d4f946..7bc9f00fac 160000
--- a/packages/pro
+++ b/packages/pro
@@ -1 +1 @@
-Subproject commit 32e4d4f946c881bd87777d99b17f13ca4a38ea99
+Subproject commit 7bc9f00fac37571b45ca41a034004860bf058cb3
From 2d019ccb6573a89353777de5dd02d26a7b2a551c Mon Sep 17 00:00:00 2001
From: Martin McKeaveney
Date: Mon, 19 Feb 2024 18:46:13 -0300
Subject: [PATCH 094/783] account portal submodule
---
packages/account-portal | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/packages/account-portal b/packages/account-portal
index cc12291732..8c446c4ba3 160000
--- a/packages/account-portal
+++ b/packages/account-portal
@@ -1 +1 @@
-Subproject commit cc12291732ee902dc832bc7d93cf2086ffdf0cff
+Subproject commit 8c446c4ba385592127fa31755d3b64467b291882
From fcea092667dd4a66de371ca4170a0405a64b7e5d Mon Sep 17 00:00:00 2001
From: mike12345567
Date: Tue, 20 Feb 2024 09:30:53 +0000
Subject: [PATCH 095/783] Remove link.
---
packages/server/src/jsRunner/tests/isolatedVM.spec.ts | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/packages/server/src/jsRunner/tests/isolatedVM.spec.ts b/packages/server/src/jsRunner/tests/isolatedVM.spec.ts
index fd26246de5..bd74940dd6 100644
--- a/packages/server/src/jsRunner/tests/isolatedVM.spec.ts
+++ b/packages/server/src/jsRunner/tests/isolatedVM.spec.ts
@@ -45,7 +45,7 @@ describe("Test isolated vm directly", () => {
}
const result = await compare(`
const dataUnnested = data.data.searchProducts.results
- const emptyLink = "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcRRC3hpq0MXqXssA28Lm5NrzcOYAyr--q3xyg&usqp=CAU"
+ const emptyLink = "https://budibase.com"
let pImage = emptyLink
let sImage = emptyLink
let uImage = emptyLink
From ca3f464523f4f57351db2f979c6392da4297756e Mon Sep 17 00:00:00 2001
From: Andrew Kingston
Date: Tue, 20 Feb 2024 10:11:27 +0000
Subject: [PATCH 096/783] Tidy up logic for showing and hiding popovers for
bindings and helpers
---
.../common/CodeEditor/CodeEditor.svelte | 22 ++++-
.../src/components/common/CodeEditor/index.js | 5 +
.../common/bindings/BindingPanel.svelte | 45 +++++++--
.../common/bindings/BindingPicker.svelte | 93 +++++++------------
4 files changed, 91 insertions(+), 74 deletions(-)
diff --git a/packages/builder/src/components/common/CodeEditor/CodeEditor.svelte b/packages/builder/src/components/common/CodeEditor/CodeEditor.svelte
index f4fa762bce..b169cd2f7c 100644
--- a/packages/builder/src/components/common/CodeEditor/CodeEditor.svelte
+++ b/packages/builder/src/components/common/CodeEditor/CodeEditor.svelte
@@ -117,7 +117,7 @@
const indentWithTabCustom = {
key: "Tab",
run: view => {
- if (completionStatus(view.state) == "active") {
+ if (completionStatus(view.state) === "active") {
acceptCompletion(view)
return true
}
@@ -131,7 +131,7 @@
}
const buildKeymap = () => {
- const baseMap = [
+ return [
...closeBracketsKeymap,
...defaultKeymap,
...historyKeymap,
@@ -139,7 +139,6 @@
...completionKeymap,
indentWithTabCustom,
]
- return baseMap
}
const buildBaseExtensions = () => {
@@ -215,7 +214,7 @@
)
}
- if (mode.name == "javascript") {
+ if (mode.name === "javascript") {
complete.push(javascript())
complete.push(highlightWhitespace())
complete.push(lineNumbers())
@@ -321,4 +320,19 @@
border-radius: var(--border-radius-s);
padding: 4px 6px;
}
+
+ .code-editor :global(.binding__example) {
+ padding: 0;
+ margin: 0;
+ font-size: 12px;
+ white-space: pre;
+ text-overflow: ellipsis;
+ overflow: hidden;
+ max-height: 480px;
+ }
+ .code-editor :global(.binding__example span) {
+ overflow: hidden !important;
+ text-overflow: ellipsis !important;
+ white-space: nowrap !important;
+ }
diff --git a/packages/builder/src/components/common/CodeEditor/index.js b/packages/builder/src/components/common/CodeEditor/index.js
index 0d71a475f0..6f55f42169 100644
--- a/packages/builder/src/components/common/CodeEditor/index.js
+++ b/packages/builder/src/components/common/CodeEditor/index.js
@@ -255,6 +255,11 @@ export const buildBindingInfoNode = (completion, binding) => {
const ele = document.createElement("div")
ele.classList.add("info-bubble")
+ if (binding.valueHTML) {
+ ele.innerHTML = `${binding.valueHTML}
`
+ return ele
+ }
+
const exampleNodeHtml = binding.readableBinding
? `{{ ${binding.readableBinding} }}
`
: ""
diff --git a/packages/builder/src/components/common/bindings/BindingPanel.svelte b/packages/builder/src/components/common/bindings/BindingPanel.svelte
index f0ded4a67b..3708f83c61 100644
--- a/packages/builder/src/components/common/bindings/BindingPanel.svelte
+++ b/packages/builder/src/components/common/bindings/BindingPanel.svelte
@@ -62,16 +62,45 @@
let targetMode = null
let expressionResult
+ $: enrichedBindings = enrichBindings(bindings, context)
$: usingJS = mode === "JavaScript"
$: editorMode =
mode === "JavaScript" ? EditorModes.JS : EditorModes.Handlebars
- $: bindingCompletions = bindingsToCompletions(bindings, editorMode)
- $: runtimeExpression = readableToRuntimeBinding(bindings, value)
+ $: bindingCompletions = bindingsToCompletions(enrichedBindings, editorMode)
+ $: runtimeExpression = readableToRuntimeBinding(enrichedBindings, value)
$: expressionResult = processStringSync(runtimeExpression || "", context)
$: bindingHelpers = new BindingHelpers(getCaretPosition, insertAtPos)
+ const getBindingValue = (binding, context) => {
+ const hbs = `{{ literal ${binding.runtimeBinding} }}`
+ const res = processStringSync(hbs, context)
+ return JSON.stringify(res, null, 2)
+ }
+
+ const highlightJSON = json => {
+ return formatHighlight(json, {
+ keyColor: "#e06c75",
+ numberColor: "#e5c07b",
+ stringColor: "#98c379",
+ trueColor: "#d19a66",
+ falseColor: "#d19a66",
+ nullColor: "#c678dd",
+ })
+ }
+
+ const enrichBindings = (bindings, context) => {
+ return bindings.map(binding => {
+ const value = getBindingValue(binding, context)
+ return {
+ ...binding,
+ value,
+ valueHTML: highlightJSON(value),
+ }
+ })
+ }
+
const updateValue = val => {
- const runtimeExpression = readableToRuntimeBinding(bindings, val)
+ const runtimeExpression = readableToRuntimeBinding(enrichedBindings, val)
valid = isValid(runtimeExpression)
if (valid) {
dispatch("change", val)
@@ -116,9 +145,9 @@
}
const convert = () => {
- const runtime = readableToRuntimeBinding(bindings, hbsValue)
+ const runtime = readableToRuntimeBinding(enrichedBindings, hbsValue)
const runtimeJs = encodeJSBinding(convertToJS(runtime))
- jsValue = runtimeToReadableBinding(bindings, runtimeJs)
+ jsValue = runtimeToReadableBinding(enrichedBindings, runtimeJs)
hbsValue = null
mode = "JavaScript"
onSelectBinding("", { forceJS: true })
@@ -143,7 +172,7 @@
}
onMount(() => {
- valid = isValid(readableToRuntimeBinding(bindings, value))
+ valid = isValid(readableToRuntimeBinding(enrichedBindings, value))
})
@@ -261,7 +290,7 @@
{#if sidebar}
{
- const hbs = `{{ literal ${binding.runtimeBinding} }}`
- const res = processStringSync(hbs, context)
- return JSON.stringify(res, null, 2)
+ const showBindingPopover = (binding, target) => {
+ stopHidingPopover()
+ popoverAnchor = target
+ hoverTarget = {
+ code: binding.valueHTML,
+ }
+ popover.show()
}
- const highlight = json => {
- return formatHighlight(json, {
- keyColor: "#e06c75",
- numberColor: "#e5c07b",
- stringColor: "#98c379",
- trueColor: "#d19a66",
- falseColor: "#d19a66",
- nullColor: "#c678dd",
- })
- }
-
- const showPopover = (target, binding) => {
- if (hideTimeout) {
- clearTimeout(hideTimeout)
- hideTimeout = null
+ const showHelperPopover = (helper, target) => {
+ stopHidingPopover()
+ if (!helper.displayText && helper.description) {
+ return
}
- let val = getBindingValue(binding)
- if (val !== "") {
- popoverAnchor = target
- hoverTarget = {
- code: val,
- }
- popover.show()
+ popoverAnchor = target
+ hoverTarget = {
+ description: helper.description,
+ code: getHelperExample(helper, mode.name === "javascript"),
}
+ popover.show()
}
const hidePopover = () => {
@@ -112,7 +102,7 @@
}, 100)
}
- const stopHiding = () => {
+ const stopHidingPopover = () => {
if (hideTimeout) {
clearTimeout(hideTimeout)
hideTimeout = null
@@ -126,9 +116,10 @@
anchor={popoverAnchor}
minWidth={0}
maxWidth={480}
- maxHeight={300}
+ maxHeight={480}
dismissible={false}
- on:mouseenter={stopHiding}
+ on:mouseenter={stopHidingPopover}
+ on:mouseleave={hidePopover}
>
@@ -139,10 +130,8 @@
{/if}
{#if hoverTarget.code}
-
-
- {@html highlight(hoverTarget.code)}
-
+
+ {@html hoverTarget.code}
{/if}
@@ -212,10 +201,8 @@
{#each category.bindings as binding}
showPopover(e.target, binding)}
+ on:mouseenter={e => showBindingPopover(binding, e.target)}
on:mouseleave={hidePopover}
- on:focus={() => {}}
- on:blur={() => {}}
on:click={() => addBinding(binding)}
>
@@ -227,7 +214,6 @@
{binding.readableBinding}
{/if}
-
{#if binding.display?.type || binding.fieldSchema?.type}
@@ -250,26 +236,9 @@
{#each filteredHelpers as helper}
showHelperPopover(helper, e.target)}
+ on:mouseleave={hidePopover}
on:click={() => addHelper(helper, mode.name === "javascript")}
- on:mouseenter={e => {
- popoverAnchor = e.target
- if (!helper.displayText && helper.description) {
- return
- }
- hoverTarget = {
- description: helper.description,
- code: getHelperExample(helper, mode.name === "javascript"),
- }
- popover.show()
- e.stopPropagation()
- }}
- on:mouseleave={() => {
- popover.hide()
- popoverAnchor = null
- hoverTarget = null
- }}
- on:focus={() => {}}
- on:blur={() => {}}
>
{helper.displayText}
@@ -287,16 +256,16 @@
From 686697e890ea4d492601ae809031d9d919c27bda Mon Sep 17 00:00:00 2001
From: Sam Rose
Date: Wed, 21 Feb 2024 11:30:22 +0000
Subject: [PATCH 127/783] Enforce using example.com as a domain for emails.
---
.eslintrc.json | 3 +-
eslint-local-rules/index.js | 37 +++++++++++++++++++
.../core/utilities/structures/accounts.ts | 2 +-
.../tests/core/utilities/structures/scim.ts | 2 +-
.../src/tests/utilities/TestConfiguration.ts | 8 ++--
.../api/routes/global/tests/groups.spec.ts | 2 +-
.../tests/accounts/accounts.cloud.spec.ts | 2 +-
qa-core/src/public-api/fixtures/users.ts | 2 +-
8 files changed, 48 insertions(+), 10 deletions(-)
diff --git a/.eslintrc.json b/.eslintrc.json
index 3de9d13046..ae9512152f 100644
--- a/.eslintrc.json
+++ b/.eslintrc.json
@@ -44,7 +44,8 @@
"no-undef": "off",
"no-prototype-builtins": "off",
"local-rules/no-budibase-imports": "error",
- "local-rules/no-test-com": "error"
+ "local-rules/no-test-com": "error",
+ "local-rules/email-domain-example-com": "error"
}
},
{
diff --git a/eslint-local-rules/index.js b/eslint-local-rules/index.js
index 71bb5068da..177b0a129c 100644
--- a/eslint-local-rules/index.js
+++ b/eslint-local-rules/index.js
@@ -51,4 +51,41 @@ module.exports = {
}
},
},
+ "email-domain-example-com": {
+ meta: {
+ type: "problem",
+ docs: {
+ description:
+ "enforce using the example.com domain for generator.email calls",
+ category: "Possible Errors",
+ recommended: false,
+ },
+ fixable: "code",
+ schema: [],
+ },
+ create: function (context) {
+ return {
+ CallExpression(node) {
+ if (
+ node.callee.type === "MemberExpression" &&
+ node.callee.object.name === "generator" &&
+ node.callee.property.name === "email" &&
+ node.arguments.length === 0
+ ) {
+ context.report({
+ node,
+ message:
+ "Prefer using generator.email with the domain \"{ domain: 'example.com' }\".",
+ fix: function (fixer) {
+ return fixer.replaceText(
+ node,
+ 'generator.email({ domain: "example.com" })'
+ )
+ },
+ })
+ }
+ },
+ }
+ },
+ },
}
diff --git a/packages/backend-core/tests/core/utilities/structures/accounts.ts b/packages/backend-core/tests/core/utilities/structures/accounts.ts
index 515f94db1e..7dcc2de116 100644
--- a/packages/backend-core/tests/core/utilities/structures/accounts.ts
+++ b/packages/backend-core/tests/core/utilities/structures/accounts.ts
@@ -18,7 +18,7 @@ export const account = (partial: Partial = {}): Account => {
return {
accountId: uuid(),
tenantId: generator.word(),
- email: generator.email(),
+ email: generator.email({ domain: "example.com" }),
tenantName: generator.word(),
hosting: Hosting.SELF,
createdAt: Date.now(),
diff --git a/packages/backend-core/tests/core/utilities/structures/scim.ts b/packages/backend-core/tests/core/utilities/structures/scim.ts
index 80f41c605d..f36ccd2374 100644
--- a/packages/backend-core/tests/core/utilities/structures/scim.ts
+++ b/packages/backend-core/tests/core/utilities/structures/scim.ts
@@ -13,7 +13,7 @@ interface CreateUserRequestFields {
export function createUserRequest(userData?: Partial) {
const defaultValues = {
externalId: uuid(),
- email: generator.email(),
+ email: generator.email({ domain: "example.com" }),
firstName: generator.first(),
lastName: generator.last(),
username: generator.name(),
diff --git a/packages/server/src/tests/utilities/TestConfiguration.ts b/packages/server/src/tests/utilities/TestConfiguration.ts
index 8e6ecdfeb1..2e6bbb6290 100644
--- a/packages/server/src/tests/utilities/TestConfiguration.ts
+++ b/packages/server/src/tests/utilities/TestConfiguration.ts
@@ -301,7 +301,7 @@ export default class TestConfiguration {
lastName = generator.last(),
builder = true,
admin = false,
- email = generator.email(),
+ email = generator.email({ domain: "example.com" }),
roles,
} = config
@@ -357,7 +357,7 @@ export default class TestConfiguration {
id,
firstName = generator.first(),
lastName = generator.last(),
- email = generator.email(),
+ email = generator.email({ domain: "example.com" }),
builder = true,
admin,
roles,
@@ -485,7 +485,7 @@ export default class TestConfiguration {
async basicRoleHeaders() {
return await this.roleHeaders({
- email: generator.email(),
+ email: generator.email({ domain: "example.com" }),
builder: false,
prodApp: true,
roleId: roles.BUILTIN_ROLE_IDS.BASIC,
@@ -493,7 +493,7 @@ export default class TestConfiguration {
}
async roleHeaders({
- email = generator.email(),
+ email = generator.email({ domain: "example.com" }),
roleId = roles.BUILTIN_ROLE_IDS.ADMIN,
builder = false,
prodApp = true,
diff --git a/packages/worker/src/api/routes/global/tests/groups.spec.ts b/packages/worker/src/api/routes/global/tests/groups.spec.ts
index 8f0739a812..b69c4781c4 100644
--- a/packages/worker/src/api/routes/global/tests/groups.spec.ts
+++ b/packages/worker/src/api/routes/global/tests/groups.spec.ts
@@ -147,7 +147,7 @@ describe("/api/global/groups", () => {
await Promise.all(
Array.from({ length: 30 }).map(async (_, i) => {
- const email = `user${i}@${generator.domain()}`
+ const email = `user${i}@example.com`
const user = await config.api.users.saveUser({
...structures.users.user(),
email,
diff --git a/qa-core/src/account-api/tests/accounts/accounts.cloud.spec.ts b/qa-core/src/account-api/tests/accounts/accounts.cloud.spec.ts
index 0969b72cf9..01338b609c 100644
--- a/qa-core/src/account-api/tests/accounts/accounts.cloud.spec.ts
+++ b/qa-core/src/account-api/tests/accounts/accounts.cloud.spec.ts
@@ -84,7 +84,7 @@ describe("Accounts", () => {
})
it("searches by email", async () => {
- const email = generator.email()
+ const email = generator.email({ domain: "example.com" })
// Empty result
const [_, emptyBody] = await config.api.accounts.search(email, "email")
diff --git a/qa-core/src/public-api/fixtures/users.ts b/qa-core/src/public-api/fixtures/users.ts
index e20c464b34..418b565d2a 100644
--- a/qa-core/src/public-api/fixtures/users.ts
+++ b/qa-core/src/public-api/fixtures/users.ts
@@ -4,7 +4,7 @@ import { generator } from "../../shared"
export const generateUser = (
overrides: Partial = {}
): CreateUserParams => ({
- email: generator.email(),
+ email: generator.email({ domain: "example.com" }),
roles: {
[generator.string({ length: 32, alpha: true, numeric: true })]:
generator.word(),
From f417c2d8a4d96cc958ecb3a35281030cfe6c1f2c Mon Sep 17 00:00:00 2001
From: Joe <49767913+joebudi@users.noreply.github.com>
Date: Wed, 21 Feb 2024 13:28:35 +0000
Subject: [PATCH 128/783] Joe's lab day minor updates (#12944)
* Change default button type to CTA
- change default button type to CTA
- change ordering of types/variants
* Fix layout shift within portal
Within the portal, when navigating from screen to screen, there's a slight layout shift caused by the scrollbar. This is a small fix.
* row/column icons change
The current row/column icons for positioning components are confusing. I believe these icons are easier to understand.
* Fix for horizontal scrollbar showing
When adding/removing actions within automations, the horizontal scrollbar flashes. Fix.
* Title change for Upload data
Upload data is not wrong, but it's best to be explicit.
* Increase size of upgrade button
* small fix for the styling inconsistency
* Dianostics padding fix
* lint fix
* update account-portal
* update icons
---------
Co-authored-by: melohagan <101575380+melohagan@users.noreply.github.com>
Co-authored-by: Mel O'Hagan
---
packages/bbui/src/Layout/Page.svelte | 1 +
packages/bbui/src/Typography/Body.svelte | 6 +++++
packages/bbui/src/Typography/Heading.svelte | 4 +++
.../FlowChart/FlowChart.svelte | 1 +
.../builder/app/[application]/data/new.svelte | 2 +-
.../portal/_components/UpgradeButton.svelte | 4 +--
.../portal/settings/diagnostics.svelte | 9 ++++---
packages/client/manifest.json | 26 +++++++++----------
.../client/src/components/app/Button.svelte | 2 +-
9 files changed, 35 insertions(+), 20 deletions(-)
diff --git a/packages/bbui/src/Layout/Page.svelte b/packages/bbui/src/Layout/Page.svelte
index 57c264231b..2169a12459 100644
--- a/packages/bbui/src/Layout/Page.svelte
+++ b/packages/bbui/src/Layout/Page.svelte
@@ -43,6 +43,7 @@
flex-direction: row;
justify-content: flex-start;
align-items: stretch;
+ overflow-y: scroll !important;
flex: 1 1 auto;
overflow-x: hidden;
}
diff --git a/packages/bbui/src/Typography/Body.svelte b/packages/bbui/src/Typography/Body.svelte
index 71b4dca248..2123eeee95 100644
--- a/packages/bbui/src/Typography/Body.svelte
+++ b/packages/bbui/src/Typography/Body.svelte
@@ -20,3 +20,9 @@
>
+
+
diff --git a/packages/bbui/src/Typography/Heading.svelte b/packages/bbui/src/Typography/Heading.svelte
index c0d0571143..50522fffc3 100644
--- a/packages/bbui/src/Typography/Heading.svelte
+++ b/packages/bbui/src/Typography/Heading.svelte
@@ -21,4 +21,8 @@
h1 {
font-family: var(--font-accent);
}
+
+ h1 {
+ text-wrap: balance;
+ }
diff --git a/packages/builder/src/components/automation/AutomationBuilder/FlowChart/FlowChart.svelte b/packages/builder/src/components/automation/AutomationBuilder/FlowChart/FlowChart.svelte
index 4c458a5627..1ace6c0f00 100644
--- a/packages/builder/src/components/automation/AutomationBuilder/FlowChart/FlowChart.svelte
+++ b/packages/builder/src/components/automation/AutomationBuilder/FlowChart/FlowChart.svelte
@@ -130,6 +130,7 @@
flex-grow: 1;
padding: 23px 23px 80px;
box-sizing: border-box;
+ overflow-x: hidden;
}
.header.scrolling {
diff --git a/packages/builder/src/pages/builder/app/[application]/data/new.svelte b/packages/builder/src/pages/builder/app/[application]/data/new.svelte
index c07a9f563d..20efd3667b 100644
--- a/packages/builder/src/pages/builder/app/[application]/data/new.svelte
+++ b/packages/builder/src/pages/builder/app/[application]/data/new.svelte
@@ -77,7 +77,7 @@
internalTableModal.show({ promptUpload: true })}
- title="Upload data"
+ title="Upload CSV / JSON"
description="Non-relational"
{disabled}
>
diff --git a/packages/builder/src/pages/builder/portal/_components/UpgradeButton.svelte b/packages/builder/src/pages/builder/portal/_components/UpgradeButton.svelte
index b12efd6f03..59a791538a 100644
--- a/packages/builder/src/pages/builder/portal/_components/UpgradeButton.svelte
+++ b/packages/builder/src/pages/builder/portal/_components/UpgradeButton.svelte
@@ -10,7 +10,7 @@
{#if $admin.cloud && $auth?.user?.accountPortalAccess}