@budibase/backend-core 2.21.3 → 2.21.5

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 (91) hide show
  1. package/dist/index.js +301 -68
  2. package/dist/index.js.map +4 -4
  3. package/dist/index.js.meta.json +1 -1
  4. package/dist/package.json +6 -5
  5. package/dist/plugins.js.meta.json +1 -1
  6. package/dist/src/cache/base/index.d.ts +33 -3
  7. package/dist/src/cache/base/index.js +60 -1
  8. package/dist/src/cache/base/index.js.map +1 -1
  9. package/dist/src/cache/docWritethrough.d.ts +21 -0
  10. package/dist/src/cache/docWritethrough.js +107 -0
  11. package/dist/src/cache/docWritethrough.js.map +1 -0
  12. package/dist/src/cache/generic.d.ts +3 -3
  13. package/dist/src/cache/generic.js.map +1 -1
  14. package/dist/src/cache/index.d.ts +1 -0
  15. package/dist/src/cache/index.js +2 -1
  16. package/dist/src/cache/index.js.map +1 -1
  17. package/dist/src/cache/user.js.map +1 -1
  18. package/dist/src/configs/configs.d.ts +1 -1
  19. package/dist/src/constants/db.d.ts +3 -0
  20. package/dist/src/constants/db.js +3 -0
  21. package/dist/src/constants/db.js.map +1 -1
  22. package/dist/src/context/mainContext.d.ts +1 -0
  23. package/dist/src/context/mainContext.js +13 -1
  24. package/dist/src/context/mainContext.js.map +1 -1
  25. package/dist/src/db/Replication.d.ts +13 -25
  26. package/dist/src/db/Replication.js +18 -33
  27. package/dist/src/db/Replication.js.map +1 -1
  28. package/dist/src/db/couch/DatabaseImpl.d.ts +3 -1
  29. package/dist/src/db/couch/DatabaseImpl.js +18 -1
  30. package/dist/src/db/couch/DatabaseImpl.js.map +1 -1
  31. package/dist/src/db/instrumentation.d.ts +1 -1
  32. package/dist/src/db/instrumentation.js +5 -2
  33. package/dist/src/db/instrumentation.js.map +1 -1
  34. package/dist/src/environment.d.ts +1 -0
  35. package/dist/src/environment.js +1 -1
  36. package/dist/src/environment.js.map +1 -1
  37. package/dist/src/events/analytics.d.ts +1 -1
  38. package/dist/src/index.d.ts +1 -0
  39. package/dist/src/queue/constants.d.ts +2 -1
  40. package/dist/src/queue/constants.js +1 -0
  41. package/dist/src/queue/constants.js.map +1 -1
  42. package/dist/src/queue/inMemoryQueue.d.ts +23 -13
  43. package/dist/src/queue/inMemoryQueue.js +83 -30
  44. package/dist/src/queue/inMemoryQueue.js.map +1 -1
  45. package/dist/src/queue/listeners.js +2 -0
  46. package/dist/src/queue/listeners.js.map +1 -1
  47. package/dist/src/queue/queue.d.ts +1 -0
  48. package/dist/src/queue/queue.js.map +1 -1
  49. package/dist/src/redis/init.d.ts +1 -0
  50. package/dist/src/redis/init.js +12 -2
  51. package/dist/src/redis/init.js.map +1 -1
  52. package/dist/src/redis/redis.d.ts +10 -5
  53. package/dist/src/redis/redis.js +52 -3
  54. package/dist/src/redis/redis.js.map +1 -1
  55. package/dist/src/redis/redlockImpl.js.map +1 -1
  56. package/dist/src/redis/utils.d.ts +2 -1
  57. package/dist/src/redis/utils.js +1 -0
  58. package/dist/src/redis/utils.js.map +1 -1
  59. package/dist/src/security/roles.d.ts +1 -1
  60. package/dist/src/security/roles.js +0 -3
  61. package/dist/src/security/roles.js.map +1 -1
  62. package/dist/tests/core/utilities/structures/accounts.js +1 -1
  63. package/dist/tests/core/utilities/structures/accounts.js.map +1 -1
  64. package/dist/tests/core/utilities/structures/scim.js +1 -1
  65. package/dist/tests/core/utilities/structures/scim.js.map +1 -1
  66. package/package.json +6 -5
  67. package/src/cache/base/index.ts +62 -4
  68. package/src/cache/docWritethrough.ts +97 -0
  69. package/src/cache/generic.ts +3 -2
  70. package/src/cache/index.ts +1 -0
  71. package/src/cache/tests/docWritethrough.spec.ts +293 -0
  72. package/src/cache/user.ts +2 -2
  73. package/src/constants/db.ts +3 -0
  74. package/src/context/mainContext.ts +11 -0
  75. package/src/db/Replication.ts +27 -40
  76. package/src/db/couch/DatabaseImpl.ts +18 -1
  77. package/src/db/instrumentation.ts +5 -2
  78. package/src/db/tests/DatabaseImpl.spec.ts +55 -0
  79. package/src/environment.ts +1 -0
  80. package/src/queue/constants.ts +1 -0
  81. package/src/queue/inMemoryQueue.ts +79 -24
  82. package/src/queue/listeners.ts +2 -0
  83. package/src/queue/queue.ts +2 -0
  84. package/src/redis/init.ts +12 -1
  85. package/src/redis/redis.ts +63 -9
  86. package/src/redis/redlockImpl.ts +1 -1
  87. package/src/redis/tests/redis.spec.ts +214 -0
  88. package/src/redis/utils.ts +1 -0
  89. package/src/security/roles.ts +1 -4
  90. package/tests/core/utilities/structures/accounts.ts +1 -1
  91. package/tests/core/utilities/structures/scim.ts +1 -1
package/dist/index.js CHANGED
@@ -19623,11 +19623,11 @@ var require_nacl_fast = __commonJS({
19623
19623
  "use strict";
19624
19624
  (function(nacl) {
19625
19625
  "use strict";
19626
- var gf = function(init9) {
19626
+ var gf = function(init10) {
19627
19627
  var i, r = new Float64Array(16);
19628
- if (init9)
19629
- for (i = 0; i < init9.length; i++)
19630
- r[i] = init9[i];
19628
+ if (init10)
19629
+ for (i = 0; i < init10.length; i++)
19630
+ r[i] = init10[i];
19631
19631
  return r;
19632
19632
  };
19633
19633
  var randombytes = function() {
@@ -54160,7 +54160,7 @@ __export(src_exports, {
54160
54160
  featureFlags: () => features_exports,
54161
54161
  features: () => installation_exports2,
54162
54162
  getPublicError: () => getPublicError,
54163
- init: () => init8,
54163
+ init: () => init9,
54164
54164
  installation: () => installation_exports,
54165
54165
  locks: () => redlockImpl_exports,
54166
54166
  logging: () => logging_exports,
@@ -54579,6 +54579,7 @@ var DocumentType = /* @__PURE__ */ ((DocumentType2) => {
54579
54579
  DocumentType2["AUTOMATION_METADATA"] = "meta_au";
54580
54580
  DocumentType2["AUDIT_LOG"] = "al";
54581
54581
  DocumentType2["APP_MIGRATION_METADATA"] = "_design/migrations";
54582
+ DocumentType2["SCIM_LOG"] = "scimlog";
54582
54583
  return DocumentType2;
54583
54584
  })(DocumentType || {});
54584
54585
  var InternalTable = /* @__PURE__ */ ((InternalTable2) => {
@@ -54682,6 +54683,9 @@ var StaticDatabases = {
54682
54683
  },
54683
54684
  AUDIT_LOGS: {
54684
54685
  name: "audit-logs"
54686
+ },
54687
+ SCIM_LOGS: {
54688
+ name: "scim-logs"
54685
54689
  }
54686
54690
  };
54687
54691
  var APP_PREFIX = prefixed("app" /* APP */);
@@ -55062,6 +55066,7 @@ __export(cache_exports, {
55062
55066
  app: () => appMetadata_exports,
55063
55067
  bustCache: () => bustCache,
55064
55068
  destroy: () => destroy,
55069
+ docWritethrough: () => docWritethrough_exports,
55065
55070
  generic: () => generic_exports,
55066
55071
  get: () => get2,
55067
55072
  invite: () => invite_exports,
@@ -55113,6 +55118,7 @@ __export(context_exports, {
55113
55118
  getPlatformURL: () => getPlatformURL,
55114
55119
  getProdAppDB: () => getProdAppDB,
55115
55120
  getProdAppId: () => getProdAppId,
55121
+ getScimDBName: () => getScimDBName,
55116
55122
  getTenantIDFromAppID: () => getTenantIDFromAppID,
55117
55123
  getTenantId: () => getTenantId,
55118
55124
  identity: () => identity_exports,
@@ -55318,7 +55324,8 @@ var environment = {
55318
55324
  process.env[key] = value;
55319
55325
  environment[key] = value;
55320
55326
  },
55321
- ROLLING_LOG_MAX_SIZE: process.env.ROLLING_LOG_MAX_SIZE || "10M"
55327
+ ROLLING_LOG_MAX_SIZE: process.env.ROLLING_LOG_MAX_SIZE || "10M",
55328
+ DISABLE_SCIM_CALLS: process.env.DISABLE_SCIM_CALLS
55322
55329
  };
55323
55330
  for (let [key, value] of Object.entries(environment)) {
55324
55331
  if (value === "0") {
@@ -55585,9 +55592,12 @@ var DDInstrumentedDatabase = class {
55585
55592
  get name() {
55586
55593
  return this.db.name;
55587
55594
  }
55588
- exists() {
55595
+ exists(docId) {
55589
55596
  return import_dd_trace.default.trace("db.exists", (span) => {
55590
- span?.addTags({ db_name: this.name });
55597
+ span?.addTags({ db_name: this.name, doc_id: docId });
55598
+ if (docId) {
55599
+ return this.db.exists(docId);
55600
+ }
55591
55601
  return this.db.exists();
55592
55602
  });
55593
55603
  }
@@ -55715,7 +55725,13 @@ var DatabaseImpl = class _DatabaseImpl {
55715
55725
  const couchInfo = getCouchInfo();
55716
55726
  _DatabaseImpl.nano = buildNano(couchInfo);
55717
55727
  }
55718
- async exists() {
55728
+ exists(docId) {
55729
+ if (docId === void 0) {
55730
+ return this.dbExists();
55731
+ }
55732
+ return this.docExists(docId);
55733
+ }
55734
+ async dbExists() {
55719
55735
  const response = await directCouchUrlCall({
55720
55736
  url: `${this.couchInfo.url}/${this.name}`,
55721
55737
  method: "HEAD",
@@ -55723,6 +55739,14 @@ var DatabaseImpl = class _DatabaseImpl {
55723
55739
  });
55724
55740
  return response.status === 200;
55725
55741
  }
55742
+ async docExists(id) {
55743
+ try {
55744
+ await this.performCall((db) => () => db.head(id));
55745
+ return true;
55746
+ } catch {
55747
+ return false;
55748
+ }
55749
+ }
55726
55750
  nano() {
55727
55751
  return this.instanceNano || _DatabaseImpl.nano;
55728
55752
  }
@@ -55946,6 +55970,16 @@ function getAuditLogDBName(tenantId) {
55946
55970
  return `${tenantId}${SEPARATOR}${StaticDatabases.AUDIT_LOGS.name}`;
55947
55971
  }
55948
55972
  }
55973
+ function getScimDBName(tenantId) {
55974
+ if (!tenantId) {
55975
+ tenantId = getTenantId();
55976
+ }
55977
+ if (tenantId === DEFAULT_TENANT_ID) {
55978
+ return StaticDatabases.SCIM_LOGS.name;
55979
+ } else {
55980
+ return `${tenantId}${SEPARATOR}${StaticDatabases.SCIM_LOGS.name}`;
55981
+ }
55982
+ }
55949
55983
  function baseGlobalDBName(tenantId) {
55950
55984
  if (!tenantId || tenantId === DEFAULT_TENANT_ID) {
55951
55985
  return StaticDatabases.GLOBAL.name;
@@ -56182,6 +56216,7 @@ var init_exports = {};
56182
56216
  __export(init_exports, {
56183
56217
  getAppClient: () => getAppClient,
56184
56218
  getCacheClient: () => getCacheClient,
56219
+ getDocWritethroughClient: () => getDocWritethroughClient,
56185
56220
  getInviteClient: () => getInviteClient,
56186
56221
  getLockClient: () => getLockClient,
56187
56222
  getPasswordResetClient: () => getPasswordResetClient,
@@ -56227,6 +56262,7 @@ var Databases = /* @__PURE__ */ ((Databases2) => {
56227
56262
  Databases2["LOCKS"] = "locks";
56228
56263
  Databases2["SOCKET_IO"] = "socket_io";
56229
56264
  Databases2["BPM_EVENTS"] = "bpmEvents";
56265
+ Databases2["DOC_WRITE_THROUGH"] = "docWriteThrough";
56230
56266
  return Databases2;
56231
56267
  })(Databases || {});
56232
56268
  var SelectableDatabase = /* @__PURE__ */ ((SelectableDatabase2) => {
@@ -57055,21 +57091,16 @@ async function queryGlobalViewRaw(viewName, params2, opts) {
57055
57091
 
57056
57092
  // src/db/Replication.ts
57057
57093
  var Replication = class {
57058
- /**
57059
- *
57060
- * @param source - the DB you want to replicate or rollback to
57061
- * @param target - the DB you want to replicate to, or rollback from
57062
- */
57063
57094
  constructor({ source, target }) {
57064
57095
  this.source = getPouchDB(source);
57065
57096
  this.target = getPouchDB(target);
57066
57097
  }
57067
- close() {
57068
- return Promise.all([closePouchDB(this.source), closePouchDB(this.target)]);
57098
+ async close() {
57099
+ await Promise.all([closePouchDB(this.source), closePouchDB(this.target)]);
57069
57100
  }
57070
- promisify(operation, opts = {}) {
57101
+ replicate(opts = {}) {
57071
57102
  return new Promise((resolve) => {
57072
- operation(this.target, opts).on("denied", function(err) {
57103
+ this.source.replicate.to(this.target, opts).on("denied", function(err) {
57073
57104
  throw new Error(`Denied: Document failed to replicate ${err}`);
57074
57105
  }).on("complete", function(info) {
57075
57106
  return resolve(info);
@@ -57078,29 +57109,22 @@ var Replication = class {
57078
57109
  });
57079
57110
  });
57080
57111
  }
57081
- /**
57082
- * Two way replication operation, intended to be promise based.
57083
- * @param opts - PouchDB replication options
57084
- */
57085
- sync(opts = {}) {
57086
- this.replication = this.promisify(this.source.sync, opts);
57087
- return this.replication;
57088
- }
57089
- /**
57090
- * One way replication operation, intended to be promise based.
57091
- * @param opts - PouchDB replication options
57092
- */
57093
- replicate(opts = {}) {
57094
- this.replication = this.promisify(this.source.replicate.to, opts);
57095
- return this.replication;
57096
- }
57097
- appReplicateOpts() {
57112
+ appReplicateOpts(opts = {}) {
57113
+ if (typeof opts.filter === "string") {
57114
+ return opts;
57115
+ }
57116
+ const filter = opts.filter;
57117
+ delete opts.filter;
57098
57118
  return {
57099
- filter: (doc) => {
57119
+ ...opts,
57120
+ filter: (doc, params2) => {
57100
57121
  if (doc._id && doc._id.startsWith("log_au" /* AUTOMATION_LOG */)) {
57101
57122
  return false;
57102
57123
  }
57103
- return doc._id !== "app_metadata" /* APP_METADATA */;
57124
+ if (doc._id === "app_metadata" /* APP_METADATA */) {
57125
+ return false;
57126
+ }
57127
+ return filter ? filter(doc, params2) : true;
57104
57128
  }
57105
57129
  };
57106
57130
  }
@@ -57112,9 +57136,6 @@ var Replication = class {
57112
57136
  this.target = getPouchDB(this.target.name);
57113
57137
  await this.replicate();
57114
57138
  }
57115
- cancel() {
57116
- this.replication.cancel();
57117
- }
57118
57139
  };
57119
57140
  var Replication_default = Replication;
57120
57141
 
@@ -58676,7 +58697,10 @@ var RedisWrapper = class {
58676
58697
  let node = this.getClient().nodes("master");
58677
58698
  stream2 = node[0].scanStream({ match: key + "*", count: 100 });
58678
58699
  } else {
58679
- stream2 = this.getClient().scanStream({ match: key + "*", count: 100 });
58700
+ stream2 = this.getClient().scanStream({
58701
+ match: key + "*",
58702
+ count: 100
58703
+ });
58680
58704
  }
58681
58705
  return promisifyStream(stream2, this.getClient());
58682
58706
  }
@@ -58690,7 +58714,7 @@ var RedisWrapper = class {
58690
58714
  }
58691
58715
  async get(key) {
58692
58716
  const db = this._db;
58693
- let response = await this.getClient().get(addDbPrefix(db, key));
58717
+ const response = await this.getClient().get(addDbPrefix(db, key));
58694
58718
  if (response != null && response.key) {
58695
58719
  response.key = key;
58696
58720
  }
@@ -58738,6 +58762,21 @@ var RedisWrapper = class {
58738
58762
  await this.getClient().expire(prefixedKey, expirySeconds);
58739
58763
  }
58740
58764
  }
58765
+ async bulkStore(data, expirySeconds = null) {
58766
+ const client = this.getClient();
58767
+ const dataToStore = Object.entries(data).reduce((acc, [key, value]) => {
58768
+ acc[addDbPrefix(this._db, key)] = typeof value === "object" ? JSON.stringify(value) : value;
58769
+ return acc;
58770
+ }, {});
58771
+ const pipeline = client.pipeline();
58772
+ pipeline.mset(dataToStore);
58773
+ if (expirySeconds !== null) {
58774
+ for (const key of Object.keys(dataToStore)) {
58775
+ pipeline.expire(key, expirySeconds);
58776
+ }
58777
+ }
58778
+ await pipeline.exec();
58779
+ }
58741
58780
  async getTTL(key) {
58742
58781
  const db = this._db;
58743
58782
  const prefixedKey = addDbPrefix(db, key);
@@ -58752,10 +58791,30 @@ var RedisWrapper = class {
58752
58791
  const db = this._db;
58753
58792
  await this.getClient().del(addDbPrefix(db, key));
58754
58793
  }
58794
+ async bulkDelete(keys2) {
58795
+ const db = this._db;
58796
+ await this.getClient().del(keys2.map((key) => addDbPrefix(db, key)));
58797
+ }
58755
58798
  async clear() {
58756
58799
  let items = await this.scan();
58757
58800
  await Promise.all(items.map((obj) => this.delete(obj.key)));
58758
58801
  }
58802
+ async increment(key) {
58803
+ const result = await this.getClient().incr(addDbPrefix(this._db, key));
58804
+ if (isNaN(result)) {
58805
+ throw new Error(`Redis ${key} does not contain a number`);
58806
+ }
58807
+ return result;
58808
+ }
58809
+ async deleteIfValue(key, value) {
58810
+ const client = this.getClient();
58811
+ const luaScript = `
58812
+ if redis.call('GET', KEYS[1]) == ARGV[1] then
58813
+ redis.call('DEL', KEYS[1])
58814
+ end
58815
+ `;
58816
+ await client.eval(luaScript, 1, addDbPrefix(this._db, key), value);
58817
+ }
58759
58818
  };
58760
58819
  var redis_default = RedisWrapper;
58761
58820
 
@@ -58769,6 +58828,7 @@ var lockClient;
58769
58828
  var socketClient;
58770
58829
  var inviteClient;
58771
58830
  var passwordResetClient;
58831
+ var docWritethroughClient;
58772
58832
  async function init3() {
58773
58833
  userClient = await new redis_default("users" /* USER_CACHE */).init();
58774
58834
  sessionClient = await new redis_default("session" /* SESSIONS */).init();
@@ -58782,6 +58842,9 @@ async function init3() {
58782
58842
  "socket_io" /* SOCKET_IO */,
58783
58843
  1 /* SOCKET_IO */
58784
58844
  ).init();
58845
+ docWritethroughClient = await new redis_default(
58846
+ "docWriteThrough" /* DOC_WRITE_THROUGH */
58847
+ ).init();
58785
58848
  }
58786
58849
  async function shutdown() {
58787
58850
  if (userClient)
@@ -58860,6 +58923,12 @@ async function getPasswordResetClient() {
58860
58923
  }
58861
58924
  return passwordResetClient;
58862
58925
  }
58926
+ async function getDocWritethroughClient() {
58927
+ if (!writethroughClient) {
58928
+ await init3();
58929
+ }
58930
+ return writethroughClient;
58931
+ }
58863
58932
 
58864
58933
  // src/cache/base/index.ts
58865
58934
  function generateTenantKey(key) {
@@ -58877,6 +58946,16 @@ var BaseCache = class {
58877
58946
  const client = await this.getClient();
58878
58947
  return client.keys(pattern);
58879
58948
  }
58949
+ async exists(key, opts = { useTenancy: true }) {
58950
+ key = opts.useTenancy ? generateTenantKey(key) : key;
58951
+ const client = await this.getClient();
58952
+ return client.exists(key);
58953
+ }
58954
+ async scan(key, opts = { useTenancy: true }) {
58955
+ key = opts.useTenancy ? generateTenantKey(key) : key;
58956
+ const client = await this.getClient();
58957
+ return client.scan(key);
58958
+ }
58880
58959
  /**
58881
58960
  * Read only from the cache.
58882
58961
  */
@@ -58885,6 +58964,14 @@ var BaseCache = class {
58885
58964
  const client = await this.getClient();
58886
58965
  return client.get(key);
58887
58966
  }
58967
+ /**
58968
+ * Read only from the cache.
58969
+ */
58970
+ async bulkGet(keys2, opts = { useTenancy: true }) {
58971
+ keys2 = opts.useTenancy ? keys2.map((key) => generateTenantKey(key)) : keys2;
58972
+ const client = await this.getClient();
58973
+ return client.bulkGet(keys2);
58974
+ }
58888
58975
  /**
58889
58976
  * Write to the cache.
58890
58977
  */
@@ -58893,6 +58980,19 @@ var BaseCache = class {
58893
58980
  const client = await this.getClient();
58894
58981
  await client.store(key, value, ttl);
58895
58982
  }
58983
+ /**
58984
+ * Bulk write to the cache.
58985
+ */
58986
+ async bulkStore(data, ttl = null, opts = { useTenancy: true }) {
58987
+ if (opts.useTenancy) {
58988
+ data = Object.entries(data).reduce((acc, [key, value]) => {
58989
+ acc[generateTenantKey(key)] = value;
58990
+ return acc;
58991
+ }, {});
58992
+ }
58993
+ const client = await this.getClient();
58994
+ await client.bulkStore(data, ttl);
58995
+ }
58896
58996
  /**
58897
58997
  * Remove from cache.
58898
58998
  */
@@ -58901,10 +59001,18 @@ var BaseCache = class {
58901
59001
  const client = await this.getClient();
58902
59002
  return client.delete(key);
58903
59003
  }
59004
+ /**
59005
+ * Remove from cache.
59006
+ */
59007
+ async bulkDelete(keys2, opts = { useTenancy: true }) {
59008
+ keys2 = opts.useTenancy ? keys2.map((key) => generateTenantKey(key)) : keys2;
59009
+ const client = await this.getClient();
59010
+ return client.bulkDelete(keys2);
59011
+ }
58904
59012
  /**
58905
59013
  * Read from the cache. Write to the cache if not exists.
58906
59014
  */
58907
- async withCache(key, ttl, fetchFn, opts = { useTenancy: true }) {
59015
+ async withCache(key, ttl = null, fetchFn, opts = { useTenancy: true }) {
58908
59016
  const cachedValue = await this.get(key, opts);
58909
59017
  if (cachedValue) {
58910
59018
  return cachedValue;
@@ -58927,6 +59035,14 @@ var BaseCache = class {
58927
59035
  throw err;
58928
59036
  }
58929
59037
  }
59038
+ /**
59039
+ * Delete the entry if the provided value matches the stored one.
59040
+ */
59041
+ async deleteIfValue(key, value, opts = { useTenancy: true }) {
59042
+ key = opts.useTenancy ? generateTenantKey(key) : key;
59043
+ const client = await this.getClient();
59044
+ await client.deleteIfValue(key, value);
59045
+ }
58930
59046
  };
58931
59047
 
58932
59048
  // src/cache/generic.ts
@@ -60243,9 +60359,6 @@ function getBuiltinRole(roleId) {
60243
60359
  return (0, import_cloneDeep2.default)(role);
60244
60360
  }
60245
60361
  function builtinRoleToNumber(id) {
60246
- if (!id) {
60247
- return 0;
60248
- }
60249
60362
  const builtins = getBuiltinRoles();
60250
60363
  const MAX = Object.values(builtins).length + 1;
60251
60364
  if (id === BUILTIN_IDS.ADMIN || id === BUILTIN_IDS.BUILDER) {
@@ -60779,19 +60892,23 @@ var LoggingProcessor = class {
60779
60892
  // src/queue/index.ts
60780
60893
  var queue_exports = {};
60781
60894
  __export(queue_exports, {
60895
+ JobOptions: () => import_bull2.JobOptions,
60782
60896
  JobQueue: () => JobQueue,
60897
+ Queue: () => import_bull2.Queue,
60898
+ QueueOptions: () => import_bull2.QueueOptions,
60783
60899
  createQueue: () => createQueue,
60784
60900
  shutdown: () => shutdown2
60785
60901
  });
60786
60902
 
60787
60903
  // src/queue/inMemoryQueue.ts
60788
60904
  var import_events2 = __toESM(require("events"));
60789
- function newJob(queue, message) {
60905
+ function newJob(queue, message, opts) {
60790
60906
  return {
60907
+ id: newid(),
60791
60908
  timestamp: Date.now(),
60792
60909
  queue,
60793
60910
  data: message,
60794
- opts: {}
60911
+ opts
60795
60912
  };
60796
60913
  }
60797
60914
  var InMemoryQueue = class {
@@ -60808,6 +60925,7 @@ var InMemoryQueue = class {
60808
60925
  this._emitter = new import_events2.default.EventEmitter();
60809
60926
  this._runCount = 0;
60810
60927
  this._addCount = 0;
60928
+ this._queuedJobIds = /* @__PURE__ */ new Set();
60811
60929
  }
60812
60930
  /**
60813
60931
  * Same callback API as Bull, each callback passed to this will consume messages as they are
@@ -60818,21 +60936,37 @@ var InMemoryQueue = class {
60818
60936
  * note this is incredibly limited compared to Bull as in reality the Job would contain
60819
60937
  * a lot more information about the queue and current status of Bull cluster.
60820
60938
  */
60821
- process(func) {
60939
+ async process(func) {
60822
60940
  this._emitter.on("message", async () => {
60823
60941
  if (this._messages.length <= 0) {
60824
60942
  return;
60825
60943
  }
60826
60944
  let msg = this._messages.shift();
60827
60945
  let resp = func(msg);
60946
+ async function retryFunc(fnc) {
60947
+ try {
60948
+ await fnc;
60949
+ } catch (e) {
60950
+ await new Promise((r) => setTimeout(() => r(), 50));
60951
+ await retryFunc(func(msg));
60952
+ }
60953
+ }
60828
60954
  if (resp.then != null) {
60829
- await resp;
60955
+ try {
60956
+ await retryFunc(resp);
60957
+ } catch (e) {
60958
+ console.error(e);
60959
+ }
60830
60960
  }
60831
60961
  this._runCount++;
60962
+ const jobId = msg?.opts?.jobId?.toString();
60963
+ if (jobId && msg?.opts?.removeOnComplete) {
60964
+ this._queuedJobIds.delete(jobId);
60965
+ }
60832
60966
  });
60833
60967
  }
60834
60968
  async isReady() {
60835
- return true;
60969
+ return this;
60836
60970
  }
60837
60971
  // simply puts a message to the queue and emits to the queue for processing
60838
60972
  /**
@@ -60844,35 +60978,51 @@ var InMemoryQueue = class {
60844
60978
  * @param repeat serves no purpose for the import queue.
60845
60979
  */
60846
60980
  // eslint-disable-next-line no-unused-vars
60847
- add(msg, repeat) {
60848
- if (typeof msg !== "object") {
60981
+ async add(data, opts) {
60982
+ const jobId = opts?.jobId?.toString();
60983
+ if (jobId && this._queuedJobIds.has(jobId)) {
60984
+ console.log(`Ignoring already queued job ${jobId}`);
60985
+ return;
60986
+ }
60987
+ if (typeof data !== "object") {
60849
60988
  throw "Queue only supports carrying JSON.";
60850
60989
  }
60851
- this._messages.push(newJob(this._name, msg));
60852
- this._addCount++;
60853
- this._emitter.emit("message");
60990
+ if (jobId) {
60991
+ this._queuedJobIds.add(jobId);
60992
+ }
60993
+ const pushMessage = () => {
60994
+ this._messages.push(newJob(this._name, data, opts));
60995
+ this._addCount++;
60996
+ this._emitter.emit("message");
60997
+ };
60998
+ const delay = opts?.delay;
60999
+ if (delay) {
61000
+ setTimeout(pushMessage, delay);
61001
+ } else {
61002
+ pushMessage();
61003
+ }
61004
+ return {};
60854
61005
  }
60855
61006
  /**
60856
61007
  * replicating the close function from bull, which waits for jobs to finish.
60857
61008
  */
60858
61009
  async close() {
60859
- return [];
60860
61010
  }
60861
61011
  /**
60862
61012
  * This removes a cron which has been implemented, this is part of Bull API.
60863
61013
  * @param cronJobId The cron which is to be removed.
60864
61014
  */
60865
- removeRepeatableByKey(cronJobId) {
61015
+ async removeRepeatableByKey(cronJobId) {
60866
61016
  console.log(cronJobId);
60867
61017
  }
60868
61018
  /**
60869
61019
  * Implemented for tests
60870
61020
  */
60871
- getRepeatableJobs() {
61021
+ async getRepeatableJobs() {
60872
61022
  return [];
60873
61023
  }
60874
61024
  // eslint-disable-next-line no-unused-vars
60875
- removeJobs(pattern) {
61025
+ async removeJobs(pattern) {
60876
61026
  }
60877
61027
  /**
60878
61028
  * Implemented for tests
@@ -60881,7 +61031,7 @@ var InMemoryQueue = class {
60881
61031
  return [];
60882
61032
  }
60883
61033
  async getJob() {
60884
- return {};
61034
+ return null;
60885
61035
  }
60886
61036
  on() {
60887
61037
  return this;
@@ -60889,7 +61039,10 @@ var InMemoryQueue = class {
60889
61039
  async waitForCompletion() {
60890
61040
  do {
60891
61041
  await timeout(50);
60892
- } while (this._addCount < this._runCount);
61042
+ } while (this.hasRunningJobs());
61043
+ }
61044
+ hasRunningJobs() {
61045
+ return this._addCount > this._runCount;
60893
61046
  }
60894
61047
  };
60895
61048
  var inMemoryQueue_default = InMemoryQueue;
@@ -60904,6 +61057,7 @@ var JobQueue = /* @__PURE__ */ ((JobQueue2) => {
60904
61057
  JobQueue2["AUDIT_LOG"] = "auditLogQueue";
60905
61058
  JobQueue2["SYSTEM_EVENT_QUEUE"] = "systemEventQueue";
60906
61059
  JobQueue2["APP_MIGRATION"] = "appMigration";
61060
+ JobQueue2["DOC_WRITETHROUGH_QUEUE"] = "docWritethroughQueue";
60907
61061
  return JobQueue2;
60908
61062
  })(JobQueue || {});
60909
61063
 
@@ -60955,7 +61109,8 @@ var EventTypeMap = {
60955
61109
  ["appBackupQueue" /* APP_BACKUP */]: "app-backup-event" /* APP_BACKUP_EVENT */,
60956
61110
  ["auditLogQueue" /* AUDIT_LOG */]: "audit-log-event" /* AUDIT_LOG_EVENT */,
60957
61111
  ["systemEventQueue" /* SYSTEM_EVENT_QUEUE */]: "system-event" /* SYSTEM_EVENT */,
60958
- ["appMigration" /* APP_MIGRATION */]: "app-migration" /* APP_MIGRATION */
61112
+ ["appMigration" /* APP_MIGRATION */]: "app-migration" /* APP_MIGRATION */,
61113
+ ["docWritethroughQueue" /* DOC_WRITETHROUGH_QUEUE */]: "doc-writethrough" /* DOC_WRITETHROUGH */
60959
61114
  };
60960
61115
  function logging(queue, jobQueue) {
60961
61116
  const eventType = EventTypeMap[jobQueue];
@@ -61026,6 +61181,7 @@ function logging(queue, jobQueue) {
61026
61181
  }
61027
61182
 
61028
61183
  // src/queue/queue.ts
61184
+ var import_bull2 = require("bull");
61029
61185
  var QUEUE_LOCK_MS = Duration.fromMinutes(5).toMs();
61030
61186
  var QUEUE_LOCK_RENEW_INTERNAL_MS = Duration.fromSeconds(30).toMs();
61031
61187
  var CLEANUP_PERIOD_MS = Duration.fromSeconds(60).toMs();
@@ -63978,6 +64134,83 @@ async function invalidateCode(code) {
63978
64134
  await client.delete(code);
63979
64135
  }
63980
64136
 
64137
+ // src/cache/docWritethrough.ts
64138
+ var docWritethrough_exports = {};
64139
+ __export(docWritethrough_exports, {
64140
+ DocWritethrough: () => DocWritethrough,
64141
+ docWritethroughProcessorQueue: () => docWritethroughProcessorQueue,
64142
+ getProcessor: () => getProcessor,
64143
+ init: () => init7
64144
+ });
64145
+ var PERSIST_MAX_ATTEMPTS = 100;
64146
+ var processor;
64147
+ var docWritethroughProcessorQueue = createQueue(
64148
+ "docWritethroughQueue" /* DOC_WRITETHROUGH_QUEUE */,
64149
+ {
64150
+ jobOptions: {
64151
+ attempts: PERSIST_MAX_ATTEMPTS
64152
+ }
64153
+ }
64154
+ );
64155
+ var DocWritethroughProcessor = class {
64156
+ init() {
64157
+ docWritethroughProcessorQueue.process(async (message) => {
64158
+ try {
64159
+ await this.persistToDb(message.data);
64160
+ } catch (err) {
64161
+ if (err.status === 409) {
64162
+ throw new Error(
64163
+ `Conflict persisting message ${message.id}. Attempt ${message.attemptsMade}`
64164
+ );
64165
+ }
64166
+ throw err;
64167
+ }
64168
+ });
64169
+ return this;
64170
+ }
64171
+ async persistToDb({
64172
+ dbName,
64173
+ docId,
64174
+ data
64175
+ }) {
64176
+ const db = getDB(dbName);
64177
+ let doc;
64178
+ try {
64179
+ doc = await db.get(docId);
64180
+ } catch {
64181
+ doc = { _id: docId };
64182
+ }
64183
+ doc = { ...doc, ...data };
64184
+ await db.put(doc);
64185
+ }
64186
+ };
64187
+ var DocWritethrough = class {
64188
+ constructor(db, docId) {
64189
+ this.db = db;
64190
+ this._docId = docId;
64191
+ }
64192
+ get docId() {
64193
+ return this._docId;
64194
+ }
64195
+ async patch(data) {
64196
+ await docWritethroughProcessorQueue.add({
64197
+ dbName: this.db.name,
64198
+ docId: this.docId,
64199
+ data
64200
+ });
64201
+ }
64202
+ };
64203
+ function init7() {
64204
+ processor = new DocWritethroughProcessor().init();
64205
+ return processor;
64206
+ }
64207
+ function getProcessor() {
64208
+ if (!processor) {
64209
+ return init7();
64210
+ }
64211
+ return processor;
64212
+ }
64213
+
63981
64214
  // src/configs/configs.ts
63982
64215
  function generateConfigID(type) {
63983
64216
  return `${"config" /* CONFIG */}${SEPARATOR}${type}`;
@@ -65747,7 +65980,7 @@ async function isBlacklisted(address) {
65747
65980
  // src/docUpdates/index.ts
65748
65981
  var docUpdates_exports = {};
65749
65982
  __export(docUpdates_exports, {
65750
- init: () => init7
65983
+ init: () => init8
65751
65984
  });
65752
65985
 
65753
65986
  // src/events/documentId.ts
@@ -65786,10 +66019,10 @@ var DocumentUpdateProcessor = class {
65786
66019
  if (!tenantId || !docId) {
65787
66020
  return;
65788
66021
  }
65789
- for (let { events: events2, processor } of this.processors) {
66022
+ for (let { events: events2, processor: processor2 } of this.processors) {
65790
66023
  if (events2.includes(event)) {
65791
66024
  await doInTenant(tenantId, async () => {
65792
- await processor({
66025
+ await processor2({
65793
66026
  id: docId,
65794
66027
  tenantId
65795
66028
  });
@@ -65805,7 +66038,7 @@ var DocumentUpdateProcessor = class {
65805
66038
  // src/docUpdates/index.ts
65806
66039
  var processingPromise;
65807
66040
  var documentProcessor;
65808
- function init7(processors2) {
66041
+ function init8(processors2) {
65809
66042
  if (!asyncEventQueue) {
65810
66043
  init5();
65811
66044
  }
@@ -65830,7 +66063,7 @@ var tenancy = {
65830
66063
  ...tenancy_exports,
65831
66064
  ...context_exports
65832
66065
  };
65833
- var init8 = (opts = {}) => {
66066
+ var init9 = (opts = {}) => {
65834
66067
  init(opts.db);
65835
66068
  };
65836
66069
  // Annotate the CommonJS export names for ESM import in node: