@budibase/backend-core 2.32.12 → 2.32.13

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.
Files changed (33) hide show
  1. package/dist/index.js +125 -49
  2. package/dist/index.js.map +4 -4
  3. package/dist/index.js.meta.json +1 -1
  4. package/dist/package.json +4 -4
  5. package/dist/plugins.js.meta.json +1 -1
  6. package/dist/src/db/couch/DatabaseImpl.js +10 -2
  7. package/dist/src/db/couch/DatabaseImpl.js.map +1 -1
  8. package/dist/src/features/features.d.ts +47 -0
  9. package/dist/src/features/features.js +269 -0
  10. package/dist/src/features/features.js.map +1 -0
  11. package/dist/src/features/index.d.ts +2 -39
  12. package/dist/src/features/index.js +6 -235
  13. package/dist/src/features/index.js.map +1 -1
  14. package/dist/src/features/tests/utils.d.ts +3 -0
  15. package/dist/src/features/tests/utils.js +56 -0
  16. package/dist/src/features/tests/utils.js.map +1 -0
  17. package/dist/src/middleware/passport/sso/sso.js +0 -25
  18. package/dist/src/middleware/passport/sso/sso.js.map +1 -1
  19. package/dist/src/users/users.js +8 -1
  20. package/dist/src/users/users.js.map +1 -1
  21. package/dist/tests/core/utilities/structures/accounts.js +2 -2
  22. package/dist/tests/core/utilities/structures/accounts.js.map +1 -1
  23. package/dist/tests/core/utilities/structures/users.js +2 -5
  24. package/dist/tests/core/utilities/structures/users.js.map +1 -1
  25. package/package.json +4 -4
  26. package/src/db/couch/DatabaseImpl.ts +12 -2
  27. package/src/features/features.ts +300 -0
  28. package/src/features/index.ts +2 -281
  29. package/src/features/tests/utils.ts +64 -0
  30. package/src/middleware/passport/sso/sso.ts +0 -24
  31. package/src/users/users.ts +10 -2
  32. package/tests/core/utilities/structures/accounts.ts +0 -4
  33. package/tests/core/utilities/structures/users.ts +0 -5
package/dist/index.js CHANGED
@@ -61260,7 +61260,7 @@ __export(src_exports, {
61260
61260
  sql: () => sql_exports,
61261
61261
  tenancy: () => tenancy,
61262
61262
  timers: () => timers_exports,
61263
- userUtils: () => utils_exports5,
61263
+ userUtils: () => utils_exports6,
61264
61264
  users: () => users_exports3,
61265
61265
  utils: () => utils_exports4,
61266
61266
  withEnv: () => withEnv
@@ -61995,10 +61995,18 @@ function isSupportedUserSearch(query) {
61995
61995
  { op: "equal" /* EQUAL */, key: "_id" },
61996
61996
  { op: "oneOf" /* ONE_OF */, key: "_id" }
61997
61997
  ];
61998
- for (let [key, operation] of Object.entries(query)) {
61998
+ for (const [key, operation] of Object.entries(query)) {
61999
61999
  if (typeof operation !== "object") {
62000
62000
  return false;
62001
62001
  }
62002
+ if (isLogicalSearchOperator(key)) {
62003
+ for (const condition of query[key].conditions) {
62004
+ if (!isSupportedUserSearch(condition)) {
62005
+ return false;
62006
+ }
62007
+ }
62008
+ return true;
62009
+ }
62002
62010
  const fields = Object.keys(operation || {});
62003
62011
  if (fields.length === 0) {
62004
62012
  continue;
@@ -62281,6 +62289,7 @@ var views_exports = {};
62281
62289
  __export(views_exports, {
62282
62290
  basicFields: () => basicFields,
62283
62291
  calculationFields: () => calculationFields,
62292
+ hasCalculationFields: () => hasCalculationFields,
62284
62293
  isBasicViewField: () => isBasicViewField,
62285
62294
  isCalculationField: () => isCalculationField,
62286
62295
  isCalculationView: () => isCalculationView
@@ -62293,6 +62302,9 @@ function isBasicViewField(field) {
62293
62302
  return !isCalculationField(field);
62294
62303
  }
62295
62304
  function isCalculationView(view) {
62305
+ return view.type === "calculation" /* CALCULATION */;
62306
+ }
62307
+ function hasCalculationFields(view) {
62296
62308
  return Object.values(view.schema || {}).some(isCalculationField);
62297
62309
  }
62298
62310
  function calculationFields(view) {
@@ -62726,7 +62738,7 @@ function search(docs, query) {
62726
62738
  if (query.sort) {
62727
62739
  result = sort(result, query.sort, query.sortOrder || "ascending" /* ASCENDING */);
62728
62740
  }
62729
- let totalRows = result.length;
62741
+ const totalRows = result.length;
62730
62742
  if (query.limit) {
62731
62743
  result = limit(result, query.limit.toString());
62732
62744
  }
@@ -67116,8 +67128,12 @@ __export(features_exports, {
67116
67128
  FlagSet: () => FlagSet,
67117
67129
  flags: () => flags,
67118
67130
  init: () => init4,
67119
- shutdown: () => shutdown2
67131
+ parseEnvFlags: () => parseEnvFlags,
67132
+ shutdown: () => shutdown2,
67133
+ testutils: () => utils_exports5
67120
67134
  });
67135
+
67136
+ // src/features/features.ts
67121
67137
  var import_posthog_node = require("posthog-node");
67122
67138
  var import_dd_trace3 = __toESM(require("dd-trace"));
67123
67139
 
@@ -67498,7 +67514,7 @@ var Duration = class _Duration {
67498
67514
  }
67499
67515
  };
67500
67516
 
67501
- // src/features/index.ts
67517
+ // src/features/features.ts
67502
67518
  var posthog;
67503
67519
  function init4(opts) {
67504
67520
  if (environment_default.POSTHOG_TOKEN && environment_default.POSTHOG_API_HOST && !environment_default.SELF_HOSTED && environment_default.POSTHOG_FEATURE_FLAGS_ENABLED) {
@@ -67563,6 +67579,21 @@ var NumberFlag = class extends Flag {
67563
67579
  throw new Error(`could not parse value "${value}" as number`);
67564
67580
  }
67565
67581
  };
67582
+ function parseEnvFlags(flags2) {
67583
+ const split = flags2.split(",").map((x) => x.split(":"));
67584
+ const result = [];
67585
+ for (const [tenantId, ...features] of split) {
67586
+ for (let feature of features) {
67587
+ let value = true;
67588
+ if (feature.startsWith("!")) {
67589
+ feature = feature.slice(1);
67590
+ value = false;
67591
+ }
67592
+ result.push({ tenantId, key: feature, value });
67593
+ }
67594
+ }
67595
+ return result;
67596
+ }
67566
67597
  var FlagSet = class {
67567
67598
  constructor(flagSchema) {
67568
67599
  this.flagSchema = flagSchema;
@@ -67597,28 +67628,24 @@ var FlagSet = class {
67597
67628
  const flagValues = this.defaults();
67598
67629
  const currentTenantId = getTenantId();
67599
67630
  const specificallySetFalse = /* @__PURE__ */ new Set();
67600
- const split = (environment_default.TENANT_FEATURE_FLAGS || "").split(",").map((x) => x.split(":"));
67601
- for (const [tenantId, ...features] of split) {
67631
+ for (const { tenantId, key, value } of parseEnvFlags(
67632
+ environment_default.TENANT_FEATURE_FLAGS || ""
67633
+ )) {
67602
67634
  if (!tenantId || tenantId !== "*" && tenantId !== currentTenantId) {
67603
67635
  continue;
67604
67636
  }
67605
67637
  tags[`readFromEnvironmentVars`] = true;
67606
- for (let feature of features) {
67607
- let value = true;
67608
- if (feature.startsWith("!")) {
67609
- feature = feature.slice(1);
67610
- value = false;
67611
- specificallySetFalse.add(feature);
67612
- }
67613
- if (!this.isFlagName(feature)) {
67614
- continue;
67615
- }
67616
- if (typeof flagValues[feature] !== "boolean") {
67617
- throw new Error(`Feature: ${feature} is not a boolean`);
67618
- }
67619
- flagValues[feature] = value;
67620
- tags[`flags.${feature}.source`] = "environment";
67638
+ if (value === false) {
67639
+ specificallySetFalse.add(key);
67640
+ }
67641
+ if (!this.isFlagName(key)) {
67642
+ continue;
67643
+ }
67644
+ if (typeof flagValues[key] !== "boolean") {
67645
+ throw new Error(`Feature: ${key} is not a boolean`);
67621
67646
  }
67647
+ flagValues[key] = value;
67648
+ tags[`flags.${key}.source`] = "environment";
67622
67649
  }
67623
67650
  const license = ctx?.user?.license;
67624
67651
  if (license) {
@@ -67685,6 +67712,60 @@ var flags = new FlagSet({
67685
67712
  ["ENRICHED_RELATIONSHIPS" /* ENRICHED_RELATIONSHIPS */]: Flag.boolean(environment_default.isDev())
67686
67713
  });
67687
67714
 
67715
+ // src/features/tests/utils.ts
67716
+ var utils_exports5 = {};
67717
+ __export(utils_exports5, {
67718
+ setFeatureFlags: () => setFeatureFlags2,
67719
+ withFeatureFlags: () => withFeatureFlags
67720
+ });
67721
+ function getCurrentFlags() {
67722
+ const result = {};
67723
+ for (const { tenantId, key, value } of parseEnvFlags(
67724
+ process.env.TENANT_FEATURE_FLAGS || ""
67725
+ )) {
67726
+ const tenantFlags = result[tenantId] || {};
67727
+ if (tenantFlags[key] === false) {
67728
+ continue;
67729
+ }
67730
+ tenantFlags[key] = value;
67731
+ result[tenantId] = tenantFlags;
67732
+ }
67733
+ return result;
67734
+ }
67735
+ function buildFlagString(flags2) {
67736
+ const parts = [];
67737
+ for (const [tenantId, tenantFlags] of Object.entries(flags2)) {
67738
+ for (const [key, value] of Object.entries(tenantFlags)) {
67739
+ if (value === false) {
67740
+ parts.push(`${tenantId}:!${key}`);
67741
+ } else {
67742
+ parts.push(`${tenantId}:${key}`);
67743
+ }
67744
+ }
67745
+ }
67746
+ return parts.join(",");
67747
+ }
67748
+ function setFeatureFlags2(tenantId, flags2) {
67749
+ const current = getCurrentFlags();
67750
+ for (const [key, value] of Object.entries(flags2)) {
67751
+ const tenantFlags = current[tenantId] || {};
67752
+ tenantFlags[key] = value;
67753
+ current[tenantId] = tenantFlags;
67754
+ }
67755
+ const flagString = buildFlagString(current);
67756
+ return setEnv({ TENANT_FEATURE_FLAGS: flagString });
67757
+ }
67758
+ function withFeatureFlags(tenantId, flags2, f) {
67759
+ const cleanup3 = setFeatureFlags2(tenantId, flags2);
67760
+ const result = f();
67761
+ if (result instanceof Promise) {
67762
+ return result.finally(cleanup3);
67763
+ } else {
67764
+ cleanup3();
67765
+ return result;
67766
+ }
67767
+ }
67768
+
67688
67769
  // src/db/couch/DatabaseImpl.ts
67689
67770
  var DATABASE_NOT_FOUND = "Database does not exist.";
67690
67771
  function buildNano(couchInfo) {
@@ -67948,11 +68029,21 @@ var DatabaseImpl = class _DatabaseImpl {
67948
68029
  return this.performCall(() => {
67949
68030
  return async () => {
67950
68031
  const response = await directCouchUrlCall(args);
67951
- const json = await response.json();
68032
+ const text = await response.text();
67952
68033
  if (response.status > 300) {
68034
+ let json;
68035
+ try {
68036
+ json = JSON.parse(text);
68037
+ } catch (err) {
68038
+ console.error(`SQS error: ${text}`);
68039
+ throw new CouchDBError(
68040
+ "error while running SQS query, please try again later",
68041
+ { name: "sqs_error", status: response.status }
68042
+ );
68043
+ }
67953
68044
  throw json;
67954
68045
  }
67955
- return json;
68046
+ return JSON.parse(text);
67956
68047
  };
67957
68048
  });
67958
68049
  }
@@ -68965,8 +69056,8 @@ __export(users_exports3, {
68965
69056
  });
68966
69057
 
68967
69058
  // src/users/utils.ts
68968
- var utils_exports5 = {};
68969
- __export(utils_exports5, {
69059
+ var utils_exports6 = {};
69060
+ __export(utils_exports6, {
68970
69061
  getAccountHolderFromUserIds: () => getAccountHolderFromUserIds,
68971
69062
  hasAdminPermissions: () => hasAdminPermissions2,
68972
69063
  hasAppBuilderPermissions: () => hasAppBuilderPermissions2,
@@ -72991,6 +73082,12 @@ async function paginatedUsers({
72991
73082
  userList = await bulkGetGlobalUsersById(query?.oneOf?._id, {
72992
73083
  cleanup: true
72993
73084
  });
73085
+ } else if (query) {
73086
+ const response = await db.allDocs(
73087
+ getGlobalUserParams(null, { ...opts, limit: void 0 })
73088
+ );
73089
+ userList = response.rows.map((row) => row.doc);
73090
+ userList = filters_exports.search(userList, { query, limit: opts.limit }).rows;
72994
73091
  } else {
72995
73092
  const response = await db.allDocs(getGlobalUserParams(null, opts));
72996
73093
  userList = response.rows.map((row) => row.doc);
@@ -73808,7 +73905,6 @@ __export(google_exports, {
73808
73905
  });
73809
73906
 
73810
73907
  // src/middleware/passport/sso/sso.ts
73811
- var import_node_fetch5 = __toESM(require("node-fetch"));
73812
73908
  var ssoSaveUserNoOp = (user) => Promise.resolve(user);
73813
73909
  async function authenticate2(details, requireLocalAccount = true, done, saveUserFn) {
73814
73910
  if (!saveUserFn) {
@@ -73863,24 +73959,10 @@ async function authenticate2(details, requireLocalAccount = true, done, saveUser
73863
73959
  }
73864
73960
  return done(null, ssoUser);
73865
73961
  }
73866
- async function getProfilePictureUrl(user, details) {
73867
- const pictureUrl = details.profile?._json.picture;
73868
- if (pictureUrl) {
73869
- const response = await (0, import_node_fetch5.default)(pictureUrl);
73870
- if (response.status === 200) {
73871
- const type = response.headers.get("content-type");
73872
- if (type.startsWith("image/")) {
73873
- return pictureUrl;
73874
- }
73875
- }
73876
- }
73877
- }
73878
73962
  async function syncUser(user, details) {
73879
73963
  let firstName;
73880
73964
  let lastName;
73881
- let pictureUrl;
73882
73965
  let oauth2;
73883
- let thirdPartyProfile;
73884
73966
  if (details.profile) {
73885
73967
  const profile = details.profile;
73886
73968
  if (profile.name) {
@@ -73892,10 +73974,6 @@ async function syncUser(user, details) {
73892
73974
  lastName = name.familyName;
73893
73975
  }
73894
73976
  }
73895
- pictureUrl = await getProfilePictureUrl(user, details);
73896
- thirdPartyProfile = {
73897
- ...profile._json
73898
- };
73899
73977
  }
73900
73978
  if (details.oauth2) {
73901
73979
  oauth2 = {
@@ -73908,8 +73986,6 @@ async function syncUser(user, details) {
73908
73986
  providerType: details.providerType,
73909
73987
  firstName,
73910
73988
  lastName,
73911
- thirdPartyProfile,
73912
- pictureUrl,
73913
73989
  oauth2
73914
73990
  };
73915
73991
  }
@@ -73971,7 +74047,7 @@ __export(oidc_exports, {
73971
74047
  getCallbackUrl: () => getCallbackUrl2,
73972
74048
  strategyFactory: () => strategyFactory2
73973
74049
  });
73974
- var import_node_fetch6 = __toESM(require("node-fetch"));
74050
+ var import_node_fetch5 = __toESM(require("node-fetch"));
73975
74051
  var OIDCStrategy = require_lib9().Strategy;
73976
74052
  function buildVerifyFn2(saveUserFn) {
73977
74053
  return async (issuer, sub, profile, jwtClaims, accessToken, refreshToken, idToken, params2, done) => {
@@ -74031,7 +74107,7 @@ async function fetchStrategyConfig(oidcConfig, callbackUrl) {
74031
74107
  "Configuration invalid. Must contain clientID, clientSecret, callbackUrl and configUrl"
74032
74108
  );
74033
74109
  }
74034
- const response = await (0, import_node_fetch6.default)(configUrl);
74110
+ const response = await (0, import_node_fetch5.default)(configUrl);
74035
74111
  if (!response.ok) {
74036
74112
  throw new Error(
74037
74113
  `Unexpected response when fetching openid-configuration: ${response.statusText}`