@budibase/backend-core 2.32.13 → 2.32.15
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/index.js +50 -35
- package/dist/index.js.map +4 -4
- package/dist/index.js.meta.json +1 -1
- package/dist/package.json +4 -4
- package/dist/plugins.js.meta.json +1 -1
- package/dist/src/context/mainContext.d.ts +2 -0
- package/dist/src/context/mainContext.js +9 -0
- package/dist/src/context/mainContext.js.map +1 -1
- package/dist/src/context/types.d.ts +1 -0
- package/dist/src/db/couch/DatabaseImpl.d.ts +1 -0
- package/dist/src/db/couch/DatabaseImpl.js +5 -3
- package/dist/src/db/couch/DatabaseImpl.js.map +1 -1
- package/dist/src/features/features.d.ts +3 -4
- package/dist/src/features/features.js +23 -32
- package/dist/src/features/features.js.map +1 -1
- package/dist/src/index.d.ts +2 -0
- package/dist/src/middleware/index.d.ts +1 -0
- package/dist/src/middleware/index.js +3 -1
- package/dist/src/middleware/index.js.map +1 -1
- package/dist/src/middleware/ip.d.ts +3 -0
- package/dist/src/middleware/ip.js +23 -0
- package/dist/src/middleware/ip.js.map +1 -0
- package/package.json +4 -4
- package/src/context/mainContext.ts +9 -0
- package/src/context/types.ts +1 -0
- package/src/db/couch/DatabaseImpl.ts +8 -4
- package/src/features/features.ts +25 -47
- package/src/features/tests/features.spec.ts +59 -31
- package/src/middleware/index.ts +1 -0
- package/src/middleware/ip.ts +12 -0
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { PostHogOptions } from "posthog-node";
|
|
2
|
-
import { UserCtx } from "@budibase/types";
|
|
3
2
|
export declare function init(opts?: PostHogOptions): void;
|
|
4
3
|
export declare function shutdown(): void;
|
|
5
4
|
export declare abstract class Flag<T> {
|
|
@@ -31,9 +30,9 @@ export declare class FlagSet<V extends Flag<any>, T extends {
|
|
|
31
30
|
constructor(flagSchema: T);
|
|
32
31
|
defaults(): FlagValues<T>;
|
|
33
32
|
isFlagName(name: string | number | symbol): name is keyof T;
|
|
34
|
-
get<K extends keyof T>(key: K
|
|
35
|
-
isEnabled<K extends KeysOfType<T, boolean>>(key: K
|
|
36
|
-
fetch(
|
|
33
|
+
get<K extends keyof T>(key: K): Promise<FlagValues<T>[K]>;
|
|
34
|
+
isEnabled<K extends KeysOfType<T, boolean>>(key: K): Promise<boolean>;
|
|
35
|
+
fetch(): Promise<FlagValues<T>>;
|
|
37
36
|
}
|
|
38
37
|
export declare const flags: FlagSet<Flag<any>, {
|
|
39
38
|
DEFAULT_VALUES: Flag<boolean>;
|
|
@@ -40,6 +40,7 @@ exports.init = init;
|
|
|
40
40
|
exports.shutdown = shutdown;
|
|
41
41
|
exports.parseEnvFlags = parseEnvFlags;
|
|
42
42
|
const environment_1 = __importDefault(require("../environment"));
|
|
43
|
+
const crypto = __importStar(require("crypto"));
|
|
43
44
|
const context = __importStar(require("../context"));
|
|
44
45
|
const posthog_node_1 = require("posthog-node");
|
|
45
46
|
const types_1 = require("@budibase/types");
|
|
@@ -139,22 +140,22 @@ class FlagSet {
|
|
|
139
140
|
isFlagName(name) {
|
|
140
141
|
return this.flagSchema[name] !== undefined;
|
|
141
142
|
}
|
|
142
|
-
get(key
|
|
143
|
+
get(key) {
|
|
143
144
|
return __awaiter(this, void 0, void 0, function* () {
|
|
144
|
-
const flags = yield this.fetch(
|
|
145
|
+
const flags = yield this.fetch();
|
|
145
146
|
return flags[key];
|
|
146
147
|
});
|
|
147
148
|
}
|
|
148
|
-
isEnabled(key
|
|
149
|
+
isEnabled(key) {
|
|
149
150
|
return __awaiter(this, void 0, void 0, function* () {
|
|
150
|
-
const flags = yield this.fetch(
|
|
151
|
+
const flags = yield this.fetch();
|
|
151
152
|
return flags[key];
|
|
152
153
|
});
|
|
153
154
|
}
|
|
154
|
-
fetch(
|
|
155
|
+
fetch() {
|
|
155
156
|
return __awaiter(this, void 0, void 0, function* () {
|
|
156
157
|
return yield dd_trace_1.default.trace("features.fetch", (span) => __awaiter(this, void 0, void 0, function* () {
|
|
157
|
-
var _a
|
|
158
|
+
var _a;
|
|
158
159
|
const cachedFlags = context.getFeatureFlags(this.setId);
|
|
159
160
|
if (cachedFlags) {
|
|
160
161
|
span === null || span === void 0 ? void 0 : span.addTags({ fromCache: true });
|
|
@@ -184,36 +185,26 @@ class FlagSet {
|
|
|
184
185
|
flagValues[key] = value;
|
|
185
186
|
tags[`flags.${key}.source`] = "environment";
|
|
186
187
|
}
|
|
187
|
-
const
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
}
|
|
194
|
-
if (flagValues[feature] === true ||
|
|
195
|
-
specificallySetFalse.has(feature)) {
|
|
196
|
-
// If the flag is already set to through environment variables, we
|
|
197
|
-
// don't want to override it back to false here.
|
|
198
|
-
continue;
|
|
199
|
-
}
|
|
200
|
-
// @ts-expect-error - TS does not like you writing into a generic type,
|
|
201
|
-
// but we know that it's okay in this case because it's just an object.
|
|
202
|
-
flagValues[feature] = true;
|
|
203
|
-
tags[`flags.${feature}.source`] = "license";
|
|
188
|
+
const identity = context.getIdentity();
|
|
189
|
+
let userId = identity === null || identity === void 0 ? void 0 : identity._id;
|
|
190
|
+
if (!userId) {
|
|
191
|
+
const ip = context.getIP();
|
|
192
|
+
if (ip) {
|
|
193
|
+
userId = crypto.createHash("sha512").update(ip).digest("hex");
|
|
204
194
|
}
|
|
205
195
|
}
|
|
206
|
-
|
|
196
|
+
let tenantId = identity === null || identity === void 0 ? void 0 : identity.tenantId;
|
|
197
|
+
if (!tenantId) {
|
|
198
|
+
tenantId = currentTenantId;
|
|
199
|
+
}
|
|
207
200
|
tags[`identity.type`] = identity === null || identity === void 0 ? void 0 : identity.type;
|
|
208
|
-
tags[`identity.tenantId`] = identity === null || identity === void 0 ? void 0 : identity.tenantId;
|
|
209
201
|
tags[`identity._id`] = identity === null || identity === void 0 ? void 0 : identity._id;
|
|
210
|
-
|
|
202
|
+
tags[`tenantId`] = tenantId;
|
|
203
|
+
tags[`userId`] = userId;
|
|
204
|
+
if (posthog && userId) {
|
|
211
205
|
tags[`readFromPostHog`] = true;
|
|
212
|
-
const personProperties = {};
|
|
213
|
-
|
|
214
|
-
personProperties.tenantId = identity.tenantId;
|
|
215
|
-
}
|
|
216
|
-
const posthogFlags = yield posthog.getAllFlagsAndPayloads(identity._id, {
|
|
206
|
+
const personProperties = { tenantId };
|
|
207
|
+
const posthogFlags = yield posthog.getAllFlagsAndPayloads(userId, {
|
|
217
208
|
personProperties,
|
|
218
209
|
});
|
|
219
210
|
for (const [name, value] of Object.entries(posthogFlags.featureFlags)) {
|
|
@@ -228,7 +219,7 @@ class FlagSet {
|
|
|
228
219
|
// don't want to override it back to false here.
|
|
229
220
|
continue;
|
|
230
221
|
}
|
|
231
|
-
const payload = (
|
|
222
|
+
const payload = (_a = posthogFlags.featureFlagPayloads) === null || _a === void 0 ? void 0 : _a[name];
|
|
232
223
|
const flag = this.flagSchema[name];
|
|
233
224
|
try {
|
|
234
225
|
// @ts-expect-error - TS does not like you writing into a generic
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"features.js","sourceRoot":"","sources":["../../../src/features/features.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"features.js","sourceRoot":"","sources":["../../../src/features/features.ts"],"names":[],"mappings":"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"}
|
package/dist/src/index.d.ts
CHANGED
|
@@ -61,8 +61,10 @@ export declare const tenancy: {
|
|
|
61
61
|
getTenantId(): string;
|
|
62
62
|
getAutomationId(): string | undefined;
|
|
63
63
|
getAppId(): string | undefined;
|
|
64
|
+
getIP(): string | undefined;
|
|
64
65
|
doInEnvironmentContext(values: Record<string, string>, task: any): Promise<unknown>;
|
|
65
66
|
doInScimContext(task: any): Promise<unknown>;
|
|
67
|
+
doInIPContext(ip: string, task: any): Promise<unknown>;
|
|
66
68
|
ensureSnippetContext(enabled?: boolean): Promise<void>;
|
|
67
69
|
getEnvironmentVariables(): Record<string, string> | null;
|
|
68
70
|
getGlobalDB(): import("@budibase/types").Database;
|
|
@@ -19,3 +19,4 @@ export { default as correlation } from "../logging/correlation/middleware";
|
|
|
19
19
|
export { default as errorHandling } from "./errorHandling";
|
|
20
20
|
export { default as querystringToBody } from "./querystringToBody";
|
|
21
21
|
export * as joiValidator from "./joi-validator";
|
|
22
|
+
export { default as ip } from "./ip";
|
|
@@ -26,7 +26,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
26
26
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
27
27
|
};
|
|
28
28
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
29
|
-
exports.joiValidator = exports.querystringToBody = exports.errorHandling = exports.correlation = exports.pino = exports.builderOnly = exports.builderOrAdmin = exports.adminOnly = exports.csrf = exports.internalApi = exports.tenancy = exports.auditLog = exports.authenticated = exports.ssoCallbackUrl = exports.authError = exports.datasource = exports.oidc = exports.google = exports.local = void 0;
|
|
29
|
+
exports.ip = exports.joiValidator = exports.querystringToBody = exports.errorHandling = exports.correlation = exports.pino = exports.builderOnly = exports.builderOrAdmin = exports.adminOnly = exports.csrf = exports.internalApi = exports.tenancy = exports.auditLog = exports.authenticated = exports.ssoCallbackUrl = exports.authError = exports.datasource = exports.oidc = exports.google = exports.local = void 0;
|
|
30
30
|
exports.local = __importStar(require("./passport/local"));
|
|
31
31
|
exports.google = __importStar(require("./passport/sso/google"));
|
|
32
32
|
exports.oidc = __importStar(require("./passport/sso/oidc"));
|
|
@@ -62,4 +62,6 @@ Object.defineProperty(exports, "errorHandling", { enumerable: true, get: functio
|
|
|
62
62
|
var querystringToBody_1 = require("./querystringToBody");
|
|
63
63
|
Object.defineProperty(exports, "querystringToBody", { enumerable: true, get: function () { return __importDefault(querystringToBody_1).default; } });
|
|
64
64
|
exports.joiValidator = __importStar(require("./joi-validator"));
|
|
65
|
+
var ip_1 = require("./ip");
|
|
66
|
+
Object.defineProperty(exports, "ip", { enumerable: true, get: function () { return __importDefault(ip_1).default; } });
|
|
65
67
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/middleware/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,0DAAyC;AACzC,gEAA+C;AAC/C,4DAA2C;AAC3C,+EAAgE;AAEnD,QAAA,UAAU,GAAG;IACxB,MAAM,EAAE,gBAAgB;CACzB,CAAA;AACD,0CAA4D;AAAnD,kGAAA,SAAS,OAAA;AAAE,uGAAA,cAAc,OAAA;AAClC,iDAA0D;AAAjD,+HAAA,OAAO,OAAiB;AACjC,uCAAgD;AAAvC,qHAAA,OAAO,OAAY;AAC5B,qCAA8C;AAArC,mHAAA,OAAO,OAAW;AAC3B,6CAAsD;AAA7C,2HAAA,OAAO,OAAe;AAC/B,+BAAwC;AAA/B,6GAAA,OAAO,OAAQ;AACxB,yCAAkD;AAAzC,uHAAA,OAAO,OAAa;AAC7B,mDAA4D;AAAnD,iIAAA,OAAO,OAAkB;AAClC,6CAAsD;AAA7C,2HAAA,OAAO,OAAe;AAC/B,yDAA4D;AAAnD,mHAAA,OAAO,OAAQ;AACxB,gEAA0E;AAAjE,0HAAA,OAAO,OAAe;AAC/B,iDAA0D;AAAjD,+HAAA,OAAO,OAAiB;AACjC,yDAAkE;AAAzD,uIAAA,OAAO,OAAqB;AACrC,gEAA+C"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/middleware/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,0DAAyC;AACzC,gEAA+C;AAC/C,4DAA2C;AAC3C,+EAAgE;AAEnD,QAAA,UAAU,GAAG;IACxB,MAAM,EAAE,gBAAgB;CACzB,CAAA;AACD,0CAA4D;AAAnD,kGAAA,SAAS,OAAA;AAAE,uGAAA,cAAc,OAAA;AAClC,iDAA0D;AAAjD,+HAAA,OAAO,OAAiB;AACjC,uCAAgD;AAAvC,qHAAA,OAAO,OAAY;AAC5B,qCAA8C;AAArC,mHAAA,OAAO,OAAW;AAC3B,6CAAsD;AAA7C,2HAAA,OAAO,OAAe;AAC/B,+BAAwC;AAA/B,6GAAA,OAAO,OAAQ;AACxB,yCAAkD;AAAzC,uHAAA,OAAO,OAAa;AAC7B,mDAA4D;AAAnD,iIAAA,OAAO,OAAkB;AAClC,6CAAsD;AAA7C,2HAAA,OAAO,OAAe;AAC/B,yDAA4D;AAAnD,mHAAA,OAAO,OAAQ;AACxB,gEAA0E;AAAjE,0HAAA,OAAO,OAAe;AAC/B,iDAA0D;AAAjD,+HAAA,OAAO,OAAiB;AACjC,yDAAkE;AAAzD,uIAAA,OAAO,OAAqB;AACrC,gEAA+C;AAC/C,2BAAoC;AAA3B,yGAAA,OAAO,OAAM"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
const context_1 = require("../context");
|
|
13
|
+
exports.default = (ctx, next) => __awaiter(void 0, void 0, void 0, function* () {
|
|
14
|
+
if (ctx.ip) {
|
|
15
|
+
return yield (0, context_1.doInIPContext)(ctx.ip, () => {
|
|
16
|
+
return next();
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
else {
|
|
20
|
+
return next();
|
|
21
|
+
}
|
|
22
|
+
});
|
|
23
|
+
//# sourceMappingURL=ip.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ip.js","sourceRoot":"","sources":["../../../src/middleware/ip.ts"],"names":[],"mappings":";;;;;;;;;;;AACA,wCAA0C;AAE1C,kBAAe,CAAO,GAAQ,EAAE,IAAS,EAAE,EAAE;IAC3C,IAAI,GAAG,CAAC,EAAE,EAAE,CAAC;QACX,OAAO,MAAM,IAAA,uBAAa,EAAC,GAAG,CAAC,EAAE,EAAE,GAAG,EAAE;YACtC,OAAO,IAAI,EAAE,CAAA;QACf,CAAC,CAAC,CAAA;IACJ,CAAC;SAAM,CAAC;QACN,OAAO,IAAI,EAAE,CAAA;IACf,CAAC;AACH,CAAC,CAAA,CAAA"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@budibase/backend-core",
|
|
3
|
-
"version": "2.32.
|
|
3
|
+
"version": "2.32.15",
|
|
4
4
|
"description": "Budibase backend core libraries used in server and worker",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/src/index.d.ts",
|
|
@@ -23,8 +23,8 @@
|
|
|
23
23
|
"dependencies": {
|
|
24
24
|
"@budibase/nano": "10.1.5",
|
|
25
25
|
"@budibase/pouchdb-replication-stream": "1.2.11",
|
|
26
|
-
"@budibase/shared-core": "2.32.
|
|
27
|
-
"@budibase/types": "2.32.
|
|
26
|
+
"@budibase/shared-core": "2.32.15",
|
|
27
|
+
"@budibase/types": "2.32.15",
|
|
28
28
|
"aws-cloudfront-sign": "3.0.2",
|
|
29
29
|
"aws-sdk": "2.1030.0",
|
|
30
30
|
"bcrypt": "5.1.0",
|
|
@@ -95,5 +95,5 @@
|
|
|
95
95
|
}
|
|
96
96
|
}
|
|
97
97
|
},
|
|
98
|
-
"gitHead": "
|
|
98
|
+
"gitHead": "6de055ea381e66939d0e9ddd7e3431d07a1c20e8"
|
|
99
99
|
}
|
|
@@ -253,6 +253,11 @@ export function getAppId(): string | undefined {
|
|
|
253
253
|
}
|
|
254
254
|
}
|
|
255
255
|
|
|
256
|
+
export function getIP(): string | undefined {
|
|
257
|
+
const context = Context.get()
|
|
258
|
+
return context?.ip
|
|
259
|
+
}
|
|
260
|
+
|
|
256
261
|
export const getProdAppId = () => {
|
|
257
262
|
const appId = getAppId()
|
|
258
263
|
if (!appId) {
|
|
@@ -281,6 +286,10 @@ export function doInScimContext(task: any) {
|
|
|
281
286
|
return newContext(updates, task)
|
|
282
287
|
}
|
|
283
288
|
|
|
289
|
+
export function doInIPContext(ip: string, task: any) {
|
|
290
|
+
return newContext({ ip }, task)
|
|
291
|
+
}
|
|
292
|
+
|
|
284
293
|
export async function ensureSnippetContext(enabled = !env.isTest()) {
|
|
285
294
|
const ctx = getCurrentContext()
|
|
286
295
|
|
package/src/context/types.ts
CHANGED
|
@@ -213,17 +213,21 @@ export class DatabaseImpl implements Database {
|
|
|
213
213
|
|
|
214
214
|
async getMultiple<T extends Document>(
|
|
215
215
|
ids: string[],
|
|
216
|
-
opts?: { allowMissing?: boolean }
|
|
216
|
+
opts?: { allowMissing?: boolean; excludeDocs?: boolean }
|
|
217
217
|
): Promise<T[]> {
|
|
218
218
|
// get unique
|
|
219
219
|
ids = [...new Set(ids)]
|
|
220
|
+
const includeDocs = !opts?.excludeDocs
|
|
220
221
|
const response = await this.allDocs<T>({
|
|
221
222
|
keys: ids,
|
|
222
|
-
include_docs:
|
|
223
|
+
include_docs: includeDocs,
|
|
223
224
|
})
|
|
224
225
|
const rowUnavailable = (row: RowResponse<T>) => {
|
|
225
226
|
// row is deleted - key lookup can return this
|
|
226
|
-
if (
|
|
227
|
+
if (
|
|
228
|
+
(includeDocs && row.doc == null) ||
|
|
229
|
+
(row.value && "deleted" in row.value && row.value.deleted)
|
|
230
|
+
) {
|
|
227
231
|
return true
|
|
228
232
|
}
|
|
229
233
|
return row.error === "not_found"
|
|
@@ -237,7 +241,7 @@ export class DatabaseImpl implements Database {
|
|
|
237
241
|
const missingIds = missing.map(row => row.key).join(", ")
|
|
238
242
|
throw new Error(`Unable to get documents: ${missingIds}`)
|
|
239
243
|
}
|
|
240
|
-
return rows.map(row => row.doc!)
|
|
244
|
+
return rows.map(row => (includeDocs ? row.doc! : row.value))
|
|
241
245
|
}
|
|
242
246
|
|
|
243
247
|
async remove(idOrDoc: string | Document, rev?: string) {
|
package/src/features/features.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import env from "../environment"
|
|
2
|
+
import * as crypto from "crypto"
|
|
2
3
|
import * as context from "../context"
|
|
3
4
|
import { PostHog, PostHogOptions } from "posthog-node"
|
|
4
|
-
import { FeatureFlag
|
|
5
|
+
import { FeatureFlag } from "@budibase/types"
|
|
5
6
|
import tracer from "dd-trace"
|
|
6
7
|
import { Duration } from "../utils"
|
|
7
8
|
|
|
@@ -141,23 +142,17 @@ export class FlagSet<V extends Flag<any>, T extends { [key: string]: V }> {
|
|
|
141
142
|
return this.flagSchema[name as keyof T] !== undefined
|
|
142
143
|
}
|
|
143
144
|
|
|
144
|
-
async get<K extends keyof T>(
|
|
145
|
-
|
|
146
|
-
ctx?: UserCtx
|
|
147
|
-
): Promise<FlagValues<T>[K]> {
|
|
148
|
-
const flags = await this.fetch(ctx)
|
|
145
|
+
async get<K extends keyof T>(key: K): Promise<FlagValues<T>[K]> {
|
|
146
|
+
const flags = await this.fetch()
|
|
149
147
|
return flags[key]
|
|
150
148
|
}
|
|
151
149
|
|
|
152
|
-
async isEnabled<K extends KeysOfType<T, boolean>>(
|
|
153
|
-
|
|
154
|
-
ctx?: UserCtx
|
|
155
|
-
): Promise<boolean> {
|
|
156
|
-
const flags = await this.fetch(ctx)
|
|
150
|
+
async isEnabled<K extends KeysOfType<T, boolean>>(key: K): Promise<boolean> {
|
|
151
|
+
const flags = await this.fetch()
|
|
157
152
|
return flags[key]
|
|
158
153
|
}
|
|
159
154
|
|
|
160
|
-
async fetch(
|
|
155
|
+
async fetch(): Promise<FlagValues<T>> {
|
|
161
156
|
return await tracer.trace("features.fetch", async span => {
|
|
162
157
|
const cachedFlags = context.getFeatureFlags<FlagValues<T>>(this.setId)
|
|
163
158
|
if (cachedFlags) {
|
|
@@ -198,50 +193,33 @@ export class FlagSet<V extends Flag<any>, T extends { [key: string]: V }> {
|
|
|
198
193
|
tags[`flags.${key}.source`] = "environment"
|
|
199
194
|
}
|
|
200
195
|
|
|
201
|
-
const
|
|
202
|
-
if (license) {
|
|
203
|
-
tags[`readFromLicense`] = true
|
|
204
|
-
|
|
205
|
-
for (const feature of license.features) {
|
|
206
|
-
if (!this.isFlagName(feature)) {
|
|
207
|
-
continue
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
if (
|
|
211
|
-
flagValues[feature] === true ||
|
|
212
|
-
specificallySetFalse.has(feature)
|
|
213
|
-
) {
|
|
214
|
-
// If the flag is already set to through environment variables, we
|
|
215
|
-
// don't want to override it back to false here.
|
|
216
|
-
continue
|
|
217
|
-
}
|
|
196
|
+
const identity = context.getIdentity()
|
|
218
197
|
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
198
|
+
let userId = identity?._id
|
|
199
|
+
if (!userId) {
|
|
200
|
+
const ip = context.getIP()
|
|
201
|
+
if (ip) {
|
|
202
|
+
userId = crypto.createHash("sha512").update(ip).digest("hex")
|
|
223
203
|
}
|
|
224
204
|
}
|
|
225
205
|
|
|
226
|
-
|
|
206
|
+
let tenantId = identity?.tenantId
|
|
207
|
+
if (!tenantId) {
|
|
208
|
+
tenantId = currentTenantId
|
|
209
|
+
}
|
|
210
|
+
|
|
227
211
|
tags[`identity.type`] = identity?.type
|
|
228
|
-
tags[`identity.tenantId`] = identity?.tenantId
|
|
229
212
|
tags[`identity._id`] = identity?._id
|
|
213
|
+
tags[`tenantId`] = tenantId
|
|
214
|
+
tags[`userId`] = userId
|
|
230
215
|
|
|
231
|
-
if (posthog &&
|
|
216
|
+
if (posthog && userId) {
|
|
232
217
|
tags[`readFromPostHog`] = true
|
|
233
218
|
|
|
234
|
-
const personProperties: Record<string, string> = {}
|
|
235
|
-
|
|
236
|
-
personProperties
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
const posthogFlags = await posthog.getAllFlagsAndPayloads(
|
|
240
|
-
identity._id,
|
|
241
|
-
{
|
|
242
|
-
personProperties,
|
|
243
|
-
}
|
|
244
|
-
)
|
|
219
|
+
const personProperties: Record<string, string> = { tenantId }
|
|
220
|
+
const posthogFlags = await posthog.getAllFlagsAndPayloads(userId, {
|
|
221
|
+
personProperties,
|
|
222
|
+
})
|
|
245
223
|
|
|
246
224
|
for (const [name, value] of Object.entries(posthogFlags.featureFlags)) {
|
|
247
225
|
if (!this.isFlagName(name)) {
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
import { IdentityContext, IdentityType
|
|
1
|
+
import { IdentityContext, IdentityType } from "@budibase/types"
|
|
2
2
|
import { Flag, FlagSet, FlagValues, init, shutdown } from "../"
|
|
3
3
|
import * as context from "../../context"
|
|
4
4
|
import environment, { withEnv } from "../../environment"
|
|
5
5
|
import nodeFetch from "node-fetch"
|
|
6
6
|
import nock from "nock"
|
|
7
|
+
import * as crypto from "crypto"
|
|
7
8
|
|
|
8
9
|
const schema = {
|
|
9
10
|
TEST_BOOLEAN: Flag.boolean(false),
|
|
@@ -17,7 +18,6 @@ interface TestCase {
|
|
|
17
18
|
identity?: Partial<IdentityContext>
|
|
18
19
|
environmentFlags?: string
|
|
19
20
|
posthogFlags?: PostHogFlags
|
|
20
|
-
licenseFlags?: Array<string>
|
|
21
21
|
expected?: Partial<FlagValues<typeof schema>>
|
|
22
22
|
errorMessage?: string | RegExp
|
|
23
23
|
}
|
|
@@ -27,10 +27,14 @@ interface PostHogFlags {
|
|
|
27
27
|
featureFlagPayloads?: Record<string, string>
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
-
function mockPosthogFlags(
|
|
30
|
+
function mockPosthogFlags(
|
|
31
|
+
flags: PostHogFlags,
|
|
32
|
+
opts?: { token?: string; distinct_id?: string }
|
|
33
|
+
) {
|
|
34
|
+
const { token = "test", distinct_id = "us_1234" } = opts || {}
|
|
31
35
|
nock("https://us.i.posthog.com")
|
|
32
36
|
.post("/decide/?v=3", body => {
|
|
33
|
-
return body.token ===
|
|
37
|
+
return body.token === token && body.distinct_id === distinct_id
|
|
34
38
|
})
|
|
35
39
|
.reply(200, flags)
|
|
36
40
|
.persist()
|
|
@@ -112,17 +116,6 @@ describe("feature flags", () => {
|
|
|
112
116
|
},
|
|
113
117
|
expected: { TEST_BOOLEAN: true },
|
|
114
118
|
},
|
|
115
|
-
{
|
|
116
|
-
it: "should be able to set boolean flags through the license",
|
|
117
|
-
licenseFlags: ["TEST_BOOLEAN"],
|
|
118
|
-
expected: { TEST_BOOLEAN: true },
|
|
119
|
-
},
|
|
120
|
-
{
|
|
121
|
-
it: "should not be able to override a negative environment flag from license",
|
|
122
|
-
environmentFlags: "default:!TEST_BOOLEAN",
|
|
123
|
-
licenseFlags: ["TEST_BOOLEAN"],
|
|
124
|
-
expected: { TEST_BOOLEAN: false },
|
|
125
|
-
},
|
|
126
119
|
{
|
|
127
120
|
it: "should not error on unrecognised PostHog flag",
|
|
128
121
|
posthogFlags: {
|
|
@@ -130,18 +123,12 @@ describe("feature flags", () => {
|
|
|
130
123
|
},
|
|
131
124
|
expected: flags.defaults(),
|
|
132
125
|
},
|
|
133
|
-
{
|
|
134
|
-
it: "should not error on unrecognised license flag",
|
|
135
|
-
licenseFlags: ["UNDEFINED"],
|
|
136
|
-
expected: flags.defaults(),
|
|
137
|
-
},
|
|
138
126
|
])(
|
|
139
127
|
"$it",
|
|
140
128
|
async ({
|
|
141
129
|
identity,
|
|
142
130
|
environmentFlags,
|
|
143
131
|
posthogFlags,
|
|
144
|
-
licenseFlags,
|
|
145
132
|
expected,
|
|
146
133
|
errorMessage,
|
|
147
134
|
}) => {
|
|
@@ -157,8 +144,6 @@ describe("feature flags", () => {
|
|
|
157
144
|
env.POSTHOG_API_HOST = "https://us.i.posthog.com"
|
|
158
145
|
}
|
|
159
146
|
|
|
160
|
-
const ctx = { user: { license: { features: licenseFlags || [] } } }
|
|
161
|
-
|
|
162
147
|
await withEnv(env, async () => {
|
|
163
148
|
// We need to pass in node-fetch here otherwise nock won't get used
|
|
164
149
|
// because posthog-node uses axios under the hood.
|
|
@@ -180,18 +165,13 @@ describe("feature flags", () => {
|
|
|
180
165
|
|
|
181
166
|
await context.doInIdentityContext(fullIdentity, async () => {
|
|
182
167
|
if (errorMessage) {
|
|
183
|
-
await expect(flags.fetch(
|
|
184
|
-
errorMessage
|
|
185
|
-
)
|
|
168
|
+
await expect(flags.fetch()).rejects.toThrow(errorMessage)
|
|
186
169
|
} else if (expected) {
|
|
187
|
-
const values = await flags.fetch(
|
|
170
|
+
const values = await flags.fetch()
|
|
188
171
|
expect(values).toMatchObject(expected)
|
|
189
172
|
|
|
190
173
|
for (const [key, expectedValue] of Object.entries(expected)) {
|
|
191
|
-
const value = await flags.get(
|
|
192
|
-
key as keyof typeof schema,
|
|
193
|
-
ctx as UserCtx
|
|
194
|
-
)
|
|
174
|
+
const value = await flags.get(key as keyof typeof schema)
|
|
195
175
|
expect(value).toBe(expectedValue)
|
|
196
176
|
}
|
|
197
177
|
} else {
|
|
@@ -214,6 +194,14 @@ describe("feature flags", () => {
|
|
|
214
194
|
lastName: "User",
|
|
215
195
|
}
|
|
216
196
|
|
|
197
|
+
// We need to pass in node-fetch here otherwise nock won't get used
|
|
198
|
+
// because posthog-node uses axios under the hood.
|
|
199
|
+
init({
|
|
200
|
+
fetch: (url, opts) => {
|
|
201
|
+
return nodeFetch(url, opts)
|
|
202
|
+
},
|
|
203
|
+
})
|
|
204
|
+
|
|
217
205
|
nock("https://us.i.posthog.com")
|
|
218
206
|
.post("/decide/?v=3", body => {
|
|
219
207
|
return body.token === "test" && body.distinct_id === "us_1234"
|
|
@@ -230,4 +218,44 @@ describe("feature flags", () => {
|
|
|
230
218
|
}
|
|
231
219
|
)
|
|
232
220
|
})
|
|
221
|
+
|
|
222
|
+
it("should still get flags when user is logged out", async () => {
|
|
223
|
+
const env: Partial<typeof environment> = {
|
|
224
|
+
SELF_HOSTED: false,
|
|
225
|
+
POSTHOG_FEATURE_FLAGS_ENABLED: "true",
|
|
226
|
+
POSTHOG_API_HOST: "https://us.i.posthog.com",
|
|
227
|
+
POSTHOG_TOKEN: "test",
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
const ip = "127.0.0.1"
|
|
231
|
+
const hashedIp = crypto.createHash("sha512").update(ip).digest("hex")
|
|
232
|
+
|
|
233
|
+
await withEnv(env, async () => {
|
|
234
|
+
mockPosthogFlags(
|
|
235
|
+
{
|
|
236
|
+
featureFlags: { TEST_BOOLEAN: true },
|
|
237
|
+
},
|
|
238
|
+
{
|
|
239
|
+
distinct_id: hashedIp,
|
|
240
|
+
}
|
|
241
|
+
)
|
|
242
|
+
|
|
243
|
+
// We need to pass in node-fetch here otherwise nock won't get used
|
|
244
|
+
// because posthog-node uses axios under the hood.
|
|
245
|
+
init({
|
|
246
|
+
fetch: (url, opts) => {
|
|
247
|
+
return nodeFetch(url, opts)
|
|
248
|
+
},
|
|
249
|
+
})
|
|
250
|
+
|
|
251
|
+
await context.doInIPContext(ip, async () => {
|
|
252
|
+
await context.doInTenant("default", async () => {
|
|
253
|
+
const result = await flags.fetch()
|
|
254
|
+
expect(result.TEST_BOOLEAN).toBe(true)
|
|
255
|
+
})
|
|
256
|
+
})
|
|
257
|
+
|
|
258
|
+
shutdown()
|
|
259
|
+
})
|
|
260
|
+
})
|
|
233
261
|
})
|
package/src/middleware/index.ts
CHANGED
|
@@ -20,3 +20,4 @@ export { default as correlation } from "../logging/correlation/middleware"
|
|
|
20
20
|
export { default as errorHandling } from "./errorHandling"
|
|
21
21
|
export { default as querystringToBody } from "./querystringToBody"
|
|
22
22
|
export * as joiValidator from "./joi-validator"
|
|
23
|
+
export { default as ip } from "./ip"
|