@budibase/backend-core 2.6.18 → 2.6.19-alpha.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/package.json +3 -5
- package/dist/src/constants/db.d.ts +1 -1
- package/dist/src/constants/db.js +1 -1
- package/dist/src/db/couch/DatabaseImpl.d.ts +1 -0
- package/dist/src/db/couch/DatabaseImpl.js +8 -3
- package/dist/src/db/couch/DatabaseImpl.js.map +1 -1
- package/dist/src/db/couch/connections.js +11 -10
- package/dist/src/db/couch/connections.js.map +1 -1
- package/dist/src/db/couch/utils.d.ts +6 -0
- package/dist/src/db/couch/utils.js +9 -3
- package/dist/src/db/couch/utils.js.map +1 -1
- package/dist/src/logging/pino/logger.js +25 -1
- package/dist/src/logging/pino/logger.js.map +1 -1
- package/dist/src/queue/listeners.js +12 -3
- package/dist/src/queue/listeners.js.map +1 -1
- package/dist/src/utils/utils.d.ts +3 -0
- package/dist/src/utils/utils.js +17 -3
- package/dist/src/utils/utils.js.map +1 -1
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/package.json +3 -5
- package/src/constants/db.ts +1 -1
- package/src/db/couch/DatabaseImpl.ts +10 -4
- package/src/db/couch/connections.ts +8 -8
- package/src/db/couch/utils.ts +15 -1
- package/src/logging/pino/logger.ts +27 -2
- package/src/queue/listeners.ts +13 -2
- package/src/utils/tests/utils.spec.ts +82 -0
- package/src/utils/utils.ts +18 -10
- package/tsconfig.json +3 -8
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@budibase/backend-core",
|
|
3
|
-
"version": "2.6.
|
|
3
|
+
"version": "2.6.19-alpha.0",
|
|
4
4
|
"description": "Budibase backend core libraries used in server and worker",
|
|
5
5
|
"main": "dist/src/index.js",
|
|
6
6
|
"types": "dist/src/index.d.ts",
|
|
@@ -15,8 +15,6 @@
|
|
|
15
15
|
"prebuild": "rimraf dist/",
|
|
16
16
|
"prepack": "cp package.json dist",
|
|
17
17
|
"build": "tsc -p tsconfig.build.json",
|
|
18
|
-
"build:pro": "../../scripts/pro/build.sh",
|
|
19
|
-
"postbuild": "yarn run build:pro",
|
|
20
18
|
"build:dev": "yarn prebuild && tsc --build --watch --preserveWatchOutput",
|
|
21
19
|
"test": "bash scripts/test.sh",
|
|
22
20
|
"test:watch": "jest --watchAll"
|
|
@@ -24,7 +22,7 @@
|
|
|
24
22
|
"dependencies": {
|
|
25
23
|
"@budibase/nano": "10.1.2",
|
|
26
24
|
"@budibase/pouchdb-replication-stream": "1.2.10",
|
|
27
|
-
"@budibase/types": "
|
|
25
|
+
"@budibase/types": "2.6.19-alpha.0",
|
|
28
26
|
"@shopify/jest-koa-mocks": "5.0.1",
|
|
29
27
|
"@techpass/passport-openidconnect": "0.3.2",
|
|
30
28
|
"aws-cloudfront-sign": "2.2.0",
|
|
@@ -90,5 +88,5 @@
|
|
|
90
88
|
"tsconfig-paths": "4.0.0",
|
|
91
89
|
"typescript": "4.7.3"
|
|
92
90
|
},
|
|
93
|
-
"gitHead": "
|
|
91
|
+
"gitHead": "82e867c0f5b41fe3af88333effeb88f29b8b4d23"
|
|
94
92
|
}
|
package/src/constants/db.ts
CHANGED
|
@@ -21,7 +21,7 @@ export enum ViewName {
|
|
|
21
21
|
AUTOMATION_LOGS = "automation_logs",
|
|
22
22
|
ACCOUNT_BY_EMAIL = "account_by_email",
|
|
23
23
|
PLATFORM_USERS_LOWERCASE = "platform_users_lowercase",
|
|
24
|
-
USER_BY_GROUP = "
|
|
24
|
+
USER_BY_GROUP = "user_by_group",
|
|
25
25
|
APP_BACKUP_BY_TRIGGER = "by_trigger",
|
|
26
26
|
}
|
|
27
27
|
|
|
@@ -12,7 +12,7 @@ import {
|
|
|
12
12
|
isDocument,
|
|
13
13
|
} from "@budibase/types"
|
|
14
14
|
import { getCouchInfo } from "./connections"
|
|
15
|
-
import {
|
|
15
|
+
import { directCouchUrlCall } from "./utils"
|
|
16
16
|
import { getPouchDB } from "./pouchDB"
|
|
17
17
|
import { WriteStream, ReadStream } from "fs"
|
|
18
18
|
import { newid } from "../../docIds/newid"
|
|
@@ -46,6 +46,8 @@ export class DatabaseImpl implements Database {
|
|
|
46
46
|
private readonly instanceNano?: Nano.ServerScope
|
|
47
47
|
private readonly pouchOpts: DatabaseOpts
|
|
48
48
|
|
|
49
|
+
private readonly couchInfo = getCouchInfo()
|
|
50
|
+
|
|
49
51
|
constructor(dbName?: string, opts?: DatabaseOpts, connection?: string) {
|
|
50
52
|
if (dbName == null) {
|
|
51
53
|
throw new Error("Database name cannot be undefined.")
|
|
@@ -53,8 +55,8 @@ export class DatabaseImpl implements Database {
|
|
|
53
55
|
this.name = dbName
|
|
54
56
|
this.pouchOpts = opts || {}
|
|
55
57
|
if (connection) {
|
|
56
|
-
|
|
57
|
-
this.instanceNano = buildNano(couchInfo)
|
|
58
|
+
this.couchInfo = getCouchInfo(connection)
|
|
59
|
+
this.instanceNano = buildNano(this.couchInfo)
|
|
58
60
|
}
|
|
59
61
|
if (!DatabaseImpl.nano) {
|
|
60
62
|
DatabaseImpl.init()
|
|
@@ -67,7 +69,11 @@ export class DatabaseImpl implements Database {
|
|
|
67
69
|
}
|
|
68
70
|
|
|
69
71
|
async exists() {
|
|
70
|
-
|
|
72
|
+
const response = await directCouchUrlCall({
|
|
73
|
+
url: `${this.couchInfo.url}/${this.name}`,
|
|
74
|
+
method: "HEAD",
|
|
75
|
+
cookie: this.couchInfo.cookie,
|
|
76
|
+
})
|
|
71
77
|
return response.status === 200
|
|
72
78
|
}
|
|
73
79
|
|
|
@@ -4,21 +4,21 @@ export const getCouchInfo = (connection?: string) => {
|
|
|
4
4
|
const urlInfo = getUrlInfo(connection)
|
|
5
5
|
let username
|
|
6
6
|
let password
|
|
7
|
-
if (
|
|
8
|
-
// set from env
|
|
9
|
-
username = env.COUCH_DB_USERNAME
|
|
10
|
-
} else if (urlInfo.auth.username) {
|
|
7
|
+
if (urlInfo.auth?.username) {
|
|
11
8
|
// set from url
|
|
12
9
|
username = urlInfo.auth.username
|
|
10
|
+
} else if (env.COUCH_DB_USERNAME) {
|
|
11
|
+
// set from env
|
|
12
|
+
username = env.COUCH_DB_USERNAME
|
|
13
13
|
} else if (!env.isTest()) {
|
|
14
14
|
throw new Error("CouchDB username not set")
|
|
15
15
|
}
|
|
16
|
-
if (
|
|
17
|
-
// set from env
|
|
18
|
-
password = env.COUCH_DB_PASSWORD
|
|
19
|
-
} else if (urlInfo.auth.password) {
|
|
16
|
+
if (urlInfo.auth?.password) {
|
|
20
17
|
// set from url
|
|
21
18
|
password = urlInfo.auth.password
|
|
19
|
+
} else if (env.COUCH_DB_PASSWORD) {
|
|
20
|
+
// set from env
|
|
21
|
+
password = env.COUCH_DB_PASSWORD
|
|
22
22
|
} else if (!env.isTest()) {
|
|
23
23
|
throw new Error("CouchDB password not set")
|
|
24
24
|
}
|
package/src/db/couch/utils.ts
CHANGED
|
@@ -9,6 +9,20 @@ export async function directCouchCall(
|
|
|
9
9
|
) {
|
|
10
10
|
let { url, cookie } = getCouchInfo()
|
|
11
11
|
const couchUrl = `${url}/${path}`
|
|
12
|
+
return await directCouchUrlCall({ url: couchUrl, cookie, method, body })
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export async function directCouchUrlCall({
|
|
16
|
+
url,
|
|
17
|
+
cookie,
|
|
18
|
+
method,
|
|
19
|
+
body,
|
|
20
|
+
}: {
|
|
21
|
+
url: string
|
|
22
|
+
cookie: string
|
|
23
|
+
method: string
|
|
24
|
+
body?: any
|
|
25
|
+
}) {
|
|
12
26
|
const params: any = {
|
|
13
27
|
method: method,
|
|
14
28
|
headers: {
|
|
@@ -19,7 +33,7 @@ export async function directCouchCall(
|
|
|
19
33
|
params.body = JSON.stringify(body)
|
|
20
34
|
params.headers["Content-Type"] = "application/json"
|
|
21
35
|
}
|
|
22
|
-
return await fetch(checkSlashesInUrl(encodeURI(
|
|
36
|
+
return await fetch(checkSlashesInUrl(encodeURI(url)), params)
|
|
23
37
|
}
|
|
24
38
|
|
|
25
39
|
export async function directCouchQuery(
|
|
@@ -94,12 +94,37 @@ if (!env.DISABLE_PINO_LOGGER) {
|
|
|
94
94
|
}
|
|
95
95
|
}
|
|
96
96
|
|
|
97
|
-
const mergingObject = {
|
|
98
|
-
objects: objects.length ? objects : undefined,
|
|
97
|
+
const mergingObject: any = {
|
|
99
98
|
err: error,
|
|
100
99
|
...contextObject,
|
|
101
100
|
}
|
|
102
101
|
|
|
102
|
+
if (objects.length) {
|
|
103
|
+
// init generic data object for params supplied that don't have a
|
|
104
|
+
// '_logKey' field. This prints an object using argument index as the key
|
|
105
|
+
// e.g. { 0: {}, 1: {} }
|
|
106
|
+
const data: any = {}
|
|
107
|
+
let dataIndex = 0
|
|
108
|
+
|
|
109
|
+
for (let i = 0; i < objects.length; i++) {
|
|
110
|
+
const object = objects[i]
|
|
111
|
+
// the object has specified a log key
|
|
112
|
+
// use this instead of generic key
|
|
113
|
+
const logKey = object._logKey
|
|
114
|
+
if (logKey) {
|
|
115
|
+
delete object._logKey
|
|
116
|
+
mergingObject[logKey] = object
|
|
117
|
+
} else {
|
|
118
|
+
data[dataIndex] = object
|
|
119
|
+
dataIndex++
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
if (Object.keys(data).length) {
|
|
124
|
+
mergingObject.data = data
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
103
128
|
return [mergingObject, message]
|
|
104
129
|
}
|
|
105
130
|
|
package/src/queue/listeners.ts
CHANGED
|
@@ -45,7 +45,8 @@ function getLogParams(
|
|
|
45
45
|
const message = `[BULL] ${eventType}=${event}`
|
|
46
46
|
const err = opts.error
|
|
47
47
|
|
|
48
|
-
const
|
|
48
|
+
const bullLog = {
|
|
49
|
+
_logKey: "bull",
|
|
49
50
|
eventType,
|
|
50
51
|
event,
|
|
51
52
|
job: opts.job,
|
|
@@ -53,7 +54,17 @@ function getLogParams(
|
|
|
53
54
|
...extra,
|
|
54
55
|
}
|
|
55
56
|
|
|
56
|
-
|
|
57
|
+
let automationLog
|
|
58
|
+
if (opts.job?.data?.automation) {
|
|
59
|
+
automationLog = {
|
|
60
|
+
_logKey: "automation",
|
|
61
|
+
trigger: opts.job
|
|
62
|
+
? opts.job.data.automation.definition.trigger.event
|
|
63
|
+
: undefined,
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
return [message, err, bullLog, automationLog]
|
|
57
68
|
}
|
|
58
69
|
|
|
59
70
|
enum BullEvent {
|
|
@@ -5,6 +5,7 @@ import * as db from "../../db"
|
|
|
5
5
|
import { Header } from "../../constants"
|
|
6
6
|
import { newid } from "../../utils"
|
|
7
7
|
import env from "../../environment"
|
|
8
|
+
import { BBContext } from "@budibase/types"
|
|
8
9
|
|
|
9
10
|
describe("utils", () => {
|
|
10
11
|
const config = new DBTestConfiguration()
|
|
@@ -106,4 +107,85 @@ describe("utils", () => {
|
|
|
106
107
|
expect(actual).toBe(undefined)
|
|
107
108
|
})
|
|
108
109
|
})
|
|
110
|
+
|
|
111
|
+
describe("isServingBuilder", () => {
|
|
112
|
+
let ctx: BBContext
|
|
113
|
+
|
|
114
|
+
const expectResult = (result: boolean) =>
|
|
115
|
+
expect(utils.isServingBuilder(ctx)).toBe(result)
|
|
116
|
+
|
|
117
|
+
beforeEach(() => {
|
|
118
|
+
ctx = structures.koa.newContext()
|
|
119
|
+
})
|
|
120
|
+
|
|
121
|
+
it("returns true if current path is in builder", async () => {
|
|
122
|
+
ctx.path = "/builder/app/app_"
|
|
123
|
+
expectResult(true)
|
|
124
|
+
})
|
|
125
|
+
|
|
126
|
+
it("returns false if current path doesn't have '/' suffix", async () => {
|
|
127
|
+
ctx.path = "/builder/app"
|
|
128
|
+
expectResult(false)
|
|
129
|
+
|
|
130
|
+
ctx.path = "/xx"
|
|
131
|
+
expectResult(false)
|
|
132
|
+
})
|
|
133
|
+
})
|
|
134
|
+
|
|
135
|
+
describe("isServingBuilderPreview", () => {
|
|
136
|
+
let ctx: BBContext
|
|
137
|
+
|
|
138
|
+
const expectResult = (result: boolean) =>
|
|
139
|
+
expect(utils.isServingBuilderPreview(ctx)).toBe(result)
|
|
140
|
+
|
|
141
|
+
beforeEach(() => {
|
|
142
|
+
ctx = structures.koa.newContext()
|
|
143
|
+
})
|
|
144
|
+
|
|
145
|
+
it("returns true if current path is in builder preview", async () => {
|
|
146
|
+
ctx.path = "/app/preview/xx"
|
|
147
|
+
expectResult(true)
|
|
148
|
+
})
|
|
149
|
+
|
|
150
|
+
it("returns false if current path is not in builder preview", async () => {
|
|
151
|
+
ctx.path = "/builder"
|
|
152
|
+
expectResult(false)
|
|
153
|
+
|
|
154
|
+
ctx.path = "/xx"
|
|
155
|
+
expectResult(false)
|
|
156
|
+
})
|
|
157
|
+
})
|
|
158
|
+
|
|
159
|
+
describe("isPublicAPIRequest", () => {
|
|
160
|
+
let ctx: BBContext
|
|
161
|
+
|
|
162
|
+
const expectResult = (result: boolean) =>
|
|
163
|
+
expect(utils.isPublicApiRequest(ctx)).toBe(result)
|
|
164
|
+
|
|
165
|
+
beforeEach(() => {
|
|
166
|
+
ctx = structures.koa.newContext()
|
|
167
|
+
})
|
|
168
|
+
|
|
169
|
+
it("returns true if current path remains to public API", async () => {
|
|
170
|
+
ctx.path = "/api/public/v1/invoices"
|
|
171
|
+
expectResult(true)
|
|
172
|
+
|
|
173
|
+
ctx.path = "/api/public/v1"
|
|
174
|
+
expectResult(true)
|
|
175
|
+
|
|
176
|
+
ctx.path = "/api/public/v2"
|
|
177
|
+
expectResult(true)
|
|
178
|
+
|
|
179
|
+
ctx.path = "/api/public/v21"
|
|
180
|
+
expectResult(true)
|
|
181
|
+
})
|
|
182
|
+
|
|
183
|
+
it("returns false if current path doesn't remain to public API", async () => {
|
|
184
|
+
ctx.path = "/api/public"
|
|
185
|
+
expectResult(false)
|
|
186
|
+
|
|
187
|
+
ctx.path = "/xx"
|
|
188
|
+
expectResult(false)
|
|
189
|
+
})
|
|
190
|
+
})
|
|
109
191
|
})
|
package/src/utils/utils.ts
CHANGED
|
@@ -1,11 +1,5 @@
|
|
|
1
|
-
import { getAllApps
|
|
2
|
-
import {
|
|
3
|
-
Header,
|
|
4
|
-
MAX_VALID_DATE,
|
|
5
|
-
DocumentType,
|
|
6
|
-
SEPARATOR,
|
|
7
|
-
ViewName,
|
|
8
|
-
} from "../constants"
|
|
1
|
+
import { getAllApps } from "../db"
|
|
2
|
+
import { Header, MAX_VALID_DATE, DocumentType, SEPARATOR } from "../constants"
|
|
9
3
|
import env from "../environment"
|
|
10
4
|
import * as tenancy from "../tenancy"
|
|
11
5
|
import * as context from "../context"
|
|
@@ -23,7 +17,9 @@ const APP_PREFIX = DocumentType.APP + SEPARATOR
|
|
|
23
17
|
const PROD_APP_PREFIX = "/app/"
|
|
24
18
|
|
|
25
19
|
const BUILDER_PREVIEW_PATH = "/app/preview"
|
|
26
|
-
const
|
|
20
|
+
const BUILDER_PREFIX = "/builder"
|
|
21
|
+
const BUILDER_APP_PREFIX = `${BUILDER_PREFIX}/app/`
|
|
22
|
+
const PUBLIC_API_PREFIX = "/api/public/v"
|
|
27
23
|
|
|
28
24
|
function confirmAppId(possibleAppId: string | undefined) {
|
|
29
25
|
return possibleAppId && possibleAppId.startsWith(APP_PREFIX)
|
|
@@ -69,6 +65,18 @@ export function isServingApp(ctx: Ctx) {
|
|
|
69
65
|
return false
|
|
70
66
|
}
|
|
71
67
|
|
|
68
|
+
export function isServingBuilder(ctx: Ctx): boolean {
|
|
69
|
+
return ctx.path.startsWith(BUILDER_APP_PREFIX)
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export function isServingBuilderPreview(ctx: Ctx): boolean {
|
|
73
|
+
return ctx.path.startsWith(BUILDER_PREVIEW_PATH)
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export function isPublicApiRequest(ctx: Ctx): boolean {
|
|
77
|
+
return ctx.path.startsWith(PUBLIC_API_PREFIX)
|
|
78
|
+
}
|
|
79
|
+
|
|
72
80
|
/**
|
|
73
81
|
* Given a request tries to find the appId, which can be located in various places
|
|
74
82
|
* @param {object} ctx The main request body to look through.
|
|
@@ -110,7 +118,7 @@ export async function getAppIdFromCtx(ctx: Ctx) {
|
|
|
110
118
|
// make sure this is performed after prod app url resolution, in case the
|
|
111
119
|
// referer header is present from a builder redirect
|
|
112
120
|
const referer = ctx.request.headers.referer
|
|
113
|
-
if (!appId && referer?.includes(
|
|
121
|
+
if (!appId && referer?.includes(BUILDER_APP_PREFIX)) {
|
|
114
122
|
const refererId = parseAppIdFromUrl(ctx.request.headers.referer)
|
|
115
123
|
appId = confirmAppId(refererId)
|
|
116
124
|
}
|