@budibase/backend-core 2.13.10 → 2.13.11

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 (44) hide show
  1. package/dist/index.js +474 -342
  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/cache/generic.js +6 -2
  7. package/dist/src/cache/generic.js.map +1 -1
  8. package/dist/src/cache/index.d.ts +2 -0
  9. package/dist/src/cache/index.js +3 -1
  10. package/dist/src/cache/index.js.map +1 -1
  11. package/dist/src/cache/invite.d.ts +33 -0
  12. package/dist/src/cache/invite.js +119 -0
  13. package/dist/src/cache/invite.js.map +1 -0
  14. package/dist/src/cache/passwordReset.d.ts +19 -0
  15. package/dist/src/cache/passwordReset.js +72 -0
  16. package/dist/src/cache/passwordReset.js.map +1 -0
  17. package/dist/src/index.d.ts +1 -0
  18. package/dist/src/index.js +2 -1
  19. package/dist/src/index.js.map +1 -1
  20. package/dist/src/redis/init.d.ts +3 -0
  21. package/dist/src/redis/init.js +27 -2
  22. package/dist/src/redis/init.js.map +1 -1
  23. package/dist/src/security/permissions.d.ts +1 -1
  24. package/dist/src/users/db.d.ts +1 -1
  25. package/dist/src/users/db.js +1 -1
  26. package/dist/src/users/db.js.map +1 -1
  27. package/dist/src/users/lookup.js +3 -0
  28. package/dist/src/users/lookup.js.map +1 -1
  29. package/dist/src/utils/Duration.d.ts +5 -0
  30. package/dist/src/utils/Duration.js +3 -0
  31. package/dist/src/utils/Duration.js.map +1 -1
  32. package/dist/tests/core/utilities/structures/users.js +1 -1
  33. package/dist/tests/core/utilities/structures/users.js.map +1 -1
  34. package/package.json +4 -4
  35. package/src/cache/generic.ts +3 -2
  36. package/src/cache/index.ts +2 -0
  37. package/src/cache/invite.ts +86 -0
  38. package/src/cache/passwordReset.ts +38 -0
  39. package/src/index.ts +2 -0
  40. package/src/redis/init.ts +22 -2
  41. package/src/users/db.ts +2 -2
  42. package/src/users/lookup.ts +4 -0
  43. package/src/utils/Duration.ts +3 -0
  44. package/tests/core/utilities/structures/users.ts +1 -1
package/dist/index.js CHANGED
@@ -3151,11 +3151,14 @@ var init_exports = {};
3151
3151
  __export(init_exports, {
3152
3152
  getAppClient: () => getAppClient,
3153
3153
  getCacheClient: () => getCacheClient,
3154
+ getInviteClient: () => getInviteClient,
3154
3155
  getLockClient: () => getLockClient,
3156
+ getPasswordResetClient: () => getPasswordResetClient,
3155
3157
  getSessionClient: () => getSessionClient,
3156
3158
  getSocketClient: () => getSocketClient,
3157
3159
  getUserClient: () => getUserClient,
3158
3160
  getWritethroughClient: () => getWritethroughClient,
3161
+ init: () => init3,
3159
3162
  shutdown: () => shutdown
3160
3163
  });
3161
3164
  async function init3() {
@@ -3165,6 +3168,8 @@ async function init3() {
3165
3168
  cacheClient = await new redis_default("data_cache" /* GENERIC_CACHE */).init();
3166
3169
  lockClient = await new redis_default("locks" /* LOCKS */).init();
3167
3170
  writethroughClient = await new redis_default("writeThrough" /* WRITE_THROUGH */).init();
3171
+ inviteClient = await new redis_default("invitation" /* INVITATIONS */).init();
3172
+ passwordResetClient = await new redis_default("pwReset" /* PW_RESETS */).init();
3168
3173
  socketClient = await new redis_default(
3169
3174
  "socket_io" /* SOCKET_IO */,
3170
3175
  1 /* SOCKET_IO */
@@ -3183,6 +3188,10 @@ async function shutdown() {
3183
3188
  await writethroughClient.finish();
3184
3189
  if (lockClient)
3185
3190
  await lockClient.finish();
3191
+ if (inviteClient)
3192
+ await inviteClient.finish();
3193
+ if (passwordResetClient)
3194
+ await passwordResetClient.finish();
3186
3195
  if (socketClient)
3187
3196
  await socketClient.finish();
3188
3197
  }
@@ -3228,7 +3237,19 @@ async function getSocketClient() {
3228
3237
  }
3229
3238
  return socketClient;
3230
3239
  }
3231
- var userClient, sessionClient, appClient, cacheClient, writethroughClient, lockClient, socketClient;
3240
+ async function getInviteClient() {
3241
+ if (!inviteClient) {
3242
+ await init3();
3243
+ }
3244
+ return inviteClient;
3245
+ }
3246
+ async function getPasswordResetClient() {
3247
+ if (!passwordResetClient) {
3248
+ await init3();
3249
+ }
3250
+ return passwordResetClient;
3251
+ }
3252
+ var userClient, sessionClient, appClient, cacheClient, writethroughClient, lockClient, socketClient, inviteClient, passwordResetClient;
3232
3253
  var init_init = __esm({
3233
3254
  "src/redis/init.ts"() {
3234
3255
  "use strict";
@@ -3240,86 +3261,6 @@ var init_init = __esm({
3240
3261
  }
3241
3262
  });
3242
3263
 
3243
- // src/cache/base/index.ts
3244
- var base_exports = {};
3245
- __export(base_exports, {
3246
- default: () => BaseCache
3247
- });
3248
- function generateTenantKey(key) {
3249
- const tenantId = getTenantId();
3250
- return `${key}:${tenantId}`;
3251
- }
3252
- var BaseCache;
3253
- var init_base = __esm({
3254
- "src/cache/base/index.ts"() {
3255
- "use strict";
3256
- init_context2();
3257
- init_init();
3258
- BaseCache = class {
3259
- constructor(client = void 0) {
3260
- this.client = client;
3261
- }
3262
- async getClient() {
3263
- return !this.client ? await getCacheClient() : this.client;
3264
- }
3265
- async keys(pattern) {
3266
- const client = await this.getClient();
3267
- return client.keys(pattern);
3268
- }
3269
- /**
3270
- * Read only from the cache.
3271
- */
3272
- async get(key, opts = { useTenancy: true }) {
3273
- key = opts.useTenancy ? generateTenantKey(key) : key;
3274
- const client = await this.getClient();
3275
- return client.get(key);
3276
- }
3277
- /**
3278
- * Write to the cache.
3279
- */
3280
- async store(key, value, ttl = null, opts = { useTenancy: true }) {
3281
- key = opts.useTenancy ? generateTenantKey(key) : key;
3282
- const client = await this.getClient();
3283
- await client.store(key, value, ttl);
3284
- }
3285
- /**
3286
- * Remove from cache.
3287
- */
3288
- async delete(key, opts = { useTenancy: true }) {
3289
- key = opts.useTenancy ? generateTenantKey(key) : key;
3290
- const client = await this.getClient();
3291
- return client.delete(key);
3292
- }
3293
- /**
3294
- * Read from the cache. Write to the cache if not exists.
3295
- */
3296
- async withCache(key, ttl, fetchFn, opts = { useTenancy: true }) {
3297
- const cachedValue = await this.get(key, opts);
3298
- if (cachedValue) {
3299
- return cachedValue;
3300
- }
3301
- try {
3302
- const fetchedValue = await fetchFn();
3303
- await this.store(key, fetchedValue, ttl, opts);
3304
- return fetchedValue;
3305
- } catch (err) {
3306
- console.error("Error fetching before cache - ", err);
3307
- throw err;
3308
- }
3309
- }
3310
- async bustCache(key, opts = { client: null }) {
3311
- const client = await this.getClient();
3312
- try {
3313
- await client.delete(generateTenantKey(key));
3314
- } catch (err) {
3315
- console.error("Error busting cache - ", err);
3316
- throw err;
3317
- }
3318
- }
3319
- };
3320
- }
3321
- });
3322
-
3323
3264
  // src/logging/correlation/correlation.ts
3324
3265
  var correlation_exports = {};
3325
3266
  __export(correlation_exports, {
@@ -3606,6 +3547,35 @@ var init_params = __esm({
3606
3547
  });
3607
3548
 
3608
3549
  // src/docIds/index.ts
3550
+ var docIds_exports = {};
3551
+ __export(docIds_exports, {
3552
+ generateAppID: () => generateAppID,
3553
+ generateAppUserID: () => generateAppUserID,
3554
+ generateDevInfoID: () => generateDevInfoID,
3555
+ generateGlobalUserID: () => generateGlobalUserID,
3556
+ generatePluginID: () => generatePluginID,
3557
+ generateRoleID: () => generateRoleID,
3558
+ generateRowID: () => generateRowID,
3559
+ generateTemplateID: () => generateTemplateID,
3560
+ generateUserMetadataID: () => generateUserMetadataID,
3561
+ generateWorkspaceID: () => generateWorkspaceID,
3562
+ getDocParams: () => getDocParams,
3563
+ getGlobalIDFromUserMetadataID: () => getGlobalIDFromUserMetadataID,
3564
+ getGlobalUserParams: () => getGlobalUserParams,
3565
+ getPluginParams: () => getPluginParams,
3566
+ getQueryIndex: () => getQueryIndex,
3567
+ getRoleParams: () => getRoleParams,
3568
+ getRowParams: () => getRowParams,
3569
+ getStartEndKeyURL: () => getStartEndKeyURL,
3570
+ getTemplateParams: () => getTemplateParams,
3571
+ getUserMetadataParams: () => getUserMetadataParams,
3572
+ getUsersByAppParams: () => getUsersByAppParams,
3573
+ getWorkspaceParams: () => getWorkspaceParams,
3574
+ isDatasourceId: () => isDatasourceId,
3575
+ isGlobalUserID: () => isGlobalUserID,
3576
+ isTableId: () => isTableId,
3577
+ prefixRoleID: () => prefixRoleID
3578
+ });
3609
3579
  var init_docIds = __esm({
3610
3580
  "src/docIds/index.ts"() {
3611
3581
  "use strict";
@@ -5672,6 +5642,7 @@ __export(src_exports, {
5672
5642
  constants: () => constants_exports,
5673
5643
  context: () => context_exports,
5674
5644
  db: () => db_exports,
5645
+ docIds: () => docIds_exports,
5675
5646
  docUpdates: () => docUpdates_exports,
5676
5647
  encryption: () => encryption_exports,
5677
5648
  env: () => environment_default,
@@ -5697,7 +5668,7 @@ __export(src_exports, {
5697
5668
  tenancy: () => tenancy,
5698
5669
  timers: () => timers_exports,
5699
5670
  users: () => users_exports3,
5700
- utils: () => utils_exports3
5671
+ utils: () => utils_exports2
5701
5672
  });
5702
5673
  module.exports = __toCommonJS(src_exports);
5703
5674
 
@@ -5736,7 +5707,9 @@ __export(cache_exports, {
5736
5707
  destroy: () => destroy,
5737
5708
  generic: () => generic_exports,
5738
5709
  get: () => get,
5710
+ invite: () => invite_exports,
5739
5711
  keys: () => keys,
5712
+ passwordReset: () => passwordReset_exports,
5740
5713
  store: () => store,
5741
5714
  user: () => user_exports,
5742
5715
  withCache: () => withCache,
@@ -5755,8 +5728,79 @@ __export(generic_exports, {
5755
5728
  store: () => store,
5756
5729
  withCache: () => withCache
5757
5730
  });
5758
- var BaseCache2 = (init_base(), __toCommonJS(base_exports));
5759
- var GENERIC = new BaseCache2.default();
5731
+
5732
+ // src/cache/base/index.ts
5733
+ init_context2();
5734
+ init_init();
5735
+ function generateTenantKey(key) {
5736
+ const tenantId = getTenantId();
5737
+ return `${key}:${tenantId}`;
5738
+ }
5739
+ var BaseCache = class {
5740
+ constructor(client = void 0) {
5741
+ this.client = client;
5742
+ }
5743
+ async getClient() {
5744
+ return !this.client ? await getCacheClient() : this.client;
5745
+ }
5746
+ async keys(pattern) {
5747
+ const client = await this.getClient();
5748
+ return client.keys(pattern);
5749
+ }
5750
+ /**
5751
+ * Read only from the cache.
5752
+ */
5753
+ async get(key, opts = { useTenancy: true }) {
5754
+ key = opts.useTenancy ? generateTenantKey(key) : key;
5755
+ const client = await this.getClient();
5756
+ return client.get(key);
5757
+ }
5758
+ /**
5759
+ * Write to the cache.
5760
+ */
5761
+ async store(key, value, ttl = null, opts = { useTenancy: true }) {
5762
+ key = opts.useTenancy ? generateTenantKey(key) : key;
5763
+ const client = await this.getClient();
5764
+ await client.store(key, value, ttl);
5765
+ }
5766
+ /**
5767
+ * Remove from cache.
5768
+ */
5769
+ async delete(key, opts = { useTenancy: true }) {
5770
+ key = opts.useTenancy ? generateTenantKey(key) : key;
5771
+ const client = await this.getClient();
5772
+ return client.delete(key);
5773
+ }
5774
+ /**
5775
+ * Read from the cache. Write to the cache if not exists.
5776
+ */
5777
+ async withCache(key, ttl, fetchFn, opts = { useTenancy: true }) {
5778
+ const cachedValue = await this.get(key, opts);
5779
+ if (cachedValue) {
5780
+ return cachedValue;
5781
+ }
5782
+ try {
5783
+ const fetchedValue = await fetchFn();
5784
+ await this.store(key, fetchedValue, ttl, opts);
5785
+ return fetchedValue;
5786
+ } catch (err) {
5787
+ console.error("Error fetching before cache - ", err);
5788
+ throw err;
5789
+ }
5790
+ }
5791
+ async bustCache(key, opts = { client: null }) {
5792
+ const client = await this.getClient();
5793
+ try {
5794
+ await client.delete(generateTenantKey(key));
5795
+ } catch (err) {
5796
+ console.error("Error busting cache - ", err);
5797
+ throw err;
5798
+ }
5799
+ }
5800
+ };
5801
+
5802
+ // src/cache/generic.ts
5803
+ var GENERIC = new BaseCache();
5760
5804
  var CacheKey = /* @__PURE__ */ ((CacheKey2) => {
5761
5805
  CacheKey2["CHECKLIST"] = "checklist";
5762
5806
  CacheKey2["INSTALLATION"] = "installation";
@@ -6371,8 +6415,320 @@ init_context2();
6371
6415
  init_environment2();
6372
6416
 
6373
6417
  // src/users/lookup.ts
6374
- init_db4();
6375
- init_constants3();
6418
+ init_db4();
6419
+ init_constants3();
6420
+
6421
+ // src/cache/invite.ts
6422
+ var invite_exports = {};
6423
+ __export(invite_exports, {
6424
+ createCode: () => createCode,
6425
+ deleteCode: () => deleteCode,
6426
+ getCode: () => getCode,
6427
+ getExistingInvites: () => getExistingInvites,
6428
+ getInviteCodes: () => getInviteCodes,
6429
+ updateCode: () => updateCode
6430
+ });
6431
+
6432
+ // src/utils/index.ts
6433
+ var utils_exports2 = {};
6434
+ __export(utils_exports2, {
6435
+ Duration: () => Duration,
6436
+ DurationType: () => DurationType,
6437
+ clearCookie: () => clearCookie,
6438
+ compare: () => compare,
6439
+ getAppIdFromCtx: () => getAppIdFromCtx,
6440
+ getCookie: () => getCookie,
6441
+ hasCircularStructure: () => hasCircularStructure,
6442
+ hash: () => hash,
6443
+ isAudited: () => isAudited,
6444
+ isClient: () => isClient,
6445
+ isPublicApiRequest: () => isPublicApiRequest,
6446
+ isServingApp: () => isServingApp,
6447
+ isServingBuilder: () => isServingBuilder,
6448
+ isServingBuilderPreview: () => isServingBuilderPreview,
6449
+ isValidInternalAPIKey: () => isValidInternalAPIKey,
6450
+ newid: () => newid,
6451
+ openJwt: () => openJwt,
6452
+ resolveAppUrl: () => resolveAppUrl,
6453
+ setCookie: () => setCookie,
6454
+ timeout: () => timeout,
6455
+ validEmail: () => validEmail
6456
+ });
6457
+
6458
+ // src/utils/hashing.ts
6459
+ init_environment2();
6460
+ init_newid();
6461
+ var bcrypt = environment_default.JS_BCRYPT ? require("bcryptjs") : require("bcrypt");
6462
+ var SALT_ROUNDS = environment_default.SALT_ROUNDS || 10;
6463
+ async function hash(data) {
6464
+ const salt = await bcrypt.genSalt(SALT_ROUNDS);
6465
+ return bcrypt.hash(data, salt);
6466
+ }
6467
+ async function compare(data, encrypted) {
6468
+ return bcrypt.compare(data, encrypted);
6469
+ }
6470
+
6471
+ // src/utils/utils.ts
6472
+ init_db4();
6473
+ init_constants3();
6474
+ init_environment2();
6475
+ init_context2();
6476
+ init_src();
6477
+ var jwt = require("jsonwebtoken");
6478
+ var APP_PREFIX2 = "app" /* APP */ + SEPARATOR;
6479
+ var PROD_APP_PREFIX = "/app/";
6480
+ var BUILDER_PREVIEW_PATH = "/app/preview";
6481
+ var BUILDER_PREFIX = "/builder";
6482
+ var BUILDER_APP_PREFIX = `${BUILDER_PREFIX}/app/`;
6483
+ var PUBLIC_API_PREFIX = "/api/public/v";
6484
+ function confirmAppId(possibleAppId) {
6485
+ return possibleAppId && possibleAppId.startsWith(APP_PREFIX2) ? possibleAppId : void 0;
6486
+ }
6487
+ async function resolveAppUrl(ctx) {
6488
+ const appUrl = ctx.path.split("/")[2];
6489
+ let possibleAppUrl = `/${appUrl.toLowerCase()}`;
6490
+ let tenantId = getTenantId();
6491
+ if (environment_default.MULTI_TENANCY) {
6492
+ tenantId = getTenantIDFromCtx(ctx, {
6493
+ includeStrategies: ["subdomain" /* SUBDOMAIN */]
6494
+ });
6495
+ }
6496
+ const apps = await doInTenant(
6497
+ tenantId,
6498
+ () => getAllApps({ dev: false })
6499
+ );
6500
+ const app = apps.filter(
6501
+ (a) => a.url && a.url.toLowerCase() === possibleAppUrl
6502
+ )[0];
6503
+ return app && app.appId ? app.appId : void 0;
6504
+ }
6505
+ function isServingApp(ctx) {
6506
+ if (ctx.path.startsWith(`/${APP_PREFIX2}`)) {
6507
+ return true;
6508
+ }
6509
+ if (ctx.path.startsWith(PROD_APP_PREFIX)) {
6510
+ return true;
6511
+ }
6512
+ return false;
6513
+ }
6514
+ function isServingBuilder(ctx) {
6515
+ return ctx.path.startsWith(BUILDER_APP_PREFIX);
6516
+ }
6517
+ function isServingBuilderPreview(ctx) {
6518
+ return ctx.path.startsWith(BUILDER_PREVIEW_PATH);
6519
+ }
6520
+ function isPublicApiRequest(ctx) {
6521
+ return ctx.path.startsWith(PUBLIC_API_PREFIX);
6522
+ }
6523
+ async function getAppIdFromCtx(ctx) {
6524
+ const options2 = [ctx.request.headers["x-budibase-app-id" /* APP_ID */]];
6525
+ let appId;
6526
+ for (let option of options2) {
6527
+ appId = confirmAppId(option);
6528
+ if (appId) {
6529
+ break;
6530
+ }
6531
+ }
6532
+ if (!appId && ctx.request.body && ctx.request.body.appId) {
6533
+ appId = confirmAppId(ctx.request.body.appId);
6534
+ }
6535
+ const pathId = parseAppIdFromUrl(ctx.path);
6536
+ if (!appId && pathId) {
6537
+ appId = confirmAppId(pathId);
6538
+ }
6539
+ const isBuilderPreview = ctx.path.startsWith(BUILDER_PREVIEW_PATH);
6540
+ const isViewingProdApp = ctx.path.startsWith(PROD_APP_PREFIX) && !isBuilderPreview;
6541
+ if (!appId && isViewingProdApp) {
6542
+ appId = confirmAppId(await resolveAppUrl(ctx));
6543
+ }
6544
+ const referer = ctx.request.headers.referer;
6545
+ if (!appId && referer?.includes(BUILDER_APP_PREFIX)) {
6546
+ const refererId = parseAppIdFromUrl(ctx.request.headers.referer);
6547
+ appId = confirmAppId(refererId);
6548
+ }
6549
+ return appId;
6550
+ }
6551
+ function parseAppIdFromUrl(url) {
6552
+ if (!url) {
6553
+ return;
6554
+ }
6555
+ return url.split("/").find((subPath) => subPath.startsWith(APP_PREFIX2));
6556
+ }
6557
+ function openJwt(token) {
6558
+ if (!token) {
6559
+ return token;
6560
+ }
6561
+ try {
6562
+ return jwt.verify(token, environment_default.JWT_SECRET);
6563
+ } catch (e) {
6564
+ if (environment_default.JWT_SECRET_FALLBACK) {
6565
+ return jwt.verify(token, environment_default.JWT_SECRET_FALLBACK);
6566
+ } else {
6567
+ throw e;
6568
+ }
6569
+ }
6570
+ }
6571
+ function isValidInternalAPIKey(apiKey) {
6572
+ if (environment_default.INTERNAL_API_KEY && environment_default.INTERNAL_API_KEY === apiKey) {
6573
+ return true;
6574
+ }
6575
+ if (environment_default.INTERNAL_API_KEY_FALLBACK && environment_default.INTERNAL_API_KEY_FALLBACK === apiKey) {
6576
+ return true;
6577
+ }
6578
+ return false;
6579
+ }
6580
+ function getCookie(ctx, name) {
6581
+ const cookie = ctx.cookies.get(name);
6582
+ if (!cookie) {
6583
+ return cookie;
6584
+ }
6585
+ return openJwt(cookie);
6586
+ }
6587
+ function setCookie(ctx, value, name = "builder", opts = { sign: true }) {
6588
+ if (value && opts && opts.sign) {
6589
+ value = jwt.sign(value, environment_default.JWT_SECRET);
6590
+ }
6591
+ const config = {
6592
+ expires: MAX_VALID_DATE,
6593
+ path: "/",
6594
+ httpOnly: false,
6595
+ overwrite: true
6596
+ };
6597
+ if (environment_default.COOKIE_DOMAIN) {
6598
+ config.domain = environment_default.COOKIE_DOMAIN;
6599
+ }
6600
+ ctx.cookies.set(name, value, config);
6601
+ }
6602
+ function clearCookie(ctx, name) {
6603
+ setCookie(ctx, null, name);
6604
+ }
6605
+ function isClient(ctx) {
6606
+ return ctx.headers["x-budibase-type" /* TYPE */] === "client";
6607
+ }
6608
+ function timeout(timeMs) {
6609
+ return new Promise((resolve) => setTimeout(resolve, timeMs));
6610
+ }
6611
+ function isAudited(event) {
6612
+ return !!AuditedEventFriendlyName[event];
6613
+ }
6614
+ function hasCircularStructure(json) {
6615
+ if (typeof json !== "object") {
6616
+ return false;
6617
+ }
6618
+ try {
6619
+ JSON.stringify(json);
6620
+ } catch (err) {
6621
+ if (err instanceof Error && err?.message.includes("circular structure")) {
6622
+ return true;
6623
+ }
6624
+ }
6625
+ return false;
6626
+ }
6627
+
6628
+ // src/utils/stringUtils.ts
6629
+ function validEmail(value) {
6630
+ return value && !!value.match(
6631
+ /^(([^<>()[\]\\.,;:\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,}))$/
6632
+ );
6633
+ }
6634
+
6635
+ // src/utils/Duration.ts
6636
+ var DurationType = /* @__PURE__ */ ((DurationType4) => {
6637
+ DurationType4["MILLISECONDS"] = "milliseconds";
6638
+ DurationType4["SECONDS"] = "seconds";
6639
+ DurationType4["MINUTES"] = "minutes";
6640
+ DurationType4["HOURS"] = "hours";
6641
+ DurationType4["DAYS"] = "days";
6642
+ return DurationType4;
6643
+ })(DurationType || {});
6644
+ var conversion = {
6645
+ milliseconds: 1,
6646
+ seconds: 1e3,
6647
+ minutes: 60 * 1e3,
6648
+ hours: 60 * 60 * 1e3,
6649
+ days: 24 * 60 * 60 * 1e3
6650
+ };
6651
+ var Duration = class _Duration {
6652
+ static convert(from, to, duration) {
6653
+ const milliseconds = duration * conversion[from];
6654
+ return milliseconds / conversion[to];
6655
+ }
6656
+ static from(from, duration) {
6657
+ return {
6658
+ to: (to) => {
6659
+ return _Duration.convert(from, to, duration);
6660
+ },
6661
+ toMs: () => {
6662
+ return _Duration.convert(from, "milliseconds" /* MILLISECONDS */, duration);
6663
+ },
6664
+ toSeconds: () => {
6665
+ return _Duration.convert(from, "seconds" /* SECONDS */, duration);
6666
+ }
6667
+ };
6668
+ }
6669
+ static fromSeconds(duration) {
6670
+ return _Duration.from("seconds" /* SECONDS */, duration);
6671
+ }
6672
+ static fromMinutes(duration) {
6673
+ return _Duration.from("minutes" /* MINUTES */, duration);
6674
+ }
6675
+ static fromHours(duration) {
6676
+ return _Duration.from("hours" /* HOURS */, duration);
6677
+ }
6678
+ static fromDays(duration) {
6679
+ return _Duration.from("days" /* DAYS */, duration);
6680
+ }
6681
+ };
6682
+
6683
+ // src/cache/invite.ts
6684
+ init_environment2();
6685
+ init_context2();
6686
+ init_init();
6687
+ var TTL_SECONDS = Duration.fromDays(7).toSeconds();
6688
+ async function updateCode(code, value) {
6689
+ const client = await getInviteClient();
6690
+ await client.store(code, value, TTL_SECONDS);
6691
+ }
6692
+ async function createCode(email, info) {
6693
+ const code = newid();
6694
+ const client = await getInviteClient();
6695
+ await client.store(code, { email, info }, TTL_SECONDS);
6696
+ return code;
6697
+ }
6698
+ async function getCode(code) {
6699
+ const client = await getInviteClient();
6700
+ const value = await client.get(code);
6701
+ if (!value) {
6702
+ throw "Invitation is not valid or has expired, please request a new one.";
6703
+ }
6704
+ return value;
6705
+ }
6706
+ async function deleteCode(code) {
6707
+ const client = await getInviteClient();
6708
+ await client.delete(code);
6709
+ }
6710
+ async function getInviteCodes() {
6711
+ const client = await getInviteClient();
6712
+ const invites = await client.scan();
6713
+ const results = invites.map((invite) => {
6714
+ return {
6715
+ ...invite.value,
6716
+ code: invite.key
6717
+ };
6718
+ });
6719
+ if (!environment_default.MULTI_TENANCY) {
6720
+ return results;
6721
+ }
6722
+ const tenantId = getTenantId();
6723
+ return results.filter((invite) => tenantId === invite.info.tenantId);
6724
+ }
6725
+ async function getExistingInvites(emails) {
6726
+ return (await getInviteCodes()).filter(
6727
+ (invite) => emails.includes(invite.email)
6728
+ );
6729
+ }
6730
+
6731
+ // src/users/lookup.ts
6376
6732
  async function searchExistingEmails(emails) {
6377
6733
  let matchedEmails = [];
6378
6734
  const existingTenantUsers = await getExistingTenantUsers(emails);
@@ -6381,6 +6737,8 @@ async function searchExistingEmails(emails) {
6381
6737
  matchedEmails.push(...existingPlatformUsers.map((user) => user._id));
6382
6738
  const existingAccounts = await getExistingAccounts(emails);
6383
6739
  matchedEmails.push(...existingAccounts.map((account) => account.email));
6740
+ const invitedEmails = await getExistingInvites(emails);
6741
+ matchedEmails.push(...invitedEmails.map((invite) => invite.email));
6384
6742
  return [...new Set(matchedEmails.map((email) => email.toLowerCase()))];
6385
6743
  }
6386
6744
  async function getPlatformUser(identifier) {
@@ -6618,7 +6976,7 @@ __export(applications_exports, {
6618
6976
  getProdAppID: () => getProdAppID2
6619
6977
  });
6620
6978
  init_src();
6621
- var APP_PREFIX2 = prefixed("app" /* APP */);
6979
+ var APP_PREFIX3 = prefixed("app" /* APP */);
6622
6980
  var APP_DEV_PREFIX2 = prefixed("app_dev" /* APP_DEV */);
6623
6981
  function getDevAppID2(appId) {
6624
6982
  if (!appId) {
@@ -6627,9 +6985,9 @@ function getDevAppID2(appId) {
6627
6985
  if (appId.startsWith(APP_DEV_PREFIX2)) {
6628
6986
  return appId;
6629
6987
  }
6630
- const split = appId.split(APP_PREFIX2);
6988
+ const split = appId.split(APP_PREFIX3);
6631
6989
  split.shift();
6632
- const rest = split.join(APP_PREFIX2);
6990
+ const rest = split.join(APP_PREFIX3);
6633
6991
  return `${APP_DEV_PREFIX2}${rest}`;
6634
6992
  }
6635
6993
  function getProdAppID2(appId) {
@@ -6642,7 +7000,7 @@ function getProdAppID2(appId) {
6642
7000
  const split = appId.split(APP_DEV_PREFIX2);
6643
7001
  split.shift();
6644
7002
  const rest = split.join(APP_DEV_PREFIX2);
6645
- return `${APP_PREFIX2}${rest}`;
7003
+ return `${APP_PREFIX3}${rest}`;
6646
7004
  }
6647
7005
 
6648
7006
  // ../shared-core/src/sdk/documents/users.ts
@@ -7359,256 +7717,6 @@ init_utils2();
7359
7717
 
7360
7718
  // src/queue/inMemoryQueue.ts
7361
7719
  var import_events2 = __toESM(require("events"));
7362
-
7363
- // src/utils/index.ts
7364
- var utils_exports3 = {};
7365
- __export(utils_exports3, {
7366
- Duration: () => Duration,
7367
- DurationType: () => DurationType,
7368
- clearCookie: () => clearCookie,
7369
- compare: () => compare,
7370
- getAppIdFromCtx: () => getAppIdFromCtx,
7371
- getCookie: () => getCookie,
7372
- hasCircularStructure: () => hasCircularStructure,
7373
- hash: () => hash,
7374
- isAudited: () => isAudited,
7375
- isClient: () => isClient,
7376
- isPublicApiRequest: () => isPublicApiRequest,
7377
- isServingApp: () => isServingApp,
7378
- isServingBuilder: () => isServingBuilder,
7379
- isServingBuilderPreview: () => isServingBuilderPreview,
7380
- isValidInternalAPIKey: () => isValidInternalAPIKey,
7381
- newid: () => newid,
7382
- openJwt: () => openJwt,
7383
- resolveAppUrl: () => resolveAppUrl,
7384
- setCookie: () => setCookie,
7385
- timeout: () => timeout,
7386
- validEmail: () => validEmail
7387
- });
7388
-
7389
- // src/utils/hashing.ts
7390
- init_environment2();
7391
- init_newid();
7392
- var bcrypt = environment_default.JS_BCRYPT ? require("bcryptjs") : require("bcrypt");
7393
- var SALT_ROUNDS = environment_default.SALT_ROUNDS || 10;
7394
- async function hash(data) {
7395
- const salt = await bcrypt.genSalt(SALT_ROUNDS);
7396
- return bcrypt.hash(data, salt);
7397
- }
7398
- async function compare(data, encrypted) {
7399
- return bcrypt.compare(data, encrypted);
7400
- }
7401
-
7402
- // src/utils/utils.ts
7403
- init_db4();
7404
- init_constants3();
7405
- init_environment2();
7406
- init_context2();
7407
- init_src();
7408
- var jwt = require("jsonwebtoken");
7409
- var APP_PREFIX3 = "app" /* APP */ + SEPARATOR;
7410
- var PROD_APP_PREFIX = "/app/";
7411
- var BUILDER_PREVIEW_PATH = "/app/preview";
7412
- var BUILDER_PREFIX = "/builder";
7413
- var BUILDER_APP_PREFIX = `${BUILDER_PREFIX}/app/`;
7414
- var PUBLIC_API_PREFIX = "/api/public/v";
7415
- function confirmAppId(possibleAppId) {
7416
- return possibleAppId && possibleAppId.startsWith(APP_PREFIX3) ? possibleAppId : void 0;
7417
- }
7418
- async function resolveAppUrl(ctx) {
7419
- const appUrl = ctx.path.split("/")[2];
7420
- let possibleAppUrl = `/${appUrl.toLowerCase()}`;
7421
- let tenantId = getTenantId();
7422
- if (environment_default.MULTI_TENANCY) {
7423
- tenantId = getTenantIDFromCtx(ctx, {
7424
- includeStrategies: ["subdomain" /* SUBDOMAIN */]
7425
- });
7426
- }
7427
- const apps = await doInTenant(
7428
- tenantId,
7429
- () => getAllApps({ dev: false })
7430
- );
7431
- const app = apps.filter(
7432
- (a) => a.url && a.url.toLowerCase() === possibleAppUrl
7433
- )[0];
7434
- return app && app.appId ? app.appId : void 0;
7435
- }
7436
- function isServingApp(ctx) {
7437
- if (ctx.path.startsWith(`/${APP_PREFIX3}`)) {
7438
- return true;
7439
- }
7440
- if (ctx.path.startsWith(PROD_APP_PREFIX)) {
7441
- return true;
7442
- }
7443
- return false;
7444
- }
7445
- function isServingBuilder(ctx) {
7446
- return ctx.path.startsWith(BUILDER_APP_PREFIX);
7447
- }
7448
- function isServingBuilderPreview(ctx) {
7449
- return ctx.path.startsWith(BUILDER_PREVIEW_PATH);
7450
- }
7451
- function isPublicApiRequest(ctx) {
7452
- return ctx.path.startsWith(PUBLIC_API_PREFIX);
7453
- }
7454
- async function getAppIdFromCtx(ctx) {
7455
- const options2 = [ctx.request.headers["x-budibase-app-id" /* APP_ID */]];
7456
- let appId;
7457
- for (let option of options2) {
7458
- appId = confirmAppId(option);
7459
- if (appId) {
7460
- break;
7461
- }
7462
- }
7463
- if (!appId && ctx.request.body && ctx.request.body.appId) {
7464
- appId = confirmAppId(ctx.request.body.appId);
7465
- }
7466
- const pathId = parseAppIdFromUrl(ctx.path);
7467
- if (!appId && pathId) {
7468
- appId = confirmAppId(pathId);
7469
- }
7470
- const isBuilderPreview = ctx.path.startsWith(BUILDER_PREVIEW_PATH);
7471
- const isViewingProdApp = ctx.path.startsWith(PROD_APP_PREFIX) && !isBuilderPreview;
7472
- if (!appId && isViewingProdApp) {
7473
- appId = confirmAppId(await resolveAppUrl(ctx));
7474
- }
7475
- const referer = ctx.request.headers.referer;
7476
- if (!appId && referer?.includes(BUILDER_APP_PREFIX)) {
7477
- const refererId = parseAppIdFromUrl(ctx.request.headers.referer);
7478
- appId = confirmAppId(refererId);
7479
- }
7480
- return appId;
7481
- }
7482
- function parseAppIdFromUrl(url) {
7483
- if (!url) {
7484
- return;
7485
- }
7486
- return url.split("/").find((subPath) => subPath.startsWith(APP_PREFIX3));
7487
- }
7488
- function openJwt(token) {
7489
- if (!token) {
7490
- return token;
7491
- }
7492
- try {
7493
- return jwt.verify(token, environment_default.JWT_SECRET);
7494
- } catch (e) {
7495
- if (environment_default.JWT_SECRET_FALLBACK) {
7496
- return jwt.verify(token, environment_default.JWT_SECRET_FALLBACK);
7497
- } else {
7498
- throw e;
7499
- }
7500
- }
7501
- }
7502
- function isValidInternalAPIKey(apiKey) {
7503
- if (environment_default.INTERNAL_API_KEY && environment_default.INTERNAL_API_KEY === apiKey) {
7504
- return true;
7505
- }
7506
- if (environment_default.INTERNAL_API_KEY_FALLBACK && environment_default.INTERNAL_API_KEY_FALLBACK === apiKey) {
7507
- return true;
7508
- }
7509
- return false;
7510
- }
7511
- function getCookie(ctx, name) {
7512
- const cookie = ctx.cookies.get(name);
7513
- if (!cookie) {
7514
- return cookie;
7515
- }
7516
- return openJwt(cookie);
7517
- }
7518
- function setCookie(ctx, value, name = "builder", opts = { sign: true }) {
7519
- if (value && opts && opts.sign) {
7520
- value = jwt.sign(value, environment_default.JWT_SECRET);
7521
- }
7522
- const config = {
7523
- expires: MAX_VALID_DATE,
7524
- path: "/",
7525
- httpOnly: false,
7526
- overwrite: true
7527
- };
7528
- if (environment_default.COOKIE_DOMAIN) {
7529
- config.domain = environment_default.COOKIE_DOMAIN;
7530
- }
7531
- ctx.cookies.set(name, value, config);
7532
- }
7533
- function clearCookie(ctx, name) {
7534
- setCookie(ctx, null, name);
7535
- }
7536
- function isClient(ctx) {
7537
- return ctx.headers["x-budibase-type" /* TYPE */] === "client";
7538
- }
7539
- function timeout(timeMs) {
7540
- return new Promise((resolve) => setTimeout(resolve, timeMs));
7541
- }
7542
- function isAudited(event) {
7543
- return !!AuditedEventFriendlyName[event];
7544
- }
7545
- function hasCircularStructure(json) {
7546
- if (typeof json !== "object") {
7547
- return false;
7548
- }
7549
- try {
7550
- JSON.stringify(json);
7551
- } catch (err) {
7552
- if (err instanceof Error && err?.message.includes("circular structure")) {
7553
- return true;
7554
- }
7555
- }
7556
- return false;
7557
- }
7558
-
7559
- // src/utils/stringUtils.ts
7560
- function validEmail(value) {
7561
- return value && !!value.match(
7562
- /^(([^<>()[\]\\.,;:\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,}))$/
7563
- );
7564
- }
7565
-
7566
- // src/utils/Duration.ts
7567
- var DurationType = /* @__PURE__ */ ((DurationType2) => {
7568
- DurationType2["MILLISECONDS"] = "milliseconds";
7569
- DurationType2["SECONDS"] = "seconds";
7570
- DurationType2["MINUTES"] = "minutes";
7571
- DurationType2["HOURS"] = "hours";
7572
- DurationType2["DAYS"] = "days";
7573
- return DurationType2;
7574
- })(DurationType || {});
7575
- var conversion = {
7576
- milliseconds: 1,
7577
- seconds: 1e3,
7578
- minutes: 60 * 1e3,
7579
- hours: 60 * 60 * 1e3,
7580
- days: 24 * 60 * 60 * 1e3
7581
- };
7582
- var Duration = class _Duration {
7583
- static convert(from, to, duration) {
7584
- const milliseconds = duration * conversion[from];
7585
- return milliseconds / conversion[to];
7586
- }
7587
- static from(from, duration) {
7588
- return {
7589
- to: (to) => {
7590
- return _Duration.convert(from, to, duration);
7591
- },
7592
- toMs: () => {
7593
- return _Duration.convert(from, "milliseconds" /* MILLISECONDS */, duration);
7594
- }
7595
- };
7596
- }
7597
- static fromSeconds(duration) {
7598
- return _Duration.from("seconds" /* SECONDS */, duration);
7599
- }
7600
- static fromMinutes(duration) {
7601
- return _Duration.from("minutes" /* MINUTES */, duration);
7602
- }
7603
- static fromHours(duration) {
7604
- return _Duration.from("hours" /* HOURS */, duration);
7605
- }
7606
- static fromDays(duration) {
7607
- return _Duration.from("days" /* DAYS */, duration);
7608
- }
7609
- };
7610
-
7611
- // src/queue/inMemoryQueue.ts
7612
7720
  function newJob(queue, message) {
7613
7721
  return {
7614
7722
  timestamp: Date.now(),
@@ -10162,7 +10270,7 @@ var UserDB = class _UserDB {
10162
10270
  });
10163
10271
  continue;
10164
10272
  }
10165
- newUser.userGroups = groups;
10273
+ newUser.userGroups = groups || [];
10166
10274
  newUsers.push(newUser);
10167
10275
  if (isCreator2(newUser)) {
10168
10276
  newCreators.push(newUser);
@@ -10395,7 +10503,6 @@ var writethrough_exports = {};
10395
10503
  __export(writethrough_exports, {
10396
10504
  Writethrough: () => Writethrough
10397
10505
  });
10398
- init_base();
10399
10506
  init_init();
10400
10507
  init_logging();
10401
10508
  init_src();
@@ -10501,6 +10608,29 @@ var Writethrough = class {
10501
10608
  }
10502
10609
  };
10503
10610
 
10611
+ // src/cache/passwordReset.ts
10612
+ var passwordReset_exports = {};
10613
+ __export(passwordReset_exports, {
10614
+ createCode: () => createCode2,
10615
+ getCode: () => getCode2
10616
+ });
10617
+ init_init();
10618
+ var TTL_SECONDS2 = Duration.fromHours(1).toSeconds();
10619
+ async function createCode2(userId, info) {
10620
+ const code = newid();
10621
+ const client = await getPasswordResetClient();
10622
+ await client.store(code, { userId, info }, TTL_SECONDS2);
10623
+ return code;
10624
+ }
10625
+ async function getCode2(code) {
10626
+ const client = await getPasswordResetClient();
10627
+ const value = await client.get(code);
10628
+ if (!value) {
10629
+ throw "Provided information is not valid, cannot reset password - please try again.";
10630
+ }
10631
+ return value;
10632
+ }
10633
+
10504
10634
  // src/configs/configs.ts
10505
10635
  init_context2();
10506
10636
  init_environment2();
@@ -12844,6 +12974,7 @@ function init7(processors2) {
12844
12974
 
12845
12975
  // src/index.ts
12846
12976
  init_db4();
12977
+ init_docIds();
12847
12978
  init_context2();
12848
12979
  init_constants3();
12849
12980
  init_db4();
@@ -12896,6 +13027,7 @@ var init8 = (opts = {}) => {
12896
13027
  constants,
12897
13028
  context,
12898
13029
  db,
13030
+ docIds,
12899
13031
  docUpdates,
12900
13032
  encryption,
12901
13033
  env,