@budibase/backend-core 2.32.7 → 2.32.8

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 CHANGED
@@ -58453,6 +58453,7 @@ var AppState = /* @__PURE__ */ ((AppState2) => {
58453
58453
  return AppState2;
58454
58454
  })(AppState || {});
58455
58455
  var EXPIRY_SECONDS = 3600;
58456
+ var INVALID_EXPIRY_SECONDS = 60;
58456
58457
  async function populateFromDB(appId) {
58457
58458
  return doWithDB(
58458
58459
  appId,
@@ -58475,7 +58476,7 @@ async function getAppMetadata(appId) {
58475
58476
  } catch (err) {
58476
58477
  if (err && err.status === 404) {
58477
58478
  metadata = { state: "invalid" /* INVALID */ };
58478
- expiry = void 0;
58479
+ expiry = INVALID_EXPIRY_SECONDS;
58479
58480
  } else {
58480
58481
  throw err;
58481
58482
  }
@@ -59815,6 +59816,385 @@ __export(features_exports, {
59815
59816
  });
59816
59817
  var import_posthog_node = require("posthog-node");
59817
59818
  var import_dd_trace3 = __toESM(require("dd-trace"));
59819
+
59820
+ // src/utils/index.ts
59821
+ var utils_exports4 = {};
59822
+ __export(utils_exports4, {
59823
+ Duration: () => Duration,
59824
+ DurationType: () => DurationType,
59825
+ clearCookie: () => clearCookie,
59826
+ compare: () => compare,
59827
+ getAppIdFromCtx: () => getAppIdFromCtx,
59828
+ getCookie: () => getCookie,
59829
+ hasCircularStructure: () => hasCircularStructure,
59830
+ hash: () => hash,
59831
+ isAudited: () => isAudited,
59832
+ isClient: () => isClient,
59833
+ isPublicApiRequest: () => isPublicApiRequest,
59834
+ isServingApp: () => isServingApp,
59835
+ isServingBuilder: () => isServingBuilder,
59836
+ isServingBuilderPreview: () => isServingBuilderPreview,
59837
+ isValidInternalAPIKey: () => isValidInternalAPIKey,
59838
+ newid: () => newid,
59839
+ openJwt: () => openJwt,
59840
+ resolveAppUrl: () => resolveAppUrl,
59841
+ setCookie: () => setCookie,
59842
+ timeout: () => timeout,
59843
+ validEmail: () => validEmail
59844
+ });
59845
+
59846
+ // src/utils/hashing.ts
59847
+ var bcrypt = environment_default.JS_BCRYPT ? require("bcryptjs") : require("bcrypt");
59848
+ var SALT_ROUNDS = environment_default.SALT_ROUNDS || 10;
59849
+ async function hash(data) {
59850
+ const salt = await bcrypt.genSalt(SALT_ROUNDS);
59851
+ return bcrypt.hash(data, salt);
59852
+ }
59853
+ async function compare(data, encrypted) {
59854
+ return bcrypt.compare(data, encrypted);
59855
+ }
59856
+
59857
+ // src/tenancy/index.ts
59858
+ var tenancy_exports = {};
59859
+ __export(tenancy_exports, {
59860
+ addTenantToUrl: () => addTenantToUrl,
59861
+ getTenantDB: () => getTenantDB,
59862
+ getTenantIDFromCtx: () => getTenantIDFromCtx,
59863
+ getTenantInfo: () => getTenantInfo,
59864
+ isUserInAppTenant: () => isUserInAppTenant,
59865
+ saveTenantInfo: () => saveTenantInfo
59866
+ });
59867
+
59868
+ // src/tenancy/db.ts
59869
+ function getTenantDB(tenantId) {
59870
+ return getDB(getGlobalDBName(tenantId));
59871
+ }
59872
+ async function saveTenantInfo(tenantInfo) {
59873
+ const db = getTenantDB(tenantInfo.tenantId);
59874
+ return db.put({
59875
+ _id: "tenant_info",
59876
+ ...tenantInfo
59877
+ });
59878
+ }
59879
+ async function getTenantInfo(tenantId) {
59880
+ try {
59881
+ const db = getTenantDB(tenantId);
59882
+ const tenantInfo = await db.get("tenant_info");
59883
+ delete tenantInfo.owner.password;
59884
+ return tenantInfo;
59885
+ } catch {
59886
+ return void 0;
59887
+ }
59888
+ }
59889
+
59890
+ // src/tenancy/tenancy.ts
59891
+ function addTenantToUrl(url) {
59892
+ const tenantId = getTenantId();
59893
+ if (isMultiTenant()) {
59894
+ const char = url.indexOf("?") === -1 ? "?" : "&";
59895
+ url += `${char}tenantId=${tenantId}`;
59896
+ }
59897
+ return url;
59898
+ }
59899
+ var isUserInAppTenant = (appId, user) => {
59900
+ let userTenantId;
59901
+ if (user) {
59902
+ userTenantId = user.tenantId || DEFAULT_TENANT_ID;
59903
+ } else {
59904
+ userTenantId = getTenantId();
59905
+ }
59906
+ const tenantId = getTenantIDFromAppID(appId) || DEFAULT_TENANT_ID;
59907
+ return tenantId === userTenantId;
59908
+ };
59909
+ var ALL_STRATEGIES = Object.values(TenantResolutionStrategy);
59910
+ var getTenantIDFromCtx = (ctx, opts) => {
59911
+ if (!isMultiTenant()) {
59912
+ return DEFAULT_TENANT_ID;
59913
+ }
59914
+ if (opts.allowNoTenant === void 0) {
59915
+ opts.allowNoTenant = false;
59916
+ }
59917
+ if (!opts.includeStrategies) {
59918
+ opts.includeStrategies = ALL_STRATEGIES;
59919
+ }
59920
+ if (!opts.excludeStrategies) {
59921
+ opts.excludeStrategies = [];
59922
+ }
59923
+ const isAllowed = (strategy) => {
59924
+ if (opts.excludeStrategies?.includes(strategy)) {
59925
+ return false;
59926
+ }
59927
+ if (opts.includeStrategies?.includes(strategy)) {
59928
+ return true;
59929
+ }
59930
+ };
59931
+ if (isAllowed("user" /* USER */)) {
59932
+ const userTenantId = ctx.user?.tenantId;
59933
+ if (userTenantId) {
59934
+ return userTenantId;
59935
+ }
59936
+ }
59937
+ if (isAllowed("header" /* HEADER */)) {
59938
+ const headerTenantId = ctx.request.headers["x-budibase-tenant-id" /* TENANT_ID */];
59939
+ if (headerTenantId) {
59940
+ return headerTenantId;
59941
+ }
59942
+ }
59943
+ if (isAllowed("query" /* QUERY */)) {
59944
+ const queryTenantId = ctx.request.query.tenantId;
59945
+ if (queryTenantId) {
59946
+ return queryTenantId;
59947
+ }
59948
+ }
59949
+ if (isAllowed("subdomain" /* SUBDOMAIN */)) {
59950
+ let platformHost;
59951
+ try {
59952
+ platformHost = new URL(getPlatformURL()).host.split(":")[0];
59953
+ } catch (err) {
59954
+ if (err.code !== "ERR_INVALID_URL") {
59955
+ throw err;
59956
+ }
59957
+ }
59958
+ const requestHost = ctx.host;
59959
+ if (platformHost && requestHost.includes(platformHost)) {
59960
+ const tenantId = requestHost.substring(
59961
+ 0,
59962
+ requestHost.indexOf(`.${platformHost}`)
59963
+ );
59964
+ if (tenantId) {
59965
+ return tenantId;
59966
+ }
59967
+ }
59968
+ }
59969
+ if (isAllowed("path" /* PATH */)) {
59970
+ const match = ctx.matched.find(
59971
+ (m) => !!m.paramNames.find((p) => p.name === "tenantId")
59972
+ );
59973
+ const ctxUrl = ctx.originalUrl;
59974
+ let url;
59975
+ if (ctxUrl.includes("?")) {
59976
+ url = ctxUrl.split("?")[0];
59977
+ } else {
59978
+ url = ctxUrl;
59979
+ }
59980
+ if (match) {
59981
+ const params2 = match.params(url, match.captures(url), {});
59982
+ if (params2.tenantId) {
59983
+ return params2.tenantId;
59984
+ }
59985
+ }
59986
+ }
59987
+ if (!opts.allowNoTenant) {
59988
+ ctx.throw(403, "Tenant id not set");
59989
+ }
59990
+ return void 0;
59991
+ };
59992
+
59993
+ // src/utils/utils.ts
59994
+ var import_jsonwebtoken = __toESM(require("jsonwebtoken"));
59995
+ var APP_PREFIX3 = "app" /* APP */ + SEPARATOR;
59996
+ var PROD_APP_PREFIX = "/app/";
59997
+ var BUILDER_PREVIEW_PATH = "/app/preview";
59998
+ var BUILDER_PREFIX = "/builder";
59999
+ var BUILDER_APP_PREFIX = `${BUILDER_PREFIX}/app/`;
60000
+ var PUBLIC_API_PREFIX = "/api/public/v";
60001
+ function confirmAppId(possibleAppId) {
60002
+ return possibleAppId && possibleAppId.startsWith(APP_PREFIX3) ? possibleAppId : void 0;
60003
+ }
60004
+ async function resolveAppUrl(ctx) {
60005
+ const appUrl = ctx.path.split("/")[2];
60006
+ let possibleAppUrl = `/${appUrl.toLowerCase()}`;
60007
+ let tenantId = getTenantId();
60008
+ if (!environment_default.isDev() && environment_default.MULTI_TENANCY) {
60009
+ tenantId = getTenantIDFromCtx(ctx, {
60010
+ includeStrategies: ["subdomain" /* SUBDOMAIN */]
60011
+ });
60012
+ }
60013
+ const apps = await doInTenant(
60014
+ tenantId,
60015
+ () => getAllApps({ dev: false })
60016
+ );
60017
+ const app = apps.filter(
60018
+ (a) => a.url && a.url.toLowerCase() === possibleAppUrl
60019
+ )[0];
60020
+ return app && app.appId ? app.appId : void 0;
60021
+ }
60022
+ function isServingApp(ctx) {
60023
+ if (ctx.path.startsWith(`/${APP_PREFIX3}`)) {
60024
+ return true;
60025
+ }
60026
+ return ctx.path.startsWith(PROD_APP_PREFIX);
60027
+ }
60028
+ function isServingBuilder(ctx) {
60029
+ return ctx.path.startsWith(BUILDER_APP_PREFIX);
60030
+ }
60031
+ function isServingBuilderPreview(ctx) {
60032
+ return ctx.path.startsWith(BUILDER_PREVIEW_PATH);
60033
+ }
60034
+ function isPublicApiRequest(ctx) {
60035
+ return ctx.path.startsWith(PUBLIC_API_PREFIX);
60036
+ }
60037
+ async function getAppIdFromCtx(ctx) {
60038
+ const options2 = [ctx.request.headers["x-budibase-app-id" /* APP_ID */]];
60039
+ let appId;
60040
+ for (let option of options2) {
60041
+ appId = confirmAppId(option);
60042
+ if (appId) {
60043
+ break;
60044
+ }
60045
+ }
60046
+ if (!appId && ctx.request.body && ctx.request.body.appId) {
60047
+ appId = confirmAppId(ctx.request.body.appId);
60048
+ }
60049
+ const pathId = parseAppIdFromUrlPath(ctx.path);
60050
+ if (!appId && pathId) {
60051
+ appId = confirmAppId(pathId);
60052
+ }
60053
+ const isBuilderPreview = ctx.path.startsWith(BUILDER_PREVIEW_PATH);
60054
+ const isViewingProdApp = ctx.path.startsWith(PROD_APP_PREFIX) && !isBuilderPreview;
60055
+ if (!appId && isViewingProdApp) {
60056
+ appId = confirmAppId(await resolveAppUrl(ctx));
60057
+ }
60058
+ const referer = ctx.request.headers.referer;
60059
+ if (!appId && referer?.includes(BUILDER_APP_PREFIX)) {
60060
+ const refererId = parseAppIdFromUrlPath(ctx.request.headers.referer);
60061
+ appId = confirmAppId(refererId);
60062
+ }
60063
+ return appId;
60064
+ }
60065
+ function parseAppIdFromUrlPath(url) {
60066
+ if (!url) {
60067
+ return;
60068
+ }
60069
+ return url.split("?")[0].split("/").find((subPath) => subPath.startsWith(APP_PREFIX3));
60070
+ }
60071
+ function openJwt(token) {
60072
+ if (!token) {
60073
+ return void 0;
60074
+ }
60075
+ try {
60076
+ return import_jsonwebtoken.default.verify(token, environment_default.JWT_SECRET);
60077
+ } catch (e) {
60078
+ if (environment_default.JWT_SECRET_FALLBACK) {
60079
+ return import_jsonwebtoken.default.verify(token, environment_default.JWT_SECRET_FALLBACK);
60080
+ } else {
60081
+ throw e;
60082
+ }
60083
+ }
60084
+ }
60085
+ function isValidInternalAPIKey(apiKey) {
60086
+ if (environment_default.INTERNAL_API_KEY && environment_default.INTERNAL_API_KEY === apiKey) {
60087
+ return true;
60088
+ }
60089
+ return !!(environment_default.INTERNAL_API_KEY_FALLBACK && environment_default.INTERNAL_API_KEY_FALLBACK === apiKey);
60090
+ }
60091
+ function getCookie(ctx, name) {
60092
+ const cookie = ctx.cookies.get(name);
60093
+ if (!cookie) {
60094
+ return void 0;
60095
+ }
60096
+ return openJwt(cookie);
60097
+ }
60098
+ function setCookie(ctx, value, name = "builder", opts = { sign: true }) {
60099
+ if (value && opts && opts.sign) {
60100
+ value = import_jsonwebtoken.default.sign(value, environment_default.JWT_SECRET);
60101
+ }
60102
+ const config = {
60103
+ expires: MAX_VALID_DATE,
60104
+ path: "/",
60105
+ httpOnly: false,
60106
+ overwrite: true
60107
+ };
60108
+ if (environment_default.COOKIE_DOMAIN) {
60109
+ config.domain = environment_default.COOKIE_DOMAIN;
60110
+ }
60111
+ ctx.cookies.set(name, value, config);
60112
+ }
60113
+ function clearCookie(ctx, name) {
60114
+ setCookie(ctx, null, name);
60115
+ }
60116
+ function isClient(ctx) {
60117
+ return ctx.headers["x-budibase-type" /* TYPE */] === "client";
60118
+ }
60119
+ function timeout(timeMs) {
60120
+ return new Promise((resolve) => setTimeout(resolve, timeMs));
60121
+ }
60122
+ function isAudited(event) {
60123
+ return !!AuditedEventFriendlyName[event];
60124
+ }
60125
+ function hasCircularStructure(json) {
60126
+ if (typeof json !== "object") {
60127
+ return false;
60128
+ }
60129
+ try {
60130
+ JSON.stringify(json);
60131
+ } catch (err) {
60132
+ if (err instanceof Error && err?.message.includes("circular structure")) {
60133
+ return true;
60134
+ }
60135
+ }
60136
+ return false;
60137
+ }
60138
+
60139
+ // src/utils/stringUtils.ts
60140
+ function validEmail(value) {
60141
+ return value && !!value.match(
60142
+ /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/
60143
+ );
60144
+ }
60145
+
60146
+ // src/utils/Duration.ts
60147
+ var DurationType = /* @__PURE__ */ ((DurationType2) => {
60148
+ DurationType2["MILLISECONDS"] = "milliseconds";
60149
+ DurationType2["SECONDS"] = "seconds";
60150
+ DurationType2["MINUTES"] = "minutes";
60151
+ DurationType2["HOURS"] = "hours";
60152
+ DurationType2["DAYS"] = "days";
60153
+ return DurationType2;
60154
+ })(DurationType || {});
60155
+ var conversion = {
60156
+ milliseconds: 1,
60157
+ seconds: 1e3,
60158
+ minutes: 60 * 1e3,
60159
+ hours: 60 * 60 * 1e3,
60160
+ days: 24 * 60 * 60 * 1e3
60161
+ };
60162
+ var Duration = class _Duration {
60163
+ static convert(from, to, duration) {
60164
+ const milliseconds = duration * conversion[from];
60165
+ return milliseconds / conversion[to];
60166
+ }
60167
+ static from(from, duration) {
60168
+ return {
60169
+ to: (to) => {
60170
+ return _Duration.convert(from, to, duration);
60171
+ },
60172
+ toMs: () => {
60173
+ return _Duration.convert(from, "milliseconds" /* MILLISECONDS */, duration);
60174
+ },
60175
+ toSeconds: () => {
60176
+ return _Duration.convert(from, "seconds" /* SECONDS */, duration);
60177
+ }
60178
+ };
60179
+ }
60180
+ static fromSeconds(duration) {
60181
+ return _Duration.from("seconds" /* SECONDS */, duration);
60182
+ }
60183
+ static fromMinutes(duration) {
60184
+ return _Duration.from("minutes" /* MINUTES */, duration);
60185
+ }
60186
+ static fromHours(duration) {
60187
+ return _Duration.from("hours" /* HOURS */, duration);
60188
+ }
60189
+ static fromDays(duration) {
60190
+ return _Duration.from("days" /* DAYS */, duration);
60191
+ }
60192
+ static fromMilliseconds(duration) {
60193
+ return _Duration.from("milliseconds" /* MILLISECONDS */, duration);
60194
+ }
60195
+ };
60196
+
60197
+ // src/features/index.ts
59818
60198
  var posthog;
59819
60199
  function init4(opts) {
59820
60200
  if (environment_default.POSTHOG_TOKEN && environment_default.POSTHOG_API_HOST && !environment_default.SELF_HOSTED && environment_default.POSTHOG_FEATURE_FLAGS_ENABLED) {
@@ -59822,6 +60202,7 @@ function init4(opts) {
59822
60202
  posthog = new import_posthog_node.PostHog(environment_default.POSTHOG_TOKEN, {
59823
60203
  host: environment_default.POSTHOG_API_HOST,
59824
60204
  personalApiKey: environment_default.POSTHOG_PERSONAL_TOKEN,
60205
+ featureFlagsPollingInterval: Duration.fromMinutes(3).toMs(),
59825
60206
  ...opts
59826
60207
  });
59827
60208
  } else {
@@ -60098,7 +60479,7 @@ var DatabaseImpl = class _DatabaseImpl {
60098
60479
  return this.getDb();
60099
60480
  }
60100
60481
  // this function fetches the DB and handles if DB creation is needed
60101
- async performCall(call) {
60482
+ async performCallWithDBCreation(call) {
60102
60483
  const db = this.getDb();
60103
60484
  const fnc = await call(db);
60104
60485
  try {
@@ -60106,11 +60487,20 @@ var DatabaseImpl = class _DatabaseImpl {
60106
60487
  } catch (err) {
60107
60488
  if (err.statusCode === 404 && err.reason === DATABASE_NOT_FOUND) {
60108
60489
  await this.checkAndCreateDb();
60109
- return await this.performCall(call);
60490
+ return await this.performCallWithDBCreation(call);
60110
60491
  }
60111
60492
  throw new CouchDBError(`CouchDB error: ${err.message}`, err);
60112
60493
  }
60113
60494
  }
60495
+ async performCall(call) {
60496
+ const db = this.getDb();
60497
+ const fnc = await call(db);
60498
+ try {
60499
+ return await fnc();
60500
+ } catch (err) {
60501
+ throw new CouchDBError(`CouchDB error: ${err.message}`, err);
60502
+ }
60503
+ }
60114
60504
  async get(id) {
60115
60505
  return this.performCall((db) => {
60116
60506
  if (!id) {
@@ -60194,7 +60584,7 @@ var DatabaseImpl = class _DatabaseImpl {
60194
60584
  if (!document._id) {
60195
60585
  throw new Error("Cannot store document without _id field.");
60196
60586
  }
60197
- return this.performCall(async (db) => {
60587
+ return this.performCallWithDBCreation(async (db) => {
60198
60588
  if (!document.createdAt) {
60199
60589
  document.createdAt = (/* @__PURE__ */ new Date()).toISOString();
60200
60590
  }
@@ -60216,7 +60606,7 @@ var DatabaseImpl = class _DatabaseImpl {
60216
60606
  }
60217
60607
  async bulkDocs(documents) {
60218
60608
  const now = (/* @__PURE__ */ new Date()).toISOString();
60219
- return this.performCall((db) => {
60609
+ return this.performCallWithDBCreation((db) => {
60220
60610
  return () => db.bulk({
60221
60611
  docs: documents.map((d) => ({ createdAt: now, ...d, updatedAt: now }))
60222
60612
  });
@@ -60224,7 +60614,21 @@ var DatabaseImpl = class _DatabaseImpl {
60224
60614
  }
60225
60615
  async allDocs(params2) {
60226
60616
  return this.performCall((db) => {
60227
- return () => db.list(params2);
60617
+ return async () => {
60618
+ try {
60619
+ return await db.list(params2);
60620
+ } catch (err) {
60621
+ if (err.reason === DATABASE_NOT_FOUND) {
60622
+ return {
60623
+ offset: 0,
60624
+ total_rows: 0,
60625
+ rows: []
60626
+ };
60627
+ } else {
60628
+ throw err;
60629
+ }
60630
+ }
60631
+ };
60228
60632
  });
60229
60633
  }
60230
60634
  async _sqlQuery(url, method, body2) {
@@ -60773,155 +61177,19 @@ var TTL = /* @__PURE__ */ ((TTL2) => {
60773
61177
  return TTL2;
60774
61178
  })(TTL || {});
60775
61179
  var keys = (...args) => GENERIC.keys(...args);
60776
- var get2 = (...args) => GENERIC.get(...args);
60777
- var store = (...args) => GENERIC.store(...args);
60778
- var destroy = (...args) => GENERIC.delete(...args);
60779
- var withCache = (...args) => GENERIC.withCache(...args);
60780
- var bustCache = (...args) => GENERIC.bustCache(...args);
60781
-
60782
- // src/cache/user.ts
60783
- var user_exports = {};
60784
- __export(user_exports, {
60785
- getUser: () => getUser,
60786
- getUsers: () => getUsers,
60787
- invalidateUser: () => invalidateUser
60788
- });
60789
-
60790
- // src/tenancy/index.ts
60791
- var tenancy_exports = {};
60792
- __export(tenancy_exports, {
60793
- addTenantToUrl: () => addTenantToUrl,
60794
- getTenantDB: () => getTenantDB,
60795
- getTenantIDFromCtx: () => getTenantIDFromCtx,
60796
- getTenantInfo: () => getTenantInfo,
60797
- isUserInAppTenant: () => isUserInAppTenant,
60798
- saveTenantInfo: () => saveTenantInfo
60799
- });
60800
-
60801
- // src/tenancy/db.ts
60802
- function getTenantDB(tenantId) {
60803
- return getDB(getGlobalDBName(tenantId));
60804
- }
60805
- async function saveTenantInfo(tenantInfo) {
60806
- const db = getTenantDB(tenantInfo.tenantId);
60807
- return db.put({
60808
- _id: "tenant_info",
60809
- ...tenantInfo
60810
- });
60811
- }
60812
- async function getTenantInfo(tenantId) {
60813
- try {
60814
- const db = getTenantDB(tenantId);
60815
- const tenantInfo = await db.get("tenant_info");
60816
- delete tenantInfo.owner.password;
60817
- return tenantInfo;
60818
- } catch {
60819
- return void 0;
60820
- }
60821
- }
60822
-
60823
- // src/tenancy/tenancy.ts
60824
- function addTenantToUrl(url) {
60825
- const tenantId = getTenantId();
60826
- if (isMultiTenant()) {
60827
- const char = url.indexOf("?") === -1 ? "?" : "&";
60828
- url += `${char}tenantId=${tenantId}`;
60829
- }
60830
- return url;
60831
- }
60832
- var isUserInAppTenant = (appId, user) => {
60833
- let userTenantId;
60834
- if (user) {
60835
- userTenantId = user.tenantId || DEFAULT_TENANT_ID;
60836
- } else {
60837
- userTenantId = getTenantId();
60838
- }
60839
- const tenantId = getTenantIDFromAppID(appId) || DEFAULT_TENANT_ID;
60840
- return tenantId === userTenantId;
60841
- };
60842
- var ALL_STRATEGIES = Object.values(TenantResolutionStrategy);
60843
- var getTenantIDFromCtx = (ctx, opts) => {
60844
- if (!isMultiTenant()) {
60845
- return DEFAULT_TENANT_ID;
60846
- }
60847
- if (opts.allowNoTenant === void 0) {
60848
- opts.allowNoTenant = false;
60849
- }
60850
- if (!opts.includeStrategies) {
60851
- opts.includeStrategies = ALL_STRATEGIES;
60852
- }
60853
- if (!opts.excludeStrategies) {
60854
- opts.excludeStrategies = [];
60855
- }
60856
- const isAllowed = (strategy) => {
60857
- if (opts.excludeStrategies?.includes(strategy)) {
60858
- return false;
60859
- }
60860
- if (opts.includeStrategies?.includes(strategy)) {
60861
- return true;
60862
- }
60863
- };
60864
- if (isAllowed("user" /* USER */)) {
60865
- const userTenantId = ctx.user?.tenantId;
60866
- if (userTenantId) {
60867
- return userTenantId;
60868
- }
60869
- }
60870
- if (isAllowed("header" /* HEADER */)) {
60871
- const headerTenantId = ctx.request.headers["x-budibase-tenant-id" /* TENANT_ID */];
60872
- if (headerTenantId) {
60873
- return headerTenantId;
60874
- }
60875
- }
60876
- if (isAllowed("query" /* QUERY */)) {
60877
- const queryTenantId = ctx.request.query.tenantId;
60878
- if (queryTenantId) {
60879
- return queryTenantId;
60880
- }
60881
- }
60882
- if (isAllowed("subdomain" /* SUBDOMAIN */)) {
60883
- let platformHost;
60884
- try {
60885
- platformHost = new URL(getPlatformURL()).host.split(":")[0];
60886
- } catch (err) {
60887
- if (err.code !== "ERR_INVALID_URL") {
60888
- throw err;
60889
- }
60890
- }
60891
- const requestHost = ctx.host;
60892
- if (platformHost && requestHost.includes(platformHost)) {
60893
- const tenantId = requestHost.substring(
60894
- 0,
60895
- requestHost.indexOf(`.${platformHost}`)
60896
- );
60897
- if (tenantId) {
60898
- return tenantId;
60899
- }
60900
- }
60901
- }
60902
- if (isAllowed("path" /* PATH */)) {
60903
- const match = ctx.matched.find(
60904
- (m) => !!m.paramNames.find((p) => p.name === "tenantId")
60905
- );
60906
- const ctxUrl = ctx.originalUrl;
60907
- let url;
60908
- if (ctxUrl.includes("?")) {
60909
- url = ctxUrl.split("?")[0];
60910
- } else {
60911
- url = ctxUrl;
60912
- }
60913
- if (match) {
60914
- const params2 = match.params(url, match.captures(url), {});
60915
- if (params2.tenantId) {
60916
- return params2.tenantId;
60917
- }
60918
- }
60919
- }
60920
- if (!opts.allowNoTenant) {
60921
- ctx.throw(403, "Tenant id not set");
60922
- }
60923
- return void 0;
60924
- };
61180
+ var get2 = (...args) => GENERIC.get(...args);
61181
+ var store = (...args) => GENERIC.store(...args);
61182
+ var destroy = (...args) => GENERIC.delete(...args);
61183
+ var withCache = (...args) => GENERIC.withCache(...args);
61184
+ var bustCache = (...args) => GENERIC.bustCache(...args);
61185
+
61186
+ // src/cache/user.ts
61187
+ var user_exports = {};
61188
+ __export(user_exports, {
61189
+ getUser: () => getUser,
61190
+ getUsers: () => getUsers,
61191
+ invalidateUser: () => invalidateUser
61192
+ });
60925
61193
 
60926
61194
  // src/platform/index.ts
60927
61195
  var platform_exports = {};
@@ -61045,249 +61313,6 @@ __export(redlockImpl_exports, {
61045
61313
  newRedlock: () => newRedlock
61046
61314
  });
61047
61315
  var import_redlock = __toESM(require("redlock"));
61048
-
61049
- // src/utils/index.ts
61050
- var utils_exports4 = {};
61051
- __export(utils_exports4, {
61052
- Duration: () => Duration,
61053
- DurationType: () => DurationType,
61054
- clearCookie: () => clearCookie,
61055
- compare: () => compare,
61056
- getAppIdFromCtx: () => getAppIdFromCtx,
61057
- getCookie: () => getCookie,
61058
- hasCircularStructure: () => hasCircularStructure,
61059
- hash: () => hash,
61060
- isAudited: () => isAudited,
61061
- isClient: () => isClient,
61062
- isPublicApiRequest: () => isPublicApiRequest,
61063
- isServingApp: () => isServingApp,
61064
- isServingBuilder: () => isServingBuilder,
61065
- isServingBuilderPreview: () => isServingBuilderPreview,
61066
- isValidInternalAPIKey: () => isValidInternalAPIKey,
61067
- newid: () => newid,
61068
- openJwt: () => openJwt,
61069
- resolveAppUrl: () => resolveAppUrl,
61070
- setCookie: () => setCookie,
61071
- timeout: () => timeout,
61072
- validEmail: () => validEmail
61073
- });
61074
-
61075
- // src/utils/hashing.ts
61076
- var bcrypt = environment_default.JS_BCRYPT ? require("bcryptjs") : require("bcrypt");
61077
- var SALT_ROUNDS = environment_default.SALT_ROUNDS || 10;
61078
- async function hash(data) {
61079
- const salt = await bcrypt.genSalt(SALT_ROUNDS);
61080
- return bcrypt.hash(data, salt);
61081
- }
61082
- async function compare(data, encrypted) {
61083
- return bcrypt.compare(data, encrypted);
61084
- }
61085
-
61086
- // src/utils/utils.ts
61087
- var import_jsonwebtoken = __toESM(require("jsonwebtoken"));
61088
- var APP_PREFIX3 = "app" /* APP */ + SEPARATOR;
61089
- var PROD_APP_PREFIX = "/app/";
61090
- var BUILDER_PREVIEW_PATH = "/app/preview";
61091
- var BUILDER_PREFIX = "/builder";
61092
- var BUILDER_APP_PREFIX = `${BUILDER_PREFIX}/app/`;
61093
- var PUBLIC_API_PREFIX = "/api/public/v";
61094
- function confirmAppId(possibleAppId) {
61095
- return possibleAppId && possibleAppId.startsWith(APP_PREFIX3) ? possibleAppId : void 0;
61096
- }
61097
- async function resolveAppUrl(ctx) {
61098
- const appUrl = ctx.path.split("/")[2];
61099
- let possibleAppUrl = `/${appUrl.toLowerCase()}`;
61100
- let tenantId = getTenantId();
61101
- if (!environment_default.isDev() && environment_default.MULTI_TENANCY) {
61102
- tenantId = getTenantIDFromCtx(ctx, {
61103
- includeStrategies: ["subdomain" /* SUBDOMAIN */]
61104
- });
61105
- }
61106
- const apps = await doInTenant(
61107
- tenantId,
61108
- () => getAllApps({ dev: false })
61109
- );
61110
- const app = apps.filter(
61111
- (a) => a.url && a.url.toLowerCase() === possibleAppUrl
61112
- )[0];
61113
- return app && app.appId ? app.appId : void 0;
61114
- }
61115
- function isServingApp(ctx) {
61116
- if (ctx.path.startsWith(`/${APP_PREFIX3}`)) {
61117
- return true;
61118
- }
61119
- return ctx.path.startsWith(PROD_APP_PREFIX);
61120
- }
61121
- function isServingBuilder(ctx) {
61122
- return ctx.path.startsWith(BUILDER_APP_PREFIX);
61123
- }
61124
- function isServingBuilderPreview(ctx) {
61125
- return ctx.path.startsWith(BUILDER_PREVIEW_PATH);
61126
- }
61127
- function isPublicApiRequest(ctx) {
61128
- return ctx.path.startsWith(PUBLIC_API_PREFIX);
61129
- }
61130
- async function getAppIdFromCtx(ctx) {
61131
- const options2 = [ctx.request.headers["x-budibase-app-id" /* APP_ID */]];
61132
- let appId;
61133
- for (let option of options2) {
61134
- appId = confirmAppId(option);
61135
- if (appId) {
61136
- break;
61137
- }
61138
- }
61139
- if (!appId && ctx.request.body && ctx.request.body.appId) {
61140
- appId = confirmAppId(ctx.request.body.appId);
61141
- }
61142
- const pathId = parseAppIdFromUrlPath(ctx.path);
61143
- if (!appId && pathId) {
61144
- appId = confirmAppId(pathId);
61145
- }
61146
- const isBuilderPreview = ctx.path.startsWith(BUILDER_PREVIEW_PATH);
61147
- const isViewingProdApp = ctx.path.startsWith(PROD_APP_PREFIX) && !isBuilderPreview;
61148
- if (!appId && isViewingProdApp) {
61149
- appId = confirmAppId(await resolveAppUrl(ctx));
61150
- }
61151
- const referer = ctx.request.headers.referer;
61152
- if (!appId && referer?.includes(BUILDER_APP_PREFIX)) {
61153
- const refererId = parseAppIdFromUrlPath(ctx.request.headers.referer);
61154
- appId = confirmAppId(refererId);
61155
- }
61156
- return appId;
61157
- }
61158
- function parseAppIdFromUrlPath(url) {
61159
- if (!url) {
61160
- return;
61161
- }
61162
- return url.split("?")[0].split("/").find((subPath) => subPath.startsWith(APP_PREFIX3));
61163
- }
61164
- function openJwt(token) {
61165
- if (!token) {
61166
- return void 0;
61167
- }
61168
- try {
61169
- return import_jsonwebtoken.default.verify(token, environment_default.JWT_SECRET);
61170
- } catch (e) {
61171
- if (environment_default.JWT_SECRET_FALLBACK) {
61172
- return import_jsonwebtoken.default.verify(token, environment_default.JWT_SECRET_FALLBACK);
61173
- } else {
61174
- throw e;
61175
- }
61176
- }
61177
- }
61178
- function isValidInternalAPIKey(apiKey) {
61179
- if (environment_default.INTERNAL_API_KEY && environment_default.INTERNAL_API_KEY === apiKey) {
61180
- return true;
61181
- }
61182
- return !!(environment_default.INTERNAL_API_KEY_FALLBACK && environment_default.INTERNAL_API_KEY_FALLBACK === apiKey);
61183
- }
61184
- function getCookie(ctx, name) {
61185
- const cookie = ctx.cookies.get(name);
61186
- if (!cookie) {
61187
- return void 0;
61188
- }
61189
- return openJwt(cookie);
61190
- }
61191
- function setCookie(ctx, value, name = "builder", opts = { sign: true }) {
61192
- if (value && opts && opts.sign) {
61193
- value = import_jsonwebtoken.default.sign(value, environment_default.JWT_SECRET);
61194
- }
61195
- const config = {
61196
- expires: MAX_VALID_DATE,
61197
- path: "/",
61198
- httpOnly: false,
61199
- overwrite: true
61200
- };
61201
- if (environment_default.COOKIE_DOMAIN) {
61202
- config.domain = environment_default.COOKIE_DOMAIN;
61203
- }
61204
- ctx.cookies.set(name, value, config);
61205
- }
61206
- function clearCookie(ctx, name) {
61207
- setCookie(ctx, null, name);
61208
- }
61209
- function isClient(ctx) {
61210
- return ctx.headers["x-budibase-type" /* TYPE */] === "client";
61211
- }
61212
- function timeout(timeMs) {
61213
- return new Promise((resolve) => setTimeout(resolve, timeMs));
61214
- }
61215
- function isAudited(event) {
61216
- return !!AuditedEventFriendlyName[event];
61217
- }
61218
- function hasCircularStructure(json) {
61219
- if (typeof json !== "object") {
61220
- return false;
61221
- }
61222
- try {
61223
- JSON.stringify(json);
61224
- } catch (err) {
61225
- if (err instanceof Error && err?.message.includes("circular structure")) {
61226
- return true;
61227
- }
61228
- }
61229
- return false;
61230
- }
61231
-
61232
- // src/utils/stringUtils.ts
61233
- function validEmail(value) {
61234
- return value && !!value.match(
61235
- /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/
61236
- );
61237
- }
61238
-
61239
- // src/utils/Duration.ts
61240
- var DurationType = /* @__PURE__ */ ((DurationType2) => {
61241
- DurationType2["MILLISECONDS"] = "milliseconds";
61242
- DurationType2["SECONDS"] = "seconds";
61243
- DurationType2["MINUTES"] = "minutes";
61244
- DurationType2["HOURS"] = "hours";
61245
- DurationType2["DAYS"] = "days";
61246
- return DurationType2;
61247
- })(DurationType || {});
61248
- var conversion = {
61249
- milliseconds: 1,
61250
- seconds: 1e3,
61251
- minutes: 60 * 1e3,
61252
- hours: 60 * 60 * 1e3,
61253
- days: 24 * 60 * 60 * 1e3
61254
- };
61255
- var Duration = class _Duration {
61256
- static convert(from, to, duration) {
61257
- const milliseconds = duration * conversion[from];
61258
- return milliseconds / conversion[to];
61259
- }
61260
- static from(from, duration) {
61261
- return {
61262
- to: (to) => {
61263
- return _Duration.convert(from, to, duration);
61264
- },
61265
- toMs: () => {
61266
- return _Duration.convert(from, "milliseconds" /* MILLISECONDS */, duration);
61267
- },
61268
- toSeconds: () => {
61269
- return _Duration.convert(from, "seconds" /* SECONDS */, duration);
61270
- }
61271
- };
61272
- }
61273
- static fromSeconds(duration) {
61274
- return _Duration.from("seconds" /* SECONDS */, duration);
61275
- }
61276
- static fromMinutes(duration) {
61277
- return _Duration.from("minutes" /* MINUTES */, duration);
61278
- }
61279
- static fromHours(duration) {
61280
- return _Duration.from("hours" /* HOURS */, duration);
61281
- }
61282
- static fromDays(duration) {
61283
- return _Duration.from("days" /* DAYS */, duration);
61284
- }
61285
- static fromMilliseconds(duration) {
61286
- return _Duration.from("milliseconds" /* MILLISECONDS */, duration);
61287
- }
61288
- };
61289
-
61290
- // src/redis/redlockImpl.ts
61291
61316
  async function getClient(type, opts) {
61292
61317
  if (type === "custom" /* CUSTOM */) {
61293
61318
  return newRedlock(opts);