@budibase/backend-core 2.29.9 → 2.29.14

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 +2325 -2263
  2. package/dist/index.js.map +4 -4
  3. package/dist/index.js.meta.json +1 -1
  4. package/dist/package.json +5 -6
  5. package/dist/plugins.js.map +1 -1
  6. package/dist/plugins.js.meta.json +1 -1
  7. package/dist/src/db/couch/DatabaseImpl.js +5 -0
  8. package/dist/src/db/couch/DatabaseImpl.js.map +1 -1
  9. package/dist/src/db/couch/index.d.ts +0 -1
  10. package/dist/src/db/couch/index.js +0 -1
  11. package/dist/src/db/couch/index.js.map +1 -1
  12. package/dist/src/environment.d.ts +5 -0
  13. package/dist/src/environment.js +17 -1
  14. package/dist/src/environment.js.map +1 -1
  15. package/dist/src/middleware/errorHandling.js +9 -1
  16. package/dist/src/middleware/errorHandling.js.map +1 -1
  17. package/dist/src/security/secrets.d.ts +1 -0
  18. package/dist/src/security/secrets.js +43 -0
  19. package/dist/src/security/secrets.js.map +1 -0
  20. package/dist/src/sql/sql.js +3 -14
  21. package/dist/src/sql/sql.js.map +1 -1
  22. package/dist/src/sql/utils.d.ts +3 -1
  23. package/dist/src/sql/utils.js +31 -3
  24. package/dist/src/sql/utils.js.map +1 -1
  25. package/dist/src/users/db.js +10 -8
  26. package/dist/src/users/db.js.map +1 -1
  27. package/dist/tests/core/utilities/jestUtils.d.ts +3 -3
  28. package/dist/tests/core/utilities/jestUtils.js.map +1 -1
  29. package/package.json +5 -6
  30. package/src/db/couch/DatabaseImpl.ts +8 -0
  31. package/src/db/couch/index.ts +0 -1
  32. package/src/environment.ts +20 -0
  33. package/src/middleware/errorHandling.ts +10 -1
  34. package/src/security/secrets.ts +20 -0
  35. package/src/security/tests/secrets.spec.ts +35 -0
  36. package/src/sql/sql.ts +6 -16
  37. package/src/sql/utils.ts +27 -2
  38. package/src/users/db.ts +13 -9
  39. package/src/users/test/db.spec.ts +188 -0
  40. package/tests/core/utilities/jestUtils.ts +6 -3
  41. package/dist/src/db/constants.d.ts +0 -1
  42. package/dist/src/db/constants.js +0 -8
  43. package/dist/src/db/constants.js.map +0 -1
  44. package/src/db/constants.ts +0 -5
package/dist/index.js CHANGED
@@ -53704,7 +53704,10 @@ var require_strategy2 = __commonJS({
53704
53704
  var meta = state2;
53705
53705
  var callbackURL = meta.callbackURL;
53706
53706
  var oauth2 = self2._getOAuth2Client(meta);
53707
- var params2 = { grant_type: "authorization_code", redirect_uri: callbackURL };
53707
+ var params2 = {
53708
+ grant_type: "authorization_code",
53709
+ redirect_uri: callbackURL
53710
+ };
53708
53711
  if (state2.pkce) {
53709
53712
  params2.code_verifier = state2.params.verifier;
53710
53713
  }
@@ -53818,6 +53821,9 @@ var require_strategy2 = __commonJS({
53818
53821
  try {
53819
53822
  var json = JSON.parse(body2);
53820
53823
  profile.id = json.sub;
53824
+ if (jwtClaims && jwtClaims.oid) {
53825
+ profile.id = jwtClaims.oid;
53826
+ }
53821
53827
  if (!profile.id) {
53822
53828
  profile.id = json.user_id;
53823
53829
  }
@@ -54040,13 +54046,19 @@ var require_strategy2 = __commonJS({
54040
54046
  var verifier = base64url(crypto2.pseudoRandomBytes(32));
54041
54047
  switch (config.pkce) {
54042
54048
  case "S256":
54043
- params2.code_challenge = base64url(crypto2.createHash("sha256").update(verifier).digest());
54049
+ params2.code_challenge = base64url(
54050
+ crypto2.createHash("sha256").update(verifier).digest()
54051
+ );
54044
54052
  break;
54045
54053
  case "plain":
54046
54054
  params2.code_challenge = verifier;
54047
54055
  break;
54048
54056
  default:
54049
- return self2.error(new Error("Unsupported code verifier transformation method: " + config.pkce));
54057
+ return self2.error(
54058
+ new Error(
54059
+ "Unsupported code verifier transformation method: " + config.pkce
54060
+ )
54061
+ );
54050
54062
  }
54051
54063
  params2.code_challenge_method = config.pkce;
54052
54064
  params2.verifier = verifier;
@@ -54204,9 +54216,9 @@ __export(src_exports, {
54204
54216
  sql: () => sql_exports,
54205
54217
  tenancy: () => tenancy,
54206
54218
  timers: () => timers_exports,
54207
- userUtils: () => utils_exports4,
54219
+ userUtils: () => utils_exports5,
54208
54220
  users: () => users_exports3,
54209
- utils: () => utils_exports3
54221
+ utils: () => utils_exports4
54210
54222
  });
54211
54223
  module.exports = __toCommonJS(src_exports);
54212
54224
 
@@ -54739,20 +54751,6 @@ var SWITCHABLE_TYPES = {
54739
54751
  ["number" /* NUMBER */]: ["number" /* NUMBER */, "boolean" /* BOOLEAN */]
54740
54752
  };
54741
54753
 
54742
- // ../shared-core/src/constants/rows.ts
54743
- var CONSTANT_INTERNAL_ROW_COLS = [
54744
- "_id",
54745
- "_rev",
54746
- "type",
54747
- "createdAt",
54748
- "updatedAt",
54749
- "tableId"
54750
- ];
54751
- var CONSTANT_EXTERNAL_ROW_COLS = ["_id", "_rev", "tableId"];
54752
- function isInternalColumnName(name) {
54753
- return CONSTANT_INTERNAL_ROW_COLS.includes(name);
54754
- }
54755
-
54756
54754
  // ../shared-core/src/constants/index.ts
54757
54755
  var OperatorOptions = {
54758
54756
  Equals: {
@@ -56098,8 +56096,26 @@ var environment = {
56098
56096
  environment[key] = value;
56099
56097
  },
56100
56098
  ROLLING_LOG_MAX_SIZE: process.env.ROLLING_LOG_MAX_SIZE || "10M",
56101
- DISABLE_SCIM_CALLS: process.env.DISABLE_SCIM_CALLS
56099
+ DISABLE_SCIM_CALLS: process.env.DISABLE_SCIM_CALLS,
56100
+ BB_ADMIN_USER_EMAIL: process.env.BB_ADMIN_USER_EMAIL,
56101
+ BB_ADMIN_USER_PASSWORD: process.env.BB_ADMIN_USER_PASSWORD,
56102
+ OPENAI_API_KEY: process.env.OPENAI_API_KEY
56102
56103
  };
56104
+ var SECRETS = [
56105
+ "API_ENCRYPTION_KEY",
56106
+ "BB_ADMIN_USER_PASSWORD",
56107
+ "COUCH_DB_PASSWORD",
56108
+ "COUCH_DB_SQL_URL",
56109
+ "COUCH_DB_URL",
56110
+ "GOOGLE_CLIENT_SECRET",
56111
+ "INTERNAL_API_KEY_FALLBACK",
56112
+ "INTERNAL_API_KEY",
56113
+ "JWT_SECRET",
56114
+ "MINIO_ACCESS_KEY",
56115
+ "MINIO_SECRET_KEY",
56116
+ "OPENAI_API_KEY",
56117
+ "REDIS_PASSWORD"
56118
+ ];
56103
56119
  for (let [key, value] of Object.entries(environment)) {
56104
56120
  if (value === "0") {
56105
56121
  environment[key] = 0;
@@ -56497,1016 +56513,1650 @@ var DDInstrumentedDatabase = class {
56497
56513
  }
56498
56514
  };
56499
56515
 
56500
- // src/db/couch/DatabaseImpl.ts
56501
- var DATABASE_NOT_FOUND = "Database does not exist.";
56502
- function buildNano(couchInfo) {
56503
- return (0, import_nano.default)({
56504
- url: couchInfo.url,
56505
- requestDefaults: {
56506
- headers: {
56507
- Authorization: couchInfo.cookie
56508
- }
56509
- },
56510
- parseUrl: false
56511
- });
56512
- }
56513
- var CouchDBError = class extends Error {
56514
- constructor(message, info) {
56515
- super(message);
56516
- const statusCode = info.status || info.statusCode || 500;
56517
- this.status = statusCode;
56518
- this.statusCode = statusCode;
56519
- this.reason = info.reason;
56520
- this.name = info.name;
56521
- this.errid = info.errid;
56522
- this.description = info.description;
56523
- this.error = info.error;
56516
+ // src/sql/utils.ts
56517
+ var utils_exports3 = {};
56518
+ __export(utils_exports3, {
56519
+ breakExternalTableId: () => breakExternalTableId,
56520
+ breakRowIdField: () => breakRowIdField,
56521
+ buildExternalTableId: () => buildExternalTableId,
56522
+ convertRowId: () => convertRowId,
56523
+ generateRowIdField: () => generateRowIdField,
56524
+ getNativeSql: () => getNativeSql,
56525
+ isExternalTable: () => isExternalTable,
56526
+ isExternalTableID: () => isExternalTableID,
56527
+ isInternalTableID: () => isInternalTableID,
56528
+ isInvalidISODateString: () => isInvalidISODateString,
56529
+ isRowId: () => isRowId,
56530
+ isValidFilter: () => isValidFilter,
56531
+ isValidISODateString: () => isValidISODateString,
56532
+ sqlLog: () => sqlLog
56533
+ });
56534
+
56535
+ // src/db/index.ts
56536
+ var db_exports = {};
56537
+ __export(db_exports, {
56538
+ APP_DEV: () => APP_DEV,
56539
+ APP_DEV_PREFIX: () => APP_DEV_PREFIX2,
56540
+ APP_PREFIX: () => APP_PREFIX2,
56541
+ AutomationViewMode: () => AutomationViewMode,
56542
+ BUDIBASE_DATASOURCE_TYPE: () => BUDIBASE_DATASOURCE_TYPE,
56543
+ DEFAULT_BB_DATASOURCE_ID: () => DEFAULT_BB_DATASOURCE_ID,
56544
+ DEFAULT_EMPLOYEE_TABLE_ID: () => DEFAULT_EMPLOYEE_TABLE_ID,
56545
+ DEFAULT_EXPENSES_TABLE_ID: () => DEFAULT_EXPENSES_TABLE_ID,
56546
+ DEFAULT_INVENTORY_TABLE_ID: () => DEFAULT_INVENTORY_TABLE_ID,
56547
+ DEFAULT_JOBS_TABLE_ID: () => DEFAULT_JOBS_TABLE_ID,
56548
+ DatabaseImpl: () => DatabaseImpl,
56549
+ DatabaseWithConnection: () => DatabaseWithConnection,
56550
+ DeprecatedViews: () => DeprecatedViews,
56551
+ DocumentType: () => DocumentType,
56552
+ InternalTable: () => InternalTable,
56553
+ QueryBuilder: () => QueryBuilder,
56554
+ Replication: () => Replication_default,
56555
+ SEPARATOR: () => SEPARATOR,
56556
+ SQLITE_DESIGN_DOC_ID: () => SQLITE_DESIGN_DOC_ID,
56557
+ SQS_DATASOURCE_INTERNAL: () => SQS_DATASOURCE_INTERNAL,
56558
+ StaticDatabases: () => StaticDatabases,
56559
+ UNICODE_MAX: () => UNICODE_MAX,
56560
+ ViewName: () => ViewName,
56561
+ baseGlobalDBName: () => baseGlobalDBName,
56562
+ checkErrorCode: () => checkErrorCode,
56563
+ closePouchDB: () => closePouchDB,
56564
+ createApiKeyView: () => createApiKeyView,
56565
+ createNewUserEmailView: () => createNewUserEmailView,
56566
+ createPlatformAccountEmailView: () => createPlatformAccountEmailView,
56567
+ createPlatformUserView: () => createPlatformUserView,
56568
+ createUserAppView: () => createUserAppView,
56569
+ createView: () => createView,
56570
+ dbExists: () => dbExists,
56571
+ directCouchAllDbs: () => directCouchAllDbs,
56572
+ directCouchCall: () => directCouchCall,
56573
+ directCouchFind: () => directCouchFind,
56574
+ directCouchQuery: () => directCouchQuery,
56575
+ directCouchUrlCall: () => directCouchUrlCall,
56576
+ doWithDB: () => doWithDB,
56577
+ extractAppUUID: () => extractAppUUID,
56578
+ fullSearch: () => fullSearch,
56579
+ generateAppID: () => generateAppID,
56580
+ generateAppUserID: () => generateAppUserID,
56581
+ generateDevInfoID: () => generateDevInfoID,
56582
+ generateGlobalUserID: () => generateGlobalUserID,
56583
+ generatePluginID: () => generatePluginID,
56584
+ generateRoleID: () => generateRoleID,
56585
+ generateRowID: () => generateRowID,
56586
+ generateTableID: () => generateTableID,
56587
+ generateTemplateID: () => generateTemplateID,
56588
+ generateUserMetadataID: () => generateUserMetadataID,
56589
+ generateWorkspaceID: () => generateWorkspaceID,
56590
+ getAllApps: () => getAllApps,
56591
+ getAllDbs: () => getAllDbs,
56592
+ getAppsByIDs: () => getAppsByIDs,
56593
+ getCouchInfo: () => getCouchInfo,
56594
+ getDB: () => getDB,
56595
+ getDevAppID: () => getDevAppID2,
56596
+ getDevAppIDs: () => getDevAppIDs,
56597
+ getDevelopmentAppID: () => getDevelopmentAppID,
56598
+ getDocParams: () => getDocParams,
56599
+ getGlobalDBName: () => getGlobalDBName,
56600
+ getGlobalIDFromUserMetadataID: () => getGlobalIDFromUserMetadataID,
56601
+ getGlobalUserParams: () => getGlobalUserParams,
56602
+ getPluginParams: () => getPluginParams,
56603
+ getPouch: () => getPouch,
56604
+ getPouchDB: () => getPouchDB,
56605
+ getProdAppID: () => getProdAppID2,
56606
+ getProdAppIDs: () => getProdAppIDs,
56607
+ getQueryIndex: () => getQueryIndex,
56608
+ getRoleParams: () => getRoleParams,
56609
+ getRowParams: () => getRowParams,
56610
+ getStartEndKeyURL: () => getStartEndKeyURL,
56611
+ getTemplateParams: () => getTemplateParams,
56612
+ getUrlInfo: () => getUrlInfo,
56613
+ getUserMetadataParams: () => getUserMetadataParams,
56614
+ getUsersByAppParams: () => getUsersByAppParams,
56615
+ getWorkspaceParams: () => getWorkspaceParams,
56616
+ init: () => init,
56617
+ isDatasourceId: () => isDatasourceId,
56618
+ isDevApp: () => isDevApp,
56619
+ isDevAppID: () => isDevAppID,
56620
+ isDocumentConflictError: () => isDocumentConflictError,
56621
+ isGlobalUserID: () => isGlobalUserID,
56622
+ isProdAppID: () => isProdAppID,
56623
+ isSameAppID: () => isSameAppID,
56624
+ isTableId: () => isTableId,
56625
+ paginatedSearch: () => paginatedSearch,
56626
+ pagination: () => pagination,
56627
+ prefixRoleID: () => prefixRoleID,
56628
+ queryGlobalView: () => queryGlobalView,
56629
+ queryGlobalViewRaw: () => queryGlobalViewRaw,
56630
+ queryPlatformView: () => queryPlatformView,
56631
+ queryView: () => queryView,
56632
+ queryViewRaw: () => queryViewRaw,
56633
+ removeKeyNumbering: () => removeKeyNumbering2,
56634
+ searchIndexes: () => searchIndexes_exports
56635
+ });
56636
+
56637
+ // src/cache/appMetadata.ts
56638
+ var appMetadata_exports = {};
56639
+ __export(appMetadata_exports, {
56640
+ AppState: () => AppState,
56641
+ getAppMetadata: () => getAppMetadata,
56642
+ invalidateAppMetadata: () => invalidateAppMetadata
56643
+ });
56644
+
56645
+ // src/redis/init.ts
56646
+ var init_exports = {};
56647
+ __export(init_exports, {
56648
+ getAppClient: () => getAppClient,
56649
+ getCacheClient: () => getCacheClient,
56650
+ getDocWritethroughClient: () => getDocWritethroughClient,
56651
+ getInviteClient: () => getInviteClient,
56652
+ getLockClient: () => getLockClient,
56653
+ getPasswordResetClient: () => getPasswordResetClient,
56654
+ getSessionClient: () => getSessionClient,
56655
+ getSocketClient: () => getSocketClient,
56656
+ getUserClient: () => getUserClient,
56657
+ getWritethroughClient: () => getWritethroughClient,
56658
+ init: () => init3,
56659
+ shutdown: () => shutdown
56660
+ });
56661
+
56662
+ // src/redis/redis.ts
56663
+ var import_ioredis = __toESM(require("ioredis"));
56664
+
56665
+ // src/redis/utils.ts
56666
+ var utils_exports2 = {};
56667
+ __export(utils_exports2, {
56668
+ Databases: () => Databases,
56669
+ SEPARATOR: () => SEPARATOR2,
56670
+ SelectableDatabase: () => SelectableDatabase,
56671
+ addDbPrefix: () => addDbPrefix,
56672
+ getRedisConnectionDetails: () => getRedisConnectionDetails,
56673
+ getRedisOptions: () => getRedisOptions,
56674
+ removeDbPrefix: () => removeDbPrefix
56675
+ });
56676
+ var SLOT_REFRESH_MS = 2e3;
56677
+ var CONNECT_TIMEOUT_MS = 1e4;
56678
+ var SEPARATOR2 = "-";
56679
+ var Databases = /* @__PURE__ */ ((Databases2) => {
56680
+ Databases2["PW_RESETS"] = "pwReset";
56681
+ Databases2["VERIFICATIONS"] = "verification";
56682
+ Databases2["INVITATIONS"] = "invitation";
56683
+ Databases2["DEV_LOCKS"] = "devLocks";
56684
+ Databases2["DEBOUNCE"] = "debounce";
56685
+ Databases2["SESSIONS"] = "session";
56686
+ Databases2["USER_CACHE"] = "users";
56687
+ Databases2["FLAGS"] = "flags";
56688
+ Databases2["APP_METADATA"] = "appMetadata";
56689
+ Databases2["QUERY_VARS"] = "queryVars";
56690
+ Databases2["LICENSES"] = "license";
56691
+ Databases2["GENERIC_CACHE"] = "data_cache";
56692
+ Databases2["WRITE_THROUGH"] = "writeThrough";
56693
+ Databases2["LOCKS"] = "locks";
56694
+ Databases2["SOCKET_IO"] = "socket_io";
56695
+ Databases2["BPM_EVENTS"] = "bpmEvents";
56696
+ Databases2["DOC_WRITE_THROUGH"] = "docWriteThrough";
56697
+ return Databases2;
56698
+ })(Databases || {});
56699
+ var SelectableDatabase = /* @__PURE__ */ ((SelectableDatabase2) => {
56700
+ SelectableDatabase2[SelectableDatabase2["DEFAULT"] = 0] = "DEFAULT";
56701
+ SelectableDatabase2[SelectableDatabase2["SOCKET_IO"] = 1] = "SOCKET_IO";
56702
+ SelectableDatabase2[SelectableDatabase2["RATE_LIMITING"] = 2] = "RATE_LIMITING";
56703
+ SelectableDatabase2[SelectableDatabase2["UNUSED_2"] = 3] = "UNUSED_2";
56704
+ SelectableDatabase2[SelectableDatabase2["UNUSED_3"] = 4] = "UNUSED_3";
56705
+ SelectableDatabase2[SelectableDatabase2["UNUSED_4"] = 5] = "UNUSED_4";
56706
+ SelectableDatabase2[SelectableDatabase2["UNUSED_5"] = 6] = "UNUSED_5";
56707
+ SelectableDatabase2[SelectableDatabase2["UNUSED_6"] = 7] = "UNUSED_6";
56708
+ SelectableDatabase2[SelectableDatabase2["UNUSED_7"] = 8] = "UNUSED_7";
56709
+ SelectableDatabase2[SelectableDatabase2["UNUSED_8"] = 9] = "UNUSED_8";
56710
+ SelectableDatabase2[SelectableDatabase2["UNUSED_9"] = 10] = "UNUSED_9";
56711
+ SelectableDatabase2[SelectableDatabase2["UNUSED_10"] = 11] = "UNUSED_10";
56712
+ SelectableDatabase2[SelectableDatabase2["UNUSED_11"] = 12] = "UNUSED_11";
56713
+ SelectableDatabase2[SelectableDatabase2["UNUSED_12"] = 13] = "UNUSED_12";
56714
+ SelectableDatabase2[SelectableDatabase2["UNUSED_13"] = 14] = "UNUSED_13";
56715
+ SelectableDatabase2[SelectableDatabase2["UNUSED_14"] = 15] = "UNUSED_14";
56716
+ return SelectableDatabase2;
56717
+ })(SelectableDatabase || {});
56718
+ function getRedisConnectionDetails() {
56719
+ let password = environment_default.REDIS_PASSWORD;
56720
+ let url = environment_default.REDIS_URL.split("//");
56721
+ url = url.length > 1 ? url[1] : url[0];
56722
+ url = url.split("@");
56723
+ if (url.length > 1) {
56724
+ password = url[0].split(":")[1];
56725
+ url = url[1];
56726
+ } else {
56727
+ url = url[0];
56524
56728
  }
56525
- };
56526
- function DatabaseWithConnection(dbName, connection, opts) {
56527
- const db = new DatabaseImpl(dbName, opts, connection);
56528
- return new DDInstrumentedDatabase(db);
56729
+ const [host, port] = url.split(":");
56730
+ const portNumber = parseInt(port);
56731
+ return {
56732
+ host,
56733
+ password,
56734
+ // assume default port for redis if invalid found
56735
+ port: isNaN(portNumber) ? 6379 : portNumber
56736
+ };
56529
56737
  }
56530
- var DatabaseImpl = class _DatabaseImpl {
56531
- constructor(dbName, opts, connection) {
56532
- this.couchInfo = getCouchInfo();
56533
- this.name = dbName;
56534
- this.pouchOpts = opts || {};
56535
- if (connection) {
56536
- this.couchInfo = getCouchInfo(connection);
56537
- this.instanceNano = buildNano(this.couchInfo);
56538
- }
56539
- if (!_DatabaseImpl.nano) {
56540
- _DatabaseImpl.init();
56541
- }
56738
+ function getRedisOptions() {
56739
+ const { host, password, port } = getRedisConnectionDetails();
56740
+ let redisOpts = {
56741
+ connectTimeout: CONNECT_TIMEOUT_MS,
56742
+ port,
56743
+ host,
56744
+ password
56745
+ };
56746
+ let opts = redisOpts;
56747
+ if (environment_default.REDIS_CLUSTERED) {
56748
+ opts = {
56749
+ connectTimeout: CONNECT_TIMEOUT_MS,
56750
+ redisOptions: {
56751
+ ...redisOpts,
56752
+ tls: {}
56753
+ },
56754
+ slotsRefreshTimeout: SLOT_REFRESH_MS,
56755
+ dnsLookup: (address, callback) => callback(null, address)
56756
+ };
56542
56757
  }
56543
- static init() {
56544
- const couchInfo = getCouchInfo();
56545
- _DatabaseImpl.nano = buildNano(couchInfo);
56758
+ return opts;
56759
+ }
56760
+ function addDbPrefix(db, key) {
56761
+ if (key.includes(db)) {
56762
+ return key;
56546
56763
  }
56547
- exists(docId) {
56548
- if (docId === void 0) {
56549
- return this.dbExists();
56550
- }
56551
- return this.docExists(docId);
56764
+ return `${db}${SEPARATOR2}${key}`;
56765
+ }
56766
+ function removeDbPrefix(key) {
56767
+ let parts = key.split(SEPARATOR2);
56768
+ if (parts.length >= 2) {
56769
+ parts.shift();
56770
+ return parts.join(SEPARATOR2);
56771
+ } else {
56772
+ return parts[0];
56552
56773
  }
56553
- async dbExists() {
56554
- const response = await directCouchUrlCall({
56555
- url: `${this.couchInfo.url}/${this.name}`,
56556
- method: "HEAD",
56557
- cookie: this.couchInfo.cookie
56558
- });
56559
- return response.status === 200;
56774
+ }
56775
+
56776
+ // src/logging/index.ts
56777
+ var logging_exports = {};
56778
+ __export(logging_exports, {
56779
+ correlation: () => correlation_exports,
56780
+ logAlert: () => logAlert,
56781
+ logAlertWithInfo: () => logAlertWithInfo,
56782
+ logWarn: () => logWarn,
56783
+ logger: () => logger,
56784
+ system: () => system_exports
56785
+ });
56786
+
56787
+ // src/logging/correlation/correlation.ts
56788
+ var correlation_exports = {};
56789
+ __export(correlation_exports, {
56790
+ getId: () => getId,
56791
+ setHeader: () => setHeader
56792
+ });
56793
+ var correlator = require("correlation-id");
56794
+ var setHeader = (headers) => {
56795
+ const correlationId = correlator.getId();
56796
+ if (!correlationId) {
56797
+ return;
56560
56798
  }
56561
- async docExists(id) {
56562
- try {
56563
- await this.performCall((db) => () => db.head(id));
56564
- return true;
56565
- } catch {
56566
- return false;
56799
+ headers["x-budibase-correlation-id" /* CORRELATION_ID */] = correlationId;
56800
+ };
56801
+ function getId() {
56802
+ return correlator.getId();
56803
+ }
56804
+
56805
+ // src/logging/pino/logger.ts
56806
+ var import_pino = __toESM(require("pino"));
56807
+ var import_pino_pretty = __toESM(require("pino-pretty"));
56808
+ var import_dd_trace2 = __toESM(require("dd-trace"));
56809
+ var import_ext = require("dd-trace/ext");
56810
+
56811
+ // src/logging/system.ts
56812
+ var system_exports = {};
56813
+ __export(system_exports, {
56814
+ getLogReadStream: () => getLogReadStream,
56815
+ getSingleFileMaxSizeInfo: () => getSingleFileMaxSizeInfo,
56816
+ localFileDestination: () => localFileDestination
56817
+ });
56818
+ var import_fs4 = __toESM(require("fs"));
56819
+ var import_path3 = __toESM(require("path"));
56820
+ var rfs = __toESM(require("rotating-file-stream"));
56821
+
56822
+ // src/objectStore/index.ts
56823
+ var objectStore_exports2 = {};
56824
+ __export(objectStore_exports2, {
56825
+ ObjectStore: () => ObjectStore,
56826
+ ObjectStoreBuckets: () => ObjectStoreBuckets,
56827
+ SIGNED_FILE_PREFIX: () => SIGNED_FILE_PREFIX,
56828
+ bucketTTLConfig: () => bucketTTLConfig,
56829
+ budibaseTempDir: () => budibaseTempDir,
56830
+ clientLibraryCDNUrl: () => clientLibraryCDNUrl,
56831
+ clientLibraryPath: () => clientLibraryPath,
56832
+ clientLibraryUrl: () => clientLibraryUrl,
56833
+ createBucketIfNotExists: () => createBucketIfNotExists,
56834
+ deleteFile: () => deleteFile,
56835
+ deleteFiles: () => deleteFiles,
56836
+ deleteFolder: () => deleteFolder,
56837
+ downloadTarball: () => downloadTarball,
56838
+ downloadTarballDirect: () => downloadTarballDirect,
56839
+ enrichPluginURLs: () => enrichPluginURLs,
56840
+ extractBucketAndPath: () => extractBucketAndPath,
56841
+ getAppFileUrl: () => getAppFileUrl,
56842
+ getGlobalFileS3Key: () => getGlobalFileS3Key,
56843
+ getGlobalFileUrl: () => getGlobalFileUrl,
56844
+ getObjectMetadata: () => getObjectMetadata,
56845
+ getPluginIconKey: () => getPluginIconKey,
56846
+ getPluginJSKey: () => getPluginJSKey,
56847
+ getPluginS3Dir: () => getPluginS3Dir,
56848
+ getPresignedUrl: () => getPresignedUrl,
56849
+ getReadStream: () => getReadStream,
56850
+ listAllObjects: () => listAllObjects,
56851
+ processAutomationAttachment: () => processAutomationAttachment,
56852
+ processObjectStoreAttachment: () => processObjectStoreAttachment,
56853
+ retrieve: () => retrieve,
56854
+ retrieveDirectory: () => retrieveDirectory,
56855
+ retrieveToTmp: () => retrieveToTmp,
56856
+ sanitizeBucket: () => sanitizeBucket,
56857
+ sanitizeKey: () => sanitizeKey,
56858
+ streamUpload: () => streamUpload,
56859
+ upload: () => upload,
56860
+ uploadDirectory: () => uploadDirectory
56861
+ });
56862
+
56863
+ // src/objectStore/objectStore.ts
56864
+ var import_aws_sdk = __toESM(require("aws-sdk"));
56865
+ var import_stream2 = __toESM(require("stream"));
56866
+ var import_node_fetch2 = __toESM(require("node-fetch"));
56867
+ var import_tar_fs = __toESM(require("tar-fs"));
56868
+ var import_zlib = __toESM(require("zlib"));
56869
+ var import_util = require("util");
56870
+ var import_path2 = require("path");
56871
+ var import_fs3 = __toESM(require("fs"));
56872
+
56873
+ // src/objectStore/utils.ts
56874
+ var import_path = __toESM(require("path"));
56875
+ var import_os = require("os");
56876
+ var import_fs2 = __toESM(require("fs"));
56877
+ var import_stream = __toESM(require("stream"));
56878
+ var ObjectStoreBuckets = {
56879
+ BACKUPS: environment_default.BACKUPS_BUCKET_NAME,
56880
+ APPS: environment_default.APPS_BUCKET_NAME,
56881
+ TEMPLATES: environment_default.TEMPLATES_BUCKET_NAME,
56882
+ GLOBAL: environment_default.GLOBAL_BUCKET_NAME,
56883
+ PLUGINS: environment_default.PLUGIN_BUCKET_NAME,
56884
+ TEMP: environment_default.TEMP_BUCKET_NAME
56885
+ };
56886
+ var bbTmp = (0, import_path.join)((0, import_os.tmpdir)(), ".budibase");
56887
+ try {
56888
+ import_fs2.default.mkdirSync(bbTmp);
56889
+ } catch (e) {
56890
+ if (e.code !== "EEXIST") {
56891
+ throw e;
56892
+ }
56893
+ }
56894
+ function budibaseTempDir() {
56895
+ return bbTmp;
56896
+ }
56897
+ var bucketTTLConfig = (bucketName, days) => {
56898
+ const lifecycleRule = {
56899
+ ID: `${bucketName}-ExpireAfter${days}days`,
56900
+ Prefix: "",
56901
+ Status: "Enabled",
56902
+ Expiration: {
56903
+ Days: days
56567
56904
  }
56905
+ };
56906
+ const lifecycleConfiguration = {
56907
+ Rules: [lifecycleRule]
56908
+ };
56909
+ return {
56910
+ Bucket: bucketName,
56911
+ LifecycleConfiguration: lifecycleConfiguration
56912
+ };
56913
+ };
56914
+ async function processUrlAttachment(attachment) {
56915
+ const response = await fetch(attachment.url);
56916
+ if (!response.ok || !response.body) {
56917
+ throw new Error(`Unexpected response ${response.statusText}`);
56568
56918
  }
56569
- nano() {
56570
- return this.instanceNano || _DatabaseImpl.nano;
56919
+ const fallbackFilename = import_path.default.basename(new URL(attachment.url).pathname);
56920
+ if (!response.body) {
56921
+ throw new Error("No response received for attachment");
56571
56922
  }
56572
- getDb() {
56573
- return this.nano().db.use(this.name);
56923
+ return {
56924
+ filename: attachment.filename || fallbackFilename,
56925
+ content: import_stream.default.Readable.fromWeb(response.body)
56926
+ };
56927
+ }
56928
+ async function processObjectStoreAttachment(attachment) {
56929
+ const result = extractBucketAndPath(attachment.url);
56930
+ if (result === null) {
56931
+ throw new Error("Invalid signed URL");
56574
56932
  }
56575
- async checkAndCreateDb() {
56576
- let shouldCreate = !this.pouchOpts?.skip_setup;
56577
- let exists2 = await this.exists();
56578
- if (!shouldCreate && !exists2) {
56579
- throw new Error("DB does not exist");
56580
- }
56581
- if (!exists2) {
56582
- try {
56583
- await this.nano().db.create(this.name);
56584
- } catch (err) {
56585
- if (err.statusCode !== 412) {
56586
- throw new CouchDBError(err.message, err);
56587
- }
56588
- }
56589
- }
56590
- return this.getDb();
56933
+ const { bucket, path: objectPath } = result;
56934
+ const readStream = await getReadStream(bucket, objectPath);
56935
+ const fallbackFilename = import_path.default.basename(objectPath);
56936
+ return {
56937
+ bucket,
56938
+ path: objectPath,
56939
+ filename: attachment.filename || fallbackFilename,
56940
+ content: readStream
56941
+ };
56942
+ }
56943
+ async function processAutomationAttachment(attachment) {
56944
+ const isFullyFormedUrl = attachment.url?.startsWith("http://") || attachment.url?.startsWith("https://");
56945
+ if (isFullyFormedUrl) {
56946
+ return await processUrlAttachment(attachment);
56947
+ } else {
56948
+ return await processObjectStoreAttachment(attachment);
56591
56949
  }
56592
- // this function fetches the DB and handles if DB creation is needed
56593
- async performCall(call) {
56594
- const db = this.getDb();
56595
- const fnc = await call(db);
56596
- try {
56597
- return await fnc();
56598
- } catch (err) {
56599
- if (err.statusCode === 404 && err.reason === DATABASE_NOT_FOUND) {
56600
- await this.checkAndCreateDb();
56601
- return await this.performCall(call);
56602
- }
56603
- throw new CouchDBError(`CouchDB error: ${err.message}`, err);
56604
- }
56950
+ }
56951
+
56952
+ // src/objectStore/objectStore.ts
56953
+ var import_uuid2 = require("uuid");
56954
+ var import_promises = __toESM(require("fs/promises"));
56955
+ var sanitize = require("sanitize-s3-objectkey");
56956
+ var streamPipeline = (0, import_util.promisify)(import_stream2.default.pipeline);
56957
+ var STATE = {
56958
+ bucketCreationPromises: {}
56959
+ };
56960
+ var SIGNED_FILE_PREFIX = "/files/signed";
56961
+ var CONTENT_TYPE_MAP = {
56962
+ txt: "text/plain",
56963
+ html: "text/html",
56964
+ css: "text/css",
56965
+ js: "application/javascript",
56966
+ json: "application/json",
56967
+ gz: "application/gzip",
56968
+ svg: "image/svg+xml",
56969
+ form: "multipart/form-data"
56970
+ };
56971
+ var STRING_CONTENT_TYPES = [
56972
+ CONTENT_TYPE_MAP.html,
56973
+ CONTENT_TYPE_MAP.css,
56974
+ CONTENT_TYPE_MAP.js,
56975
+ CONTENT_TYPE_MAP.json
56976
+ ];
56977
+ function sanitizeKey(input) {
56978
+ return sanitize(sanitizeBucket(input)).replace(/\\/g, "/");
56979
+ }
56980
+ function sanitizeBucket(input) {
56981
+ return input.replace(new RegExp(APP_DEV_PREFIX2, "g"), APP_PREFIX2);
56982
+ }
56983
+ function ObjectStore(bucket, opts = { presigning: false }) {
56984
+ const config = {
56985
+ s3ForcePathStyle: true,
56986
+ signatureVersion: "v4",
56987
+ apiVersion: "2006-03-01",
56988
+ accessKeyId: environment_default.MINIO_ACCESS_KEY,
56989
+ secretAccessKey: environment_default.MINIO_SECRET_KEY,
56990
+ region: environment_default.AWS_REGION
56991
+ };
56992
+ if (bucket) {
56993
+ config.params = {
56994
+ Bucket: sanitizeBucket(bucket)
56995
+ };
56605
56996
  }
56606
- async get(id) {
56607
- return this.performCall((db) => {
56608
- if (!id) {
56609
- throw new Error("Unable to get doc without a valid _id.");
56610
- }
56611
- return () => db.get(id);
56612
- });
56997
+ if (!environment_default.MINIO_ENABLED && environment_default.AWS_SESSION_TOKEN) {
56998
+ config.sessionToken = environment_default.AWS_SESSION_TOKEN;
56613
56999
  }
56614
- async getMultiple(ids, opts) {
56615
- ids = [...new Set(ids)];
56616
- const response = await this.allDocs({
56617
- keys: ids,
56618
- include_docs: true
56619
- });
56620
- const rowUnavailable = (row) => {
56621
- if (row.doc == null || "deleted" in row.value && row.value.deleted) {
56622
- return true;
56623
- }
56624
- return row.error === "not_found";
56625
- };
56626
- const rows = response.rows.filter((row) => !rowUnavailable(row));
56627
- const someMissing = rows.length !== response.rows.length;
56628
- if (!opts?.allowMissing && someMissing) {
56629
- const missing = response.rows.filter((row) => rowUnavailable(row));
56630
- const missingIds = missing.map((row) => row.key).join(", ");
56631
- throw new Error(`Unable to get documents: ${missingIds}`);
57000
+ if (environment_default.MINIO_URL) {
57001
+ if (opts.presigning && environment_default.MINIO_ENABLED) {
57002
+ config.endpoint = "minio-service";
57003
+ } else {
57004
+ config.endpoint = environment_default.MINIO_URL;
56632
57005
  }
56633
- return rows.map((row) => row.doc);
56634
57006
  }
56635
- async remove(idOrDoc, rev) {
56636
- return this.performCall((db) => {
56637
- let _id;
56638
- let _rev;
56639
- if (isDocument(idOrDoc)) {
56640
- _id = idOrDoc._id;
56641
- _rev = idOrDoc._rev;
57007
+ return new import_aws_sdk.default.S3(config);
57008
+ }
57009
+ async function createBucketIfNotExists(client, bucketName) {
57010
+ bucketName = sanitizeBucket(bucketName);
57011
+ try {
57012
+ await client.headBucket({
57013
+ Bucket: bucketName
57014
+ }).promise();
57015
+ return { created: false, exists: true };
57016
+ } catch (err) {
57017
+ const promises = STATE.bucketCreationPromises;
57018
+ const doesntExist = err.statusCode === 404, noAccess = err.statusCode === 403;
57019
+ if (promises[bucketName]) {
57020
+ await promises[bucketName];
57021
+ return { created: false, exists: true };
57022
+ } else if (doesntExist || noAccess) {
57023
+ if (doesntExist) {
57024
+ promises[bucketName] = client.createBucket({
57025
+ Bucket: bucketName
57026
+ }).promise();
57027
+ await promises[bucketName];
57028
+ delete promises[bucketName];
57029
+ return { created: true, exists: false };
56642
57030
  } else {
56643
- _id = idOrDoc;
56644
- _rev = rev;
56645
- }
56646
- if (!_id || !_rev) {
56647
- throw new Error("Unable to remove doc without a valid _id and _rev.");
57031
+ throw new Error("Access denied to object store bucket." + err);
56648
57032
  }
56649
- return () => db.destroy(_id, _rev);
56650
- });
56651
- }
56652
- async post(document, opts) {
56653
- if (!document._id) {
56654
- document._id = newid();
57033
+ } else {
57034
+ throw new Error("Unable to write to object store bucket.");
56655
57035
  }
56656
- return this.put(document, opts);
56657
57036
  }
56658
- async put(document, opts) {
56659
- if (!document._id) {
56660
- throw new Error("Cannot store document without _id field.");
56661
- }
56662
- return this.performCall(async (db) => {
56663
- if (!document.createdAt) {
56664
- document.createdAt = (/* @__PURE__ */ new Date()).toISOString();
56665
- }
56666
- document.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
56667
- if (opts?.force && document._id) {
56668
- try {
56669
- const existing = await this.get(document._id);
56670
- if (existing) {
56671
- document._rev = existing._rev;
56672
- }
56673
- } catch (err) {
56674
- if (err.status !== 404) {
56675
- throw err;
56676
- }
56677
- }
57037
+ }
57038
+ async function upload({
57039
+ bucket: bucketName,
57040
+ filename,
57041
+ path: path3,
57042
+ type,
57043
+ metadata,
57044
+ body: body2,
57045
+ ttl
57046
+ }) {
57047
+ const extension = filename.split(".").pop();
57048
+ const fileBytes = path3 ? (await import_promises.default.open(path3)).createReadStream() : body2;
57049
+ const objectStore = ObjectStore(bucketName);
57050
+ const bucketCreated = await createBucketIfNotExists(objectStore, bucketName);
57051
+ if (ttl && bucketCreated.created) {
57052
+ let ttlConfig = bucketTTLConfig(bucketName, ttl);
57053
+ await objectStore.putBucketLifecycleConfiguration(ttlConfig).promise();
57054
+ }
57055
+ let contentType = type;
57056
+ if (!contentType) {
57057
+ contentType = extension ? CONTENT_TYPE_MAP[extension.toLowerCase()] : CONTENT_TYPE_MAP.txt;
57058
+ }
57059
+ const config = {
57060
+ // windows file paths need to be converted to forward slashes for s3
57061
+ Key: sanitizeKey(filename),
57062
+ Body: fileBytes,
57063
+ ContentType: contentType
57064
+ };
57065
+ if (metadata && typeof metadata === "object") {
57066
+ for (let key of Object.keys(metadata)) {
57067
+ if (!metadata[key] || typeof metadata[key] !== "string") {
57068
+ delete metadata[key];
56678
57069
  }
56679
- return () => db.insert(document);
56680
- });
57070
+ }
57071
+ config.Metadata = metadata;
56681
57072
  }
56682
- async bulkDocs(documents) {
56683
- return this.performCall((db) => {
56684
- return () => db.bulk({ docs: documents });
56685
- });
57073
+ return objectStore.upload(config).promise();
57074
+ }
57075
+ async function streamUpload({
57076
+ bucket: bucketName,
57077
+ stream: stream3,
57078
+ filename,
57079
+ type,
57080
+ extra,
57081
+ ttl
57082
+ }) {
57083
+ if (!stream3) {
57084
+ throw new Error("Stream to upload is invalid/undefined");
56686
57085
  }
56687
- async allDocs(params2) {
56688
- return this.performCall((db) => {
56689
- return () => db.list(params2);
56690
- });
57086
+ const extension = filename.split(".").pop();
57087
+ const objectStore = ObjectStore(bucketName);
57088
+ const bucketCreated = await createBucketIfNotExists(objectStore, bucketName);
57089
+ if (ttl && bucketCreated.created) {
57090
+ let ttlConfig = bucketTTLConfig(bucketName, ttl);
57091
+ await objectStore.putBucketLifecycleConfiguration(ttlConfig).promise();
56691
57092
  }
56692
- async _sqlQuery(url, method, body2) {
56693
- url = checkSlashesInUrl(`${this.couchInfo.sqlUrl}/${url}`);
56694
- const args = {
56695
- url,
56696
- method,
56697
- cookie: this.couchInfo.cookie
57093
+ if (filename?.endsWith(".js")) {
57094
+ extra = {
57095
+ ...extra,
57096
+ ContentType: "application/javascript"
57097
+ };
57098
+ } else if (filename?.endsWith(".svg")) {
57099
+ extra = {
57100
+ ...extra,
57101
+ ContentType: "image"
56698
57102
  };
56699
- if (body2) {
56700
- args.body = body2;
56701
- }
56702
- return this.performCall(() => {
56703
- return async () => {
56704
- const response = await directCouchUrlCall(args);
56705
- const json = await response.json();
56706
- if (response.status > 300) {
56707
- throw json;
56708
- }
56709
- return json;
56710
- };
56711
- });
56712
- }
56713
- async sql(sql, parameters) {
56714
- const dbName = this.name;
56715
- const url = `/${dbName}/${SQLITE_DESIGN_DOC_ID}`;
56716
- return await this._sqlQuery(url, "POST", {
56717
- query: sql,
56718
- args: parameters
56719
- });
56720
57103
  }
56721
- // checks design document is accurate (cleans up tables)
56722
- // this will check the design document and remove anything from
56723
- // disk which is not supposed to be there
56724
- async sqlDiskCleanup() {
56725
- const dbName = this.name;
56726
- const url = `/${dbName}/_cleanup`;
56727
- try {
56728
- await this._sqlQuery(url, "POST");
56729
- } catch (err) {
56730
- if (err.status !== 500) {
56731
- throw err;
56732
- }
56733
- }
56734
- }
56735
- // removes a document from sqlite
56736
- async sqlPurgeDocument(docIds) {
56737
- if (!Array.isArray(docIds)) {
56738
- docIds = [docIds];
56739
- }
56740
- const dbName = this.name;
56741
- const url = `/${dbName}/_purge`;
56742
- return await this._sqlQuery(url, "POST", { docs: docIds });
57104
+ let contentType = type;
57105
+ if (!contentType) {
57106
+ contentType = extension ? CONTENT_TYPE_MAP[extension.toLowerCase()] : CONTENT_TYPE_MAP.txt;
56743
57107
  }
56744
- async query(viewName, params2) {
56745
- return this.performCall((db) => {
56746
- const [database, view] = viewName.split("/");
56747
- return () => db.view(database, view, params2);
56748
- });
57108
+ const bucket = sanitizeBucket(bucketName), objKey = sanitizeKey(filename);
57109
+ const params2 = {
57110
+ Bucket: bucket,
57111
+ Key: objKey,
57112
+ Body: stream3,
57113
+ ContentType: contentType,
57114
+ ...extra
57115
+ };
57116
+ const details = await objectStore.upload(params2).promise();
57117
+ const headDetails = await objectStore.headObject({
57118
+ Bucket: bucket,
57119
+ Key: objKey
57120
+ }).promise();
57121
+ return {
57122
+ ...details,
57123
+ ContentLength: headDetails.ContentLength
57124
+ };
57125
+ }
57126
+ async function retrieve(bucketName, filepath) {
57127
+ const objectStore = ObjectStore(bucketName);
57128
+ const params2 = {
57129
+ Bucket: sanitizeBucket(bucketName),
57130
+ Key: sanitizeKey(filepath)
57131
+ };
57132
+ const response = await objectStore.getObject(params2).promise();
57133
+ if (STRING_CONTENT_TYPES.includes(response.ContentType)) {
57134
+ return response.Body.toString("utf8");
57135
+ } else {
57136
+ return response.Body;
56749
57137
  }
56750
- async destroy() {
56751
- if (environment_default.SQS_SEARCH_ENABLE && await this.exists(SQLITE_DESIGN_DOC_ID)) {
56752
- const definition = await this.get(SQLITE_DESIGN_DOC_ID);
56753
- definition.sql.tables = {};
56754
- await this.put(definition);
56755
- await this.sqlDiskCleanup();
57138
+ }
57139
+ async function listAllObjects(bucketName, path3) {
57140
+ const objectStore = ObjectStore(bucketName);
57141
+ const list = (params2 = {}) => {
57142
+ return objectStore.listObjectsV2({
57143
+ ...params2,
57144
+ Bucket: sanitizeBucket(bucketName),
57145
+ Prefix: sanitizeKey(path3)
57146
+ }).promise();
57147
+ };
57148
+ let isTruncated = false, token, objects = [];
57149
+ do {
57150
+ let params2 = {};
57151
+ if (token) {
57152
+ params2.ContinuationToken = token;
56756
57153
  }
56757
- try {
56758
- return await this.nano().db.destroy(this.name);
56759
- } catch (err) {
56760
- if (err.statusCode === 404) {
56761
- return;
56762
- } else {
56763
- throw new CouchDBError(err.message, err);
56764
- }
57154
+ const response = await list(params2);
57155
+ if (response.Contents) {
57156
+ objects = objects.concat(response.Contents);
56765
57157
  }
57158
+ isTruncated = !!response.IsTruncated;
57159
+ token = response.NextContinuationToken;
57160
+ } while (isTruncated && token);
57161
+ return objects;
57162
+ }
57163
+ function getPresignedUrl(bucketName, key, durationSeconds = 3600) {
57164
+ const objectStore = ObjectStore(bucketName, { presigning: true });
57165
+ const params2 = {
57166
+ Bucket: sanitizeBucket(bucketName),
57167
+ Key: sanitizeKey(key),
57168
+ Expires: durationSeconds
57169
+ };
57170
+ const url = objectStore.getSignedUrl("getObject", params2);
57171
+ if (!environment_default.MINIO_ENABLED) {
57172
+ return url;
57173
+ } else {
57174
+ const signedUrl = new URL(url);
57175
+ const path3 = signedUrl.pathname;
57176
+ const query = signedUrl.search;
57177
+ return `${SIGNED_FILE_PREFIX}${path3}${query}`;
56766
57178
  }
56767
- async compact() {
56768
- return this.performCall((db) => {
56769
- return () => db.compact();
56770
- });
56771
- }
56772
- // All below functions are in-frequently called, just utilise PouchDB
56773
- // for them as it implements them better than we can
56774
- async dump(stream3, opts) {
56775
- const pouch = getPouchDB(this.name);
56776
- return pouch.dump(stream3, opts);
56777
- }
56778
- async load(stream3) {
56779
- const pouch = getPouchDB(this.name);
56780
- return pouch.load(stream3);
56781
- }
56782
- async createIndex(opts) {
56783
- const pouch = getPouchDB(this.name);
56784
- return pouch.createIndex(opts);
56785
- }
56786
- async deleteIndex(opts) {
56787
- const pouch = getPouchDB(this.name);
56788
- return pouch.deleteIndex(opts);
56789
- }
56790
- async getIndexes() {
56791
- const pouch = getPouchDB(this.name);
56792
- return pouch.getIndexes();
56793
- }
56794
- };
56795
-
56796
- // src/db/db.ts
56797
- function getDB(dbName, opts) {
56798
- return new DDInstrumentedDatabase(new DatabaseImpl(dbName, opts));
56799
57179
  }
56800
- async function doWithDB(dbName, cb, opts) {
56801
- const db = getDB(dbName, opts);
56802
- return await cb(db);
57180
+ async function retrieveToTmp(bucketName, filepath) {
57181
+ bucketName = sanitizeBucket(bucketName);
57182
+ filepath = sanitizeKey(filepath);
57183
+ const data = await retrieve(bucketName, filepath);
57184
+ const outputPath = (0, import_path2.join)(budibaseTempDir(), (0, import_uuid2.v4)());
57185
+ import_fs3.default.writeFileSync(outputPath, data);
57186
+ return outputPath;
56803
57187
  }
56804
- async function directCouchAllDbs(queryString) {
56805
- let couchPath = "/_all_dbs";
56806
- if (queryString) {
56807
- couchPath += `?${queryString}`;
57188
+ async function retrieveDirectory(bucketName, path3) {
57189
+ let writePath = (0, import_path2.join)(budibaseTempDir(), (0, import_uuid2.v4)());
57190
+ import_fs3.default.mkdirSync(writePath);
57191
+ const objects = await listAllObjects(bucketName, path3);
57192
+ let streams = await Promise.all(
57193
+ objects.map((obj) => getReadStream(bucketName, obj.Key))
57194
+ );
57195
+ let count = 0;
57196
+ const writePromises = [];
57197
+ for (let obj of objects) {
57198
+ const filename = obj.Key;
57199
+ const stream3 = streams[count++];
57200
+ const possiblePath = filename.split("/");
57201
+ const dirs = possiblePath.slice(0, possiblePath.length - 1);
57202
+ const possibleDir = (0, import_path2.join)(writePath, ...dirs);
57203
+ if (possiblePath.length > 1 && !import_fs3.default.existsSync(possibleDir)) {
57204
+ import_fs3.default.mkdirSync(possibleDir, { recursive: true });
57205
+ }
57206
+ const writeStream = import_fs3.default.createWriteStream((0, import_path2.join)(writePath, ...possiblePath), {
57207
+ mode: 420
57208
+ });
57209
+ stream3.pipe(writeStream);
57210
+ writePromises.push(
57211
+ new Promise((resolve, reject) => {
57212
+ stream3.on("finish", resolve);
57213
+ stream3.on("error", reject);
57214
+ writeStream.on("error", reject);
57215
+ })
57216
+ );
56808
57217
  }
56809
- return await directCouchQuery(couchPath);
57218
+ await Promise.all(writePromises);
57219
+ return writePath;
56810
57220
  }
56811
- async function directCouchFind(dbName, opts) {
56812
- const json = await directCouchQuery(`${dbName}/_find`, "POST", opts);
56813
- return { rows: json.docs, bookmark: json.bookmark };
57221
+ async function deleteFile(bucketName, filepath) {
57222
+ const objectStore = ObjectStore(bucketName);
57223
+ await createBucketIfNotExists(objectStore, bucketName);
57224
+ const params2 = {
57225
+ Bucket: bucketName,
57226
+ Key: sanitizeKey(filepath)
57227
+ };
57228
+ return objectStore.deleteObject(params2).promise();
56814
57229
  }
56815
-
56816
- // src/context/mainContext.ts
56817
- var TEST_APP_ID = null;
56818
- function getGlobalDBName(tenantId) {
56819
- if (!tenantId) {
56820
- tenantId = getTenantId();
56821
- }
56822
- return baseGlobalDBName(tenantId);
57230
+ async function deleteFiles(bucketName, filepaths) {
57231
+ const objectStore = ObjectStore(bucketName);
57232
+ await createBucketIfNotExists(objectStore, bucketName);
57233
+ const params2 = {
57234
+ Bucket: bucketName,
57235
+ Delete: {
57236
+ Objects: filepaths.map((path3) => ({ Key: sanitizeKey(path3) }))
57237
+ }
57238
+ };
57239
+ return objectStore.deleteObjects(params2).promise();
56823
57240
  }
56824
- function getAuditLogDBName(tenantId) {
56825
- if (!tenantId) {
56826
- tenantId = getTenantId();
57241
+ async function deleteFolder(bucketName, folder) {
57242
+ bucketName = sanitizeBucket(bucketName);
57243
+ folder = sanitizeKey(folder);
57244
+ const client = ObjectStore(bucketName);
57245
+ const listParams = {
57246
+ Bucket: bucketName,
57247
+ Prefix: folder
57248
+ };
57249
+ const existingObjectsResponse = await client.listObjects(listParams).promise();
57250
+ if (existingObjectsResponse.Contents?.length === 0) {
57251
+ return;
56827
57252
  }
56828
- if (tenantId === DEFAULT_TENANT_ID) {
56829
- return StaticDatabases.AUDIT_LOGS.name;
56830
- } else {
56831
- return `${tenantId}${SEPARATOR}${StaticDatabases.AUDIT_LOGS.name}`;
57253
+ const deleteParams = {
57254
+ Bucket: bucketName,
57255
+ Delete: {
57256
+ Objects: []
57257
+ }
57258
+ };
57259
+ existingObjectsResponse.Contents?.forEach((content) => {
57260
+ deleteParams.Delete.Objects.push({ Key: content.Key });
57261
+ });
57262
+ const deleteResponse = await client.deleteObjects(deleteParams).promise();
57263
+ if (deleteResponse.Deleted?.length === 1e3) {
57264
+ return deleteFolder(bucketName, folder);
56832
57265
  }
56833
57266
  }
56834
- function getScimDBName(tenantId) {
56835
- if (!tenantId) {
56836
- tenantId = getTenantId();
56837
- }
56838
- if (tenantId === DEFAULT_TENANT_ID) {
56839
- return StaticDatabases.SCIM_LOGS.name;
56840
- } else {
56841
- return `${tenantId}${SEPARATOR}${StaticDatabases.SCIM_LOGS.name}`;
56842
- }
56843
- }
56844
- function baseGlobalDBName(tenantId) {
56845
- if (!tenantId || tenantId === DEFAULT_TENANT_ID) {
56846
- return StaticDatabases.GLOBAL.name;
56847
- } else {
56848
- return `${tenantId}${SEPARATOR}${StaticDatabases.GLOBAL.name}`;
57267
+ async function uploadDirectory(bucketName, localPath, bucketPath) {
57268
+ bucketName = sanitizeBucket(bucketName);
57269
+ let uploads = [];
57270
+ const files = import_fs3.default.readdirSync(localPath, { withFileTypes: true });
57271
+ for (let file of files) {
57272
+ const path3 = sanitizeKey((0, import_path2.join)(bucketPath, file.name));
57273
+ const local = (0, import_path2.join)(localPath, file.name);
57274
+ if (file.isDirectory()) {
57275
+ uploads.push(uploadDirectory(bucketName, local, path3));
57276
+ } else {
57277
+ uploads.push(
57278
+ streamUpload({
57279
+ bucket: bucketName,
57280
+ filename: path3,
57281
+ stream: import_fs3.default.createReadStream(local)
57282
+ })
57283
+ );
57284
+ }
56849
57285
  }
57286
+ await Promise.all(uploads);
57287
+ return files;
56850
57288
  }
56851
- function getPlatformURL() {
56852
- return environment_default.PLATFORM_URL;
56853
- }
56854
- function isMultiTenant() {
56855
- return !!environment_default.MULTI_TENANCY;
56856
- }
56857
- function isTenantIdSet() {
56858
- const context = Context.get();
56859
- return !!context?.tenantId;
56860
- }
56861
- function isTenancyEnabled() {
56862
- return environment_default.MULTI_TENANCY;
56863
- }
56864
- function getTenantIDFromAppID(appId) {
56865
- if (!appId) {
56866
- return void 0;
56867
- }
56868
- if (!isMultiTenant()) {
56869
- return DEFAULT_TENANT_ID;
57289
+ async function downloadTarballDirect(url, path3, headers = {}) {
57290
+ path3 = sanitizeKey(path3);
57291
+ const response = await (0, import_node_fetch2.default)(url, { headers });
57292
+ if (!response.ok) {
57293
+ throw new Error(`unexpected response ${response.statusText}`);
56870
57294
  }
56871
- const split = appId.split(SEPARATOR);
56872
- const hasDev = split[1] === "dev" /* DEV */;
56873
- if (hasDev && split.length === 3 || !hasDev && split.length === 2) {
56874
- return void 0;
57295
+ await streamPipeline(response.body, import_zlib.default.createUnzip(), import_tar_fs.default.extract(path3));
57296
+ }
57297
+ async function downloadTarball(url, bucketName, path3) {
57298
+ bucketName = sanitizeBucket(bucketName);
57299
+ path3 = sanitizeKey(path3);
57300
+ const response = await (0, import_node_fetch2.default)(url);
57301
+ if (!response.ok) {
57302
+ throw new Error(`unexpected response ${response.statusText}`);
56875
57303
  }
56876
- if (hasDev) {
56877
- return split[2];
56878
- } else {
56879
- return split[1];
57304
+ const tmpPath = (0, import_path2.join)(budibaseTempDir(), path3);
57305
+ await streamPipeline(response.body, import_zlib.default.createUnzip(), import_tar_fs.default.extract(tmpPath));
57306
+ if (!environment_default.isTest() && environment_default.SELF_HOSTED) {
57307
+ await uploadDirectory(bucketName, tmpPath, path3);
56880
57308
  }
57309
+ return tmpPath;
56881
57310
  }
56882
- function updateContext(updates) {
56883
- let context;
57311
+ async function getReadStream(bucketName, path3) {
57312
+ bucketName = sanitizeBucket(bucketName);
57313
+ path3 = sanitizeKey(path3);
57314
+ const client = ObjectStore(bucketName);
57315
+ const params2 = {
57316
+ Bucket: bucketName,
57317
+ Key: path3
57318
+ };
57319
+ return client.getObject(params2).createReadStream();
57320
+ }
57321
+ async function getObjectMetadata(bucket, path3) {
57322
+ bucket = sanitizeBucket(bucket);
57323
+ path3 = sanitizeKey(path3);
57324
+ const client = ObjectStore(bucket);
57325
+ const params2 = {
57326
+ Bucket: bucket,
57327
+ Key: path3
57328
+ };
56884
57329
  try {
56885
- context = Context.get();
57330
+ return await client.headObject(params2).promise();
56886
57331
  } catch (err) {
56887
- context = {};
57332
+ throw new Error("Unable to retrieve metadata from object");
56888
57333
  }
56889
- context = {
56890
- ...context,
56891
- ...updates
56892
- };
56893
- return context;
56894
- }
56895
- async function newContext(updates, task) {
56896
- guardMigration();
56897
- let context = updateContext(updates);
56898
- return Context.run(context, task);
56899
- }
56900
- async function doInAutomationContext(params2) {
56901
- await ensureSnippetContext();
56902
- return newContext(
56903
- {
56904
- tenantId: getTenantIDFromAppID(params2.appId),
56905
- appId: params2.appId,
56906
- automationId: params2.automationId
56907
- },
56908
- params2.task
56909
- );
56910
57334
  }
56911
- async function doInContext(appId, task) {
56912
- const tenantId = getTenantIDFromAppID(appId);
56913
- return newContext(
56914
- {
56915
- tenantId,
56916
- appId
56917
- },
56918
- task
57335
+ function extractBucketAndPath(url) {
57336
+ const baseUrl = url.split("?")[0];
57337
+ const regex = new RegExp(
57338
+ `^${SIGNED_FILE_PREFIX}/(?<bucket>[^/]+)/(?<path>.+)$`
56919
57339
  );
56920
- }
56921
- async function doInTenant(tenantId, task) {
56922
- if (!environment_default.MULTI_TENANCY) {
56923
- tenantId = tenantId || DEFAULT_TENANT_ID;
57340
+ const match = baseUrl.match(regex);
57341
+ if (match && match.groups) {
57342
+ const { bucket, path: path3 } = match.groups;
57343
+ return { bucket, path: path3 };
56924
57344
  }
56925
- const updates = tenantId ? { tenantId } : {};
56926
- return newContext(updates, task);
56927
- }
56928
- async function doInAppContext(appId, task) {
56929
- return _doInAppContext(appId, task);
57345
+ return null;
56930
57346
  }
56931
- async function _doInAppContext(appId, task, extraContextSettings) {
56932
- if (!appId) {
56933
- throw new Error("appId is required");
57347
+
57348
+ // src/objectStore/cloudfront.ts
57349
+ var cfsign = __toESM(require("aws-cloudfront-sign"));
57350
+ var PRIVATE_KEY;
57351
+ function getPrivateKey() {
57352
+ if (!environment_default.CLOUDFRONT_PRIVATE_KEY_64) {
57353
+ throw new Error("CLOUDFRONT_PRIVATE_KEY_64 is not set");
56934
57354
  }
56935
- const tenantId = getTenantIDFromAppID(appId);
56936
- const updates = { appId, ...extraContextSettings };
56937
- if (tenantId) {
56938
- updates.tenantId = tenantId;
57355
+ if (PRIVATE_KEY) {
57356
+ return PRIVATE_KEY;
56939
57357
  }
56940
- return newContext(updates, task);
57358
+ PRIVATE_KEY = Buffer.from(environment_default.CLOUDFRONT_PRIVATE_KEY_64, "base64").toString(
57359
+ "utf-8"
57360
+ );
57361
+ return PRIVATE_KEY;
56941
57362
  }
56942
- async function doInIdentityContext(identity, task) {
56943
- if (!identity) {
56944
- throw new Error("identity is required");
56945
- }
56946
- const context = {
56947
- identity
57363
+ var getCloudfrontSignParams = () => {
57364
+ return {
57365
+ keypairId: environment_default.CLOUDFRONT_PUBLIC_KEY_ID,
57366
+ privateKeyString: getPrivateKey(),
57367
+ expireTime: (/* @__PURE__ */ new Date()).getTime() + 1e3 * 60 * 60 * 24
57368
+ // 1 day
56948
57369
  };
56949
- if (identity.tenantId) {
56950
- context.tenantId = identity.tenantId;
57370
+ };
57371
+ var getPresignedUrl2 = (s3Key) => {
57372
+ const url = getUrl(s3Key);
57373
+ return cfsign.getSignedUrl(url, getCloudfrontSignParams());
57374
+ };
57375
+ var getUrl = (s3Key) => {
57376
+ let prefix = "/";
57377
+ if (s3Key.startsWith("/")) {
57378
+ prefix = "";
56951
57379
  }
56952
- return newContext(context, task);
57380
+ return `${environment_default.CLOUDFRONT_CDN}${prefix}${s3Key}`;
57381
+ };
57382
+
57383
+ // src/objectStore/buckets/app.ts
57384
+ var import_querystring = __toESM(require("querystring"));
57385
+ function clientLibraryPath(appId) {
57386
+ return `${sanitizeKey(appId)}/budibase-client.js`;
56953
57387
  }
56954
- function guardMigration() {
56955
- const context = Context.get();
56956
- if (context?.isMigrating) {
56957
- throw new Error(
56958
- "The context cannot be changed, a migration is currently running"
56959
- );
57388
+ function clientLibraryCDNUrl(appId, version) {
57389
+ let file = clientLibraryPath(appId);
57390
+ if (environment_default.CLOUDFRONT_CDN) {
57391
+ if (version) {
57392
+ file += `?v=${version}`;
57393
+ }
57394
+ return getUrl(file);
57395
+ } else {
57396
+ return getPresignedUrl(environment_default.APPS_BUCKET_NAME, file);
56960
57397
  }
56961
57398
  }
56962
- async function doInAppMigrationContext(appId, task) {
56963
- return _doInAppContext(appId, task, {
56964
- isMigrating: true
56965
- });
56966
- }
56967
- function getIdentity() {
57399
+ function clientLibraryUrl(appId, version) {
57400
+ let tenantId, qsParams;
56968
57401
  try {
56969
- const context = Context.get();
56970
- return context?.identity;
56971
- } catch (e) {
56972
- }
56973
- }
56974
- function getTenantId() {
56975
- if (!isMultiTenant()) {
56976
- return DEFAULT_TENANT_ID;
57402
+ tenantId = getTenantId();
57403
+ } finally {
57404
+ qsParams = {
57405
+ appId,
57406
+ version
57407
+ };
56977
57408
  }
56978
- const context = Context.get();
56979
- const tenantId = context?.tenantId;
56980
- if (!tenantId) {
56981
- throw new Error("Tenant id not found");
57409
+ if (tenantId && tenantId !== DEFAULT_TENANT_ID) {
57410
+ qsParams.tenantId = tenantId;
56982
57411
  }
56983
- return tenantId;
56984
- }
56985
- function getAutomationId() {
56986
- const context = Context.get();
56987
- return context?.automationId;
57412
+ return `/api/assets/client?${import_querystring.default.encode(qsParams)}`;
56988
57413
  }
56989
- function getAppId() {
56990
- const context = Context.get();
56991
- const foundId = context?.appId;
56992
- if (!foundId && environment_default.isTest() && TEST_APP_ID) {
56993
- return TEST_APP_ID;
57414
+ function getAppFileUrl(s3Key) {
57415
+ if (environment_default.CLOUDFRONT_CDN) {
57416
+ return getPresignedUrl2(s3Key);
56994
57417
  } else {
56995
- return foundId;
57418
+ return getPresignedUrl(environment_default.APPS_BUCKET_NAME, s3Key);
56996
57419
  }
56997
57420
  }
56998
- var getProdAppId = () => {
56999
- const appId = getAppId();
57000
- if (!appId) {
57001
- throw new Error("Could not get appId");
57002
- }
57003
- return getProdAppID2(appId);
57421
+
57422
+ // src/objectStore/buckets/global.ts
57423
+ var getGlobalFileUrl = (type, name, etag) => {
57424
+ let file = getGlobalFileS3Key(type, name);
57425
+ if (environment_default.CLOUDFRONT_CDN) {
57426
+ if (etag) {
57427
+ file = `${file}?etag=${etag}`;
57428
+ }
57429
+ return getPresignedUrl2(file);
57430
+ } else {
57431
+ return getPresignedUrl(environment_default.GLOBAL_BUCKET_NAME, file);
57432
+ }
57004
57433
  };
57005
- function doInEnvironmentContext(values2, task) {
57006
- if (!values2) {
57007
- throw new Error("Must supply environment variables.");
57434
+ var getGlobalFileS3Key = (type, name) => {
57435
+ let file = `${type}/${name}`;
57436
+ if (environment_default.MULTI_TENANCY) {
57437
+ const tenantId = getTenantId();
57438
+ file = `${tenantId}/${file}`;
57008
57439
  }
57009
- const updates = {
57010
- environmentVariables: values2
57011
- };
57012
- return newContext(updates, task);
57440
+ return file;
57441
+ };
57442
+
57443
+ // src/objectStore/buckets/plugins.ts
57444
+ function enrichPluginURLs(plugins) {
57445
+ if (!plugins || !plugins.length) {
57446
+ return [];
57447
+ }
57448
+ return plugins.map((plugin) => {
57449
+ const jsUrl = getPluginJSUrl(plugin);
57450
+ const iconUrl = getPluginIconUrl(plugin);
57451
+ return { ...plugin, jsUrl, iconUrl };
57452
+ });
57013
57453
  }
57014
- function doInScimContext(task) {
57015
- const updates = {
57016
- isScim: true
57017
- };
57018
- return newContext(updates, task);
57454
+ function getPluginJSUrl(plugin) {
57455
+ const s3Key = getPluginJSKey(plugin);
57456
+ return getPluginUrl(s3Key);
57019
57457
  }
57020
- async function ensureSnippetContext(enabled2 = !environment_default.isTest()) {
57021
- const ctx = getCurrentContext();
57022
- if (!ctx || ctx.snippets) {
57458
+ function getPluginIconUrl(plugin) {
57459
+ const s3Key = getPluginIconKey(plugin);
57460
+ if (!s3Key) {
57023
57461
  return;
57024
57462
  }
57025
- let snippets;
57026
- const db = getAppDB();
57027
- if (db && enabled2) {
57028
- const app = await db.get("app_metadata" /* APP_METADATA */);
57029
- snippets = app.snippets;
57030
- }
57031
- ctx.snippets = snippets || [];
57463
+ return getPluginUrl(s3Key);
57032
57464
  }
57033
- function getEnvironmentVariables() {
57034
- const context = Context.get();
57035
- if (!context.environmentVariables) {
57036
- return null;
57465
+ function getPluginUrl(s3Key) {
57466
+ if (environment_default.CLOUDFRONT_CDN) {
57467
+ return getPresignedUrl2(s3Key);
57037
57468
  } else {
57038
- return context.environmentVariables;
57469
+ return getPresignedUrl(environment_default.PLUGIN_BUCKET_NAME, s3Key);
57039
57470
  }
57040
57471
  }
57041
- function getGlobalDB() {
57042
- const context = Context.get();
57043
- if (!context || environment_default.MULTI_TENANCY && !context.tenantId) {
57044
- throw new Error("Global DB not found");
57045
- }
57046
- return getDB(baseGlobalDBName(context?.tenantId));
57472
+ function getPluginJSKey(plugin) {
57473
+ return getPluginS3Key(plugin, "plugin.min.js");
57047
57474
  }
57048
- function getAuditLogsDB() {
57049
- if (!getTenantId()) {
57050
- throw new Error("No tenant ID found - cannot open audit log DB");
57475
+ function getPluginIconKey(plugin) {
57476
+ const iconFileName = plugin.iconUrl ? "icon.svg" : plugin.iconFileName;
57477
+ if (!iconFileName) {
57478
+ return;
57051
57479
  }
57052
- return getDB(getAuditLogDBName());
57480
+ return getPluginS3Key(plugin, iconFileName);
57053
57481
  }
57054
- function getAppDB(opts) {
57055
- const appId = getAppId();
57056
- if (!appId) {
57057
- throw new Error("Unable to retrieve app DB - no app ID.");
57058
- }
57059
- return getDB(appId, opts);
57482
+ function getPluginS3Key(plugin, fileName) {
57483
+ const s3Key = getPluginS3Dir(plugin.name);
57484
+ return `${s3Key}/${fileName}`;
57060
57485
  }
57061
- function getProdAppDB(opts) {
57062
- const appId = getAppId();
57063
- if (!appId) {
57064
- throw new Error("Unable to retrieve prod DB - no app ID.");
57486
+ function getPluginS3Dir(pluginName) {
57487
+ let s3Key = `${pluginName}`;
57488
+ if (environment_default.MULTI_TENANCY) {
57489
+ const tenantId = getTenantId();
57490
+ s3Key = `${tenantId}/${s3Key}`;
57065
57491
  }
57066
- return getDB(getProdAppID2(appId), opts);
57067
- }
57068
- function getDevAppDB(opts) {
57069
- const appId = getAppId();
57070
- if (!appId) {
57071
- throw new Error("Unable to retrieve dev DB - no app ID.");
57492
+ if (environment_default.CLOUDFRONT_CDN) {
57493
+ s3Key = `plugins/${s3Key}`;
57072
57494
  }
57073
- return getDB(getDevelopmentAppID(appId), opts);
57495
+ return s3Key;
57074
57496
  }
57075
- function isScim() {
57076
- const context = Context.get();
57077
- const scimCall = context?.isScim;
57078
- return !!scimCall;
57497
+
57498
+ // src/logging/system.ts
57499
+ var logsFileName = `budibase.log`;
57500
+ var budibaseLogsHistoryFileName = "budibase-logs-history.txt";
57501
+ var logsPath = import_path3.default.join(budibaseTempDir(), "systemlogs");
57502
+ function getFullPath(fileName) {
57503
+ return import_path3.default.join(logsPath, fileName);
57079
57504
  }
57080
- function getCurrentContext() {
57081
- try {
57082
- return Context.get();
57083
- } catch (e) {
57505
+ function getSingleFileMaxSizeInfo(totalMaxSize) {
57506
+ const regex = /(\d+)([A-Za-z])/;
57507
+ const match = totalMaxSize?.match(regex);
57508
+ if (!match) {
57509
+ console.warn(`totalMaxSize does not have a valid value`, {
57510
+ totalMaxSize
57511
+ });
57084
57512
  return void 0;
57085
57513
  }
57086
- }
57087
-
57088
- // src/redis/init.ts
57089
- var init_exports = {};
57090
- __export(init_exports, {
57091
- getAppClient: () => getAppClient,
57092
- getCacheClient: () => getCacheClient,
57093
- getDocWritethroughClient: () => getDocWritethroughClient,
57094
- getInviteClient: () => getInviteClient,
57095
- getLockClient: () => getLockClient,
57096
- getPasswordResetClient: () => getPasswordResetClient,
57097
- getSessionClient: () => getSessionClient,
57098
- getSocketClient: () => getSocketClient,
57099
- getUserClient: () => getUserClient,
57100
- getWritethroughClient: () => getWritethroughClient,
57101
- init: () => init3,
57102
- shutdown: () => shutdown
57103
- });
57104
-
57105
- // src/redis/redis.ts
57106
- var import_ioredis = __toESM(require("ioredis"));
57107
-
57108
- // src/redis/utils.ts
57109
- var utils_exports2 = {};
57110
- __export(utils_exports2, {
57111
- Databases: () => Databases,
57112
- SEPARATOR: () => SEPARATOR2,
57113
- SelectableDatabase: () => SelectableDatabase,
57114
- addDbPrefix: () => addDbPrefix,
57115
- getRedisConnectionDetails: () => getRedisConnectionDetails,
57116
- getRedisOptions: () => getRedisOptions,
57117
- removeDbPrefix: () => removeDbPrefix
57118
- });
57119
- var SLOT_REFRESH_MS = 2e3;
57120
- var CONNECT_TIMEOUT_MS = 1e4;
57121
- var SEPARATOR2 = "-";
57122
- var Databases = /* @__PURE__ */ ((Databases2) => {
57123
- Databases2["PW_RESETS"] = "pwReset";
57124
- Databases2["VERIFICATIONS"] = "verification";
57125
- Databases2["INVITATIONS"] = "invitation";
57126
- Databases2["DEV_LOCKS"] = "devLocks";
57127
- Databases2["DEBOUNCE"] = "debounce";
57128
- Databases2["SESSIONS"] = "session";
57129
- Databases2["USER_CACHE"] = "users";
57130
- Databases2["FLAGS"] = "flags";
57131
- Databases2["APP_METADATA"] = "appMetadata";
57132
- Databases2["QUERY_VARS"] = "queryVars";
57133
- Databases2["LICENSES"] = "license";
57134
- Databases2["GENERIC_CACHE"] = "data_cache";
57135
- Databases2["WRITE_THROUGH"] = "writeThrough";
57136
- Databases2["LOCKS"] = "locks";
57137
- Databases2["SOCKET_IO"] = "socket_io";
57138
- Databases2["BPM_EVENTS"] = "bpmEvents";
57139
- Databases2["DOC_WRITE_THROUGH"] = "docWriteThrough";
57140
- return Databases2;
57141
- })(Databases || {});
57142
- var SelectableDatabase = /* @__PURE__ */ ((SelectableDatabase2) => {
57143
- SelectableDatabase2[SelectableDatabase2["DEFAULT"] = 0] = "DEFAULT";
57144
- SelectableDatabase2[SelectableDatabase2["SOCKET_IO"] = 1] = "SOCKET_IO";
57145
- SelectableDatabase2[SelectableDatabase2["RATE_LIMITING"] = 2] = "RATE_LIMITING";
57146
- SelectableDatabase2[SelectableDatabase2["UNUSED_2"] = 3] = "UNUSED_2";
57147
- SelectableDatabase2[SelectableDatabase2["UNUSED_3"] = 4] = "UNUSED_3";
57148
- SelectableDatabase2[SelectableDatabase2["UNUSED_4"] = 5] = "UNUSED_4";
57149
- SelectableDatabase2[SelectableDatabase2["UNUSED_5"] = 6] = "UNUSED_5";
57150
- SelectableDatabase2[SelectableDatabase2["UNUSED_6"] = 7] = "UNUSED_6";
57151
- SelectableDatabase2[SelectableDatabase2["UNUSED_7"] = 8] = "UNUSED_7";
57152
- SelectableDatabase2[SelectableDatabase2["UNUSED_8"] = 9] = "UNUSED_8";
57153
- SelectableDatabase2[SelectableDatabase2["UNUSED_9"] = 10] = "UNUSED_9";
57154
- SelectableDatabase2[SelectableDatabase2["UNUSED_10"] = 11] = "UNUSED_10";
57155
- SelectableDatabase2[SelectableDatabase2["UNUSED_11"] = 12] = "UNUSED_11";
57156
- SelectableDatabase2[SelectableDatabase2["UNUSED_12"] = 13] = "UNUSED_12";
57157
- SelectableDatabase2[SelectableDatabase2["UNUSED_13"] = 14] = "UNUSED_13";
57158
- SelectableDatabase2[SelectableDatabase2["UNUSED_14"] = 15] = "UNUSED_14";
57159
- return SelectableDatabase2;
57160
- })(SelectableDatabase || {});
57161
- function getRedisConnectionDetails() {
57162
- let password = environment_default.REDIS_PASSWORD;
57163
- let url = environment_default.REDIS_URL.split("//");
57164
- url = url.length > 1 ? url[1] : url[0];
57165
- url = url.split("@");
57166
- if (url.length > 1) {
57167
- password = url[0].split(":")[1];
57168
- url = url[1];
57169
- } else {
57170
- url = url[0];
57514
+ const size = +match[1];
57515
+ const unit = match[2];
57516
+ if (size === 1) {
57517
+ switch (unit) {
57518
+ case "B":
57519
+ return { size: `${size}B`, totalHistoryFiles: 1 };
57520
+ case "K":
57521
+ return { size: `${size * 1e3 / 2}B`, totalHistoryFiles: 1 };
57522
+ case "M":
57523
+ return { size: `${size * 1e3 / 2}K`, totalHistoryFiles: 1 };
57524
+ case "G":
57525
+ return { size: `${size * 1e3 / 2}M`, totalHistoryFiles: 1 };
57526
+ default:
57527
+ return void 0;
57528
+ }
57171
57529
  }
57172
- const [host, port] = url.split(":");
57173
- const portNumber = parseInt(port);
57174
- return {
57175
- host,
57176
- password,
57177
- // assume default port for redis if invalid found
57178
- port: isNaN(portNumber) ? 6379 : portNumber
57179
- };
57530
+ if (size % 2 === 0) {
57531
+ return { size: `${size / 2}${unit}`, totalHistoryFiles: 1 };
57532
+ }
57533
+ return { size: `1${unit}`, totalHistoryFiles: size - 1 };
57180
57534
  }
57181
- function getRedisOptions() {
57182
- const { host, password, port } = getRedisConnectionDetails();
57183
- let redisOpts = {
57184
- connectTimeout: CONNECT_TIMEOUT_MS,
57185
- port,
57186
- host,
57187
- password
57188
- };
57189
- let opts = redisOpts;
57190
- if (environment_default.REDIS_CLUSTERED) {
57191
- opts = {
57192
- connectTimeout: CONNECT_TIMEOUT_MS,
57193
- redisOptions: {
57194
- ...redisOpts,
57195
- tls: {}
57196
- },
57197
- slotsRefreshTimeout: SLOT_REFRESH_MS,
57198
- dnsLookup: (address, callback) => callback(null, address)
57199
- };
57200
- }
57201
- return opts;
57535
+ function localFileDestination() {
57536
+ const fileInfo = getSingleFileMaxSizeInfo(environment_default.ROLLING_LOG_MAX_SIZE);
57537
+ const outFile = rfs.createStream(logsFileName, {
57538
+ // As we have a rolling size, we want to half the max size
57539
+ size: fileInfo?.size,
57540
+ path: logsPath,
57541
+ maxFiles: fileInfo?.totalHistoryFiles || 1,
57542
+ immutable: true,
57543
+ history: budibaseLogsHistoryFileName,
57544
+ initialRotation: false
57545
+ });
57546
+ return outFile;
57202
57547
  }
57203
- function addDbPrefix(db, key) {
57204
- if (key.includes(db)) {
57205
- return key;
57548
+ function getLogReadStream() {
57549
+ const streams = [];
57550
+ const historyFile = getFullPath(budibaseLogsHistoryFileName);
57551
+ if (import_fs4.default.existsSync(historyFile)) {
57552
+ const fileContent = import_fs4.default.readFileSync(historyFile, "utf-8");
57553
+ const historyFiles = fileContent.split("\n");
57554
+ for (const historyFile2 of historyFiles.filter((x) => x)) {
57555
+ streams.push(import_fs4.default.readFileSync(historyFile2));
57556
+ }
57206
57557
  }
57207
- return `${db}${SEPARATOR2}${key}`;
57558
+ streams.push(import_fs4.default.readFileSync(getFullPath(logsFileName)));
57559
+ const combinedContent = Buffer.concat(streams);
57560
+ return combinedContent;
57208
57561
  }
57209
- function removeDbPrefix(key) {
57210
- let parts = key.split(SEPARATOR2);
57211
- if (parts.length >= 2) {
57212
- parts.shift();
57213
- return parts.join(SEPARATOR2);
57214
- } else {
57215
- return parts[0];
57562
+
57563
+ // src/logging/pino/logger.ts
57564
+ function isPlainObject(obj) {
57565
+ return typeof obj === "object" && obj !== null && !(obj instanceof Error);
57566
+ }
57567
+ function isError(obj) {
57568
+ return obj instanceof Error;
57569
+ }
57570
+ function isMessage(obj) {
57571
+ return typeof obj === "string";
57572
+ }
57573
+ var pinoInstance;
57574
+ if (!environment_default.DISABLE_PINO_LOGGER) {
57575
+ const level = environment_default.LOG_LEVEL;
57576
+ const pinoOptions = {
57577
+ level,
57578
+ formatters: {
57579
+ level: (level2) => {
57580
+ return { level: level2.toUpperCase() };
57581
+ },
57582
+ bindings: () => {
57583
+ if (environment_default.SELF_HOSTED) {
57584
+ return {
57585
+ service: environment_default.SERVICE_NAME
57586
+ };
57587
+ } else {
57588
+ return {};
57589
+ }
57590
+ }
57591
+ },
57592
+ timestamp: () => `,"timestamp":"${new Date(Date.now()).toISOString()}"`
57593
+ };
57594
+ const destinations = [];
57595
+ destinations.push(
57596
+ environment_default.isDev() ? {
57597
+ stream: (0, import_pino_pretty.default)({ singleLine: true }),
57598
+ level
57599
+ } : { stream: process.stdout, level }
57600
+ );
57601
+ if (environment_default.SELF_HOSTED) {
57602
+ destinations.push({
57603
+ stream: localFileDestination(),
57604
+ level
57605
+ });
57216
57606
  }
57607
+ pinoInstance = destinations.length ? (0, import_pino.default)(pinoOptions, import_pino.default.multistream(destinations)) : (0, import_pino.default)(pinoOptions);
57608
+ const getLogParams2 = (args) => {
57609
+ let error = void 0;
57610
+ let objects = [];
57611
+ let message = "";
57612
+ args.forEach((arg) => {
57613
+ if (isMessage(arg)) {
57614
+ message = `${message} ${arg}`.trimStart();
57615
+ }
57616
+ if (isPlainObject(arg)) {
57617
+ objects.push(arg);
57618
+ }
57619
+ if (isError(arg)) {
57620
+ error = arg;
57621
+ }
57622
+ });
57623
+ const identity = getIdentity3();
57624
+ let contextObject = {};
57625
+ contextObject = {
57626
+ tenantId: getTenantId2(),
57627
+ appId: getAppId2(),
57628
+ automationId: getAutomationId2(),
57629
+ identityId: identity?._id,
57630
+ identityType: identity?.type,
57631
+ correlationId: getId()
57632
+ };
57633
+ const span = import_dd_trace2.default.scope().active();
57634
+ if (span) {
57635
+ import_dd_trace2.default.inject(span.context(), import_ext.formats.LOG, contextObject);
57636
+ }
57637
+ const mergingObject = {
57638
+ err: error,
57639
+ pid: process.pid,
57640
+ ...contextObject
57641
+ };
57642
+ if (objects.length) {
57643
+ const data = {};
57644
+ let dataIndex = 0;
57645
+ for (let i = 0; i < objects.length; i++) {
57646
+ const object = objects[i];
57647
+ const logKey = object._logKey;
57648
+ if (logKey) {
57649
+ delete object._logKey;
57650
+ mergingObject[logKey] = object;
57651
+ } else {
57652
+ data[dataIndex] = object;
57653
+ dataIndex++;
57654
+ }
57655
+ }
57656
+ if (Object.keys(data).length) {
57657
+ mergingObject.data = data;
57658
+ }
57659
+ }
57660
+ return [mergingObject, message];
57661
+ };
57662
+ console.log = (...arg) => {
57663
+ const [obj, msg] = getLogParams2(arg);
57664
+ pinoInstance?.info(obj, msg);
57665
+ };
57666
+ console.info = (...arg) => {
57667
+ const [obj, msg] = getLogParams2(arg);
57668
+ pinoInstance?.info(obj, msg);
57669
+ };
57670
+ console.warn = (...arg) => {
57671
+ const [obj, msg] = getLogParams2(arg);
57672
+ pinoInstance?.warn(obj, msg);
57673
+ };
57674
+ console.error = (...arg) => {
57675
+ const [obj, msg] = getLogParams2(arg);
57676
+ pinoInstance?.error(obj, msg);
57677
+ };
57678
+ console.trace = (...arg) => {
57679
+ const [obj, msg] = getLogParams2(arg);
57680
+ if (!obj.err) {
57681
+ obj.err = new Error();
57682
+ }
57683
+ pinoInstance?.trace(obj, msg);
57684
+ };
57685
+ console.debug = (...arg) => {
57686
+ const [obj, msg] = getLogParams2(arg);
57687
+ pinoInstance?.debug(obj, msg);
57688
+ };
57689
+ const getTenantId2 = () => {
57690
+ let tenantId;
57691
+ try {
57692
+ tenantId = getTenantId();
57693
+ } catch (e) {
57694
+ }
57695
+ return tenantId;
57696
+ };
57697
+ const getAppId2 = () => {
57698
+ let appId;
57699
+ try {
57700
+ appId = getAppId();
57701
+ } catch (e) {
57702
+ }
57703
+ return appId;
57704
+ };
57705
+ const getAutomationId2 = () => {
57706
+ let appId;
57707
+ try {
57708
+ appId = getAutomationId();
57709
+ } catch (e) {
57710
+ }
57711
+ return appId;
57712
+ };
57713
+ const getIdentity3 = () => {
57714
+ let identity;
57715
+ try {
57716
+ identity = getIdentity();
57717
+ } catch (e) {
57718
+ }
57719
+ return identity;
57720
+ };
57217
57721
  }
57722
+ var logger = pinoInstance;
57218
57723
 
57219
- // src/logging/index.ts
57220
- var logging_exports = {};
57221
- __export(logging_exports, {
57222
- correlation: () => correlation_exports,
57223
- logAlert: () => logAlert,
57224
- logAlertWithInfo: () => logAlertWithInfo,
57225
- logWarn: () => logWarn,
57226
- logger: () => logger,
57227
- system: () => system_exports
57228
- });
57229
-
57230
- // src/logging/correlation/correlation.ts
57231
- var correlation_exports = {};
57232
- __export(correlation_exports, {
57233
- getId: () => getId,
57234
- setHeader: () => setHeader
57235
- });
57236
- var correlator = require("correlation-id");
57237
- var setHeader = (headers) => {
57238
- const correlationId = correlator.getId();
57239
- if (!correlationId) {
57724
+ // src/logging/alerts.ts
57725
+ var NonErrors = ["AccountError"];
57726
+ function isSuppressed(e) {
57727
+ return e && e["suppressAlert"];
57728
+ }
57729
+ function logAlert(message, e) {
57730
+ if (e && NonErrors.includes(e.name) && isSuppressed(e)) {
57240
57731
  return;
57241
57732
  }
57242
- headers["x-budibase-correlation-id" /* CORRELATION_ID */] = correlationId;
57243
- };
57244
- function getId() {
57245
- return correlator.getId();
57733
+ console.error(`bb-alert: ${message}`, e);
57734
+ }
57735
+ function logAlertWithInfo(message, db, id, error) {
57736
+ message = `${message} - db: ${db} - doc: ${id} - error: `;
57737
+ logAlert(message, error);
57738
+ }
57739
+ function logWarn(message, e) {
57740
+ console.warn(`bb-warn: ${message}`, e);
57246
57741
  }
57247
57742
 
57248
- // src/logging/pino/logger.ts
57249
- var import_pino = __toESM(require("pino"));
57250
- var import_pino_pretty = __toESM(require("pino-pretty"));
57251
- var import_dd_trace2 = __toESM(require("dd-trace"));
57252
- var import_ext = require("dd-trace/ext");
57253
-
57254
- // src/logging/system.ts
57255
- var system_exports = {};
57256
- __export(system_exports, {
57257
- getLogReadStream: () => getLogReadStream,
57258
- getSingleFileMaxSizeInfo: () => getSingleFileMaxSizeInfo,
57259
- localFileDestination: () => localFileDestination
57743
+ // src/timers/index.ts
57744
+ var timers_exports = {};
57745
+ __export(timers_exports, {
57746
+ cleanup: () => cleanup,
57747
+ clear: () => clear,
57748
+ set: () => set
57260
57749
  });
57261
- var import_fs4 = __toESM(require("fs"));
57262
- var import_path3 = __toESM(require("path"));
57263
- var rfs = __toESM(require("rotating-file-stream"));
57264
57750
 
57265
- // src/objectStore/index.ts
57266
- var objectStore_exports2 = {};
57267
- __export(objectStore_exports2, {
57268
- ObjectStore: () => ObjectStore,
57269
- ObjectStoreBuckets: () => ObjectStoreBuckets,
57270
- SIGNED_FILE_PREFIX: () => SIGNED_FILE_PREFIX,
57271
- bucketTTLConfig: () => bucketTTLConfig,
57272
- budibaseTempDir: () => budibaseTempDir,
57273
- clientLibraryCDNUrl: () => clientLibraryCDNUrl,
57274
- clientLibraryPath: () => clientLibraryPath,
57275
- clientLibraryUrl: () => clientLibraryUrl,
57276
- createBucketIfNotExists: () => createBucketIfNotExists,
57277
- deleteFile: () => deleteFile,
57278
- deleteFiles: () => deleteFiles,
57279
- deleteFolder: () => deleteFolder,
57280
- downloadTarball: () => downloadTarball,
57281
- downloadTarballDirect: () => downloadTarballDirect,
57282
- enrichPluginURLs: () => enrichPluginURLs,
57283
- extractBucketAndPath: () => extractBucketAndPath,
57284
- getAppFileUrl: () => getAppFileUrl,
57285
- getGlobalFileS3Key: () => getGlobalFileS3Key,
57286
- getGlobalFileUrl: () => getGlobalFileUrl,
57287
- getObjectMetadata: () => getObjectMetadata,
57288
- getPluginIconKey: () => getPluginIconKey,
57289
- getPluginJSKey: () => getPluginJSKey,
57290
- getPluginS3Dir: () => getPluginS3Dir,
57291
- getPresignedUrl: () => getPresignedUrl,
57292
- getReadStream: () => getReadStream,
57293
- listAllObjects: () => listAllObjects,
57294
- processAutomationAttachment: () => processAutomationAttachment,
57295
- processObjectStoreAttachment: () => processObjectStoreAttachment,
57296
- retrieve: () => retrieve,
57297
- retrieveDirectory: () => retrieveDirectory,
57298
- retrieveToTmp: () => retrieveToTmp,
57299
- sanitizeBucket: () => sanitizeBucket,
57300
- sanitizeKey: () => sanitizeKey,
57301
- streamUpload: () => streamUpload,
57302
- upload: () => upload,
57303
- uploadDirectory: () => uploadDirectory
57751
+ // src/timers/timers.ts
57752
+ var intervals = [];
57753
+ function set(callback, period) {
57754
+ const interval = setInterval(callback, period);
57755
+ intervals.push(interval);
57756
+ return interval;
57757
+ }
57758
+ function clear(interval) {
57759
+ const idx = intervals.indexOf(interval);
57760
+ if (idx !== -1) {
57761
+ intervals.splice(idx, 1);
57762
+ }
57763
+ clearInterval(interval);
57764
+ }
57765
+ function cleanup() {
57766
+ for (let interval of intervals) {
57767
+ clearInterval(interval);
57768
+ }
57769
+ intervals = [];
57770
+ }
57771
+
57772
+ // src/redis/redis.ts
57773
+ var MockRedis;
57774
+ if (environment_default.MOCK_REDIS) {
57775
+ try {
57776
+ MockRedis = require("ioredis-mock");
57777
+ } catch (err) {
57778
+ console.log("Mock redis unavailable");
57779
+ }
57780
+ }
57781
+ var RETRY_PERIOD_MS = 2e3;
57782
+ var STARTUP_TIMEOUT_MS = 5e3;
57783
+ var CLUSTERED = environment_default.REDIS_CLUSTERED;
57784
+ var DEFAULT_SELECT_DB = 0 /* DEFAULT */;
57785
+ var CLOSED = false;
57786
+ var CLIENTS = {};
57787
+ var CONNECTED = false;
57788
+ if (environment_default.MOCK_REDIS) {
57789
+ CONNECTED = true;
57790
+ }
57791
+ function pickClient(selectDb) {
57792
+ return CLIENTS[selectDb];
57793
+ }
57794
+ function connectionError(timeout2, err) {
57795
+ if (CLOSED) {
57796
+ return;
57797
+ }
57798
+ CLOSED = true;
57799
+ clearTimeout(timeout2);
57800
+ CONNECTED = false;
57801
+ logAlert("Redis connection failed", err);
57802
+ setTimeout(() => {
57803
+ init2();
57804
+ }, RETRY_PERIOD_MS);
57805
+ }
57806
+ function init2(selectDb = DEFAULT_SELECT_DB) {
57807
+ const RedisCore = environment_default.MOCK_REDIS && MockRedis ? MockRedis : import_ioredis.default;
57808
+ let timeout2;
57809
+ CLOSED = false;
57810
+ let client = pickClient(selectDb);
57811
+ if (client && CONNECTED) {
57812
+ return;
57813
+ }
57814
+ if (environment_default.MOCK_REDIS) {
57815
+ CLIENTS[selectDb] = new RedisCore(getRedisOptions());
57816
+ }
57817
+ timeout2 = setTimeout(() => {
57818
+ if (!CONNECTED) {
57819
+ connectionError(timeout2, "Did not successfully connect in timeout");
57820
+ }
57821
+ }, STARTUP_TIMEOUT_MS);
57822
+ if (client) {
57823
+ client.disconnect();
57824
+ }
57825
+ const { host, port } = getRedisConnectionDetails();
57826
+ const opts = getRedisOptions();
57827
+ if (CLUSTERED) {
57828
+ client = new RedisCore.Cluster([{ host, port }], opts);
57829
+ } else {
57830
+ client = new RedisCore(opts);
57831
+ }
57832
+ client.on("end", (err) => {
57833
+ if (environment_default.isTest()) {
57834
+ return;
57835
+ }
57836
+ connectionError(timeout2, err);
57837
+ });
57838
+ client.on("error", (err) => {
57839
+ connectionError(timeout2, err);
57840
+ });
57841
+ client.on("connect", () => {
57842
+ console.log(`Connected to Redis DB: ${selectDb}`);
57843
+ clearTimeout(timeout2);
57844
+ CONNECTED = true;
57845
+ });
57846
+ CLIENTS[selectDb] = client;
57847
+ }
57848
+ function waitForConnection(selectDb = DEFAULT_SELECT_DB) {
57849
+ return new Promise((resolve) => {
57850
+ if (pickClient(selectDb) == null) {
57851
+ init2();
57852
+ } else if (CONNECTED) {
57853
+ resolve("");
57854
+ return;
57855
+ }
57856
+ const interval = set(() => {
57857
+ if (CONNECTED) {
57858
+ clear(interval);
57859
+ resolve("");
57860
+ }
57861
+ }, 500);
57862
+ });
57863
+ }
57864
+ function promisifyStream(stream3, client) {
57865
+ return new Promise((resolve, reject) => {
57866
+ const outputKeys = /* @__PURE__ */ new Set();
57867
+ stream3.on("data", (keys2) => {
57868
+ keys2.forEach((key) => {
57869
+ outputKeys.add(key);
57870
+ });
57871
+ });
57872
+ stream3.on("error", (err) => {
57873
+ reject(err);
57874
+ });
57875
+ stream3.on("end", async () => {
57876
+ const keysArray = Array.from(outputKeys);
57877
+ try {
57878
+ let getPromises = [];
57879
+ for (let key of keysArray) {
57880
+ getPromises.push(client.get(key));
57881
+ }
57882
+ const jsonArray = await Promise.all(getPromises);
57883
+ resolve(
57884
+ keysArray.map((key) => ({
57885
+ key: removeDbPrefix(key),
57886
+ value: JSON.parse(jsonArray.shift())
57887
+ }))
57888
+ );
57889
+ } catch (err) {
57890
+ reject(err);
57891
+ }
57892
+ });
57893
+ });
57894
+ }
57895
+ var RedisWrapper = class {
57896
+ constructor(db, selectDb = null) {
57897
+ this._db = db;
57898
+ this._select = selectDb || DEFAULT_SELECT_DB;
57899
+ }
57900
+ getClient() {
57901
+ return pickClient(this._select);
57902
+ }
57903
+ async init() {
57904
+ CLOSED = false;
57905
+ init2(this._select);
57906
+ await waitForConnection(this._select);
57907
+ if (this._select && !environment_default.isTest()) {
57908
+ this.getClient().select(this._select);
57909
+ }
57910
+ return this;
57911
+ }
57912
+ async finish() {
57913
+ CLOSED = true;
57914
+ this.getClient().disconnect();
57915
+ }
57916
+ async scan(key = "") {
57917
+ const db = this._db;
57918
+ key = `${db}${SEPARATOR2}${key}`;
57919
+ let stream3;
57920
+ if (CLUSTERED) {
57921
+ let node = this.getClient().nodes("master");
57922
+ stream3 = node[0].scanStream({ match: key + "*", count: 100 });
57923
+ } else {
57924
+ stream3 = this.getClient().scanStream({
57925
+ match: key + "*",
57926
+ count: 100
57927
+ });
57928
+ }
57929
+ return promisifyStream(stream3, this.getClient());
57930
+ }
57931
+ async keys(pattern) {
57932
+ const db = this._db;
57933
+ return this.getClient().keys(addDbPrefix(db, pattern));
57934
+ }
57935
+ async exists(key) {
57936
+ const db = this._db;
57937
+ return await this.getClient().exists(addDbPrefix(db, key));
57938
+ }
57939
+ async get(key) {
57940
+ const db = this._db;
57941
+ const response = await this.getClient().get(addDbPrefix(db, key));
57942
+ if (response != null && response.key) {
57943
+ response.key = key;
57944
+ }
57945
+ try {
57946
+ return JSON.parse(response);
57947
+ } catch (err) {
57948
+ return response;
57949
+ }
57950
+ }
57951
+ async bulkGet(keys2) {
57952
+ const db = this._db;
57953
+ if (keys2.length === 0) {
57954
+ return {};
57955
+ }
57956
+ const prefixedKeys = keys2.map((key) => addDbPrefix(db, key));
57957
+ let response = await this.getClient().mget(prefixedKeys);
57958
+ if (Array.isArray(response)) {
57959
+ let final = {};
57960
+ let count = 0;
57961
+ for (let result of response) {
57962
+ if (result) {
57963
+ let parsed;
57964
+ try {
57965
+ parsed = JSON.parse(result);
57966
+ } catch (err) {
57967
+ parsed = result;
57968
+ }
57969
+ final[keys2[count]] = parsed;
57970
+ }
57971
+ count++;
57972
+ }
57973
+ return final;
57974
+ } else {
57975
+ throw new Error(`Invalid response: ${response}`);
57976
+ }
57977
+ }
57978
+ async store(key, value, expirySeconds = null) {
57979
+ const db = this._db;
57980
+ if (typeof value === "object") {
57981
+ value = JSON.stringify(value);
57982
+ }
57983
+ const prefixedKey = addDbPrefix(db, key);
57984
+ await this.getClient().set(prefixedKey, value);
57985
+ if (expirySeconds) {
57986
+ await this.getClient().expire(prefixedKey, expirySeconds);
57987
+ }
57988
+ }
57989
+ async bulkStore(data, expirySeconds = null) {
57990
+ const client = this.getClient();
57991
+ const dataToStore = Object.entries(data).reduce((acc, [key, value]) => {
57992
+ acc[addDbPrefix(this._db, key)] = typeof value === "object" ? JSON.stringify(value) : value;
57993
+ return acc;
57994
+ }, {});
57995
+ const pipeline = client.pipeline();
57996
+ pipeline.mset(dataToStore);
57997
+ if (expirySeconds !== null) {
57998
+ for (const key of Object.keys(dataToStore)) {
57999
+ pipeline.expire(key, expirySeconds);
58000
+ }
58001
+ }
58002
+ await pipeline.exec();
58003
+ }
58004
+ async getTTL(key) {
58005
+ const db = this._db;
58006
+ const prefixedKey = addDbPrefix(db, key);
58007
+ return this.getClient().ttl(prefixedKey);
58008
+ }
58009
+ async setExpiry(key, expirySeconds) {
58010
+ const db = this._db;
58011
+ const prefixedKey = addDbPrefix(db, key);
58012
+ await this.getClient().expire(prefixedKey, expirySeconds);
58013
+ }
58014
+ async delete(key) {
58015
+ const db = this._db;
58016
+ await this.getClient().del(addDbPrefix(db, key));
58017
+ }
58018
+ async bulkDelete(keys2) {
58019
+ const db = this._db;
58020
+ await this.getClient().del(keys2.map((key) => addDbPrefix(db, key)));
58021
+ }
58022
+ async clear() {
58023
+ let items = await this.scan();
58024
+ await Promise.all(items.map((obj) => this.delete(obj.key)));
58025
+ }
58026
+ async increment(key) {
58027
+ const result = await this.getClient().incr(addDbPrefix(this._db, key));
58028
+ if (isNaN(result)) {
58029
+ throw new Error(`Redis ${key} does not contain a number`);
58030
+ }
58031
+ return result;
58032
+ }
58033
+ async deleteIfValue(key, value) {
58034
+ const client = this.getClient();
58035
+ const luaScript = `
58036
+ if redis.call('GET', KEYS[1]) == ARGV[1] then
58037
+ redis.call('DEL', KEYS[1])
58038
+ end
58039
+ `;
58040
+ await client.eval(luaScript, 1, addDbPrefix(this._db, key), value);
58041
+ }
58042
+ };
58043
+ var redis_default = RedisWrapper;
58044
+
58045
+ // src/redis/init.ts
58046
+ var userClient;
58047
+ var sessionClient;
58048
+ var appClient;
58049
+ var cacheClient;
58050
+ var writethroughClient;
58051
+ var lockClient;
58052
+ var socketClient;
58053
+ var inviteClient;
58054
+ var passwordResetClient;
58055
+ var docWritethroughClient;
58056
+ async function init3() {
58057
+ userClient = await new redis_default("users" /* USER_CACHE */).init();
58058
+ sessionClient = await new redis_default("session" /* SESSIONS */).init();
58059
+ appClient = await new redis_default("appMetadata" /* APP_METADATA */).init();
58060
+ cacheClient = await new redis_default("data_cache" /* GENERIC_CACHE */).init();
58061
+ lockClient = await new redis_default("locks" /* LOCKS */).init();
58062
+ writethroughClient = await new redis_default("writeThrough" /* WRITE_THROUGH */).init();
58063
+ inviteClient = await new redis_default("invitation" /* INVITATIONS */).init();
58064
+ passwordResetClient = await new redis_default("pwReset" /* PW_RESETS */).init();
58065
+ socketClient = await new redis_default(
58066
+ "socket_io" /* SOCKET_IO */,
58067
+ 1 /* SOCKET_IO */
58068
+ ).init();
58069
+ docWritethroughClient = await new redis_default(
58070
+ "docWriteThrough" /* DOC_WRITE_THROUGH */
58071
+ ).init();
58072
+ }
58073
+ async function shutdown() {
58074
+ if (userClient)
58075
+ await userClient.finish();
58076
+ if (sessionClient)
58077
+ await sessionClient.finish();
58078
+ if (appClient)
58079
+ await appClient.finish();
58080
+ if (cacheClient)
58081
+ await cacheClient.finish();
58082
+ if (writethroughClient)
58083
+ await writethroughClient.finish();
58084
+ if (lockClient)
58085
+ await lockClient.finish();
58086
+ if (inviteClient)
58087
+ await inviteClient.finish();
58088
+ if (passwordResetClient)
58089
+ await passwordResetClient.finish();
58090
+ if (socketClient)
58091
+ await socketClient.finish();
58092
+ if (docWritethroughClient)
58093
+ await docWritethroughClient.finish();
58094
+ }
58095
+ process.on("exit", async () => {
58096
+ await shutdown();
57304
58097
  });
57305
-
57306
- // src/objectStore/objectStore.ts
57307
- var import_aws_sdk = __toESM(require("aws-sdk"));
57308
- var import_stream2 = __toESM(require("stream"));
57309
- var import_node_fetch3 = __toESM(require("node-fetch"));
57310
- var import_tar_fs = __toESM(require("tar-fs"));
57311
- var import_zlib = __toESM(require("zlib"));
57312
- var import_util = require("util");
57313
- var import_path2 = require("path");
57314
- var import_fs3 = __toESM(require("fs"));
57315
-
57316
- // src/objectStore/utils.ts
57317
- var import_path = __toESM(require("path"));
57318
- var import_os = require("os");
57319
- var import_fs2 = __toESM(require("fs"));
57320
- var import_stream = __toESM(require("stream"));
57321
- var ObjectStoreBuckets = {
57322
- BACKUPS: environment_default.BACKUPS_BUCKET_NAME,
57323
- APPS: environment_default.APPS_BUCKET_NAME,
57324
- TEMPLATES: environment_default.TEMPLATES_BUCKET_NAME,
57325
- GLOBAL: environment_default.GLOBAL_BUCKET_NAME,
57326
- PLUGINS: environment_default.PLUGIN_BUCKET_NAME,
57327
- TEMP: environment_default.TEMP_BUCKET_NAME
57328
- };
57329
- var bbTmp = (0, import_path.join)((0, import_os.tmpdir)(), ".budibase");
57330
- try {
57331
- import_fs2.default.mkdirSync(bbTmp);
57332
- } catch (e) {
57333
- if (e.code !== "EEXIST") {
57334
- throw e;
58098
+ async function getUserClient() {
58099
+ if (!userClient) {
58100
+ await init3();
57335
58101
  }
58102
+ return userClient;
57336
58103
  }
57337
- function budibaseTempDir() {
57338
- return bbTmp;
58104
+ async function getSessionClient() {
58105
+ if (!sessionClient) {
58106
+ await init3();
58107
+ }
58108
+ return sessionClient;
57339
58109
  }
57340
- var bucketTTLConfig = (bucketName, days) => {
57341
- const lifecycleRule = {
57342
- ID: `${bucketName}-ExpireAfter${days}days`,
57343
- Prefix: "",
57344
- Status: "Enabled",
57345
- Expiration: {
57346
- Days: days
57347
- }
57348
- };
57349
- const lifecycleConfiguration = {
57350
- Rules: [lifecycleRule]
57351
- };
57352
- return {
57353
- Bucket: bucketName,
57354
- LifecycleConfiguration: lifecycleConfiguration
57355
- };
57356
- };
57357
- async function processUrlAttachment(attachment) {
57358
- const response = await fetch(attachment.url);
57359
- if (!response.ok || !response.body) {
57360
- throw new Error(`Unexpected response ${response.statusText}`);
58110
+ async function getAppClient() {
58111
+ if (!appClient) {
58112
+ await init3();
57361
58113
  }
57362
- const fallbackFilename = import_path.default.basename(new URL(attachment.url).pathname);
57363
- if (!response.body) {
57364
- throw new Error("No response received for attachment");
58114
+ return appClient;
58115
+ }
58116
+ async function getCacheClient() {
58117
+ if (!cacheClient) {
58118
+ await init3();
57365
58119
  }
57366
- return {
57367
- filename: attachment.filename || fallbackFilename,
57368
- content: import_stream.default.Readable.fromWeb(response.body)
57369
- };
58120
+ return cacheClient;
57370
58121
  }
57371
- async function processObjectStoreAttachment(attachment) {
57372
- const result = extractBucketAndPath(attachment.url);
57373
- if (result === null) {
57374
- throw new Error("Invalid signed URL");
58122
+ async function getWritethroughClient() {
58123
+ if (!writethroughClient) {
58124
+ await init3();
57375
58125
  }
57376
- const { bucket, path: objectPath } = result;
57377
- const readStream = await getReadStream(bucket, objectPath);
57378
- const fallbackFilename = import_path.default.basename(objectPath);
57379
- return {
57380
- bucket,
57381
- path: objectPath,
57382
- filename: attachment.filename || fallbackFilename,
57383
- content: readStream
57384
- };
58126
+ return writethroughClient;
57385
58127
  }
57386
- async function processAutomationAttachment(attachment) {
57387
- const isFullyFormedUrl = attachment.url?.startsWith("http://") || attachment.url?.startsWith("https://");
57388
- if (isFullyFormedUrl) {
57389
- return await processUrlAttachment(attachment);
57390
- } else {
57391
- return await processObjectStoreAttachment(attachment);
58128
+ async function getLockClient() {
58129
+ if (!lockClient) {
58130
+ await init3();
58131
+ }
58132
+ return lockClient;
58133
+ }
58134
+ async function getSocketClient() {
58135
+ if (!socketClient) {
58136
+ await init3();
57392
58137
  }
58138
+ return socketClient;
58139
+ }
58140
+ async function getInviteClient() {
58141
+ if (!inviteClient) {
58142
+ await init3();
58143
+ }
58144
+ return inviteClient;
58145
+ }
58146
+ async function getPasswordResetClient() {
58147
+ if (!passwordResetClient) {
58148
+ await init3();
58149
+ }
58150
+ return passwordResetClient;
58151
+ }
58152
+ async function getDocWritethroughClient() {
58153
+ if (!writethroughClient) {
58154
+ await init3();
58155
+ }
58156
+ return writethroughClient;
57393
58157
  }
57394
-
57395
- // src/objectStore/objectStore.ts
57396
- var import_uuid2 = require("uuid");
57397
-
57398
- // src/db/index.ts
57399
- var db_exports = {};
57400
- __export(db_exports, {
57401
- APP_DEV: () => APP_DEV,
57402
- APP_DEV_PREFIX: () => APP_DEV_PREFIX2,
57403
- APP_PREFIX: () => APP_PREFIX2,
57404
- AutomationViewMode: () => AutomationViewMode,
57405
- BUDIBASE_DATASOURCE_TYPE: () => BUDIBASE_DATASOURCE_TYPE,
57406
- CONSTANT_EXTERNAL_ROW_COLS: () => CONSTANT_EXTERNAL_ROW_COLS,
57407
- CONSTANT_INTERNAL_ROW_COLS: () => CONSTANT_INTERNAL_ROW_COLS,
57408
- DEFAULT_BB_DATASOURCE_ID: () => DEFAULT_BB_DATASOURCE_ID,
57409
- DEFAULT_EMPLOYEE_TABLE_ID: () => DEFAULT_EMPLOYEE_TABLE_ID,
57410
- DEFAULT_EXPENSES_TABLE_ID: () => DEFAULT_EXPENSES_TABLE_ID,
57411
- DEFAULT_INVENTORY_TABLE_ID: () => DEFAULT_INVENTORY_TABLE_ID,
57412
- DEFAULT_JOBS_TABLE_ID: () => DEFAULT_JOBS_TABLE_ID,
57413
- DatabaseImpl: () => DatabaseImpl,
57414
- DatabaseWithConnection: () => DatabaseWithConnection,
57415
- DeprecatedViews: () => DeprecatedViews,
57416
- DocumentType: () => DocumentType,
57417
- InternalTable: () => InternalTable,
57418
- QueryBuilder: () => QueryBuilder,
57419
- Replication: () => Replication_default,
57420
- SEPARATOR: () => SEPARATOR,
57421
- SQLITE_DESIGN_DOC_ID: () => SQLITE_DESIGN_DOC_ID,
57422
- SQS_DATASOURCE_INTERNAL: () => SQS_DATASOURCE_INTERNAL,
57423
- StaticDatabases: () => StaticDatabases,
57424
- UNICODE_MAX: () => UNICODE_MAX,
57425
- ViewName: () => ViewName,
57426
- baseGlobalDBName: () => baseGlobalDBName,
57427
- checkErrorCode: () => checkErrorCode,
57428
- closePouchDB: () => closePouchDB,
57429
- createApiKeyView: () => createApiKeyView,
57430
- createNewUserEmailView: () => createNewUserEmailView,
57431
- createPlatformAccountEmailView: () => createPlatformAccountEmailView,
57432
- createPlatformUserView: () => createPlatformUserView,
57433
- createUserAppView: () => createUserAppView,
57434
- createView: () => createView,
57435
- dbExists: () => dbExists,
57436
- directCouchAllDbs: () => directCouchAllDbs,
57437
- directCouchCall: () => directCouchCall,
57438
- directCouchFind: () => directCouchFind,
57439
- directCouchQuery: () => directCouchQuery,
57440
- directCouchUrlCall: () => directCouchUrlCall,
57441
- doWithDB: () => doWithDB,
57442
- extractAppUUID: () => extractAppUUID,
57443
- fullSearch: () => fullSearch,
57444
- generateAppID: () => generateAppID,
57445
- generateAppUserID: () => generateAppUserID,
57446
- generateDevInfoID: () => generateDevInfoID,
57447
- generateGlobalUserID: () => generateGlobalUserID,
57448
- generatePluginID: () => generatePluginID,
57449
- generateRoleID: () => generateRoleID,
57450
- generateRowID: () => generateRowID,
57451
- generateTableID: () => generateTableID,
57452
- generateTemplateID: () => generateTemplateID,
57453
- generateUserMetadataID: () => generateUserMetadataID,
57454
- generateWorkspaceID: () => generateWorkspaceID,
57455
- getAllApps: () => getAllApps,
57456
- getAllDbs: () => getAllDbs,
57457
- getAppsByIDs: () => getAppsByIDs,
57458
- getCouchInfo: () => getCouchInfo,
57459
- getDB: () => getDB,
57460
- getDevAppID: () => getDevAppID2,
57461
- getDevAppIDs: () => getDevAppIDs,
57462
- getDevelopmentAppID: () => getDevelopmentAppID,
57463
- getDocParams: () => getDocParams,
57464
- getGlobalDBName: () => getGlobalDBName,
57465
- getGlobalIDFromUserMetadataID: () => getGlobalIDFromUserMetadataID,
57466
- getGlobalUserParams: () => getGlobalUserParams,
57467
- getPluginParams: () => getPluginParams,
57468
- getPouch: () => getPouch,
57469
- getPouchDB: () => getPouchDB,
57470
- getProdAppID: () => getProdAppID2,
57471
- getProdAppIDs: () => getProdAppIDs,
57472
- getQueryIndex: () => getQueryIndex,
57473
- getRoleParams: () => getRoleParams,
57474
- getRowParams: () => getRowParams,
57475
- getStartEndKeyURL: () => getStartEndKeyURL,
57476
- getTemplateParams: () => getTemplateParams,
57477
- getUrlInfo: () => getUrlInfo,
57478
- getUserMetadataParams: () => getUserMetadataParams,
57479
- getUsersByAppParams: () => getUsersByAppParams,
57480
- getWorkspaceParams: () => getWorkspaceParams,
57481
- init: () => init,
57482
- isDatasourceId: () => isDatasourceId,
57483
- isDevApp: () => isDevApp,
57484
- isDevAppID: () => isDevAppID,
57485
- isDocumentConflictError: () => isDocumentConflictError,
57486
- isGlobalUserID: () => isGlobalUserID,
57487
- isInternalColumnName: () => isInternalColumnName,
57488
- isProdAppID: () => isProdAppID,
57489
- isSameAppID: () => isSameAppID,
57490
- isTableId: () => isTableId,
57491
- paginatedSearch: () => paginatedSearch,
57492
- pagination: () => pagination,
57493
- prefixRoleID: () => prefixRoleID,
57494
- queryGlobalView: () => queryGlobalView,
57495
- queryGlobalViewRaw: () => queryGlobalViewRaw,
57496
- queryPlatformView: () => queryPlatformView,
57497
- queryView: () => queryView,
57498
- queryViewRaw: () => queryViewRaw,
57499
- removeKeyNumbering: () => removeKeyNumbering2,
57500
- searchIndexes: () => searchIndexes_exports
57501
- });
57502
58158
 
57503
58159
  // src/cache/appMetadata.ts
57504
- var appMetadata_exports = {};
57505
- __export(appMetadata_exports, {
57506
- AppState: () => AppState,
57507
- getAppMetadata: () => getAppMetadata,
57508
- invalidateAppMetadata: () => invalidateAppMetadata
57509
- });
57510
58160
  var AppState = /* @__PURE__ */ ((AppState2) => {
57511
58161
  AppState2["INVALID"] = "invalid";
57512
58162
  return AppState2;
@@ -58098,7 +58748,7 @@ var Replication = class {
58098
58748
  var Replication_default = Replication;
58099
58749
 
58100
58750
  // src/db/lucene.ts
58101
- var import_node_fetch2 = __toESM(require("node-fetch"));
58751
+ var import_node_fetch3 = __toESM(require("node-fetch"));
58102
58752
  var removeKeyNumbering2 = filters_exports.removeKeyNumbering;
58103
58753
  function isEmpty(value) {
58104
58754
  return value == null || value === "";
@@ -58553,7 +59203,7 @@ var QueryBuilder = class _QueryBuilder {
58553
59203
  }
58554
59204
  };
58555
59205
  async function runQuery2(url, body2, cookie) {
58556
- const response = await (0, import_node_fetch2.default)(url, {
59206
+ const response = await (0, import_node_fetch3.default)(url, {
58557
59207
  body: JSON.stringify(body2),
58558
59208
  method: "POST",
58559
59209
  headers: {
@@ -58598,1338 +59248,848 @@ async function recursiveSearch(dbName, index2, query, params2) {
58598
59248
  if (!page.rows.length) {
58599
59249
  return rows;
58600
59250
  }
58601
- if (page.rows.length < QueryBuilder.maxLimit) {
58602
- return [...rows, ...page.rows];
58603
- }
58604
- const newParams = {
58605
- ...params2,
58606
- bookmark: page.bookmark,
58607
- rows: [...rows, ...page.rows]
58608
- };
58609
- return await recursiveSearch(dbName, index2, query, newParams);
58610
- }
58611
- async function paginatedSearch(dbName, index2, query, params2) {
58612
- let limit2 = params2.limit;
58613
- if (limit2 == null || isNaN(limit2) || limit2 < 0) {
58614
- limit2 = 50;
58615
- }
58616
- limit2 = Math.min(limit2, QueryBuilder.maxLimit);
58617
- const search2 = new QueryBuilder(dbName, index2, query);
58618
- if (params2.version) {
58619
- search2.setVersion(params2.version);
58620
- }
58621
- if (params2.tableId) {
58622
- search2.setTable(params2.tableId);
58623
- }
58624
- if (params2.sort) {
58625
- search2.setSort(params2.sort).setSortOrder(params2.sortOrder).setSortType(params2.sortType);
58626
- }
58627
- if (params2.indexer) {
58628
- search2.setIndexBuilder(params2.indexer);
58629
- }
58630
- if (params2.disableEscaping) {
58631
- search2.disableEscaping();
58632
- }
58633
- const searchResults = await search2.setBookmark(params2.bookmark).setLimit(limit2).run();
58634
- search2.setBookmark(searchResults.bookmark).setLimit(1);
58635
- if (params2.tableId) {
58636
- search2.setTable(params2.tableId);
58637
- }
58638
- const nextResults = await search2.run();
58639
- return {
58640
- ...searchResults,
58641
- hasNextPage: nextResults.rows && nextResults.rows.length > 0
58642
- };
58643
- }
58644
- async function fullSearch(dbName, index2, query, params2) {
58645
- let limit2 = params2.limit;
58646
- if (limit2 == null || isNaN(limit2) || limit2 < 0) {
58647
- limit2 = 1e3;
58648
- }
58649
- params2.limit = Math.min(limit2, 1e3);
58650
- const rows = await recursiveSearch(dbName, index2, query, params2);
58651
- return { rows };
58652
- }
58653
-
58654
- // src/db/searchIndexes/index.ts
58655
- var searchIndexes_exports = {};
58656
- __export(searchIndexes_exports, {
58657
- createUserIndex: () => createUserIndex
58658
- });
58659
-
58660
- // src/db/searchIndexes/searchIndexes.ts
58661
- async function createUserIndex() {
58662
- const db = getGlobalDB();
58663
- let designDoc;
58664
- try {
58665
- designDoc = await db.get("_design/database");
58666
- } catch (err) {
58667
- if (err.status === 404) {
58668
- designDoc = { _id: "_design/database" };
58669
- }
58670
- }
58671
- const fn = function(user) {
58672
- if (user._id && !user._id.startsWith("us_")) {
58673
- return;
58674
- }
58675
- const ignoredFields = [
58676
- "_id",
58677
- "_rev",
58678
- "password",
58679
- "account",
58680
- "license",
58681
- "budibaseAccess",
58682
- "accountPortalAccess",
58683
- "csrfToken"
58684
- ];
58685
- function idx(input, prev) {
58686
- for (let key of Object.keys(input)) {
58687
- if (ignoredFields.includes(key)) {
58688
- continue;
58689
- }
58690
- let idxKey = prev != null ? `${prev}.${key}` : key;
58691
- if (typeof input[key] === "string") {
58692
- index(idxKey, input[key].toLowerCase(), { facet: true });
58693
- } else if (typeof input[key] !== "object") {
58694
- index(idxKey, input[key], { facet: true });
58695
- } else {
58696
- idx(input[key], idxKey);
58697
- }
58698
- }
58699
- }
58700
- idx(user);
58701
- };
58702
- designDoc.indexes = {
58703
- ["user" /* USER */]: {
58704
- index: fn.toString(),
58705
- analyzer: {
58706
- default: "keyword",
58707
- name: "perfield"
58708
- }
58709
- }
58710
- };
58711
- await db.put(designDoc);
58712
- }
58713
-
58714
- // src/db/errors.ts
58715
- function checkErrorCode(error, code) {
58716
- const stringCode = code.toString();
58717
- if (typeof error === "object") {
58718
- return error.status === code || error.message?.includes(stringCode);
58719
- } else if (typeof error === "number") {
58720
- return error === code;
58721
- } else if (typeof error === "string") {
58722
- return error.includes(stringCode);
58723
- }
58724
- }
58725
- function isDocumentConflictError(error) {
58726
- return checkErrorCode(error, 409);
58727
- }
58728
-
58729
- // src/objectStore/objectStore.ts
58730
- var import_promises = __toESM(require("fs/promises"));
58731
- var sanitize = require("sanitize-s3-objectkey");
58732
- var streamPipeline = (0, import_util.promisify)(import_stream2.default.pipeline);
58733
- var STATE = {
58734
- bucketCreationPromises: {}
58735
- };
58736
- var SIGNED_FILE_PREFIX = "/files/signed";
58737
- var CONTENT_TYPE_MAP = {
58738
- txt: "text/plain",
58739
- html: "text/html",
58740
- css: "text/css",
58741
- js: "application/javascript",
58742
- json: "application/json",
58743
- gz: "application/gzip",
58744
- svg: "image/svg+xml",
58745
- form: "multipart/form-data"
58746
- };
58747
- var STRING_CONTENT_TYPES = [
58748
- CONTENT_TYPE_MAP.html,
58749
- CONTENT_TYPE_MAP.css,
58750
- CONTENT_TYPE_MAP.js,
58751
- CONTENT_TYPE_MAP.json
58752
- ];
58753
- function sanitizeKey(input) {
58754
- return sanitize(sanitizeBucket(input)).replace(/\\/g, "/");
58755
- }
58756
- function sanitizeBucket(input) {
58757
- return input.replace(new RegExp(APP_DEV_PREFIX2, "g"), APP_PREFIX2);
58758
- }
58759
- function ObjectStore(bucket, opts = { presigning: false }) {
58760
- const config = {
58761
- s3ForcePathStyle: true,
58762
- signatureVersion: "v4",
58763
- apiVersion: "2006-03-01",
58764
- accessKeyId: environment_default.MINIO_ACCESS_KEY,
58765
- secretAccessKey: environment_default.MINIO_SECRET_KEY,
58766
- region: environment_default.AWS_REGION
58767
- };
58768
- if (bucket) {
58769
- config.params = {
58770
- Bucket: sanitizeBucket(bucket)
58771
- };
58772
- }
58773
- if (!environment_default.MINIO_ENABLED && environment_default.AWS_SESSION_TOKEN) {
58774
- config.sessionToken = environment_default.AWS_SESSION_TOKEN;
58775
- }
58776
- if (environment_default.MINIO_URL) {
58777
- if (opts.presigning && environment_default.MINIO_ENABLED) {
58778
- config.endpoint = "minio-service";
58779
- } else {
58780
- config.endpoint = environment_default.MINIO_URL;
58781
- }
58782
- }
58783
- return new import_aws_sdk.default.S3(config);
58784
- }
58785
- async function createBucketIfNotExists(client, bucketName) {
58786
- bucketName = sanitizeBucket(bucketName);
58787
- try {
58788
- await client.headBucket({
58789
- Bucket: bucketName
58790
- }).promise();
58791
- return { created: false, exists: true };
58792
- } catch (err) {
58793
- const promises = STATE.bucketCreationPromises;
58794
- const doesntExist = err.statusCode === 404, noAccess = err.statusCode === 403;
58795
- if (promises[bucketName]) {
58796
- await promises[bucketName];
58797
- return { created: false, exists: true };
58798
- } else if (doesntExist || noAccess) {
58799
- if (doesntExist) {
58800
- promises[bucketName] = client.createBucket({
58801
- Bucket: bucketName
58802
- }).promise();
58803
- await promises[bucketName];
58804
- delete promises[bucketName];
58805
- return { created: true, exists: false };
58806
- } else {
58807
- throw new Error("Access denied to object store bucket." + err);
58808
- }
58809
- } else {
58810
- throw new Error("Unable to write to object store bucket.");
58811
- }
58812
- }
58813
- }
58814
- async function upload({
58815
- bucket: bucketName,
58816
- filename,
58817
- path: path3,
58818
- type,
58819
- metadata,
58820
- body: body2,
58821
- ttl
58822
- }) {
58823
- const extension = filename.split(".").pop();
58824
- const fileBytes = path3 ? (await import_promises.default.open(path3)).createReadStream() : body2;
58825
- const objectStore = ObjectStore(bucketName);
58826
- const bucketCreated = await createBucketIfNotExists(objectStore, bucketName);
58827
- if (ttl && bucketCreated.created) {
58828
- let ttlConfig = bucketTTLConfig(bucketName, ttl);
58829
- await objectStore.putBucketLifecycleConfiguration(ttlConfig).promise();
58830
- }
58831
- let contentType = type;
58832
- if (!contentType) {
58833
- contentType = extension ? CONTENT_TYPE_MAP[extension.toLowerCase()] : CONTENT_TYPE_MAP.txt;
58834
- }
58835
- const config = {
58836
- // windows file paths need to be converted to forward slashes for s3
58837
- Key: sanitizeKey(filename),
58838
- Body: fileBytes,
58839
- ContentType: contentType
58840
- };
58841
- if (metadata && typeof metadata === "object") {
58842
- for (let key of Object.keys(metadata)) {
58843
- if (!metadata[key] || typeof metadata[key] !== "string") {
58844
- delete metadata[key];
58845
- }
58846
- }
58847
- config.Metadata = metadata;
59251
+ if (page.rows.length < QueryBuilder.maxLimit) {
59252
+ return [...rows, ...page.rows];
58848
59253
  }
58849
- return objectStore.upload(config).promise();
59254
+ const newParams = {
59255
+ ...params2,
59256
+ bookmark: page.bookmark,
59257
+ rows: [...rows, ...page.rows]
59258
+ };
59259
+ return await recursiveSearch(dbName, index2, query, newParams);
58850
59260
  }
58851
- async function streamUpload({
58852
- bucket: bucketName,
58853
- stream: stream3,
58854
- filename,
58855
- type,
58856
- extra,
58857
- ttl
58858
- }) {
58859
- if (!stream3) {
58860
- throw new Error("Stream to upload is invalid/undefined");
59261
+ async function paginatedSearch(dbName, index2, query, params2) {
59262
+ let limit2 = params2.limit;
59263
+ if (limit2 == null || isNaN(limit2) || limit2 < 0) {
59264
+ limit2 = 50;
58861
59265
  }
58862
- const extension = filename.split(".").pop();
58863
- const objectStore = ObjectStore(bucketName);
58864
- const bucketCreated = await createBucketIfNotExists(objectStore, bucketName);
58865
- if (ttl && bucketCreated.created) {
58866
- let ttlConfig = bucketTTLConfig(bucketName, ttl);
58867
- await objectStore.putBucketLifecycleConfiguration(ttlConfig).promise();
59266
+ limit2 = Math.min(limit2, QueryBuilder.maxLimit);
59267
+ const search2 = new QueryBuilder(dbName, index2, query);
59268
+ if (params2.version) {
59269
+ search2.setVersion(params2.version);
58868
59270
  }
58869
- if (filename?.endsWith(".js")) {
58870
- extra = {
58871
- ...extra,
58872
- ContentType: "application/javascript"
58873
- };
58874
- } else if (filename?.endsWith(".svg")) {
58875
- extra = {
58876
- ...extra,
58877
- ContentType: "image"
58878
- };
59271
+ if (params2.tableId) {
59272
+ search2.setTable(params2.tableId);
58879
59273
  }
58880
- let contentType = type;
58881
- if (!contentType) {
58882
- contentType = extension ? CONTENT_TYPE_MAP[extension.toLowerCase()] : CONTENT_TYPE_MAP.txt;
59274
+ if (params2.sort) {
59275
+ search2.setSort(params2.sort).setSortOrder(params2.sortOrder).setSortType(params2.sortType);
58883
59276
  }
58884
- const bucket = sanitizeBucket(bucketName), objKey = sanitizeKey(filename);
58885
- const params2 = {
58886
- Bucket: bucket,
58887
- Key: objKey,
58888
- Body: stream3,
58889
- ContentType: contentType,
58890
- ...extra
58891
- };
58892
- const details = await objectStore.upload(params2).promise();
58893
- const headDetails = await objectStore.headObject({
58894
- Bucket: bucket,
58895
- Key: objKey
58896
- }).promise();
59277
+ if (params2.indexer) {
59278
+ search2.setIndexBuilder(params2.indexer);
59279
+ }
59280
+ if (params2.disableEscaping) {
59281
+ search2.disableEscaping();
59282
+ }
59283
+ const searchResults = await search2.setBookmark(params2.bookmark).setLimit(limit2).run();
59284
+ search2.setBookmark(searchResults.bookmark).setLimit(1);
59285
+ if (params2.tableId) {
59286
+ search2.setTable(params2.tableId);
59287
+ }
59288
+ const nextResults = await search2.run();
58897
59289
  return {
58898
- ...details,
58899
- ContentLength: headDetails.ContentLength
59290
+ ...searchResults,
59291
+ hasNextPage: nextResults.rows && nextResults.rows.length > 0
58900
59292
  };
58901
59293
  }
58902
- async function retrieve(bucketName, filepath) {
58903
- const objectStore = ObjectStore(bucketName);
58904
- const params2 = {
58905
- Bucket: sanitizeBucket(bucketName),
58906
- Key: sanitizeKey(filepath)
58907
- };
58908
- const response = await objectStore.getObject(params2).promise();
58909
- if (STRING_CONTENT_TYPES.includes(response.ContentType)) {
58910
- return response.Body.toString("utf8");
58911
- } else {
58912
- return response.Body;
59294
+ async function fullSearch(dbName, index2, query, params2) {
59295
+ let limit2 = params2.limit;
59296
+ if (limit2 == null || isNaN(limit2) || limit2 < 0) {
59297
+ limit2 = 1e3;
58913
59298
  }
59299
+ params2.limit = Math.min(limit2, 1e3);
59300
+ const rows = await recursiveSearch(dbName, index2, query, params2);
59301
+ return { rows };
58914
59302
  }
58915
- async function listAllObjects(bucketName, path3) {
58916
- const objectStore = ObjectStore(bucketName);
58917
- const list = (params2 = {}) => {
58918
- return objectStore.listObjectsV2({
58919
- ...params2,
58920
- Bucket: sanitizeBucket(bucketName),
58921
- Prefix: sanitizeKey(path3)
58922
- }).promise();
58923
- };
58924
- let isTruncated = false, token, objects = [];
58925
- do {
58926
- let params2 = {};
58927
- if (token) {
58928
- params2.ContinuationToken = token;
58929
- }
58930
- const response = await list(params2);
58931
- if (response.Contents) {
58932
- objects = objects.concat(response.Contents);
59303
+
59304
+ // src/db/searchIndexes/index.ts
59305
+ var searchIndexes_exports = {};
59306
+ __export(searchIndexes_exports, {
59307
+ createUserIndex: () => createUserIndex
59308
+ });
59309
+
59310
+ // src/db/searchIndexes/searchIndexes.ts
59311
+ async function createUserIndex() {
59312
+ const db = getGlobalDB();
59313
+ let designDoc;
59314
+ try {
59315
+ designDoc = await db.get("_design/database");
59316
+ } catch (err) {
59317
+ if (err.status === 404) {
59318
+ designDoc = { _id: "_design/database" };
58933
59319
  }
58934
- isTruncated = !!response.IsTruncated;
58935
- token = response.NextContinuationToken;
58936
- } while (isTruncated && token);
58937
- return objects;
58938
- }
58939
- function getPresignedUrl(bucketName, key, durationSeconds = 3600) {
58940
- const objectStore = ObjectStore(bucketName, { presigning: true });
58941
- const params2 = {
58942
- Bucket: sanitizeBucket(bucketName),
58943
- Key: sanitizeKey(key),
58944
- Expires: durationSeconds
58945
- };
58946
- const url = objectStore.getSignedUrl("getObject", params2);
58947
- if (!environment_default.MINIO_ENABLED) {
58948
- return url;
58949
- } else {
58950
- const signedUrl = new URL(url);
58951
- const path3 = signedUrl.pathname;
58952
- const query = signedUrl.search;
58953
- return `${SIGNED_FILE_PREFIX}${path3}${query}`;
58954
59320
  }
58955
- }
58956
- async function retrieveToTmp(bucketName, filepath) {
58957
- bucketName = sanitizeBucket(bucketName);
58958
- filepath = sanitizeKey(filepath);
58959
- const data = await retrieve(bucketName, filepath);
58960
- const outputPath = (0, import_path2.join)(budibaseTempDir(), (0, import_uuid2.v4)());
58961
- import_fs3.default.writeFileSync(outputPath, data);
58962
- return outputPath;
58963
- }
58964
- async function retrieveDirectory(bucketName, path3) {
58965
- let writePath = (0, import_path2.join)(budibaseTempDir(), (0, import_uuid2.v4)());
58966
- import_fs3.default.mkdirSync(writePath);
58967
- const objects = await listAllObjects(bucketName, path3);
58968
- let streams = await Promise.all(
58969
- objects.map((obj) => getReadStream(bucketName, obj.Key))
58970
- );
58971
- let count = 0;
58972
- const writePromises = [];
58973
- for (let obj of objects) {
58974
- const filename = obj.Key;
58975
- const stream3 = streams[count++];
58976
- const possiblePath = filename.split("/");
58977
- const dirs = possiblePath.slice(0, possiblePath.length - 1);
58978
- const possibleDir = (0, import_path2.join)(writePath, ...dirs);
58979
- if (possiblePath.length > 1 && !import_fs3.default.existsSync(possibleDir)) {
58980
- import_fs3.default.mkdirSync(possibleDir, { recursive: true });
59321
+ const fn = function(user) {
59322
+ if (user._id && !user._id.startsWith("us_")) {
59323
+ return;
58981
59324
  }
58982
- const writeStream = import_fs3.default.createWriteStream((0, import_path2.join)(writePath, ...possiblePath), {
58983
- mode: 420
58984
- });
58985
- stream3.pipe(writeStream);
58986
- writePromises.push(
58987
- new Promise((resolve, reject) => {
58988
- stream3.on("finish", resolve);
58989
- stream3.on("error", reject);
58990
- writeStream.on("error", reject);
58991
- })
58992
- );
58993
- }
58994
- await Promise.all(writePromises);
58995
- return writePath;
58996
- }
58997
- async function deleteFile(bucketName, filepath) {
58998
- const objectStore = ObjectStore(bucketName);
58999
- await createBucketIfNotExists(objectStore, bucketName);
59000
- const params2 = {
59001
- Bucket: bucketName,
59002
- Key: sanitizeKey(filepath)
59003
- };
59004
- return objectStore.deleteObject(params2).promise();
59005
- }
59006
- async function deleteFiles(bucketName, filepaths) {
59007
- const objectStore = ObjectStore(bucketName);
59008
- await createBucketIfNotExists(objectStore, bucketName);
59009
- const params2 = {
59010
- Bucket: bucketName,
59011
- Delete: {
59012
- Objects: filepaths.map((path3) => ({ Key: sanitizeKey(path3) }))
59325
+ const ignoredFields = [
59326
+ "_id",
59327
+ "_rev",
59328
+ "password",
59329
+ "account",
59330
+ "license",
59331
+ "budibaseAccess",
59332
+ "accountPortalAccess",
59333
+ "csrfToken"
59334
+ ];
59335
+ function idx(input, prev) {
59336
+ for (let key of Object.keys(input)) {
59337
+ if (ignoredFields.includes(key)) {
59338
+ continue;
59339
+ }
59340
+ let idxKey = prev != null ? `${prev}.${key}` : key;
59341
+ if (typeof input[key] === "string") {
59342
+ index(idxKey, input[key].toLowerCase(), { facet: true });
59343
+ } else if (typeof input[key] !== "object") {
59344
+ index(idxKey, input[key], { facet: true });
59345
+ } else {
59346
+ idx(input[key], idxKey);
59347
+ }
59348
+ }
59013
59349
  }
59350
+ idx(user);
59014
59351
  };
59015
- return objectStore.deleteObjects(params2).promise();
59016
- }
59017
- async function deleteFolder(bucketName, folder) {
59018
- bucketName = sanitizeBucket(bucketName);
59019
- folder = sanitizeKey(folder);
59020
- const client = ObjectStore(bucketName);
59021
- const listParams = {
59022
- Bucket: bucketName,
59023
- Prefix: folder
59024
- };
59025
- const existingObjectsResponse = await client.listObjects(listParams).promise();
59026
- if (existingObjectsResponse.Contents?.length === 0) {
59027
- return;
59028
- }
59029
- const deleteParams = {
59030
- Bucket: bucketName,
59031
- Delete: {
59032
- Objects: []
59352
+ designDoc.indexes = {
59353
+ ["user" /* USER */]: {
59354
+ index: fn.toString(),
59355
+ analyzer: {
59356
+ default: "keyword",
59357
+ name: "perfield"
59358
+ }
59033
59359
  }
59034
59360
  };
59035
- existingObjectsResponse.Contents?.forEach((content) => {
59036
- deleteParams.Delete.Objects.push({ Key: content.Key });
59037
- });
59038
- const deleteResponse = await client.deleteObjects(deleteParams).promise();
59039
- if (deleteResponse.Deleted?.length === 1e3) {
59040
- return deleteFolder(bucketName, folder);
59041
- }
59361
+ await db.put(designDoc);
59042
59362
  }
59043
- async function uploadDirectory(bucketName, localPath, bucketPath) {
59044
- bucketName = sanitizeBucket(bucketName);
59045
- let uploads = [];
59046
- const files = import_fs3.default.readdirSync(localPath, { withFileTypes: true });
59047
- for (let file of files) {
59048
- const path3 = sanitizeKey((0, import_path2.join)(bucketPath, file.name));
59049
- const local = (0, import_path2.join)(localPath, file.name);
59050
- if (file.isDirectory()) {
59051
- uploads.push(uploadDirectory(bucketName, local, path3));
59052
- } else {
59053
- uploads.push(
59054
- streamUpload({
59055
- bucket: bucketName,
59056
- filename: path3,
59057
- stream: import_fs3.default.createReadStream(local)
59058
- })
59059
- );
59060
- }
59363
+
59364
+ // src/db/errors.ts
59365
+ function checkErrorCode(error, code) {
59366
+ const stringCode = code.toString();
59367
+ if (typeof error === "object") {
59368
+ return error.status === code || error.message?.includes(stringCode);
59369
+ } else if (typeof error === "number") {
59370
+ return error === code;
59371
+ } else if (typeof error === "string") {
59372
+ return error.includes(stringCode);
59061
59373
  }
59062
- await Promise.all(uploads);
59063
- return files;
59064
59374
  }
59065
- async function downloadTarballDirect(url, path3, headers = {}) {
59066
- path3 = sanitizeKey(path3);
59067
- const response = await (0, import_node_fetch3.default)(url, { headers });
59068
- if (!response.ok) {
59069
- throw new Error(`unexpected response ${response.statusText}`);
59070
- }
59071
- await streamPipeline(response.body, import_zlib.default.createUnzip(), import_tar_fs.default.extract(path3));
59375
+ function isDocumentConflictError(error) {
59376
+ return checkErrorCode(error, 409);
59072
59377
  }
59073
- async function downloadTarball(url, bucketName, path3) {
59074
- bucketName = sanitizeBucket(bucketName);
59075
- path3 = sanitizeKey(path3);
59076
- const response = await (0, import_node_fetch3.default)(url);
59077
- if (!response.ok) {
59078
- throw new Error(`unexpected response ${response.statusText}`);
59378
+
59379
+ // src/sql/utils.ts
59380
+ var DOUBLE_SEPARATOR = `${SEPARATOR}${SEPARATOR}`;
59381
+ var ROW_ID_REGEX = /^\[.*]$/g;
59382
+ var ENCODED_SPACE = encodeURIComponent(" ");
59383
+ var ISO_DATE_REGEX = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}.\d{3}Z$/;
59384
+ function isExternalTableID(tableId) {
59385
+ return tableId.startsWith("datasource" /* DATASOURCE */ + SEPARATOR);
59386
+ }
59387
+ function isInternalTableID(tableId) {
59388
+ return !isExternalTableID(tableId);
59389
+ }
59390
+ function getNativeSql(query) {
59391
+ let sql = query.toSQL();
59392
+ if (Array.isArray(sql)) {
59393
+ return sql;
59079
59394
  }
59080
- const tmpPath = (0, import_path2.join)(budibaseTempDir(), path3);
59081
- await streamPipeline(response.body, import_zlib.default.createUnzip(), import_tar_fs.default.extract(tmpPath));
59082
- if (!environment_default.isTest() && environment_default.SELF_HOSTED) {
59083
- await uploadDirectory(bucketName, tmpPath, path3);
59395
+ let native;
59396
+ if (sql.toNative) {
59397
+ native = sql.toNative();
59084
59398
  }
59085
- return tmpPath;
59086
- }
59087
- async function getReadStream(bucketName, path3) {
59088
- bucketName = sanitizeBucket(bucketName);
59089
- path3 = sanitizeKey(path3);
59090
- const client = ObjectStore(bucketName);
59091
- const params2 = {
59092
- Bucket: bucketName,
59093
- Key: path3
59399
+ return {
59400
+ sql: native?.sql || sql.sql,
59401
+ bindings: native?.bindings || sql.bindings
59094
59402
  };
59095
- return client.getObject(params2).createReadStream();
59096
59403
  }
59097
- async function getObjectMetadata(bucket, path3) {
59098
- bucket = sanitizeBucket(bucket);
59099
- path3 = sanitizeKey(path3);
59100
- const client = ObjectStore(bucket);
59101
- const params2 = {
59102
- Bucket: bucket,
59103
- Key: path3
59104
- };
59105
- try {
59106
- return await client.headObject(params2).promise();
59107
- } catch (err) {
59108
- throw new Error("Unable to retrieve metadata from object");
59404
+ function isExternalTable(table) {
59405
+ if (table?.sourceId && table.sourceId.includes("datasource" /* DATASOURCE */ + SEPARATOR) && table?.sourceId !== DEFAULT_BB_DATASOURCE_ID) {
59406
+ return true;
59407
+ } else if (table?.sourceType === "external" /* EXTERNAL */) {
59408
+ return true;
59409
+ } else if (table?._id && isExternalTableID(table._id)) {
59410
+ return true;
59109
59411
  }
59412
+ return false;
59110
59413
  }
59111
- function extractBucketAndPath(url) {
59112
- const baseUrl = url.split("?")[0];
59113
- const regex = new RegExp(
59114
- `^${SIGNED_FILE_PREFIX}/(?<bucket>[^/]+)/(?<path>.+)$`
59115
- );
59116
- const match = baseUrl.match(regex);
59117
- if (match && match.groups) {
59118
- const { bucket, path: path3 } = match.groups;
59119
- return { bucket, path: path3 };
59414
+ function buildExternalTableId(datasourceId, tableName) {
59415
+ if (tableName.includes(" ")) {
59416
+ tableName = encodeURIComponent(tableName);
59120
59417
  }
59121
- return null;
59418
+ return `${datasourceId}${DOUBLE_SEPARATOR}${tableName}`;
59122
59419
  }
59123
-
59124
- // src/objectStore/cloudfront.ts
59125
- var cfsign = __toESM(require("aws-cloudfront-sign"));
59126
- var PRIVATE_KEY;
59127
- function getPrivateKey() {
59128
- if (!environment_default.CLOUDFRONT_PRIVATE_KEY_64) {
59129
- throw new Error("CLOUDFRONT_PRIVATE_KEY_64 is not set");
59420
+ function breakExternalTableId(tableId) {
59421
+ const parts = tableId.split(DOUBLE_SEPARATOR);
59422
+ let datasourceId = parts.shift();
59423
+ let tableName = parts.join(DOUBLE_SEPARATOR);
59424
+ if (tableName.includes(ENCODED_SPACE)) {
59425
+ tableName = decodeURIComponent(tableName);
59130
59426
  }
59131
- if (PRIVATE_KEY) {
59132
- return PRIVATE_KEY;
59427
+ if (!datasourceId || !tableName) {
59428
+ throw new Error("Unable to get datasource/table name from table ID");
59133
59429
  }
59134
- PRIVATE_KEY = Buffer.from(environment_default.CLOUDFRONT_PRIVATE_KEY_64, "base64").toString(
59135
- "utf-8"
59136
- );
59137
- return PRIVATE_KEY;
59430
+ return { datasourceId, tableName };
59138
59431
  }
59139
- var getCloudfrontSignParams = () => {
59140
- return {
59141
- keypairId: environment_default.CLOUDFRONT_PUBLIC_KEY_ID,
59142
- privateKeyString: getPrivateKey(),
59143
- expireTime: (/* @__PURE__ */ new Date()).getTime() + 1e3 * 60 * 60 * 24
59144
- // 1 day
59145
- };
59146
- };
59147
- var getPresignedUrl2 = (s3Key) => {
59148
- const url = getUrl(s3Key);
59149
- return cfsign.getSignedUrl(url, getCloudfrontSignParams());
59150
- };
59151
- var getUrl = (s3Key) => {
59152
- let prefix = "/";
59153
- if (s3Key.startsWith("/")) {
59154
- prefix = "";
59432
+ function generateRowIdField(keyProps = []) {
59433
+ if (!Array.isArray(keyProps)) {
59434
+ keyProps = [keyProps];
59155
59435
  }
59156
- return `${environment_default.CLOUDFRONT_CDN}${prefix}${s3Key}`;
59157
- };
59158
-
59159
- // src/objectStore/buckets/app.ts
59160
- var import_querystring = __toESM(require("querystring"));
59161
- function clientLibraryPath(appId) {
59162
- return `${sanitizeKey(appId)}/budibase-client.js`;
59163
- }
59164
- function clientLibraryCDNUrl(appId, version) {
59165
- let file = clientLibraryPath(appId);
59166
- if (environment_default.CLOUDFRONT_CDN) {
59167
- if (version) {
59168
- file += `?v=${version}`;
59436
+ for (let index2 in keyProps) {
59437
+ if (keyProps[index2] instanceof Buffer) {
59438
+ keyProps[index2] = keyProps[index2].toString();
59169
59439
  }
59170
- return getUrl(file);
59171
- } else {
59172
- return getPresignedUrl(environment_default.APPS_BUCKET_NAME, file);
59173
- }
59174
- }
59175
- function clientLibraryUrl(appId, version) {
59176
- let tenantId, qsParams;
59177
- try {
59178
- tenantId = getTenantId();
59179
- } finally {
59180
- qsParams = {
59181
- appId,
59182
- version
59183
- };
59184
59440
  }
59185
- if (tenantId && tenantId !== DEFAULT_TENANT_ID) {
59186
- qsParams.tenantId = tenantId;
59187
- }
59188
- return `/api/assets/client?${import_querystring.default.encode(qsParams)}`;
59441
+ return encodeURIComponent(JSON.stringify(keyProps).replace(/"/g, "'"));
59189
59442
  }
59190
- function getAppFileUrl(s3Key) {
59191
- if (environment_default.CLOUDFRONT_CDN) {
59192
- return getPresignedUrl2(s3Key);
59193
- } else {
59194
- return getPresignedUrl(environment_default.APPS_BUCKET_NAME, s3Key);
59195
- }
59443
+ function isRowId(field) {
59444
+ return Array.isArray(field) || typeof field === "string" && field.match(ROW_ID_REGEX) != null;
59196
59445
  }
59197
-
59198
- // src/objectStore/buckets/global.ts
59199
- var getGlobalFileUrl = (type, name, etag) => {
59200
- let file = getGlobalFileS3Key(type, name);
59201
- if (environment_default.CLOUDFRONT_CDN) {
59202
- if (etag) {
59203
- file = `${file}?etag=${etag}`;
59204
- }
59205
- return getPresignedUrl2(file);
59206
- } else {
59207
- return getPresignedUrl(environment_default.GLOBAL_BUCKET_NAME, file);
59446
+ function convertRowId(field) {
59447
+ if (Array.isArray(field)) {
59448
+ return field[0];
59208
59449
  }
59209
- };
59210
- var getGlobalFileS3Key = (type, name) => {
59211
- let file = `${type}/${name}`;
59212
- if (environment_default.MULTI_TENANCY) {
59213
- const tenantId = getTenantId();
59214
- file = `${tenantId}/${file}`;
59450
+ if (typeof field === "string" && field.match(ROW_ID_REGEX) != null) {
59451
+ return field.substring(1, field.length - 1);
59215
59452
  }
59216
- return file;
59217
- };
59218
-
59219
- // src/objectStore/buckets/plugins.ts
59220
- function enrichPluginURLs(plugins) {
59221
- if (!plugins || !plugins.length) {
59453
+ return field;
59454
+ }
59455
+ function breakRowIdField(_id) {
59456
+ if (!_id) {
59222
59457
  return [];
59223
59458
  }
59224
- return plugins.map((plugin) => {
59225
- const jsUrl = getPluginJSUrl(plugin);
59226
- const iconUrl = getPluginIconUrl(plugin);
59227
- return { ...plugin, jsUrl, iconUrl };
59228
- });
59229
- }
59230
- function getPluginJSUrl(plugin) {
59231
- const s3Key = getPluginJSKey(plugin);
59232
- return getPluginUrl(s3Key);
59459
+ const id = typeof _id === "string" ? _id : _id._id;
59460
+ const decoded = decodeURIComponent(id).replace(/'/g, '"');
59461
+ try {
59462
+ const parsed = JSON.parse(decoded);
59463
+ return Array.isArray(parsed) ? parsed : [parsed];
59464
+ } catch (err) {
59465
+ return [_id];
59466
+ }
59233
59467
  }
59234
- function getPluginIconUrl(plugin) {
59235
- const s3Key = getPluginIconKey(plugin);
59236
- if (!s3Key) {
59237
- return;
59468
+ function isInvalidISODateString(str) {
59469
+ const trimmedValue = str.trim();
59470
+ if (!ISO_DATE_REGEX.test(trimmedValue)) {
59471
+ return false;
59238
59472
  }
59239
- return getPluginUrl(s3Key);
59473
+ let d = new Date(trimmedValue);
59474
+ return isNaN(d.getTime());
59240
59475
  }
59241
- function getPluginUrl(s3Key) {
59242
- if (environment_default.CLOUDFRONT_CDN) {
59243
- return getPresignedUrl2(s3Key);
59244
- } else {
59245
- return getPresignedUrl(environment_default.PLUGIN_BUCKET_NAME, s3Key);
59476
+ function isValidISODateString(str) {
59477
+ const trimmedValue = str.trim();
59478
+ if (!ISO_DATE_REGEX.test(trimmedValue)) {
59479
+ return false;
59480
+ }
59481
+ let d = new Date(trimmedValue);
59482
+ if (isNaN(d.getTime())) {
59483
+ return false;
59246
59484
  }
59485
+ return d.toISOString() === trimmedValue;
59247
59486
  }
59248
- function getPluginJSKey(plugin) {
59249
- return getPluginS3Key(plugin, "plugin.min.js");
59487
+ function isValidFilter(value) {
59488
+ return value != null && value !== "";
59250
59489
  }
59251
- function getPluginIconKey(plugin) {
59252
- const iconFileName = plugin.iconUrl ? "icon.svg" : plugin.iconFileName;
59253
- if (!iconFileName) {
59490
+ function sqlLog(client, query, values2) {
59491
+ if (!environment_default.SQL_LOGGING_ENABLE) {
59254
59492
  return;
59255
59493
  }
59256
- return getPluginS3Key(plugin, iconFileName);
59494
+ let string = `[SQL] [${client.toUpperCase()}] query="${query}"`;
59495
+ if (values2) {
59496
+ string += ` values="${values2.join(", ")}"`;
59497
+ }
59498
+ console.log(string);
59257
59499
  }
59258
- function getPluginS3Key(plugin, fileName) {
59259
- const s3Key = getPluginS3Dir(plugin.name);
59260
- return `${s3Key}/${fileName}`;
59500
+
59501
+ // src/db/couch/DatabaseImpl.ts
59502
+ var DATABASE_NOT_FOUND = "Database does not exist.";
59503
+ function buildNano(couchInfo) {
59504
+ return (0, import_nano.default)({
59505
+ url: couchInfo.url,
59506
+ requestDefaults: {
59507
+ headers: {
59508
+ Authorization: couchInfo.cookie
59509
+ }
59510
+ },
59511
+ parseUrl: false
59512
+ });
59261
59513
  }
59262
- function getPluginS3Dir(pluginName) {
59263
- let s3Key = `${pluginName}`;
59264
- if (environment_default.MULTI_TENANCY) {
59265
- const tenantId = getTenantId();
59266
- s3Key = `${tenantId}/${s3Key}`;
59514
+ var CouchDBError = class extends Error {
59515
+ constructor(message, info) {
59516
+ super(message);
59517
+ const statusCode = info.status || info.statusCode || 500;
59518
+ this.status = statusCode;
59519
+ this.statusCode = statusCode;
59520
+ this.reason = info.reason;
59521
+ this.name = info.name;
59522
+ this.errid = info.errid;
59523
+ this.description = info.description;
59524
+ this.error = info.error;
59267
59525
  }
59268
- if (environment_default.CLOUDFRONT_CDN) {
59269
- s3Key = `plugins/${s3Key}`;
59526
+ };
59527
+ function DatabaseWithConnection(dbName, connection, opts) {
59528
+ if (!dbName || !connection) {
59529
+ throw new Error(
59530
+ "Unable to create database without database name or connection"
59531
+ );
59270
59532
  }
59271
- return s3Key;
59272
- }
59273
-
59274
- // src/logging/system.ts
59275
- var logsFileName = `budibase.log`;
59276
- var budibaseLogsHistoryFileName = "budibase-logs-history.txt";
59277
- var logsPath = import_path3.default.join(budibaseTempDir(), "systemlogs");
59278
- function getFullPath(fileName) {
59279
- return import_path3.default.join(logsPath, fileName);
59533
+ const db = new DatabaseImpl(dbName, opts, connection);
59534
+ return new DDInstrumentedDatabase(db);
59280
59535
  }
59281
- function getSingleFileMaxSizeInfo(totalMaxSize) {
59282
- const regex = /(\d+)([A-Za-z])/;
59283
- const match = totalMaxSize?.match(regex);
59284
- if (!match) {
59285
- console.warn(`totalMaxSize does not have a valid value`, {
59286
- totalMaxSize
59287
- });
59288
- return void 0;
59536
+ var DatabaseImpl = class _DatabaseImpl {
59537
+ constructor(dbName, opts, connection) {
59538
+ this.couchInfo = getCouchInfo();
59539
+ this.name = dbName;
59540
+ this.pouchOpts = opts || {};
59541
+ if (connection) {
59542
+ this.couchInfo = getCouchInfo(connection);
59543
+ this.instanceNano = buildNano(this.couchInfo);
59544
+ }
59545
+ if (!_DatabaseImpl.nano) {
59546
+ _DatabaseImpl.init();
59547
+ }
59289
59548
  }
59290
- const size = +match[1];
59291
- const unit = match[2];
59292
- if (size === 1) {
59293
- switch (unit) {
59294
- case "B":
59295
- return { size: `${size}B`, totalHistoryFiles: 1 };
59296
- case "K":
59297
- return { size: `${size * 1e3 / 2}B`, totalHistoryFiles: 1 };
59298
- case "M":
59299
- return { size: `${size * 1e3 / 2}K`, totalHistoryFiles: 1 };
59300
- case "G":
59301
- return { size: `${size * 1e3 / 2}M`, totalHistoryFiles: 1 };
59302
- default:
59303
- return void 0;
59549
+ static init() {
59550
+ const couchInfo = getCouchInfo();
59551
+ _DatabaseImpl.nano = buildNano(couchInfo);
59552
+ }
59553
+ exists(docId) {
59554
+ if (docId === void 0) {
59555
+ return this.dbExists();
59304
59556
  }
59557
+ return this.docExists(docId);
59305
59558
  }
59306
- if (size % 2 === 0) {
59307
- return { size: `${size / 2}${unit}`, totalHistoryFiles: 1 };
59559
+ async dbExists() {
59560
+ const response = await directCouchUrlCall({
59561
+ url: `${this.couchInfo.url}/${this.name}`,
59562
+ method: "HEAD",
59563
+ cookie: this.couchInfo.cookie
59564
+ });
59565
+ return response.status === 200;
59308
59566
  }
59309
- return { size: `1${unit}`, totalHistoryFiles: size - 1 };
59310
- }
59311
- function localFileDestination() {
59312
- const fileInfo = getSingleFileMaxSizeInfo(environment_default.ROLLING_LOG_MAX_SIZE);
59313
- const outFile = rfs.createStream(logsFileName, {
59314
- // As we have a rolling size, we want to half the max size
59315
- size: fileInfo?.size,
59316
- path: logsPath,
59317
- maxFiles: fileInfo?.totalHistoryFiles || 1,
59318
- immutable: true,
59319
- history: budibaseLogsHistoryFileName,
59320
- initialRotation: false
59321
- });
59322
- return outFile;
59323
- }
59324
- function getLogReadStream() {
59325
- const streams = [];
59326
- const historyFile = getFullPath(budibaseLogsHistoryFileName);
59327
- if (import_fs4.default.existsSync(historyFile)) {
59328
- const fileContent = import_fs4.default.readFileSync(historyFile, "utf-8");
59329
- const historyFiles = fileContent.split("\n");
59330
- for (const historyFile2 of historyFiles.filter((x) => x)) {
59331
- streams.push(import_fs4.default.readFileSync(historyFile2));
59567
+ async docExists(id) {
59568
+ try {
59569
+ await this.performCall((db) => () => db.head(id));
59570
+ return true;
59571
+ } catch {
59572
+ return false;
59332
59573
  }
59333
59574
  }
59334
- streams.push(import_fs4.default.readFileSync(getFullPath(logsFileName)));
59335
- const combinedContent = Buffer.concat(streams);
59336
- return combinedContent;
59337
- }
59338
-
59339
- // src/logging/pino/logger.ts
59340
- function isPlainObject(obj) {
59341
- return typeof obj === "object" && obj !== null && !(obj instanceof Error);
59342
- }
59343
- function isError(obj) {
59344
- return obj instanceof Error;
59345
- }
59346
- function isMessage(obj) {
59347
- return typeof obj === "string";
59348
- }
59349
- var pinoInstance;
59350
- if (!environment_default.DISABLE_PINO_LOGGER) {
59351
- const level = environment_default.LOG_LEVEL;
59352
- const pinoOptions = {
59353
- level,
59354
- formatters: {
59355
- level: (level2) => {
59356
- return { level: level2.toUpperCase() };
59357
- },
59358
- bindings: () => {
59359
- if (environment_default.SELF_HOSTED) {
59360
- return {
59361
- service: environment_default.SERVICE_NAME
59362
- };
59363
- } else {
59364
- return {};
59575
+ nano() {
59576
+ return this.instanceNano || _DatabaseImpl.nano;
59577
+ }
59578
+ getDb() {
59579
+ return this.nano().db.use(this.name);
59580
+ }
59581
+ async checkAndCreateDb() {
59582
+ let shouldCreate = !this.pouchOpts?.skip_setup;
59583
+ let exists2 = await this.exists();
59584
+ if (!shouldCreate && !exists2) {
59585
+ throw new Error("DB does not exist");
59586
+ }
59587
+ if (!exists2) {
59588
+ try {
59589
+ await this.nano().db.create(this.name);
59590
+ } catch (err) {
59591
+ if (err.statusCode !== 412) {
59592
+ throw new CouchDBError(err.message, err);
59365
59593
  }
59366
59594
  }
59367
- },
59368
- timestamp: () => `,"timestamp":"${new Date(Date.now()).toISOString()}"`
59369
- };
59370
- const destinations = [];
59371
- destinations.push(
59372
- environment_default.isDev() ? {
59373
- stream: (0, import_pino_pretty.default)({ singleLine: true }),
59374
- level
59375
- } : { stream: process.stdout, level }
59376
- );
59377
- if (environment_default.SELF_HOSTED) {
59378
- destinations.push({
59379
- stream: localFileDestination(),
59380
- level
59595
+ }
59596
+ return this.getDb();
59597
+ }
59598
+ // this function fetches the DB and handles if DB creation is needed
59599
+ async performCall(call) {
59600
+ const db = this.getDb();
59601
+ const fnc = await call(db);
59602
+ try {
59603
+ return await fnc();
59604
+ } catch (err) {
59605
+ if (err.statusCode === 404 && err.reason === DATABASE_NOT_FOUND) {
59606
+ await this.checkAndCreateDb();
59607
+ return await this.performCall(call);
59608
+ }
59609
+ throw new CouchDBError(`CouchDB error: ${err.message}`, err);
59610
+ }
59611
+ }
59612
+ async get(id) {
59613
+ return this.performCall((db) => {
59614
+ if (!id) {
59615
+ throw new Error("Unable to get doc without a valid _id.");
59616
+ }
59617
+ return () => db.get(id);
59618
+ });
59619
+ }
59620
+ async getMultiple(ids, opts) {
59621
+ ids = [...new Set(ids)];
59622
+ const response = await this.allDocs({
59623
+ keys: ids,
59624
+ include_docs: true
59625
+ });
59626
+ const rowUnavailable = (row) => {
59627
+ if (row.doc == null || "deleted" in row.value && row.value.deleted) {
59628
+ return true;
59629
+ }
59630
+ return row.error === "not_found";
59631
+ };
59632
+ const rows = response.rows.filter((row) => !rowUnavailable(row));
59633
+ const someMissing = rows.length !== response.rows.length;
59634
+ if (!opts?.allowMissing && someMissing) {
59635
+ const missing = response.rows.filter((row) => rowUnavailable(row));
59636
+ const missingIds = missing.map((row) => row.key).join(", ");
59637
+ throw new Error(`Unable to get documents: ${missingIds}`);
59638
+ }
59639
+ return rows.map((row) => row.doc);
59640
+ }
59641
+ async remove(idOrDoc, rev) {
59642
+ return this.performCall((db) => {
59643
+ let _id;
59644
+ let _rev;
59645
+ if (isDocument(idOrDoc)) {
59646
+ _id = idOrDoc._id;
59647
+ _rev = idOrDoc._rev;
59648
+ } else {
59649
+ _id = idOrDoc;
59650
+ _rev = rev;
59651
+ }
59652
+ if (!_id || !_rev) {
59653
+ throw new Error("Unable to remove doc without a valid _id and _rev.");
59654
+ }
59655
+ return () => db.destroy(_id, _rev);
59381
59656
  });
59382
59657
  }
59383
- pinoInstance = destinations.length ? (0, import_pino.default)(pinoOptions, import_pino.default.multistream(destinations)) : (0, import_pino.default)(pinoOptions);
59384
- const getLogParams2 = (args) => {
59385
- let error = void 0;
59386
- let objects = [];
59387
- let message = "";
59388
- args.forEach((arg) => {
59389
- if (isMessage(arg)) {
59390
- message = `${message} ${arg}`.trimStart();
59391
- }
59392
- if (isPlainObject(arg)) {
59393
- objects.push(arg);
59658
+ async post(document, opts) {
59659
+ if (!document._id) {
59660
+ document._id = newid();
59661
+ }
59662
+ return this.put(document, opts);
59663
+ }
59664
+ async put(document, opts) {
59665
+ if (!document._id) {
59666
+ throw new Error("Cannot store document without _id field.");
59667
+ }
59668
+ return this.performCall(async (db) => {
59669
+ if (!document.createdAt) {
59670
+ document.createdAt = (/* @__PURE__ */ new Date()).toISOString();
59394
59671
  }
59395
- if (isError(arg)) {
59396
- error = arg;
59672
+ document.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
59673
+ if (opts?.force && document._id) {
59674
+ try {
59675
+ const existing = await this.get(document._id);
59676
+ if (existing) {
59677
+ document._rev = existing._rev;
59678
+ }
59679
+ } catch (err) {
59680
+ if (err.status !== 404) {
59681
+ throw err;
59682
+ }
59683
+ }
59397
59684
  }
59685
+ return () => db.insert(document);
59398
59686
  });
59399
- const identity = getIdentity3();
59400
- let contextObject = {};
59401
- contextObject = {
59402
- tenantId: getTenantId2(),
59403
- appId: getAppId2(),
59404
- automationId: getAutomationId2(),
59405
- identityId: identity?._id,
59406
- identityType: identity?.type,
59407
- correlationId: getId()
59687
+ }
59688
+ async bulkDocs(documents) {
59689
+ return this.performCall((db) => {
59690
+ return () => db.bulk({ docs: documents });
59691
+ });
59692
+ }
59693
+ async allDocs(params2) {
59694
+ return this.performCall((db) => {
59695
+ return () => db.list(params2);
59696
+ });
59697
+ }
59698
+ async _sqlQuery(url, method, body2) {
59699
+ url = checkSlashesInUrl(`${this.couchInfo.sqlUrl}/${url}`);
59700
+ const args = {
59701
+ url,
59702
+ method,
59703
+ cookie: this.couchInfo.cookie
59408
59704
  };
59409
- const span = import_dd_trace2.default.scope().active();
59410
- if (span) {
59411
- import_dd_trace2.default.inject(span.context(), import_ext.formats.LOG, contextObject);
59705
+ if (body2) {
59706
+ args.body = body2;
59412
59707
  }
59413
- const mergingObject = {
59414
- err: error,
59415
- pid: process.pid,
59416
- ...contextObject
59417
- };
59418
- if (objects.length) {
59419
- const data = {};
59420
- let dataIndex = 0;
59421
- for (let i = 0; i < objects.length; i++) {
59422
- const object = objects[i];
59423
- const logKey = object._logKey;
59424
- if (logKey) {
59425
- delete object._logKey;
59426
- mergingObject[logKey] = object;
59427
- } else {
59428
- data[dataIndex] = object;
59429
- dataIndex++;
59708
+ return this.performCall(() => {
59709
+ return async () => {
59710
+ const response = await directCouchUrlCall(args);
59711
+ const json = await response.json();
59712
+ if (response.status > 300) {
59713
+ throw json;
59430
59714
  }
59431
- }
59432
- if (Object.keys(data).length) {
59433
- mergingObject.data = data;
59434
- }
59435
- }
59436
- return [mergingObject, message];
59437
- };
59438
- console.log = (...arg) => {
59439
- const [obj, msg] = getLogParams2(arg);
59440
- pinoInstance?.info(obj, msg);
59441
- };
59442
- console.info = (...arg) => {
59443
- const [obj, msg] = getLogParams2(arg);
59444
- pinoInstance?.info(obj, msg);
59445
- };
59446
- console.warn = (...arg) => {
59447
- const [obj, msg] = getLogParams2(arg);
59448
- pinoInstance?.warn(obj, msg);
59449
- };
59450
- console.error = (...arg) => {
59451
- const [obj, msg] = getLogParams2(arg);
59452
- pinoInstance?.error(obj, msg);
59453
- };
59454
- console.trace = (...arg) => {
59455
- const [obj, msg] = getLogParams2(arg);
59456
- if (!obj.err) {
59457
- obj.err = new Error();
59458
- }
59459
- pinoInstance?.trace(obj, msg);
59460
- };
59461
- console.debug = (...arg) => {
59462
- const [obj, msg] = getLogParams2(arg);
59463
- pinoInstance?.debug(obj, msg);
59464
- };
59465
- const getTenantId2 = () => {
59466
- let tenantId;
59715
+ return json;
59716
+ };
59717
+ });
59718
+ }
59719
+ async sql(sql, parameters) {
59720
+ const dbName = this.name;
59721
+ const url = `/${dbName}/${SQLITE_DESIGN_DOC_ID}`;
59722
+ sqlLog("sqlite3" /* SQL_LITE */, sql, parameters);
59723
+ return await this._sqlQuery(url, "POST", {
59724
+ query: sql,
59725
+ args: parameters
59726
+ });
59727
+ }
59728
+ // checks design document is accurate (cleans up tables)
59729
+ // this will check the design document and remove anything from
59730
+ // disk which is not supposed to be there
59731
+ async sqlDiskCleanup() {
59732
+ const dbName = this.name;
59733
+ const url = `/${dbName}/_cleanup`;
59467
59734
  try {
59468
- tenantId = getTenantId();
59469
- } catch (e) {
59735
+ await this._sqlQuery(url, "POST");
59736
+ } catch (err) {
59737
+ if (err.status !== 500) {
59738
+ throw err;
59739
+ }
59470
59740
  }
59471
- return tenantId;
59472
- };
59473
- const getAppId2 = () => {
59474
- let appId;
59475
- try {
59476
- appId = getAppId();
59477
- } catch (e) {
59741
+ }
59742
+ // removes a document from sqlite
59743
+ async sqlPurgeDocument(docIds) {
59744
+ if (!Array.isArray(docIds)) {
59745
+ docIds = [docIds];
59478
59746
  }
59479
- return appId;
59480
- };
59481
- const getAutomationId2 = () => {
59482
- let appId;
59483
- try {
59484
- appId = getAutomationId();
59485
- } catch (e) {
59747
+ const dbName = this.name;
59748
+ const url = `/${dbName}/_purge`;
59749
+ return await this._sqlQuery(url, "POST", { docs: docIds });
59750
+ }
59751
+ async query(viewName, params2) {
59752
+ return this.performCall((db) => {
59753
+ const [database, view] = viewName.split("/");
59754
+ return () => db.view(database, view, params2);
59755
+ });
59756
+ }
59757
+ async destroy() {
59758
+ if (environment_default.SQS_SEARCH_ENABLE && await this.exists(SQLITE_DESIGN_DOC_ID)) {
59759
+ const definition = await this.get(SQLITE_DESIGN_DOC_ID);
59760
+ definition.sql.tables = {};
59761
+ await this.put(definition);
59762
+ await this.sqlDiskCleanup();
59486
59763
  }
59487
- return appId;
59488
- };
59489
- const getIdentity3 = () => {
59490
- let identity;
59491
59764
  try {
59492
- identity = getIdentity();
59493
- } catch (e) {
59765
+ return await this.nano().db.destroy(this.name);
59766
+ } catch (err) {
59767
+ if (err.statusCode === 404) {
59768
+ return;
59769
+ } else {
59770
+ throw new CouchDBError(err.message, err);
59771
+ }
59494
59772
  }
59495
- return identity;
59496
- };
59497
- }
59498
- var logger = pinoInstance;
59499
-
59500
- // src/logging/alerts.ts
59501
- var NonErrors = ["AccountError"];
59502
- function isSuppressed(e) {
59503
- return e && e["suppressAlert"];
59504
- }
59505
- function logAlert(message, e) {
59506
- if (e && NonErrors.includes(e.name) && isSuppressed(e)) {
59507
- return;
59508
59773
  }
59509
- console.error(`bb-alert: ${message}`, e);
59510
- }
59511
- function logAlertWithInfo(message, db, id, error) {
59512
- message = `${message} - db: ${db} - doc: ${id} - error: `;
59513
- logAlert(message, error);
59514
- }
59515
- function logWarn(message, e) {
59516
- console.warn(`bb-warn: ${message}`, e);
59517
- }
59518
-
59519
- // src/timers/index.ts
59520
- var timers_exports = {};
59521
- __export(timers_exports, {
59522
- cleanup: () => cleanup,
59523
- clear: () => clear,
59524
- set: () => set
59525
- });
59774
+ async compact() {
59775
+ return this.performCall((db) => {
59776
+ return () => db.compact();
59777
+ });
59778
+ }
59779
+ // All below functions are in-frequently called, just utilise PouchDB
59780
+ // for them as it implements them better than we can
59781
+ async dump(stream3, opts) {
59782
+ const pouch = getPouchDB(this.name);
59783
+ return pouch.dump(stream3, opts);
59784
+ }
59785
+ async load(stream3) {
59786
+ const pouch = getPouchDB(this.name);
59787
+ return pouch.load(stream3);
59788
+ }
59789
+ async createIndex(opts) {
59790
+ const pouch = getPouchDB(this.name);
59791
+ return pouch.createIndex(opts);
59792
+ }
59793
+ async deleteIndex(opts) {
59794
+ const pouch = getPouchDB(this.name);
59795
+ return pouch.deleteIndex(opts);
59796
+ }
59797
+ async getIndexes() {
59798
+ const pouch = getPouchDB(this.name);
59799
+ return pouch.getIndexes();
59800
+ }
59801
+ };
59526
59802
 
59527
- // src/timers/timers.ts
59528
- var intervals = [];
59529
- function set(callback, period) {
59530
- const interval = setInterval(callback, period);
59531
- intervals.push(interval);
59532
- return interval;
59803
+ // src/db/db.ts
59804
+ function getDB(dbName, opts) {
59805
+ return new DDInstrumentedDatabase(new DatabaseImpl(dbName, opts));
59533
59806
  }
59534
- function clear(interval) {
59535
- const idx = intervals.indexOf(interval);
59536
- if (idx !== -1) {
59537
- intervals.splice(idx, 1);
59538
- }
59539
- clearInterval(interval);
59807
+ async function doWithDB(dbName, cb, opts) {
59808
+ const db = getDB(dbName, opts);
59809
+ return await cb(db);
59540
59810
  }
59541
- function cleanup() {
59542
- for (let interval of intervals) {
59543
- clearInterval(interval);
59811
+ async function directCouchAllDbs(queryString) {
59812
+ let couchPath = "/_all_dbs";
59813
+ if (queryString) {
59814
+ couchPath += `?${queryString}`;
59544
59815
  }
59545
- intervals = [];
59816
+ return await directCouchQuery(couchPath);
59817
+ }
59818
+ async function directCouchFind(dbName, opts) {
59819
+ const json = await directCouchQuery(`${dbName}/_find`, "POST", opts);
59820
+ return { rows: json.docs, bookmark: json.bookmark };
59546
59821
  }
59547
59822
 
59548
- // src/redis/redis.ts
59549
- var MockRedis;
59550
- if (environment_default.MOCK_REDIS) {
59551
- try {
59552
- MockRedis = require("ioredis-mock");
59553
- } catch (err) {
59554
- console.log("Mock redis unavailable");
59823
+ // src/context/mainContext.ts
59824
+ var TEST_APP_ID = null;
59825
+ function getGlobalDBName(tenantId) {
59826
+ if (!tenantId) {
59827
+ tenantId = getTenantId();
59555
59828
  }
59829
+ return baseGlobalDBName(tenantId);
59556
59830
  }
59557
- var RETRY_PERIOD_MS = 2e3;
59558
- var STARTUP_TIMEOUT_MS = 5e3;
59559
- var CLUSTERED = environment_default.REDIS_CLUSTERED;
59560
- var DEFAULT_SELECT_DB = 0 /* DEFAULT */;
59561
- var CLOSED = false;
59562
- var CLIENTS = {};
59563
- var CONNECTED = false;
59564
- if (environment_default.MOCK_REDIS) {
59565
- CONNECTED = true;
59566
- }
59567
- function pickClient(selectDb) {
59568
- return CLIENTS[selectDb];
59569
- }
59570
- function connectionError(timeout2, err) {
59571
- if (CLOSED) {
59572
- return;
59831
+ function getAuditLogDBName(tenantId) {
59832
+ if (!tenantId) {
59833
+ tenantId = getTenantId();
59573
59834
  }
59574
- CLOSED = true;
59575
- clearTimeout(timeout2);
59576
- CONNECTED = false;
59577
- logAlert("Redis connection failed", err);
59578
- setTimeout(() => {
59579
- init2();
59580
- }, RETRY_PERIOD_MS);
59581
- }
59582
- function init2(selectDb = DEFAULT_SELECT_DB) {
59583
- const RedisCore = environment_default.MOCK_REDIS && MockRedis ? MockRedis : import_ioredis.default;
59584
- let timeout2;
59585
- CLOSED = false;
59586
- let client = pickClient(selectDb);
59587
- if (client && CONNECTED) {
59588
- return;
59835
+ if (tenantId === DEFAULT_TENANT_ID) {
59836
+ return StaticDatabases.AUDIT_LOGS.name;
59837
+ } else {
59838
+ return `${tenantId}${SEPARATOR}${StaticDatabases.AUDIT_LOGS.name}`;
59589
59839
  }
59590
- if (environment_default.MOCK_REDIS) {
59591
- CLIENTS[selectDb] = new RedisCore(getRedisOptions());
59840
+ }
59841
+ function getScimDBName(tenantId) {
59842
+ if (!tenantId) {
59843
+ tenantId = getTenantId();
59592
59844
  }
59593
- timeout2 = setTimeout(() => {
59594
- if (!CONNECTED) {
59595
- connectionError(timeout2, "Did not successfully connect in timeout");
59596
- }
59597
- }, STARTUP_TIMEOUT_MS);
59598
- if (client) {
59599
- client.disconnect();
59845
+ if (tenantId === DEFAULT_TENANT_ID) {
59846
+ return StaticDatabases.SCIM_LOGS.name;
59847
+ } else {
59848
+ return `${tenantId}${SEPARATOR}${StaticDatabases.SCIM_LOGS.name}`;
59600
59849
  }
59601
- const { host, port } = getRedisConnectionDetails();
59602
- const opts = getRedisOptions();
59603
- if (CLUSTERED) {
59604
- client = new RedisCore.Cluster([{ host, port }], opts);
59850
+ }
59851
+ function baseGlobalDBName(tenantId) {
59852
+ if (!tenantId || tenantId === DEFAULT_TENANT_ID) {
59853
+ return StaticDatabases.GLOBAL.name;
59605
59854
  } else {
59606
- client = new RedisCore(opts);
59855
+ return `${tenantId}${SEPARATOR}${StaticDatabases.GLOBAL.name}`;
59607
59856
  }
59608
- client.on("end", (err) => {
59609
- if (environment_default.isTest()) {
59610
- return;
59611
- }
59612
- connectionError(timeout2, err);
59613
- });
59614
- client.on("error", (err) => {
59615
- connectionError(timeout2, err);
59616
- });
59617
- client.on("connect", () => {
59618
- console.log(`Connected to Redis DB: ${selectDb}`);
59619
- clearTimeout(timeout2);
59620
- CONNECTED = true;
59621
- });
59622
- CLIENTS[selectDb] = client;
59623
59857
  }
59624
- function waitForConnection(selectDb = DEFAULT_SELECT_DB) {
59625
- return new Promise((resolve) => {
59626
- if (pickClient(selectDb) == null) {
59627
- init2();
59628
- } else if (CONNECTED) {
59629
- resolve("");
59630
- return;
59631
- }
59632
- const interval = set(() => {
59633
- if (CONNECTED) {
59634
- clear(interval);
59635
- resolve("");
59636
- }
59637
- }, 500);
59638
- });
59858
+ function getPlatformURL() {
59859
+ return environment_default.PLATFORM_URL;
59639
59860
  }
59640
- function promisifyStream(stream3, client) {
59641
- return new Promise((resolve, reject) => {
59642
- const outputKeys = /* @__PURE__ */ new Set();
59643
- stream3.on("data", (keys2) => {
59644
- keys2.forEach((key) => {
59645
- outputKeys.add(key);
59646
- });
59647
- });
59648
- stream3.on("error", (err) => {
59649
- reject(err);
59650
- });
59651
- stream3.on("end", async () => {
59652
- const keysArray = Array.from(outputKeys);
59653
- try {
59654
- let getPromises = [];
59655
- for (let key of keysArray) {
59656
- getPromises.push(client.get(key));
59657
- }
59658
- const jsonArray = await Promise.all(getPromises);
59659
- resolve(
59660
- keysArray.map((key) => ({
59661
- key: removeDbPrefix(key),
59662
- value: JSON.parse(jsonArray.shift())
59663
- }))
59664
- );
59665
- } catch (err) {
59666
- reject(err);
59667
- }
59668
- });
59669
- });
59861
+ function isMultiTenant() {
59862
+ return !!environment_default.MULTI_TENANCY;
59670
59863
  }
59671
- var RedisWrapper = class {
59672
- constructor(db, selectDb = null) {
59673
- this._db = db;
59674
- this._select = selectDb || DEFAULT_SELECT_DB;
59675
- }
59676
- getClient() {
59677
- return pickClient(this._select);
59678
- }
59679
- async init() {
59680
- CLOSED = false;
59681
- init2(this._select);
59682
- await waitForConnection(this._select);
59683
- if (this._select && !environment_default.isTest()) {
59684
- this.getClient().select(this._select);
59685
- }
59686
- return this;
59687
- }
59688
- async finish() {
59689
- CLOSED = true;
59690
- this.getClient().disconnect();
59691
- }
59692
- async scan(key = "") {
59693
- const db = this._db;
59694
- key = `${db}${SEPARATOR2}${key}`;
59695
- let stream3;
59696
- if (CLUSTERED) {
59697
- let node = this.getClient().nodes("master");
59698
- stream3 = node[0].scanStream({ match: key + "*", count: 100 });
59699
- } else {
59700
- stream3 = this.getClient().scanStream({
59701
- match: key + "*",
59702
- count: 100
59703
- });
59704
- }
59705
- return promisifyStream(stream3, this.getClient());
59706
- }
59707
- async keys(pattern) {
59708
- const db = this._db;
59709
- return this.getClient().keys(addDbPrefix(db, pattern));
59710
- }
59711
- async exists(key) {
59712
- const db = this._db;
59713
- return await this.getClient().exists(addDbPrefix(db, key));
59864
+ function isTenantIdSet() {
59865
+ const context = Context.get();
59866
+ return !!context?.tenantId;
59867
+ }
59868
+ function isTenancyEnabled() {
59869
+ return environment_default.MULTI_TENANCY;
59870
+ }
59871
+ function getTenantIDFromAppID(appId) {
59872
+ if (!appId) {
59873
+ return void 0;
59714
59874
  }
59715
- async get(key) {
59716
- const db = this._db;
59717
- const response = await this.getClient().get(addDbPrefix(db, key));
59718
- if (response != null && response.key) {
59719
- response.key = key;
59720
- }
59721
- try {
59722
- return JSON.parse(response);
59723
- } catch (err) {
59724
- return response;
59725
- }
59875
+ if (!isMultiTenant()) {
59876
+ return DEFAULT_TENANT_ID;
59726
59877
  }
59727
- async bulkGet(keys2) {
59728
- const db = this._db;
59729
- if (keys2.length === 0) {
59730
- return {};
59731
- }
59732
- const prefixedKeys = keys2.map((key) => addDbPrefix(db, key));
59733
- let response = await this.getClient().mget(prefixedKeys);
59734
- if (Array.isArray(response)) {
59735
- let final = {};
59736
- let count = 0;
59737
- for (let result of response) {
59738
- if (result) {
59739
- let parsed;
59740
- try {
59741
- parsed = JSON.parse(result);
59742
- } catch (err) {
59743
- parsed = result;
59744
- }
59745
- final[keys2[count]] = parsed;
59746
- }
59747
- count++;
59748
- }
59749
- return final;
59750
- } else {
59751
- throw new Error(`Invalid response: ${response}`);
59752
- }
59878
+ const split = appId.split(SEPARATOR);
59879
+ const hasDev = split[1] === "dev" /* DEV */;
59880
+ if (hasDev && split.length === 3 || !hasDev && split.length === 2) {
59881
+ return void 0;
59753
59882
  }
59754
- async store(key, value, expirySeconds = null) {
59755
- const db = this._db;
59756
- if (typeof value === "object") {
59757
- value = JSON.stringify(value);
59758
- }
59759
- const prefixedKey = addDbPrefix(db, key);
59760
- await this.getClient().set(prefixedKey, value);
59761
- if (expirySeconds) {
59762
- await this.getClient().expire(prefixedKey, expirySeconds);
59763
- }
59883
+ if (hasDev) {
59884
+ return split[2];
59885
+ } else {
59886
+ return split[1];
59764
59887
  }
59765
- async bulkStore(data, expirySeconds = null) {
59766
- const client = this.getClient();
59767
- const dataToStore = Object.entries(data).reduce((acc, [key, value]) => {
59768
- acc[addDbPrefix(this._db, key)] = typeof value === "object" ? JSON.stringify(value) : value;
59769
- return acc;
59770
- }, {});
59771
- const pipeline = client.pipeline();
59772
- pipeline.mset(dataToStore);
59773
- if (expirySeconds !== null) {
59774
- for (const key of Object.keys(dataToStore)) {
59775
- pipeline.expire(key, expirySeconds);
59776
- }
59777
- }
59778
- await pipeline.exec();
59888
+ }
59889
+ function updateContext(updates) {
59890
+ let context;
59891
+ try {
59892
+ context = Context.get();
59893
+ } catch (err) {
59894
+ context = {};
59779
59895
  }
59780
- async getTTL(key) {
59781
- const db = this._db;
59782
- const prefixedKey = addDbPrefix(db, key);
59783
- return this.getClient().ttl(prefixedKey);
59896
+ context = {
59897
+ ...context,
59898
+ ...updates
59899
+ };
59900
+ return context;
59901
+ }
59902
+ async function newContext(updates, task) {
59903
+ guardMigration();
59904
+ let context = updateContext(updates);
59905
+ return Context.run(context, task);
59906
+ }
59907
+ async function doInAutomationContext(params2) {
59908
+ await ensureSnippetContext();
59909
+ return newContext(
59910
+ {
59911
+ tenantId: getTenantIDFromAppID(params2.appId),
59912
+ appId: params2.appId,
59913
+ automationId: params2.automationId
59914
+ },
59915
+ params2.task
59916
+ );
59917
+ }
59918
+ async function doInContext(appId, task) {
59919
+ const tenantId = getTenantIDFromAppID(appId);
59920
+ return newContext(
59921
+ {
59922
+ tenantId,
59923
+ appId
59924
+ },
59925
+ task
59926
+ );
59927
+ }
59928
+ async function doInTenant(tenantId, task) {
59929
+ if (!environment_default.MULTI_TENANCY) {
59930
+ tenantId = tenantId || DEFAULT_TENANT_ID;
59784
59931
  }
59785
- async setExpiry(key, expirySeconds) {
59786
- const db = this._db;
59787
- const prefixedKey = addDbPrefix(db, key);
59788
- await this.getClient().expire(prefixedKey, expirySeconds);
59932
+ const updates = tenantId ? { tenantId } : {};
59933
+ return newContext(updates, task);
59934
+ }
59935
+ async function doInAppContext(appId, task) {
59936
+ return _doInAppContext(appId, task);
59937
+ }
59938
+ async function _doInAppContext(appId, task, extraContextSettings) {
59939
+ if (!appId) {
59940
+ throw new Error("appId is required");
59789
59941
  }
59790
- async delete(key) {
59791
- const db = this._db;
59792
- await this.getClient().del(addDbPrefix(db, key));
59942
+ const tenantId = getTenantIDFromAppID(appId);
59943
+ const updates = { appId, ...extraContextSettings };
59944
+ if (tenantId) {
59945
+ updates.tenantId = tenantId;
59793
59946
  }
59794
- async bulkDelete(keys2) {
59795
- const db = this._db;
59796
- await this.getClient().del(keys2.map((key) => addDbPrefix(db, key)));
59947
+ return newContext(updates, task);
59948
+ }
59949
+ async function doInIdentityContext(identity, task) {
59950
+ if (!identity) {
59951
+ throw new Error("identity is required");
59797
59952
  }
59798
- async clear() {
59799
- let items = await this.scan();
59800
- await Promise.all(items.map((obj) => this.delete(obj.key)));
59953
+ const context = {
59954
+ identity
59955
+ };
59956
+ if (identity.tenantId) {
59957
+ context.tenantId = identity.tenantId;
59801
59958
  }
59802
- async increment(key) {
59803
- const result = await this.getClient().incr(addDbPrefix(this._db, key));
59804
- if (isNaN(result)) {
59805
- throw new Error(`Redis ${key} does not contain a number`);
59806
- }
59807
- return result;
59959
+ return newContext(context, task);
59960
+ }
59961
+ function guardMigration() {
59962
+ const context = Context.get();
59963
+ if (context?.isMigrating) {
59964
+ throw new Error(
59965
+ "The context cannot be changed, a migration is currently running"
59966
+ );
59808
59967
  }
59809
- async deleteIfValue(key, value) {
59810
- const client = this.getClient();
59811
- const luaScript = `
59812
- if redis.call('GET', KEYS[1]) == ARGV[1] then
59813
- redis.call('DEL', KEYS[1])
59814
- end
59815
- `;
59816
- await client.eval(luaScript, 1, addDbPrefix(this._db, key), value);
59968
+ }
59969
+ async function doInAppMigrationContext(appId, task) {
59970
+ return _doInAppContext(appId, task, {
59971
+ isMigrating: true
59972
+ });
59973
+ }
59974
+ function getIdentity() {
59975
+ try {
59976
+ const context = Context.get();
59977
+ return context?.identity;
59978
+ } catch (e) {
59817
59979
  }
59818
- };
59819
- var redis_default = RedisWrapper;
59820
-
59821
- // src/redis/init.ts
59822
- var userClient;
59823
- var sessionClient;
59824
- var appClient;
59825
- var cacheClient;
59826
- var writethroughClient;
59827
- var lockClient;
59828
- var socketClient;
59829
- var inviteClient;
59830
- var passwordResetClient;
59831
- var docWritethroughClient;
59832
- async function init3() {
59833
- userClient = await new redis_default("users" /* USER_CACHE */).init();
59834
- sessionClient = await new redis_default("session" /* SESSIONS */).init();
59835
- appClient = await new redis_default("appMetadata" /* APP_METADATA */).init();
59836
- cacheClient = await new redis_default("data_cache" /* GENERIC_CACHE */).init();
59837
- lockClient = await new redis_default("locks" /* LOCKS */).init();
59838
- writethroughClient = await new redis_default("writeThrough" /* WRITE_THROUGH */).init();
59839
- inviteClient = await new redis_default("invitation" /* INVITATIONS */).init();
59840
- passwordResetClient = await new redis_default("pwReset" /* PW_RESETS */).init();
59841
- socketClient = await new redis_default(
59842
- "socket_io" /* SOCKET_IO */,
59843
- 1 /* SOCKET_IO */
59844
- ).init();
59845
- docWritethroughClient = await new redis_default(
59846
- "docWriteThrough" /* DOC_WRITE_THROUGH */
59847
- ).init();
59848
59980
  }
59849
- async function shutdown() {
59850
- if (userClient)
59851
- await userClient.finish();
59852
- if (sessionClient)
59853
- await sessionClient.finish();
59854
- if (appClient)
59855
- await appClient.finish();
59856
- if (cacheClient)
59857
- await cacheClient.finish();
59858
- if (writethroughClient)
59859
- await writethroughClient.finish();
59860
- if (lockClient)
59861
- await lockClient.finish();
59862
- if (inviteClient)
59863
- await inviteClient.finish();
59864
- if (passwordResetClient)
59865
- await passwordResetClient.finish();
59866
- if (socketClient)
59867
- await socketClient.finish();
59868
- if (docWritethroughClient)
59869
- await docWritethroughClient.finish();
59981
+ function getTenantId() {
59982
+ if (!isMultiTenant()) {
59983
+ return DEFAULT_TENANT_ID;
59984
+ }
59985
+ const context = Context.get();
59986
+ const tenantId = context?.tenantId;
59987
+ if (!tenantId) {
59988
+ throw new Error("Tenant id not found");
59989
+ }
59990
+ return tenantId;
59870
59991
  }
59871
- process.on("exit", async () => {
59872
- await shutdown();
59873
- });
59874
- async function getUserClient() {
59875
- if (!userClient) {
59876
- await init3();
59992
+ function getAutomationId() {
59993
+ const context = Context.get();
59994
+ return context?.automationId;
59995
+ }
59996
+ function getAppId() {
59997
+ const context = Context.get();
59998
+ const foundId = context?.appId;
59999
+ if (!foundId && environment_default.isTest() && TEST_APP_ID) {
60000
+ return TEST_APP_ID;
60001
+ } else {
60002
+ return foundId;
59877
60003
  }
59878
- return userClient;
59879
60004
  }
59880
- async function getSessionClient() {
59881
- if (!sessionClient) {
59882
- await init3();
60005
+ var getProdAppId = () => {
60006
+ const appId = getAppId();
60007
+ if (!appId) {
60008
+ throw new Error("Could not get appId");
59883
60009
  }
59884
- return sessionClient;
60010
+ return getProdAppID2(appId);
60011
+ };
60012
+ function doInEnvironmentContext(values2, task) {
60013
+ if (!values2) {
60014
+ throw new Error("Must supply environment variables.");
60015
+ }
60016
+ const updates = {
60017
+ environmentVariables: values2
60018
+ };
60019
+ return newContext(updates, task);
59885
60020
  }
59886
- async function getAppClient() {
59887
- if (!appClient) {
59888
- await init3();
60021
+ function doInScimContext(task) {
60022
+ const updates = {
60023
+ isScim: true
60024
+ };
60025
+ return newContext(updates, task);
60026
+ }
60027
+ async function ensureSnippetContext(enabled2 = !environment_default.isTest()) {
60028
+ const ctx = getCurrentContext();
60029
+ if (!ctx || ctx.snippets) {
60030
+ return;
59889
60031
  }
59890
- return appClient;
60032
+ let snippets;
60033
+ const db = getAppDB();
60034
+ if (db && enabled2) {
60035
+ const app = await db.get("app_metadata" /* APP_METADATA */);
60036
+ snippets = app.snippets;
60037
+ }
60038
+ ctx.snippets = snippets || [];
59891
60039
  }
59892
- async function getCacheClient() {
59893
- if (!cacheClient) {
59894
- await init3();
60040
+ function getEnvironmentVariables() {
60041
+ const context = Context.get();
60042
+ if (!context.environmentVariables) {
60043
+ return null;
60044
+ } else {
60045
+ return context.environmentVariables;
59895
60046
  }
59896
- return cacheClient;
59897
60047
  }
59898
- async function getWritethroughClient() {
59899
- if (!writethroughClient) {
59900
- await init3();
60048
+ function getGlobalDB() {
60049
+ const context = Context.get();
60050
+ if (!context || environment_default.MULTI_TENANCY && !context.tenantId) {
60051
+ throw new Error("Global DB not found");
59901
60052
  }
59902
- return writethroughClient;
60053
+ return getDB(baseGlobalDBName(context?.tenantId));
59903
60054
  }
59904
- async function getLockClient() {
59905
- if (!lockClient) {
59906
- await init3();
60055
+ function getAuditLogsDB() {
60056
+ if (!getTenantId()) {
60057
+ throw new Error("No tenant ID found - cannot open audit log DB");
59907
60058
  }
59908
- return lockClient;
60059
+ return getDB(getAuditLogDBName());
59909
60060
  }
59910
- async function getSocketClient() {
59911
- if (!socketClient) {
59912
- await init3();
60061
+ function getAppDB(opts) {
60062
+ const appId = getAppId();
60063
+ if (!appId) {
60064
+ throw new Error("Unable to retrieve app DB - no app ID.");
59913
60065
  }
59914
- return socketClient;
60066
+ return getDB(appId, opts);
59915
60067
  }
59916
- async function getInviteClient() {
59917
- if (!inviteClient) {
59918
- await init3();
60068
+ function getProdAppDB(opts) {
60069
+ const appId = getAppId();
60070
+ if (!appId) {
60071
+ throw new Error("Unable to retrieve prod DB - no app ID.");
59919
60072
  }
59920
- return inviteClient;
60073
+ return getDB(getProdAppID2(appId), opts);
59921
60074
  }
59922
- async function getPasswordResetClient() {
59923
- if (!passwordResetClient) {
59924
- await init3();
60075
+ function getDevAppDB(opts) {
60076
+ const appId = getAppId();
60077
+ if (!appId) {
60078
+ throw new Error("Unable to retrieve dev DB - no app ID.");
59925
60079
  }
59926
- return passwordResetClient;
60080
+ return getDB(getDevelopmentAppID(appId), opts);
59927
60081
  }
59928
- async function getDocWritethroughClient() {
59929
- if (!writethroughClient) {
59930
- await init3();
60082
+ function isScim() {
60083
+ const context = Context.get();
60084
+ const scimCall = context?.isScim;
60085
+ return !!scimCall;
60086
+ }
60087
+ function getCurrentContext() {
60088
+ try {
60089
+ return Context.get();
60090
+ } catch (e) {
60091
+ return void 0;
59931
60092
  }
59932
- return writethroughClient;
59933
60093
  }
59934
60094
 
59935
60095
  // src/cache/base/index.ts
@@ -60332,8 +60492,8 @@ __export(redlockImpl_exports, {
60332
60492
  var import_redlock = __toESM(require("redlock"));
60333
60493
 
60334
60494
  // src/utils/index.ts
60335
- var utils_exports3 = {};
60336
- __export(utils_exports3, {
60495
+ var utils_exports4 = {};
60496
+ __export(utils_exports4, {
60337
60497
  Duration: () => Duration,
60338
60498
  DurationType: () => DurationType,
60339
60499
  clearCookie: () => clearCookie,
@@ -60906,8 +61066,8 @@ __export(users_exports3, {
60906
61066
  });
60907
61067
 
60908
61068
  // src/users/utils.ts
60909
- var utils_exports4 = {};
60910
- __export(utils_exports4, {
61069
+ var utils_exports5 = {};
61070
+ __export(utils_exports5, {
60911
61071
  getAccountHolderFromUserIds: () => getAccountHolderFromUserIds,
60912
61072
  hasAdminPermissions: () => hasAdminPermissions2,
60913
61073
  hasAppBuilderPermissions: () => hasAppBuilderPermissions2,
@@ -64440,18 +64600,17 @@ var UserDB = class _UserDB {
64440
64600
  }
64441
64601
  const tenantId = getTenantId();
64442
64602
  const db = getGlobalDB();
64443
- let { email, _id, userGroups = [], roles } = user;
64603
+ const { email, _id, userGroups = [], roles } = user;
64444
64604
  if (!email && !_id) {
64445
64605
  throw new Error("_id or email is required");
64446
64606
  }
64447
64607
  let dbUser;
64448
64608
  if (_id) {
64449
64609
  try {
64450
- dbUser = await db.get(_id);
64451
- if (email && dbUser.email !== email) {
64452
- throw "Email address cannot be changed";
64610
+ dbUser = await getById(_id);
64611
+ if (email && dbUser.email !== email && !opts.allowChangingEmail) {
64612
+ throw new Error("Email address cannot be changed");
64453
64613
  }
64454
- email = dbUser.email;
64455
64614
  } catch (e) {
64456
64615
  if (e.status === 404) {
64457
64616
  } else {
@@ -64476,12 +64635,13 @@ var UserDB = class _UserDB {
64476
64635
  if (!dbUser && roles?.length) {
64477
64636
  builtUser.roles = { ...roles };
64478
64637
  }
64479
- let groupPromises = [];
64638
+ const groupPromises = [];
64480
64639
  if (!_id) {
64481
- _id = builtUser._id;
64482
64640
  if (userGroups.length > 0) {
64483
64641
  for (let groupId of userGroups) {
64484
- groupPromises.push(_UserDB.groups.addUsers(groupId, [_id]));
64642
+ groupPromises.push(
64643
+ _UserDB.groups.addUsers(groupId, [builtUser._id])
64644
+ );
64485
64645
  }
64486
64646
  }
64487
64647
  }
@@ -64489,6 +64649,9 @@ var UserDB = class _UserDB {
64489
64649
  let response = await db.put(builtUser);
64490
64650
  builtUser._rev = response.rev;
64491
64651
  await handleSaveEvents(builtUser, dbUser);
64652
+ if (dbUser && builtUser.email !== dbUser.email) {
64653
+ await users_exports2.removeUser({ email: dbUser.email });
64654
+ }
64492
64655
  await users_exports2.addUser(
64493
64656
  tenantId,
64494
64657
  builtUser._id,
@@ -66594,6 +66757,23 @@ var correlation = (ctx, next) => {
66594
66757
  };
66595
66758
  var middleware_default2 = correlation;
66596
66759
 
66760
+ // src/security/secrets.ts
66761
+ function stringContainsSecret(str) {
66762
+ if (str.includes("-----BEGIN PRIVATE KEY-----")) {
66763
+ return true;
66764
+ }
66765
+ for (const key of SECRETS) {
66766
+ const value = environment_default[key];
66767
+ if (typeof value !== "string" || value === "") {
66768
+ continue;
66769
+ }
66770
+ if (str.includes(value)) {
66771
+ return true;
66772
+ }
66773
+ }
66774
+ return false;
66775
+ }
66776
+
66597
66777
  // src/middleware/errorHandling.ts
66598
66778
  async function errorHandling(ctx, next) {
66599
66779
  try {
@@ -66612,6 +66792,13 @@ async function errorHandling(ctx, next) {
66612
66792
  validationErrors: err.validation,
66613
66793
  error: getPublicError(err)
66614
66794
  };
66795
+ if (stringContainsSecret(JSON.stringify(error))) {
66796
+ error = {
66797
+ message: "Unexpected error",
66798
+ status,
66799
+ error: "Unexpected error"
66800
+ };
66801
+ }
66615
66802
  if (environment_default.isTest() && ctx.headers["x-budibase-include-stacktrace"]) {
66616
66803
  error.stack = err.stack;
66617
66804
  }
@@ -67099,123 +67286,8 @@ __export(sql_exports, {
67099
67286
  Sql: () => sql_default,
67100
67287
  SqlTable: () => sqlTable_default,
67101
67288
  designDoc: () => designDoc_exports,
67102
- utils: () => utils_exports5
67103
- });
67104
-
67105
- // src/sql/utils.ts
67106
- var utils_exports5 = {};
67107
- __export(utils_exports5, {
67108
- breakExternalTableId: () => breakExternalTableId,
67109
- breakRowIdField: () => breakRowIdField,
67110
- buildExternalTableId: () => buildExternalTableId,
67111
- convertRowId: () => convertRowId,
67112
- generateRowIdField: () => generateRowIdField,
67113
- getNativeSql: () => getNativeSql,
67114
- isExternalTable: () => isExternalTable,
67115
- isExternalTableID: () => isExternalTableID,
67116
- isInternalTableID: () => isInternalTableID,
67117
- isIsoDateString: () => isIsoDateString,
67118
- isRowId: () => isRowId,
67119
- isValidFilter: () => isValidFilter
67289
+ utils: () => utils_exports3
67120
67290
  });
67121
- var DOUBLE_SEPARATOR = `${SEPARATOR}${SEPARATOR}`;
67122
- var ROW_ID_REGEX = /^\[.*]$/g;
67123
- var ENCODED_SPACE = encodeURIComponent(" ");
67124
- function isExternalTableID(tableId) {
67125
- return tableId.startsWith("datasource" /* DATASOURCE */ + SEPARATOR);
67126
- }
67127
- function isInternalTableID(tableId) {
67128
- return !isExternalTableID(tableId);
67129
- }
67130
- function getNativeSql(query) {
67131
- let sql = query.toSQL();
67132
- if (Array.isArray(sql)) {
67133
- return sql;
67134
- }
67135
- let native;
67136
- if (sql.toNative) {
67137
- native = sql.toNative();
67138
- }
67139
- return {
67140
- sql: native?.sql || sql.sql,
67141
- bindings: native?.bindings || sql.bindings
67142
- };
67143
- }
67144
- function isExternalTable(table) {
67145
- if (table?.sourceId && table.sourceId.includes("datasource" /* DATASOURCE */ + SEPARATOR) && table?.sourceId !== DEFAULT_BB_DATASOURCE_ID) {
67146
- return true;
67147
- } else if (table?.sourceType === "external" /* EXTERNAL */) {
67148
- return true;
67149
- } else if (table?._id && isExternalTableID(table._id)) {
67150
- return true;
67151
- }
67152
- return false;
67153
- }
67154
- function buildExternalTableId(datasourceId, tableName) {
67155
- if (tableName.includes(" ")) {
67156
- tableName = encodeURIComponent(tableName);
67157
- }
67158
- return `${datasourceId}${DOUBLE_SEPARATOR}${tableName}`;
67159
- }
67160
- function breakExternalTableId(tableId) {
67161
- const parts = tableId.split(DOUBLE_SEPARATOR);
67162
- let datasourceId = parts.shift();
67163
- let tableName = parts.join(DOUBLE_SEPARATOR);
67164
- if (tableName.includes(ENCODED_SPACE)) {
67165
- tableName = decodeURIComponent(tableName);
67166
- }
67167
- if (!datasourceId || !tableName) {
67168
- throw new Error("Unable to get datasource/table name from table ID");
67169
- }
67170
- return { datasourceId, tableName };
67171
- }
67172
- function generateRowIdField(keyProps = []) {
67173
- if (!Array.isArray(keyProps)) {
67174
- keyProps = [keyProps];
67175
- }
67176
- for (let index2 in keyProps) {
67177
- if (keyProps[index2] instanceof Buffer) {
67178
- keyProps[index2] = keyProps[index2].toString();
67179
- }
67180
- }
67181
- return encodeURIComponent(JSON.stringify(keyProps).replace(/"/g, "'"));
67182
- }
67183
- function isRowId(field) {
67184
- return Array.isArray(field) || typeof field === "string" && field.match(ROW_ID_REGEX) != null;
67185
- }
67186
- function convertRowId(field) {
67187
- if (Array.isArray(field)) {
67188
- return field[0];
67189
- }
67190
- if (typeof field === "string" && field.match(ROW_ID_REGEX) != null) {
67191
- return field.substring(1, field.length - 1);
67192
- }
67193
- return field;
67194
- }
67195
- function breakRowIdField(_id) {
67196
- if (!_id) {
67197
- return [];
67198
- }
67199
- const id = typeof _id === "string" ? _id : _id._id;
67200
- const decoded = decodeURIComponent(id).replace(/'/g, '"');
67201
- try {
67202
- const parsed = JSON.parse(decoded);
67203
- return Array.isArray(parsed) ? parsed : [parsed];
67204
- } catch (err) {
67205
- return [_id];
67206
- }
67207
- }
67208
- function isIsoDateString(str) {
67209
- const trimmedValue = str.trim();
67210
- if (!/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}.\d{3}Z$/.test(trimmedValue)) {
67211
- return false;
67212
- }
67213
- let d = new Date(trimmedValue);
67214
- return d.toISOString() === trimmedValue;
67215
- }
67216
- function isValidFilter(value) {
67217
- return value != null && value !== "";
67218
- }
67219
67291
 
67220
67292
  // src/sql/sql.ts
67221
67293
  var import_knex2 = require("knex");
@@ -67490,8 +67562,6 @@ var sqlTable_default = SqlTableQueryBuilder;
67490
67562
  // src/sql/sql.ts
67491
67563
  var envLimit = environment_default.SQL_MAX_ROWS ? parseInt(environment_default.SQL_MAX_ROWS) : null;
67492
67564
  var BASE_LIMIT = envLimit || 5e3;
67493
- var MIN_ISO_DATE = "0000-00-00T00:00:00.000Z";
67494
- var MAX_ISO_DATE = "9999-00-00T00:00:00.000Z";
67495
67565
  function likeKey(client, key) {
67496
67566
  let start2, end2;
67497
67567
  switch (client) {
@@ -67524,10 +67594,10 @@ function parse(input) {
67524
67594
  if (typeof input !== "string") {
67525
67595
  return input;
67526
67596
  }
67527
- if (input === MAX_ISO_DATE || input === MIN_ISO_DATE) {
67597
+ if (isInvalidISODateString(input)) {
67528
67598
  return null;
67529
67599
  }
67530
- if (isIsoDateString(input)) {
67600
+ if (isValidISODateString(input)) {
67531
67601
  return new Date(input.trim());
67532
67602
  }
67533
67603
  return input;
@@ -68215,15 +68285,7 @@ var SqlQueryBuilder = class extends sqlTable_default {
68215
68285
  return JsonTypes.includes(field.type) && !helpers_exports.schema.isDeprecatedSingleUserColumn(field);
68216
68286
  }
68217
68287
  log(query, values2) {
68218
- if (!environment_default.SQL_LOGGING_ENABLE) {
68219
- return;
68220
- }
68221
- const sqlClient = this.getSqlClient();
68222
- let string = `[SQL] [${sqlClient.toUpperCase()}] query="${query}"`;
68223
- if (values2) {
68224
- string += ` values="${values2.join(", ")}"`;
68225
- }
68226
- console.log(string);
68288
+ sqlLog(this.getSqlClient(), query, values2);
68227
68289
  }
68228
68290
  };
68229
68291
  var sql_default = SqlQueryBuilder;