@budibase/backend-core 2.8.21 → 2.8.22-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 +4 -3
- package/dist/src/auth/auth.js.map +1 -1
- package/dist/src/cache/user.js.map +1 -1
- package/dist/src/constants/misc.d.ts +2 -0
- package/dist/src/constants/misc.js +2 -0
- package/dist/src/constants/misc.js.map +1 -1
- package/dist/src/db/searchIndexes/searchIndexes.js.map +1 -1
- package/dist/src/environment.d.ts +5 -3
- package/dist/src/environment.js +13 -70
- package/dist/src/environment.js.map +1 -1
- package/dist/src/logging/index.d.ts +1 -1
- package/dist/src/logging/index.js +2 -3
- package/dist/src/logging/index.js.map +1 -1
- package/dist/src/logging/pino/logger.js +40 -24
- package/dist/src/logging/pino/logger.js.map +1 -1
- package/dist/src/logging/system.d.ts +9 -0
- package/dist/src/logging/system.js +101 -0
- package/dist/src/logging/system.js.map +1 -0
- package/dist/src/users.js.map +1 -1
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/package.json +4 -3
- package/src/auth/auth.ts +1 -1
- package/src/cache/user.ts +1 -1
- package/src/constants/misc.ts +2 -0
- package/src/db/searchIndexes/searchIndexes.ts +1 -1
- package/src/environment.ts +12 -4
- package/src/logging/index.ts +1 -3
- package/src/logging/pino/logger.ts +45 -24
- package/src/logging/system.ts +81 -0
- package/src/logging/tests/system.spec.ts +61 -0
- package/src/users.ts +2 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@budibase/backend-core",
|
|
3
|
-
"version": "2.8.
|
|
3
|
+
"version": "2.8.22-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",
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
"dependencies": {
|
|
23
23
|
"@budibase/nano": "10.1.2",
|
|
24
24
|
"@budibase/pouchdb-replication-stream": "1.2.10",
|
|
25
|
-
"@budibase/types": "2.8.
|
|
25
|
+
"@budibase/types": "2.8.22-alpha.0",
|
|
26
26
|
"@shopify/jest-koa-mocks": "5.0.1",
|
|
27
27
|
"@techpass/passport-openidconnect": "0.3.2",
|
|
28
28
|
"aws-cloudfront-sign": "2.2.0",
|
|
@@ -51,6 +51,7 @@
|
|
|
51
51
|
"pouchdb": "7.3.0",
|
|
52
52
|
"pouchdb-find": "7.2.2",
|
|
53
53
|
"redlock": "4.2.0",
|
|
54
|
+
"rotating-file-stream": "3.1.0",
|
|
54
55
|
"sanitize-s3-objectkey": "0.0.1",
|
|
55
56
|
"semver": "7.3.7",
|
|
56
57
|
"tar-fs": "2.1.1",
|
|
@@ -101,5 +102,5 @@
|
|
|
101
102
|
}
|
|
102
103
|
}
|
|
103
104
|
},
|
|
104
|
-
"gitHead": "
|
|
105
|
+
"gitHead": "b05edd62d8d719eb4e2de30d32ecb3e5fa0b1aa7"
|
|
105
106
|
}
|
package/src/auth/auth.ts
CHANGED
|
@@ -159,7 +159,7 @@ export async function updateUserOAuth(userId: string, oAuthConfig: any) {
|
|
|
159
159
|
|
|
160
160
|
try {
|
|
161
161
|
const db = getGlobalDB()
|
|
162
|
-
const dbUser = await db.get(userId)
|
|
162
|
+
const dbUser = await db.get<any>(userId)
|
|
163
163
|
|
|
164
164
|
//Do not overwrite the refresh token if a valid one is not provided.
|
|
165
165
|
if (typeof details.refreshToken !== "string") {
|
package/src/cache/user.ts
CHANGED
|
@@ -12,7 +12,7 @@ const EXPIRY_SECONDS = 3600
|
|
|
12
12
|
*/
|
|
13
13
|
async function populateFromDB(userId: string, tenantId: string) {
|
|
14
14
|
const db = tenancy.getTenantDB(tenantId)
|
|
15
|
-
const user = await db.get(userId)
|
|
15
|
+
const user = await db.get<any>(userId)
|
|
16
16
|
user.budibaseAccess = true
|
|
17
17
|
if (!env.SELF_HOSTED && !env.DISABLE_ACCOUNT_PORTAL) {
|
|
18
18
|
const account = await accounts.getAccount(user.email)
|
package/src/constants/misc.ts
CHANGED
|
@@ -20,6 +20,8 @@ export enum Header {
|
|
|
20
20
|
TYPE = "x-budibase-type",
|
|
21
21
|
PREVIEW_ROLE = "x-budibase-role",
|
|
22
22
|
TENANT_ID = "x-budibase-tenant-id",
|
|
23
|
+
VERIFICATION_CODE = "x-budibase-verification-code",
|
|
24
|
+
RETURN_VERIFICATION_CODE = "x-budibase-return-verification-code",
|
|
23
25
|
TOKEN = "x-budibase-token",
|
|
24
26
|
CSRF_TOKEN = "x-csrf-token",
|
|
25
27
|
CORRELATION_ID = "x-budibase-correlation-id",
|
|
@@ -5,7 +5,7 @@ export async function createUserIndex() {
|
|
|
5
5
|
const db = getGlobalDB()
|
|
6
6
|
let designDoc
|
|
7
7
|
try {
|
|
8
|
-
designDoc = await db.get("_design/database")
|
|
8
|
+
designDoc = await db.get<any>("_design/database")
|
|
9
9
|
} catch (err: any) {
|
|
10
10
|
if (err.status === 404) {
|
|
11
11
|
designDoc = { _id: "_design/database" }
|
package/src/environment.ts
CHANGED
|
@@ -47,7 +47,10 @@ function httpLogging() {
|
|
|
47
47
|
return process.env.HTTP_LOGGING
|
|
48
48
|
}
|
|
49
49
|
|
|
50
|
-
function
|
|
50
|
+
function getPackageJsonFields(): {
|
|
51
|
+
VERSION: string
|
|
52
|
+
SERVICE_NAME: string
|
|
53
|
+
} {
|
|
51
54
|
function findFileInAncestors(
|
|
52
55
|
fileName: string,
|
|
53
56
|
currentDir: string
|
|
@@ -69,10 +72,14 @@ function findVersion() {
|
|
|
69
72
|
try {
|
|
70
73
|
const packageJsonFile = findFileInAncestors("package.json", process.cwd())
|
|
71
74
|
const content = readFileSync(packageJsonFile!, "utf-8")
|
|
72
|
-
|
|
75
|
+
const parsedContent = JSON.parse(content)
|
|
76
|
+
return {
|
|
77
|
+
VERSION: parsedContent.version,
|
|
78
|
+
SERVICE_NAME: parsedContent.name,
|
|
79
|
+
}
|
|
73
80
|
} catch {
|
|
74
81
|
// throwing an error here is confusing/causes backend-core to be hard to import
|
|
75
|
-
return
|
|
82
|
+
return { VERSION: "", SERVICE_NAME: "" }
|
|
76
83
|
}
|
|
77
84
|
}
|
|
78
85
|
|
|
@@ -154,13 +161,14 @@ const environment = {
|
|
|
154
161
|
ENABLE_SSO_MAINTENANCE_MODE: selfHosted
|
|
155
162
|
? process.env.ENABLE_SSO_MAINTENANCE_MODE
|
|
156
163
|
: false,
|
|
157
|
-
|
|
164
|
+
...getPackageJsonFields(),
|
|
158
165
|
DISABLE_PINO_LOGGER: process.env.DISABLE_PINO_LOGGER,
|
|
159
166
|
_set(key: any, value: any) {
|
|
160
167
|
process.env[key] = value
|
|
161
168
|
// @ts-ignore
|
|
162
169
|
environment[key] = value
|
|
163
170
|
},
|
|
171
|
+
ROLLING_LOG_MAX_SIZE: process.env.ROLLING_LOG_MAX_SIZE || "10M",
|
|
164
172
|
}
|
|
165
173
|
|
|
166
174
|
// clean up any environment variable edge cases
|
package/src/logging/index.ts
CHANGED
|
@@ -1,37 +1,60 @@
|
|
|
1
|
-
import env from "../../environment"
|
|
2
1
|
import pino, { LoggerOptions } from "pino"
|
|
2
|
+
import pinoPretty from "pino-pretty"
|
|
3
|
+
|
|
4
|
+
import { IdentityType } from "@budibase/types"
|
|
5
|
+
import env from "../../environment"
|
|
3
6
|
import * as context from "../../context"
|
|
4
7
|
import * as correlation from "../correlation"
|
|
5
|
-
|
|
6
|
-
import {
|
|
8
|
+
|
|
9
|
+
import { localFileDestination } from "../system"
|
|
7
10
|
|
|
8
11
|
// LOGGER
|
|
9
12
|
|
|
10
13
|
let pinoInstance: pino.Logger | undefined
|
|
11
14
|
if (!env.DISABLE_PINO_LOGGER) {
|
|
15
|
+
const level = env.LOG_LEVEL
|
|
12
16
|
const pinoOptions: LoggerOptions = {
|
|
13
|
-
level
|
|
17
|
+
level,
|
|
14
18
|
formatters: {
|
|
15
|
-
level:
|
|
16
|
-
return { level:
|
|
19
|
+
level: level => {
|
|
20
|
+
return { level: level.toUpperCase() }
|
|
17
21
|
},
|
|
18
22
|
bindings: () => {
|
|
19
|
-
|
|
23
|
+
if (env.SELF_HOSTED) {
|
|
24
|
+
// "service" is being injected in datadog using the pod names,
|
|
25
|
+
// so we should leave it blank to allow the default behaviour if it's not running self-hosted
|
|
26
|
+
return {
|
|
27
|
+
service: env.SERVICE_NAME,
|
|
28
|
+
}
|
|
29
|
+
} else {
|
|
30
|
+
return {}
|
|
31
|
+
}
|
|
20
32
|
},
|
|
21
33
|
},
|
|
22
34
|
timestamp: () => `,"timestamp":"${new Date(Date.now()).toISOString()}"`,
|
|
23
35
|
}
|
|
24
36
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
37
|
+
const destinations: pino.StreamEntry[] = []
|
|
38
|
+
|
|
39
|
+
destinations.push(
|
|
40
|
+
env.isDev()
|
|
41
|
+
? {
|
|
42
|
+
stream: pinoPretty({ singleLine: true }),
|
|
43
|
+
level: level as pino.Level,
|
|
44
|
+
}
|
|
45
|
+
: { stream: process.stdout, level: level as pino.Level }
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
if (env.SELF_HOSTED) {
|
|
49
|
+
destinations.push({
|
|
50
|
+
stream: localFileDestination(),
|
|
51
|
+
level: level as pino.Level,
|
|
52
|
+
})
|
|
32
53
|
}
|
|
33
54
|
|
|
34
|
-
pinoInstance =
|
|
55
|
+
pinoInstance = destinations.length
|
|
56
|
+
? pino(pinoOptions, pino.multistream(destinations))
|
|
57
|
+
: pino(pinoOptions)
|
|
35
58
|
|
|
36
59
|
// CONSOLE OVERRIDES
|
|
37
60
|
|
|
@@ -83,15 +106,13 @@ if (!env.DISABLE_PINO_LOGGER) {
|
|
|
83
106
|
|
|
84
107
|
let contextObject = {}
|
|
85
108
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
correlationId: correlation.getId(),
|
|
94
|
-
}
|
|
109
|
+
contextObject = {
|
|
110
|
+
tenantId: getTenantId(),
|
|
111
|
+
appId: getAppId(),
|
|
112
|
+
automationId: getAutomationId(),
|
|
113
|
+
identityId: identity?._id,
|
|
114
|
+
identityType: identity?.type,
|
|
115
|
+
correlationId: correlation.getId(),
|
|
95
116
|
}
|
|
96
117
|
|
|
97
118
|
const mergingObject: any = {
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import fs from "fs"
|
|
2
|
+
import path from "path"
|
|
3
|
+
import * as rfs from "rotating-file-stream"
|
|
4
|
+
|
|
5
|
+
import env from "../environment"
|
|
6
|
+
import { budibaseTempDir } from "../objectStore"
|
|
7
|
+
|
|
8
|
+
const logsFileName = `budibase.log`
|
|
9
|
+
const budibaseLogsHistoryFileName = "budibase-logs-history.txt"
|
|
10
|
+
|
|
11
|
+
const logsPath = path.join(budibaseTempDir(), "systemlogs")
|
|
12
|
+
|
|
13
|
+
function getFullPath(fileName: string) {
|
|
14
|
+
return path.join(logsPath, fileName)
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export function getSingleFileMaxSizeInfo(totalMaxSize: string) {
|
|
18
|
+
const regex = /(\d+)([A-Za-z])/
|
|
19
|
+
const match = totalMaxSize?.match(regex)
|
|
20
|
+
if (!match) {
|
|
21
|
+
console.warn(`totalMaxSize does not have a valid value`, {
|
|
22
|
+
totalMaxSize,
|
|
23
|
+
})
|
|
24
|
+
return undefined
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const size = +match[1]
|
|
28
|
+
const unit = match[2]
|
|
29
|
+
if (size === 1) {
|
|
30
|
+
switch (unit) {
|
|
31
|
+
case "B":
|
|
32
|
+
return { size: `${size}B`, totalHistoryFiles: 1 }
|
|
33
|
+
case "K":
|
|
34
|
+
return { size: `${(size * 1000) / 2}B`, totalHistoryFiles: 1 }
|
|
35
|
+
case "M":
|
|
36
|
+
return { size: `${(size * 1000) / 2}K`, totalHistoryFiles: 1 }
|
|
37
|
+
case "G":
|
|
38
|
+
return { size: `${(size * 1000) / 2}M`, totalHistoryFiles: 1 }
|
|
39
|
+
default:
|
|
40
|
+
return undefined
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
if (size % 2 === 0) {
|
|
45
|
+
return { size: `${size / 2}${unit}`, totalHistoryFiles: 1 }
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
return { size: `1${unit}`, totalHistoryFiles: size - 1 }
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export function localFileDestination() {
|
|
52
|
+
const fileInfo = getSingleFileMaxSizeInfo(env.ROLLING_LOG_MAX_SIZE)
|
|
53
|
+
const outFile = rfs.createStream(logsFileName, {
|
|
54
|
+
// As we have a rolling size, we want to half the max size
|
|
55
|
+
size: fileInfo?.size,
|
|
56
|
+
path: logsPath,
|
|
57
|
+
maxFiles: fileInfo?.totalHistoryFiles || 1,
|
|
58
|
+
immutable: true,
|
|
59
|
+
history: budibaseLogsHistoryFileName,
|
|
60
|
+
initialRotation: false,
|
|
61
|
+
})
|
|
62
|
+
|
|
63
|
+
return outFile
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export function getLogReadStream() {
|
|
67
|
+
const streams = []
|
|
68
|
+
const historyFile = getFullPath(budibaseLogsHistoryFileName)
|
|
69
|
+
if (fs.existsSync(historyFile)) {
|
|
70
|
+
const fileContent = fs.readFileSync(historyFile, "utf-8")
|
|
71
|
+
const historyFiles = fileContent.split("\n")
|
|
72
|
+
for (const historyFile of historyFiles.filter(x => x)) {
|
|
73
|
+
streams.push(fs.readFileSync(historyFile))
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
streams.push(fs.readFileSync(getFullPath(logsFileName)))
|
|
78
|
+
|
|
79
|
+
const combinedContent = Buffer.concat(streams)
|
|
80
|
+
return combinedContent
|
|
81
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { getSingleFileMaxSizeInfo } from "../system"
|
|
2
|
+
|
|
3
|
+
describe("system", () => {
|
|
4
|
+
describe("getSingleFileMaxSizeInfo", () => {
|
|
5
|
+
it.each([
|
|
6
|
+
["100B", "50B"],
|
|
7
|
+
["200K", "100K"],
|
|
8
|
+
["20M", "10M"],
|
|
9
|
+
["4G", "2G"],
|
|
10
|
+
])(
|
|
11
|
+
"Halving even number (%s) returns halved size and 1 history file (%s)",
|
|
12
|
+
(totalValue, expectedMaxSize) => {
|
|
13
|
+
const result = getSingleFileMaxSizeInfo(totalValue)
|
|
14
|
+
expect(result).toEqual({
|
|
15
|
+
size: expectedMaxSize,
|
|
16
|
+
totalHistoryFiles: 1,
|
|
17
|
+
})
|
|
18
|
+
}
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
it.each([
|
|
22
|
+
["5B", "1B", 4],
|
|
23
|
+
["17K", "1K", 16],
|
|
24
|
+
["21M", "1M", 20],
|
|
25
|
+
["3G", "1G", 2],
|
|
26
|
+
])(
|
|
27
|
+
"Halving an odd number (%s) returns as many files as size (-1) (%s)",
|
|
28
|
+
(totalValue, expectedMaxSize, totalHistoryFiles) => {
|
|
29
|
+
const result = getSingleFileMaxSizeInfo(totalValue)
|
|
30
|
+
expect(result).toEqual({
|
|
31
|
+
size: expectedMaxSize,
|
|
32
|
+
totalHistoryFiles,
|
|
33
|
+
})
|
|
34
|
+
}
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
it.each([
|
|
38
|
+
["1B", "1B"],
|
|
39
|
+
["1K", "500B"],
|
|
40
|
+
["1M", "500K"],
|
|
41
|
+
["1G", "500M"],
|
|
42
|
+
])(
|
|
43
|
+
"Halving '%s' returns halved unit (%s)",
|
|
44
|
+
(totalValue, expectedMaxSize) => {
|
|
45
|
+
const result = getSingleFileMaxSizeInfo(totalValue)
|
|
46
|
+
expect(result).toEqual({
|
|
47
|
+
size: expectedMaxSize,
|
|
48
|
+
totalHistoryFiles: 1,
|
|
49
|
+
})
|
|
50
|
+
}
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
it.each([[undefined], [""], ["50"], ["wrongvalue"]])(
|
|
54
|
+
"Halving wrongly formatted value ('%s') returns undefined",
|
|
55
|
+
totalValue => {
|
|
56
|
+
const result = getSingleFileMaxSizeInfo(totalValue!)
|
|
57
|
+
expect(result).toBeUndefined()
|
|
58
|
+
}
|
|
59
|
+
)
|
|
60
|
+
})
|
|
61
|
+
})
|
package/src/users.ts
CHANGED
|
@@ -67,9 +67,9 @@ export const bulkUpdateGlobalUsers = async (users: User[]) => {
|
|
|
67
67
|
|
|
68
68
|
export async function getById(id: string, opts?: GetOpts): Promise<User> {
|
|
69
69
|
const db = context.getGlobalDB()
|
|
70
|
-
let user = await db.get(id)
|
|
70
|
+
let user = await db.get<User>(id)
|
|
71
71
|
if (opts?.cleanup) {
|
|
72
|
-
user = removeUserPassword(user)
|
|
72
|
+
user = removeUserPassword(user) as User
|
|
73
73
|
}
|
|
74
74
|
return user
|
|
75
75
|
}
|